diff options
Diffstat (limited to 'server/infopipe/infopipe_groups.c')
-rw-r--r-- | server/infopipe/infopipe_groups.c | 262 |
1 files changed, 254 insertions, 8 deletions
diff --git a/server/infopipe/infopipe_groups.c b/server/infopipe/infopipe_groups.c index ec02c575..bb3741c9 100644 --- a/server/infopipe/infopipe_groups.c +++ b/server/infopipe/infopipe_groups.c @@ -385,30 +385,276 @@ error: return ret; } -int infp_groups_add_members(DBusMessage *message, struct sbus_conn_ctx *sconn) +enum infp_gr_member_types { + INFP_GR_MEM_USER = 0, + INFP_GR_MEM_GROUP +}; + +struct infp_groupmember_ctx { + struct infp_req_ctx *infp_req; + struct ldb_dn *group_dn; + char **membernames; + uint32_t member_count; + uint32_t index; + uint8_t member_type; + uint8_t modify_type; + struct sysdb_req *sysdb_req; +}; + +static void infp_do_member(struct sysdb_req *req, void *pvt); + +static void infp_do_member_callback(void *pvt, int status, + struct ldb_result *res) { - DBusMessage *reply; + char *fail_msg; + DBusMessage *reply = NULL; + struct infp_groupmember_ctx *grmod_req = + talloc_get_type(pvt, struct infp_groupmember_ctx); - reply = dbus_message_new_error(message, DBUS_ERROR_NOT_SUPPORTED, "Not yet implemented"); + /* Check the results of the current add */ + if(status != EOK) goto fail; - /* send reply */ - sbus_conn_send_reply(sconn, reply); + /* Check if there are more members to process */ + grmod_req->index++; + if(grmod_req->index < grmod_req->member_count) { + infp_do_member(grmod_req->sysdb_req, grmod_req); + return; + } + /* This was the last member. Commit the transaction */ + sysdb_transaction_done(grmod_req->sysdb_req, EOK); + + /* Send an ack reply */ + reply = dbus_message_new_method_return(grmod_req->infp_req->req_message); + if(reply) { + sbus_conn_send_reply(grmod_req->infp_req->sconn, reply); + dbus_message_unref(reply); + } + + talloc_free(grmod_req); + return; + +fail: +sysdb_transaction_done(grmod_req->sysdb_req, status); + fail_msg = talloc_asprintf(grmod_req, "Could not modify group"); + reply = dbus_message_new_error(grmod_req->infp_req->req_message, + DBUS_ERROR_FAILED, + fail_msg); + sbus_conn_send_reply(grmod_req->infp_req->sconn, reply); dbus_message_unref(reply); - return EOK; + talloc_free(grmod_req); + return; +} + +static void infp_do_member(struct sysdb_req *req, void *pvt) +{ + int ret; + struct ldb_dn *member_dn; + struct infp_groupmember_ctx *grmod_req = + talloc_get_type(pvt, struct infp_groupmember_ctx); + + grmod_req->sysdb_req = req; + + if (grmod_req->member_type == INFP_GR_MEM_USER) { + member_dn = + sysdb_user_dn(grmod_req->infp_req->infp->sysdb, + grmod_req, + grmod_req->infp_req->domain->name, + grmod_req->membernames[grmod_req->index]); + if (member_dn == NULL) goto error; + } + else if (grmod_req->member_type == INFP_GR_MEM_GROUP) { + member_dn = + sysdb_group_dn(grmod_req->infp_req->infp->sysdb, + grmod_req, + grmod_req->infp_req->domain->name, + grmod_req->membernames[grmod_req->index]); + if (member_dn == NULL) goto error; + } + else goto error; + + if (grmod_req->modify_type == INFP_ACTION_TYPE_ADDMEMBER) { + ret = sysdb_add_group_member(grmod_req->sysdb_req, + member_dn, + grmod_req->group_dn, + infp_do_member_callback, + grmod_req); + } + else if (grmod_req->modify_type == INFP_ACTION_TYPE_REMOVEMEMBER) { + ret = sysdb_remove_group_member(grmod_req->sysdb_req, + member_dn, + grmod_req->group_dn, + infp_do_member_callback, + grmod_req); + } + if (ret != EOK) goto error; + + return; + +error: + talloc_free(grmod_req); + return; } -int infp_groups_remove_members(DBusMessage *message, struct sbus_conn_ctx *sconn) +static int infp_groups_modify_members(DBusMessage *message, + struct sbus_conn_ctx *sconn, + uint8_t modify_type) { DBusMessage *reply; + DBusError error; + struct infp_groupmember_ctx *grmod_req; + char *einval_msg; + int ret, i; - reply = dbus_message_new_error(message, DBUS_ERROR_NOT_SUPPORTED, "Not yet implemented"); + /* Arguments */ + const char *arg_group; + const char *arg_domain; + char **arg_members = NULL; + int arg_member_count; + uint8_t arg_membertype; + + grmod_req = talloc_zero(NULL, struct infp_groupmember_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_ARRAY, DBUS_TYPE_STRING, + &arg_members, &arg_member_count, + DBUS_TYPE_BYTE, &arg_membertype, + DBUS_TYPE_INVALID)) { + DEBUG(0, ("Parsing arguments to %s failed: %s:%s\n", + INFP_GROUPS_ADD_MEMBERS, 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, + modify_type, + INFP_ATTR_TYPE_INVALID)) goto denied; + + grmod_req->member_count = arg_member_count; + grmod_req->membernames = talloc_array(grmod_req, char *, + arg_member_count); + if (grmod_req == NULL) { + ret = ENOMEM; + goto error; + } + for (i = 0; i < arg_member_count; i++) { + grmod_req->membernames[i] = talloc_strdup(grmod_req->membernames, + arg_members[i]); + if(grmod_req->membernames[i] == NULL) { + ret = ENOMEM; + goto error; + } + } + dbus_free_string_array(arg_members); + arg_members = NULL; + + grmod_req->group_dn = + sysdb_group_dn(grmod_req->infp_req->infp->sysdb, + grmod_req, + grmod_req->infp_req->domain->name, + arg_group); + if (grmod_req->group_dn == NULL) { + ret = EIO; + goto error; + } + + grmod_req->index = 0; + grmod_req->modify_type = modify_type; + grmod_req->member_type = arg_membertype; + if ((grmod_req->member_type != INFP_GR_MEM_USER) && + (grmod_req->member_type != INFP_GR_MEM_GROUP)) { + einval_msg = talloc_strdup(grmod_req, + "Invalid member type"); + goto einval; + } + + ret = sysdb_transaction(grmod_req, + grmod_req->infp_req->infp->sysdb, + infp_do_member, + 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); + + if (arg_members) dbus_free_string_array(arg_members); + 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); + if (arg_members) dbus_free_string_array(arg_members); + talloc_free(grmod_req); return EOK; + +error: + if (arg_members) dbus_free_string_array(arg_members); + talloc_free(grmod_req); + return ret; +} + +int infp_groups_add_members(DBusMessage *message, + struct sbus_conn_ctx *sconn) +{ + return infp_groups_modify_members(message, sconn, + INFP_ACTION_TYPE_ADDMEMBER); +} + +int infp_groups_remove_members(DBusMessage *message, + struct sbus_conn_ctx *sconn) +{ + return infp_groups_modify_members(message, sconn, + INFP_ACTION_TYPE_REMOVEMEMBER); } int infp_groups_set_gid(DBusMessage *message, struct sbus_conn_ctx *sconn) |