summaryrefslogtreecommitdiff
path: root/server/infopipe
diff options
context:
space:
mode:
Diffstat (limited to 'server/infopipe')
-rw-r--r--server/infopipe/infopipe.c43
-rw-r--r--server/infopipe/infopipe_groups.c169
-rw-r--r--server/infopipe/infopipe_private.h6
-rw-r--r--server/infopipe/org.freeipa.sssd.infopipe.Introspect.xml2
4 files changed, 217 insertions, 3 deletions
diff --git a/server/infopipe/infopipe.c b/server/infopipe/infopipe.c
index 09ffcbdf..4ec971ca 100644
--- a/server/infopipe/infopipe.c
+++ b/server/infopipe/infopipe.c
@@ -141,6 +141,49 @@ static int infp_monitor_init(struct infp_ctx *infp_ctx)
return EOK;
}
+/* Helper function to return an immediate error message in the event
+ * of internal error in the InfoPipe to avoid forcing the clients to
+ * time out waiting for a reply.
+ */
+void infp_return_failure(struct infp_req_ctx *infp_req, const char *message)
+{
+ DBusMessage *reply;
+
+ reply = dbus_message_new_error(infp_req->req_message,
+ DBUS_ERROR_FAILED,
+ message);
+ /* If the reply was NULL, we ran out of memory, so we won't
+ * bother trying to queue the message to send. In this case,
+ * our safest move is to allow the client to time out waiting
+ * for a reply.
+ */
+ if(reply) {
+ sbus_conn_send_reply(infp_req->sconn, reply);
+ dbus_message_unref(reply);
+ }
+}
+
+/* Helper function to return an ack to the caller to indicate
+ * that the internal process completed succesfully. An ack in
+ * InfoPipe is simply an empty D-BUS method return (as opposed
+ * to a D-BUS error or signal)
+ */
+void infp_return_success(struct infp_req_ctx *infp_req)
+{
+ DBusMessage *reply;
+
+ reply = dbus_message_new_method_return(infp_req->req_message);
+ /* If the reply was NULL, we ran out of memory, so we won't
+ * bother trying to queue the message to send. In this case,
+ * our safest move is to allow the client to time out waiting
+ * for a reply.
+ */
+ if(reply) {
+ sbus_conn_send_reply(infp_req->sconn, reply);
+ dbus_message_unref(reply);
+ }
+}
+
struct sbus_method infp_methods[] = {
INFP_PERMISSION_METHODS
INFP_USER_METHODS
diff --git a/server/infopipe/infopipe_groups.c b/server/infopipe/infopipe_groups.c
index bb3741c9..9aaecf2f 100644
--- a/server/infopipe/infopipe_groups.c
+++ b/server/infopipe/infopipe_groups.c
@@ -657,15 +657,182 @@ int infp_groups_remove_members(DBusMessage *message,
INFP_ACTION_TYPE_REMOVEMEMBER);
}
+struct infp_setgid_ctx {
+ struct infp_req_ctx *infp_req;
+ char *group_name;
+ gid_t gid;
+ struct sysdb_req *sysdb_req;
+};
+
+static void infp_do_gid_callback(void *ptr,
+ int status,
+ struct ldb_result *res)
+{
+ char *error_msg = NULL;
+ struct infp_setgid_ctx *grmod_req =
+ talloc_get_type(ptr, struct infp_setgid_ctx);
+
+ /* Commit or cancel the transaction, based on the
+ * return status
+ */
+ sysdb_transaction_done(grmod_req->sysdb_req, status);
+
+ if(status != EOK) {
+ if (status == ENOENT) {
+ error_msg = talloc_strdup(grmod_req, "No such group");
+ }
+ infp_return_failure(grmod_req->infp_req, error_msg);
+ talloc_free(grmod_req);
+ return;
+ }
+
+ infp_return_success(grmod_req->infp_req);
+ talloc_free(grmod_req);
+}
+
+static void infp_do_gid(struct sysdb_req *req, void *pvt)
+{
+ int ret;
+ DBusMessage *reply;
+ char *error_msg;
+ gid_t max;
+ struct infp_setgid_ctx *grmod_req =
+ talloc_get_type(pvt, struct infp_setgid_ctx);
+ grmod_req->sysdb_req = req;
+
+ ret = sysdb_set_group_gid(grmod_req->sysdb_req,
+ grmod_req->infp_req->domain,
+ grmod_req->group_name,
+ grmod_req->gid,
+ infp_do_gid_callback,
+ grmod_req);
+ if (ret != EOK) {
+ if(ret == EDOM) {
+ /* GID was out of range */
+ max = grmod_req->infp_req->domain->id_max?
+ grmod_req->infp_req->domain->id_max:
+ (gid_t)-1;
+ error_msg = talloc_asprintf(grmod_req,
+ "GID %u outside the range [%u..%u]",
+ grmod_req->gid,
+ grmod_req->infp_req->domain->id_min,
+ max);
+ reply = dbus_message_new_error(grmod_req->infp_req->req_message,
+ DBUS_ERROR_LIMITS_EXCEEDED,
+ error_msg);
+ if (reply) sbus_conn_send_reply(grmod_req->infp_req->sconn, reply);
+ }
+ talloc_free(grmod_req);
+ return;
+ }
+}
+
int infp_groups_set_gid(DBusMessage *message, struct sbus_conn_ctx *sconn)
{
DBusMessage *reply;
+ DBusError error;
+ char *einval_msg;
+ struct infp_setgid_ctx *grmod_req;
+ int ret;
- reply = dbus_message_new_error(message, DBUS_ERROR_NOT_SUPPORTED, "Not yet implemented");
+ /* Arguments */
+ const char *arg_group;
+ const char *arg_domain;
+ const gid_t arg_gid;
+ grmod_req = talloc_zero(NULL, struct infp_setgid_ctx);
+ if (grmod_req == NULL) {
+ ret = ENOMEM;
+ goto error;
+ }
+
+ /* Create an infp_req_ctx */
+ grmod_req->infp_req = infp_req_init(grmod_req, message, sconn);
+ if(grmod_req->infp_req == NULL) {
+ ret = EIO;
+ goto error;
+ }
+
+ dbus_error_init(&error);
+ if (!dbus_message_get_args(message, &error,
+ DBUS_TYPE_STRING, &arg_group,
+ DBUS_TYPE_STRING, &arg_domain,
+ DBUS_TYPE_UINT32, &arg_gid,
+ DBUS_TYPE_INVALID)) {
+ DEBUG(0, ("Parsing arguments to %s failed: %s:%s\n",
+ INFP_GROUPS_SET_GID, error.name, error.message));
+ einval_msg = talloc_strdup(grmod_req, error.message);
+ dbus_error_free(&error);
+ goto einval;
+ }
+
+ /* FIXME: Allow modifying groups on domains other than LOCAL */
+ if (strcasecmp(arg_domain, "LOCAL") != 0) {
+ goto denied;
+ }
+
+ grmod_req->infp_req->domain =
+ btreemap_get_value(grmod_req->infp_req->infp->domain_map,
+ (const void *)arg_domain);
+
+ /* Check for a valid domain */
+ if(grmod_req->infp_req->domain == NULL) {
+ einval_msg = talloc_strdup(grmod_req, "Invalid domain.");
+ goto einval;
+ }
+
+ /* Check permissions */
+ if (!infp_get_permissions(grmod_req->infp_req->caller,
+ grmod_req->infp_req->domain,
+ INFP_OBJ_TYPE_GROUP,
+ arg_group,
+ INFP_ACTION_TYPE_MODIFY,
+ INFP_ATTR_TYPE_GROUPID)) goto denied;
+
+ grmod_req->gid = arg_gid;
+ grmod_req->group_name = talloc_strdup(grmod_req, arg_group);
+ if (grmod_req->group_name == NULL) {
+ ret = ENOMEM;
+ goto error;
+ }
+
+ ret = sysdb_transaction(grmod_req,
+ grmod_req->infp_req->infp->sysdb,
+ infp_do_gid,
+ grmod_req);
+ if (ret != EOK) goto error;
+
+ return EOK;
+
+denied:
+ reply = dbus_message_new_error(message, DBUS_ERROR_ACCESS_DENIED, NULL);
+ if(reply == NULL) {
+ ret = ENOMEM;
+ goto error;
+ }
/* send reply */
sbus_conn_send_reply(sconn, reply);
+ dbus_message_unref(reply);
+ talloc_free(grmod_req);
+ return EOK;
+
+einval:
+ reply = dbus_message_new_error(message,
+ DBUS_ERROR_INVALID_ARGS,
+ einval_msg);
+ if (reply == NULL) {
+ ret = ENOMEM;
+ goto error;
+ }
+ sbus_conn_send_reply(sconn, reply);
dbus_message_unref(reply);
+ talloc_free(grmod_req);
return EOK;
+
+error:
+ talloc_free(grmod_req);
+ return ret;
+
+
}
diff --git a/server/infopipe/infopipe_private.h b/server/infopipe/infopipe_private.h
index 0f523c00..066f11e9 100644
--- a/server/infopipe/infopipe_private.h
+++ b/server/infopipe/infopipe_private.h
@@ -72,7 +72,8 @@ enum infp_attribute_types {
INFP_ATTR_TYPE_SESSION,
INFP_ATTR_TYPE_LAST_LOGIN,
INFP_ATTR_TYPE_USERPIC,
- INFP_ATTR_TYPE_USERID
+ INFP_ATTR_TYPE_USERID,
+ INFP_ATTR_TYPE_GROUPID
};
int infp_get_attribute_type(const char *attribute);
@@ -91,4 +92,7 @@ int infp_get_ldb_val_from_dbus(TALLOC_CTX *mem_ctx, DBusMessageIter *iter, struc
struct infp_req_ctx *infp_req_init(TALLOC_CTX *mem_ctx, DBusMessage *message, struct sbus_conn_ctx *sconn);
+void infp_return_success(struct infp_req_ctx *infp_req);
+void infp_return_failure(struct infp_req_ctx *infp_req, const char *message);
+
#endif /* INFOPIPE_PRIVATE_H_ */
diff --git a/server/infopipe/org.freeipa.sssd.infopipe.Introspect.xml b/server/infopipe/org.freeipa.sssd.infopipe.Introspect.xml
index c1a8b3df..5656d42c 100644
--- a/server/infopipe/org.freeipa.sssd.infopipe.Introspect.xml
+++ b/server/infopipe/org.freeipa.sssd.infopipe.Introspect.xml
@@ -269,7 +269,7 @@
/>
<arg name="group" type="s" direction="in" />
<arg name="domain" type="s" direction="in" />
- <arg name="guid" type="t" direction="in" />
+ <arg name="gid" type="t" direction="in" />
</method>
</interface>
</node>