diff options
Diffstat (limited to 'server/infopipe')
-rw-r--r-- | server/infopipe/infopipe.c | 43 | ||||
-rw-r--r-- | server/infopipe/infopipe_groups.c | 169 | ||||
-rw-r--r-- | server/infopipe/infopipe_private.h | 6 | ||||
-rw-r--r-- | server/infopipe/org.freeipa.sssd.infopipe.Introspect.xml | 2 |
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> |