diff options
Diffstat (limited to 'server/infopipe/infopipe_users.c')
-rw-r--r-- | server/infopipe/infopipe_users.c | 1846 |
1 files changed, 0 insertions, 1846 deletions
diff --git a/server/infopipe/infopipe_users.c b/server/infopipe/infopipe_users.c deleted file mode 100644 index aac79f7f..00000000 --- a/server/infopipe/infopipe_users.c +++ /dev/null @@ -1,1846 +0,0 @@ -/* - SSSD - - InfoPipe - - Copyright (C) Stephen Gallagher <sgallagh@redhat.com> 2009 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ -#include <dbus/dbus.h> -#include <ldb.h> -#include <time.h> -#include "util/util.h" -#include "util/btreemap.h" -#include "confdb/confdb.h" -#include "infopipe/infopipe.h" -#include "infopipe/infopipe_private.h" -#include "infopipe/sysbus.h" -#include "db/sysdb.h" -#include "responder/common/responder.h" - -static int attr_comparator(const void *key1, const void *key2); -static int username_comparator(const void *key1, const void *key2); - -struct infp_getcached_ctx { - struct infp_req_ctx *infp_req; - struct sysdb_handle *handle; - char **usernames; - uint64_t min_last_login; -}; -static void infp_users_get_cached_callback(void *ptr, - int status, - struct ldb_result *res) -{ - DBusMessage *reply; - DBusMessageIter iter, array_iter; - dbus_bool_t dbret; - int i; - char *username; - struct infp_getcached_ctx *infp_getcached_req = - talloc_get_type(ptr, struct infp_getcached_ctx); - - if (status != LDB_SUCCESS) { - DEBUG(0, ("Failed to enumerate users in the cache db.\n")); - infp_return_failure(infp_getcached_req->infp_req, NULL); - talloc_free(infp_getcached_req); - return; - } - - /* Construct a reply */ - reply = dbus_message_new_method_return(infp_getcached_req->infp_req->req_message); - if(reply == NULL) { - infp_return_failure(infp_getcached_req->infp_req, NULL); - talloc_free(infp_getcached_req); - return; - } - - dbus_message_iter_init_append(reply, &iter); - dbret = dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, - "s", &array_iter); - if (!dbret) goto error; - - for (i = 0; i < res->count; i++) { - username = talloc_strdup(infp_getcached_req, - ldb_msg_find_attr_as_string(res->msgs[i], - SYSDB_NAME, - NULL)); - if (username != NULL) { - dbret = dbus_message_iter_append_basic(&array_iter, - DBUS_TYPE_STRING, &username); - if (!dbret) goto error; - } - } - dbret = dbus_message_iter_close_container(&iter, &array_iter); - if(!dbret) goto error; - - sbus_conn_send_reply(infp_getcached_req->infp_req->sconn, reply); - dbus_message_unref(reply); - - talloc_free(infp_getcached_req); - return; - -error: - DEBUG(0, - ("Critical error constructing reply message for %s\n", - INFP_USERS_GET_CACHED)); - dbus_message_unref(reply); - infp_return_failure(infp_getcached_req->infp_req, NULL); - talloc_free(infp_getcached_req); - return; -} - -int infp_users_get_cached(DBusMessage *message, struct sbus_conn_ctx *sconn) -{ - DBusMessage *reply; - DBusError error; - dbus_bool_t dbret; - char *einval_msg; - char *search_expression; - struct infp_getcached_ctx *infp_getcached_req; - int ret; - - /* Arguments */ - const char *arg_domain; - const uint64_t arg_minlastlogin; - - infp_getcached_req = talloc_zero(NULL, struct infp_getcached_ctx); - if (infp_getcached_req == NULL) { - ret = ENOMEM; - goto error; - } - - /* Create an infp_req_ctx */ - infp_getcached_req->infp_req = infp_req_init(infp_getcached_req, - message, sconn); - if (infp_getcached_req->infp_req == NULL) { - ret = EIO; - goto error; - } - - dbus_error_init(&error); - dbret = dbus_message_get_args(message, &error, - DBUS_TYPE_STRING, &arg_domain, - DBUS_TYPE_UINT64, &arg_minlastlogin, - DBUS_TYPE_INVALID); - if(!dbret) { - DEBUG(0, ("Parsing arguments to %s failed: %s:%s\n", - INFP_USERS_GET_CACHED, error.name, error.message)); - einval_msg = talloc_strdup(infp_getcached_req, error.message); - dbus_error_free(&error); - goto einval; - } - - infp_getcached_req->min_last_login = arg_minlastlogin; - - infp_getcached_req->infp_req->domain = - infp_get_domain_obj(infp_getcached_req->infp_req->infp, arg_domain); - /* Check for a valid domain */ - if (infp_getcached_req->infp_req->domain == NULL) { - einval_msg = talloc_strdup(infp_getcached_req, "Invalid domain."); - goto einval; - } - - /* NOTE: not checking permissions since the - * information here is all visible in NSS as well - */ - - /* Call sysdb_enumpwent with special search parameters */ - search_expression = talloc_asprintf(infp_getcached_req, - SYSDB_GETCACHED_FILTER, - infp_getcached_req->min_last_login); - ret = sysdb_enumpwent(infp_getcached_req, - infp_getcached_req->infp_req->infp->sysdb, - infp_getcached_req->infp_req->domain, - search_expression, - infp_users_get_cached_callback, infp_getcached_req); - if(ret != EOK) { - DEBUG(0, ("Could not read from the cache database.\n")); - goto error; - } - - 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(infp_getcached_req); - return EOK; - -error: - if (infp_getcached_req) - infp_return_failure(infp_getcached_req->infp_req, NULL); - talloc_free(infp_getcached_req); - return ret; -} - -struct infp_createuser_ctx { - struct infp_req_ctx *infp_req; - struct sysdb_handle *handle; - - char *username; - char *fullname; - char *homedir; - char *shell; -}; - -static void infp_do_user_create_callback(void *pvt, - int status, - struct ldb_result *res) -{ - char *error_msg = NULL; - DBusMessage *reply = NULL; - struct infp_createuser_ctx *infp_createuser_req = talloc_get_type(pvt, struct infp_createuser_ctx); - - /* Commit the transaction if it we got a successful response, or cancel it if we did not */ - sysdb_transaction_done(infp_createuser_req->handle, status); - - /* Verify that the addition completed successfully - * If LDB returned an error, run a search to determine - * if it was due the requested username already being - * in use - */ - if (status == EOK) { - /* Return reply ack */ - infp_return_success(infp_createuser_req->infp_req); - } - else if (status == EEXIST) { - /* Return error, user already exists */ - error_msg = talloc_asprintf(infp_createuser_req, - "User [%s] already exists on domain [%s]", - infp_createuser_req->username, - infp_createuser_req->infp_req->domain->name); - reply = dbus_message_new_error(infp_createuser_req->infp_req->req_message, - DBUS_ERROR_FILE_EXISTS, - error_msg); - if (reply) { - sbus_conn_send_reply(infp_createuser_req->infp_req->sconn, reply); - dbus_message_unref(reply); - } - } - else { - /* Unknown error occurred. Print DEBUG message */ - DEBUG(0, ("Failed to create user in the sysdb. Error code %d\n", status)); - infp_return_failure(infp_createuser_req->infp_req, NULL); - } - - talloc_free(infp_createuser_req); -} - -static void infp_do_user_create(struct sysdb_handle *handle, void *pvt) -{ - int ret; - struct infp_createuser_ctx *infp_createuser_req = talloc_get_type(pvt, struct infp_createuser_ctx); - infp_createuser_req->handle = handle; - - ret = sysdb_add_user(infp_createuser_req->handle, - infp_createuser_req->infp_req->domain, - infp_createuser_req->username, - 0, 0, - infp_createuser_req->fullname, - infp_createuser_req->homedir, - infp_createuser_req->shell, - infp_do_user_create_callback, - infp_createuser_req); - if (ret != EOK) { - DEBUG(0, ("Could not invoke sysdb_add_user\n")); - sysdb_transaction_done(infp_createuser_req->handle, ret); - infp_return_failure(infp_createuser_req->infp_req, NULL); - talloc_free(infp_createuser_req); - return; - } -} - -int infp_users_create(DBusMessage *message, struct sbus_conn_ctx *sconn) -{ - DBusMessage *reply; - DBusError error; - dbus_bool_t dbret; - char *einval_msg; - struct infp_createuser_ctx *infp_createuser_req; - int ret; - - /* Arguments */ - const char *arg_domain; - const char *arg_username; - const char *arg_fullname; - const char *arg_homedir; - const char *arg_shell; - - infp_createuser_req = talloc_zero(NULL, struct infp_createuser_ctx); - if (infp_createuser_req == NULL) { - ret = ENOMEM; - goto error; - } - - /* Create an infp_req_ctx */ - infp_createuser_req->infp_req = infp_req_init(infp_createuser_req, - message, sconn); - if (infp_createuser_req->infp_req == NULL) { - ret = EIO; - goto error; - } - - dbus_error_init(&error); - dbret = dbus_message_get_args(message, &error, - DBUS_TYPE_STRING, &arg_username, - DBUS_TYPE_STRING, &arg_domain, - DBUS_TYPE_STRING, &arg_fullname, - DBUS_TYPE_STRING, &arg_homedir, - DBUS_TYPE_STRING, &arg_shell, - DBUS_TYPE_INVALID); - if (!dbret) { - DEBUG(0, ("Parsing arguments to %s failed: %s:%s\n", INFP_USERS_CREATE, error.name, error.message)); - einval_msg = talloc_strdup(infp_createuser_req, error.message); - dbus_error_free(&error); - goto einval; - } - - /* FIXME: Allow creating users on domains other than LOCAL */ - if (strcasecmp(arg_domain, "LOCAL") != 0) { - goto denied; - } - - infp_createuser_req->infp_req->domain = - infp_get_domain_obj(infp_createuser_req->infp_req->infp, arg_domain); - /* Check for a valid domain */ - if (infp_createuser_req->infp_req->domain == NULL) { - einval_msg = talloc_strdup(infp_createuser_req, "Invalid domain."); - goto einval; - } - - if (strlen(arg_username)) { - infp_createuser_req->username = talloc_strdup(infp_createuser_req, arg_username); - if (infp_createuser_req->username == NULL) { - ret = ENOMEM; - goto error; - } - } else { - einval_msg = talloc_strdup(infp_createuser_req, "No username provided"); - goto einval; - } - - infp_createuser_req->fullname = NULL; - if (strlen(arg_fullname)) { - infp_createuser_req->fullname = talloc_strdup(infp_createuser_req, arg_fullname); - if(infp_createuser_req->fullname == NULL) { - ret = ENOMEM; - goto error; - } - } - - infp_createuser_req->homedir = NULL; - if (strlen(arg_homedir)) { - infp_createuser_req->homedir = talloc_strdup(infp_createuser_req, arg_homedir); - if(infp_createuser_req->homedir == NULL) { - ret = ENOMEM; - goto error; - } - } - - infp_createuser_req->shell = NULL; - if (strlen(arg_shell)) { - infp_createuser_req->shell = talloc_strdup(infp_createuser_req, arg_shell); - if(infp_createuser_req->shell == NULL) { - ret = ENOMEM; - goto error; - } - } - - /* Check permissions */ - if(!infp_get_permissions(infp_createuser_req->infp_req->caller, - infp_createuser_req->infp_req->domain, - INFP_OBJ_TYPE_USER, - NULL, - INFP_ACTION_TYPE_CREATE, - INFP_ATTR_TYPE_INVALID)) goto denied; - - ret = sysdb_transaction(infp_createuser_req, - infp_createuser_req->infp_req->infp->sysdb, - infp_do_user_create, - infp_createuser_req); - if (ret != EOK) { - DEBUG(0,("Unable to start transaction to create user\n")); - 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(infp_createuser_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(infp_createuser_req); - return EOK; - -error: - if(infp_createuser_req) - infp_return_failure(infp_createuser_req->infp_req, NULL); - talloc_free(infp_createuser_req); - return ret; -} - -struct infp_deleteuser_ctx { - struct infp_req_ctx *infp_req; - char *username; - struct sysdb_handle *handle; - struct ldb_dn *user_dn; -}; - -static void infp_do_user_delete_callback(void *pvt, int status, - struct ldb_result *res) -{ - struct infp_deleteuser_ctx *infp_deleteuser_req = - talloc_get_type(pvt, struct infp_deleteuser_ctx); - - /* Commit the transaction if it we got a successful response, or cancel it if we did not */ - sysdb_transaction_done(infp_deleteuser_req->handle, status); - - if (status != EOK) { - DEBUG(0, ("Failed to delete user from sysdb. Error code %d\n", status)); - infp_return_failure(infp_deleteuser_req->infp_req, NULL); - talloc_free(infp_deleteuser_req); - return; - } - - infp_return_success(infp_deleteuser_req->infp_req); - talloc_free(infp_deleteuser_req); -} - -static void infp_do_user_delete(struct sysdb_handle *req, void *pvt) -{ - int ret; - struct infp_deleteuser_ctx *infp_deleteuser_req = talloc_get_type(pvt, struct infp_deleteuser_ctx); - - infp_deleteuser_req->handle = handle; - - infp_deleteuser_req->user_dn = sysdb_user_dn(infp_deleteuser_req->infp_req->infp->sysdb, - infp_deleteuser_req, - infp_deleteuser_req->infp_req->domain->name, - infp_deleteuser_req->username); - if(infp_deleteuser_req->user_dn == NULL) { - DEBUG(0, ("Could not construct a user_dn for deletion.\n")); - infp_return_failure(infp_deleteuser_req->infp_req, NULL); - talloc_free(infp_deleteuser_req); - return; - } - - ret = sysdb_delete_entry(infp_deleteuser_req->handle, - infp_deleteuser_req->user_dn, - infp_do_user_delete_callback, - infp_deleteuser_req); - if(ret != EOK) { - DEBUG(0,("Could not delete user entry.\n")); - infp_return_failure(infp_deleteuser_req->infp_req, NULL); - talloc_free(infp_deleteuser_req); - return; - } -} - -int infp_users_delete(DBusMessage *message, struct sbus_conn_ctx *sconn) -{ - DBusMessage *reply = NULL; - DBusError error; - dbus_bool_t dbret; - char *einval_msg = NULL; - struct infp_deleteuser_ctx *infp_deleteuser_req; - int ret; - - /* Arguments */ - const char *arg_username; - const char *arg_domain; - - infp_deleteuser_req = talloc_zero(NULL, struct infp_deleteuser_ctx); - if (infp_deleteuser_req == NULL) { - ret = ENOMEM; - goto error; - } - - /* Create an infp_req_ctx */ - infp_deleteuser_req->infp_req = infp_req_init(infp_deleteuser_req, - message, - sconn); - if (infp_deleteuser_req->infp_req == NULL) { - ret = EIO; - goto error; - } - - /* Process the arguments */ - dbus_error_init(&error); - dbret = dbus_message_get_args(message, &error, - DBUS_TYPE_STRING, &arg_username, - DBUS_TYPE_STRING, &arg_domain, - DBUS_TYPE_INVALID); - if (!dbret) { - DEBUG(0, ("Parsing arguments to %s failed: %s:%s\n", - INFP_USERS_DELETE, error.name, error.message)); - einval_msg = talloc_strdup(infp_deleteuser_req, error.message); - dbus_error_free(&error); - goto einval; - } - - /* FIXME: Allow deleting users from domains other than local */ - if(strcasecmp(arg_domain, "LOCAL") != 0) { - goto denied; - } - - infp_deleteuser_req->infp_req->domain = - infp_get_domain_obj(infp_deleteuser_req->infp_req->infp, arg_domain); - /* Check for a valid domain */ - if (infp_deleteuser_req->infp_req->domain == NULL) { - einval_msg = talloc_strdup(infp_deleteuser_req, "Invalid domain."); - goto einval; - } - - if (strlen(arg_username)) { - infp_deleteuser_req->username = talloc_strdup(infp_deleteuser_req, arg_username); - if (infp_deleteuser_req->username == NULL) { - ret = ENOMEM; - goto error; - } - } else { - einval_msg = talloc_strdup(infp_deleteuser_req, "No username provided"); - goto einval; - } - - /* Check permissions */ - if(!infp_get_permissions(infp_deleteuser_req->infp_req->caller, - infp_deleteuser_req->infp_req->domain, - INFP_OBJ_TYPE_USER, - NULL, - INFP_ACTION_TYPE_DELETE, - INFP_ACTION_TYPE_INVALID)) goto denied; - - ret = sysdb_transaction(infp_deleteuser_req, - infp_deleteuser_req->infp_req->infp->sysdb, - infp_do_user_delete, - infp_deleteuser_req); - if (ret != EOK) { - DEBUG(0, ("Unable to start transaction to delete user\n")); - 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(infp_deleteuser_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(infp_deleteuser_req); - return EOK; - -error: - if(infp_deleteuser_req) - infp_return_failure(infp_deleteuser_req->infp_req, NULL); - talloc_free(infp_deleteuser_req); - return ret; -} - -struct infp_getattr_ctx { - struct infp_req_ctx *infp_req; - char **usernames; - uint32_t username_count; - const char **attributes; - uint32_t attr_count; - uint32_t index; - bool check_provider; - - /* The results array must have username_count elements */ - struct btreemap **results; -}; - -static int infp_get_attr_lookup(struct infp_getattr_ctx *infp_getattr_req); - -struct infp_attr_variant { - int dbus_type; - int subtype; - int count; - void *data; -}; - -/* We are restricting variants to three basic types: - * Fixed (Numeric) types - * Strings - * Arrays of fixed (numeric) types - */ -static int infp_user_getattr_append_dict(TALLOC_CTX *mem_ctx, - DBusMessageIter *iter, - struct btreemap *map) -{ - int ret, i; - char **attrs; - struct infp_attr_variant *value; - char *vartype; - char *subtype; - int attr_count; - DBusMessageIter array_iter; - DBusMessageIter dict_iter; - DBusMessageIter variant_iter; - DBusMessageIter fixed_array_iter; - dbus_bool_t dbret; - - ret = btreemap_get_keys(mem_ctx, map, (const void ***)&attrs, &attr_count); - if (ret != EOK) { - return ret; - } - - /* DICTs are an array of dict pairs */ - dbret = dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "{sv}", &array_iter); - if (!dbret) { - ret = ENOMEM; - goto error; - } - - i = 0; - while (i < attr_count) { - if (strcasecmp(attrs[i], SYSDB_LAST_UPDATE) == 0) { - /* Skip lastUpdate. We shouldn't be returning this */ - i++; - continue; - } - - /* Create the variant value */ - value = talloc_get_type(btreemap_get_value(map, attrs[i]), struct infp_attr_variant); - if (value == NULL) { - /* Skip any entries that returned an empty value */ - i++; - continue; - } - - /* Open a dict container for this pair */ - dbret = dbus_message_iter_open_container(&array_iter, DBUS_TYPE_DICT_ENTRY, NULL, &dict_iter); - if (!dbret) { - ret = ENOMEM; - goto error; - } - /* Write the dict key */ - dbret = dbus_message_iter_append_basic(&dict_iter, DBUS_TYPE_STRING, &attrs[i]); - if (!dbret) { - ret = ENOMEM; - goto error; - } - - vartype = NULL; - subtype = NULL; - if (sbus_is_dbus_string_type(value->dbus_type)) { - /* String types are strings, object paths and signatures */ - vartype = talloc_asprintf(mem_ctx, "%c", value->dbus_type); - if (vartype == NULL) { - ret = ENOMEM; - goto error; - } - dbret = dbus_message_iter_open_container(&dict_iter, DBUS_TYPE_VARIANT, vartype, &variant_iter); - if (!dbret) { - ret = ENOMEM; - goto error; - } - dbret = dbus_message_iter_append_basic(&variant_iter, DBUS_TYPE_STRING, &value->data); - if (!dbret) { - ret = ENOMEM; - goto error; - } - talloc_free(vartype); - vartype = NULL; - } - - else if (sbus_is_dbus_fixed_type(value->dbus_type)) { - /* Fixed types are booleans, bytes, the integral types and the floating-point types */ - vartype = talloc_asprintf(mem_ctx, "%c", value->dbus_type); - if (vartype == NULL) { - ret = ENOMEM; - goto error; - } - dbret = dbus_message_iter_open_container(&dict_iter, DBUS_TYPE_VARIANT, vartype, &variant_iter); - if (!dbret) { - ret = ENOMEM; - goto error; - } - dbret = dbus_message_iter_append_basic(&variant_iter, value->dbus_type, value->data); - if (!dbret) { - ret = ENOMEM; - goto error; - } - talloc_free(vartype); - vartype = NULL; - } - - else if (value->dbus_type == DBUS_TYPE_ARRAY) { - if(sbus_is_dbus_fixed_type(value->subtype)) { - /* Only support adding arrays of fixed types or strings for now */ - - subtype = talloc_asprintf(mem_ctx, "a%c", value->subtype); - if (subtype == NULL) { - ret = ENOMEM; - goto error; - } - dbret = dbus_message_iter_open_container(&dict_iter, DBUS_TYPE_VARIANT, subtype, &variant_iter); - if (!dbret) { - ret = ENOMEM; - goto error; - } - - dbret = dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY, subtype, &fixed_array_iter); - if (!dbret) { - ret = ENOMEM; - goto error; - } - - dbret = dbus_message_iter_append_fixed_array(&fixed_array_iter, value->subtype, &value->data, value->count); - if(!dbret) { - ret = ENOMEM; - goto error; - } - - dbret = dbus_message_iter_close_container(&variant_iter, &fixed_array_iter); - if(!dbret) { - ret = ENOMEM; - goto error; - } - } - else { - ret = EINVAL; - goto error; - } - } - - else { - /* Value type not yet supported */ - DEBUG(0, ("Attempted to create DICT value for something not a basic type or fixed array [%d]\n", value->dbus_type)); - ret = EINVAL; - goto error; - } - - /* Close the variant */ - dbret = dbus_message_iter_close_container(&dict_iter, &variant_iter); - if(!dbret) { - ret = ENOMEM; - goto error; - } - - /* Close the dict */ - dbret = dbus_message_iter_close_container(&array_iter, &dict_iter); - if(!dbret) { - ret = ENOMEM; - goto error; - } - i++; - } - - /* Close the dict array */ - dbret = dbus_message_iter_close_container(iter, &array_iter); - if(!dbret) { - ret = ENOMEM; - goto error; - } - - return EOK; - -error: - talloc_free(attrs); - talloc_free(vartype); - talloc_free(subtype); - return ret; -} - -static int create_getattr_result_map(TALLOC_CTX *mem_ctx, struct infp_getattr_ctx *infp_getattr_req, - struct ldb_result *res, struct btreemap **results) -{ - int i, ret; - int attr_type; - struct infp_attr_variant *variant; - const struct ldb_val *val; - - /* Iterate through the requested attributes */ - for (i=0; i < infp_getattr_req->attr_count; i++) { - /* Ignore any attributes we don't care about */ - attr_type = infp_get_attribute_type(infp_getattr_req->attributes[i]); - if (attr_type != INFP_ATTR_TYPE_INVALID) { - variant = talloc_zero(mem_ctx, struct infp_attr_variant); - if (variant == NULL) { - ret = ENOMEM; - goto end; - } - - variant->dbus_type = infp_get_user_attr_dbus_type(attr_type, &variant->subtype); - if (sbus_is_dbus_string_type(variant->dbus_type)) { - variant->data = (void *)talloc_strdup(variant, ldb_msg_find_attr_as_string(res->msgs[0], - infp_getattr_req->attributes[i], NULL)); - if (variant->data == NULL) { - talloc_free(variant); - continue; - } - } - else if (sbus_is_dbus_fixed_type(variant->dbus_type)) { - /* We'll treat all fixed(numeric) types as UINT64 internally - * These will be correctly converted to their true types - * when being marshalled on the wire. - */ - variant->data = (void *)talloc(variant, uint64_t); - if (variant->data == NULL) { - talloc_free(variant); - continue; - } - - *(uint64_t *)variant->data = ldb_msg_find_attr_as_uint64(res->msgs[0], infp_getattr_req->attributes[i], 0); - } - else if (variant->dbus_type == DBUS_TYPE_ARRAY) { - switch(variant->subtype) { - case DBUS_TYPE_BYTE: - /* Byte array (binary data) */ - val = ldb_msg_find_ldb_val(res->msgs[0], infp_getattr_req->attributes[i]); - if (val == NULL || val->length <= 0) { - talloc_free(variant); - continue; - } - variant->data = talloc_memdup(variant, val->data, val->length); - if (variant->data == NULL) { - talloc_free(variant); - continue; - } - variant->count = val->length; - break; - - default: - /* Unsupported array type */ - talloc_free(variant); - continue; - } - - } - else { - /* Unsupported type */ - talloc_free(variant); - continue; - } - - /* Add the variant to the map */ - ret = btreemap_set_value(mem_ctx, results, (const void *)infp_getattr_req->attributes[i], variant, attr_comparator); - if (ret != EOK) { - talloc_free(variant); - } - } - } - - ret = EOK; - -end: - return ret; -} - -static void infp_get_attr_lookup_callback(void *ptr, int ldb_status, struct ldb_result *res) -{ - int ret; - int i; - bool call_provider = false; - int timeout; - uint64_t lastUpdate; - DBusMessage *reply = NULL; - DBusMessageIter iter; - DBusMessageIter array_iter; - struct infp_getattr_ctx *infp_getattr_req = talloc_get_type(ptr, struct infp_getattr_ctx); - - DEBUG(9, ("Processing results for user [%s]\n", infp_getattr_req->usernames[infp_getattr_req->index])); - - /* Process the current results */ - if (ldb_status != LDB_SUCCESS) { - DEBUG(0, ("Critical error reading from sysdb.\n")); - infp_return_failure(infp_getattr_req->infp_req, NULL); - goto done; - } - - if(infp_getattr_req->check_provider) { - switch(res->count) { - case 0: - call_provider = true; - break; - - case 1: - timeout = infp_getattr_req->infp_req->infp->cache_timeout; - lastUpdate = ldb_msg_find_attr_as_uint64(res->msgs[0], - SYSDB_LAST_UPDATE, 0); - if (lastUpdate + timeout < time(NULL)) { - call_provider = true; - } - break; - - default: - DEBUG(0, ("GetUser call returned more than one result. This probably means the sysdb is corrupt!\n")); - infp_return_failure(infp_getattr_req->infp_req, NULL); - goto done; - } - } - - if (call_provider) { - /* FIXME call the provider */ - } - - switch (res->count) { - case 0: - DEBUG(2, ("No results for GetUser")); - infp_getattr_req->results[infp_getattr_req->index] = NULL; - break; - - case 1: - /* Create the result map */ - ret = create_getattr_result_map(infp_getattr_req, infp_getattr_req, res, - &infp_getattr_req->results[infp_getattr_req->index]); - if (ret != EOK) { - DEBUG(0, ("Unable to create result map!\n")); - infp_return_failure(infp_getattr_req->infp_req, NULL); - goto done; - } - break; - default: - /* We received more than one result. This is bad */ - DEBUG(0, ("GetUser call returned more than one result. This probably means the sysdb is corrupt!\n")); - infp_return_failure(infp_getattr_req->infp_req, NULL); - goto done; - } - - /* If there are more usernames remaining in the list, re-enter the loop */ - infp_getattr_req->index++; - if (infp_getattr_req->index < infp_getattr_req->username_count) { - ret = infp_get_attr_lookup(infp_getattr_req); - if (ret != EOK) { - DEBUG(0, ("Could not read from cache database\n")); - infp_return_failure(infp_getattr_req->infp_req, NULL); - goto done; - } - return; - } - - /* No more names remain, return the result DICTs */ - reply = dbus_message_new_method_return(infp_getattr_req->infp_req->req_message); - if (reply == NULL) { - infp_return_failure(infp_getattr_req->infp_req, NULL); - goto done; - } - - dbus_message_iter_init_append(reply, &iter); - - dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "a{sv}", &array_iter); - i = 0; - while (i < infp_getattr_req->username_count) { - ret = infp_user_getattr_append_dict(infp_getattr_req, &array_iter, infp_getattr_req->results[i]); - if (ret != EOK) { - DEBUG(0, ("Unable to append response DICT\n")); - goto done; - } - i++; - } - dbus_message_iter_close_container(&iter, &array_iter); - - sbus_conn_send_reply(infp_getattr_req->infp_req->sconn, reply); - -done: - if(reply) dbus_message_unref(reply); - talloc_free(infp_getattr_req); -} - -int infp_get_user_attr_dbus_type(int attr_type, int *subtype) -{ - int dbus_type; - *subtype = DBUS_TYPE_INVALID; - - switch(attr_type) { - case INFP_ATTR_TYPE_DEFAULTGROUP: - case INFP_ATTR_TYPE_GECOS: - case INFP_ATTR_TYPE_HOMEDIR: - case INFP_ATTR_TYPE_SHELL: - case INFP_ATTR_TYPE_FULLNAME: - case INFP_ATTR_TYPE_LOCALE: - case INFP_ATTR_TYPE_KEYBOARD: - case INFP_ATTR_TYPE_SESSION: - dbus_type = DBUS_TYPE_STRING; - break; - case INFP_ATTR_TYPE_LAST_LOGIN: - dbus_type = DBUS_TYPE_UINT64; - break; - case INFP_ATTR_TYPE_USERPIC: - dbus_type = DBUS_TYPE_ARRAY; - *subtype = DBUS_TYPE_BYTE; - break; - default: - dbus_type = DBUS_TYPE_INVALID; - } - return dbus_type; -} - -static int attr_comparator(const void *key1, const void *key2) -{ - return strcmp((const char *)key1, (const char *)key2); -} - -static int infp_get_attr_lookup(struct infp_getattr_ctx *infp_getattr_req) -{ - uint32_t i; - int ret; - char **attributes; - const char *last_update; - int attr_count; - - DEBUG(9, ("Processing lookup for user [%s]\n", infp_getattr_req->usernames[infp_getattr_req->index])); - - if (infp_getattr_req->index >= infp_getattr_req->username_count) { - /* Avoid index bound issues */ - return EINVAL; - } - - /* Check permissions */ - i=0; - infp_getattr_req->results[infp_getattr_req->index] = NULL; - while(i < infp_getattr_req->attr_count) { - if(infp_get_permissions(infp_getattr_req->infp_req->caller, - infp_getattr_req->infp_req->domain, - INFP_OBJ_TYPE_USER, - infp_getattr_req->usernames[infp_getattr_req->index], - INFP_ACTION_TYPE_READ, - infp_get_attribute_type(infp_getattr_req->attributes[i])) - ) { - /* Add this attribute as a key to the result map - * This will guarantee that we are requesting only unique attributes - * that we have permission to read - */ - ret = btreemap_set_value(infp_getattr_req, &infp_getattr_req->results[infp_getattr_req->index], - infp_getattr_req->attributes[i], NULL, attr_comparator); - if (ret != EOK) { - return ret; - } - } - i++; - } - - /* Always add SYSDB_LAST_UPDATE to the list, we won't return it */ - last_update = talloc_strdup(infp_getattr_req, SYSDB_LAST_UPDATE); - ret = btreemap_set_value(infp_getattr_req, &infp_getattr_req->results[infp_getattr_req->index], - last_update, NULL, attr_comparator); - if (ret != EOK) { - return ret; - } - - /* Prepare the list of attributes to request from the sysdb */ - attr_count = 0; - ret = btreemap_get_keys(infp_getattr_req, - infp_getattr_req->results[infp_getattr_req->index], - (const void ***)&attributes, &attr_count); - if (ret != EOK) { - return ret; - } - - if (attr_count == 1) { - /* There were zero authorized attributes in the list - * No need to call sysdb, just move to the next username - * The single attribute was SYSDB_LAST_UPDATE which we - * added manually. - */ - infp_getattr_req->index++; - return infp_get_attr_lookup(infp_getattr_req); - } - - /* Add a trailing NULL entry (required for sysdb) */ - attributes = talloc_realloc(infp_getattr_req, attributes, char *, attr_count+1); - if (attributes == NULL) { - return ENOMEM; - } - attributes[attr_count] = NULL; - - /* Call into the sysdb for the requested attributes */ - ret = sysdb_get_user_attr(infp_getattr_req, - infp_getattr_req->infp_req->infp->sysdb, - infp_getattr_req->infp_req->domain, - infp_getattr_req->usernames[infp_getattr_req->index], - (const char **)attributes, - infp_get_attr_lookup_callback, infp_getattr_req); - - return EOK; -} - -static const char **infp_get_all_attributes(TALLOC_CTX *mem_ctx, - uint32_t *attr_count) -{ - const char **attributes; - int offset = 0; - - *attr_count = 10; - attributes = talloc_array(mem_ctx, const char *, *attr_count); - if (attributes == NULL) { - return NULL; - } - - attributes[offset++] = SYSDB_DEFAULTGROUP; - attributes[offset++] = SYSDB_GECOS; - attributes[offset++] = SYSDB_HOMEDIR; - attributes[offset++] = SYSDB_SHELL; - attributes[offset++] = SYSDB_FULLNAME; - attributes[offset++] = SYSDB_LOCALE; - attributes[offset++] = SYSDB_KEYBOARD; - attributes[offset++] = SYSDB_SESSION; - attributes[offset++] = SYSDB_LAST_LOGIN; - attributes[offset++] = SYSDB_USERPIC; - - return attributes; -} - -/* GetUserAttributes(ARRAY(STRING) usernames, - * STRING domain, - * ARRAY(STRING) filter) - */ -int infp_users_get_attr(DBusMessage *message, struct sbus_conn_ctx *sconn) -{ - int ret, i; - DBusMessage *reply; - DBusError error; - dbus_bool_t dbret; - char **usernames; - uint32_t username_count; - char *domain; - char **attributes; - uint32_t attr_count; - struct infp_getattr_ctx *infp_getattr_req; - - usernames = NULL; - attributes = NULL; - /* Get the arguments to GetAttributes */ - dbus_error_init(&error); - dbret = dbus_message_get_args(message, &error, - DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &usernames, &username_count, - DBUS_TYPE_STRING, &domain, - DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &attributes, &attr_count, - DBUS_TYPE_INVALID); - if(!dbret) { - DEBUG(0, ("Parsing arguments failed: %s:%s\n", error.name, error.message)); - dbus_free_string_array(usernames); - dbus_free_string_array(attributes); - - reply = dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, error.message); - if (reply == NULL) { - return ENOMEM; - } - sbus_conn_send_reply(sconn, reply); - - dbus_message_unref(reply); - dbus_error_free(&error); - - return EOK; - } - - if (username_count < 1) { - /* No usernames received. Return an error */ - reply = dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, "No usernames specified."); - if (reply == NULL) { - ret = ENOMEM; - goto end; - } - sbus_conn_send_reply(sconn, reply); - - dbus_free_string_array(usernames); - dbus_free_string_array(attributes); - dbus_message_unref(reply); - ret = EOK; - goto end; - } - - /* Create a infp_getattr_ctx */ - infp_getattr_req = talloc_zero(NULL, struct infp_getattr_ctx); - if (infp_getattr_req == NULL) { - ret = ENOMEM; - goto end; - } - - /* Create an infp_req_ctx */ - infp_getattr_req->infp_req = infp_req_init(infp_getattr_req, - message, sconn); - if (infp_getattr_req->infp_req == NULL) { - ret = EIO; - goto end; - } - - infp_getattr_req->infp_req->domain = - infp_get_domain_obj(infp_getattr_req->infp_req->infp, domain); - infp_getattr_req->check_provider = - NEED_CHECK_PROVIDER(infp_getattr_req->infp_req->domain->provider); - - /* Copy the username list */ - infp_getattr_req->usernames = talloc_array(infp_getattr_req, char *, username_count); - if (infp_getattr_req->usernames == NULL) { - ret = ENOMEM; - goto end; - } - - i = 0; - while (i < username_count) { - DEBUG(9, ("Request for user [%s]\n", usernames[i])); - infp_getattr_req->usernames[i] = talloc_strdup(infp_getattr_req->usernames, usernames[i]); - if (infp_getattr_req == NULL) { - ret = ENOMEM; - goto end; - } - i++; - } - infp_getattr_req->username_count = username_count; - - /* Copy the attribute list */ - if (attr_count > 0) { - infp_getattr_req->attributes = talloc_array(infp_getattr_req, - const char *, attr_count); - if (infp_getattr_req->attributes == NULL) { - ret = ENOMEM; - goto end; - } - i = 0; - while (i < attr_count) { - infp_getattr_req->attributes[i] = talloc_strdup(infp_getattr_req, attributes[i]); - if (infp_getattr_req == NULL) { - ret = ENOMEM; - goto end; - } - i++; - } - infp_getattr_req->attr_count = attr_count; - } else { - /* No attributes specified in the call means retrieve all possible */ - infp_getattr_req->attributes = infp_get_all_attributes(infp_getattr_req, &infp_getattr_req->attr_count); - if (infp_getattr_req->attributes == NULL) { - ret = ENOMEM; - goto end; - } - } - - infp_getattr_req->index = 0; - - /* Prepare the result list */ - infp_getattr_req->results = talloc_array(infp_getattr_req, struct btreemap *, attr_count); - if (infp_getattr_req->results == NULL) { - ret = ENOMEM; - goto end; - } - - /* Look up the first username and start the async loop */ - ret = infp_get_attr_lookup(infp_getattr_req); - if (ret != EOK) { - DEBUG(0, ("Could not read from cache database\n")); - } - -end: - dbus_free_string_array(usernames); - dbus_free_string_array(attributes); - if (ret != EOK) { - infp_return_failure(infp_getattr_req->infp_req, NULL); - talloc_free(infp_getattr_req); - } - return ret; -} - -static int username_comparator(const void *key1, const void *key2) -{ - return strcmp((const char *)key1, (const char *)key2); -} - -struct infp_setattr_ctx { - struct infp_req_ctx *infp_req; - const char **usernames; - int username_count; - uint32_t index; - struct sysdb_handle *handle; - - /* Array of sysdb_attrs objects - * The number of elements in this array - * is equal to the username count; - */ - struct sysdb_attrs **changes; -}; -static void infp_do_user_set_attr(struct sysdb_handle *req, void *pvt); -static void infp_do_user_set_attr_callback(void *ptr, int ldb_status, struct ldb_result *res) -{ - struct infp_setattr_ctx *infp_setattr_req; - - infp_setattr_req = talloc_get_type(ptr, struct infp_setattr_ctx); - - /* Check the ldb_result */ - if (ldb_status != LDB_SUCCESS) { - DEBUG(0, ("Failed to store user attributes to the sysdb\n")); - /* Cancel the transaction */ - sysdb_transaction_done(infp_setattr_req->handle, sysdb_error_to_errno(ldb_status)); - infp_return_failure(infp_setattr_req->infp_req, NULL); - talloc_free(infp_setattr_req); - return; - } - - /* Process any remaining users */ - infp_setattr_req->index++; - if(infp_setattr_req->index < infp_setattr_req->username_count) { - infp_do_user_set_attr(infp_setattr_req->handle, infp_setattr_req); - return; - } - - /* This was the last user. Commit the transaction */ - sysdb_transaction_done(infp_setattr_req->handle, EOK); - - /* Send reply ack */ - infp_return_success(infp_setattr_req->infp_req); - - talloc_free(infp_setattr_req); -} - -static void infp_do_user_set_attr(struct sysdb_handle *handle, void *pvt) -{ - int ret; - struct infp_setattr_ctx *infp_setattr_req; - - infp_setattr_req = talloc_get_type(pvt, struct infp_setattr_ctx); - infp_setattr_req->handle = handle; - - DEBUG(9, ("Setting attributes for user [%s]\n", infp_setattr_req->usernames[infp_setattr_req->index])); - ret = sysdb_set_user_attr(infp_setattr_req->handle, - infp_setattr_req->infp_req->domain, - infp_setattr_req->usernames[infp_setattr_req->index], - infp_setattr_req->changes[infp_setattr_req->index], - infp_do_user_set_attr_callback, infp_setattr_req); - if(ret != EOK) { - DEBUG(0, ("Failed to set attributes for user [%s]. Cancelling transaction\n", infp_setattr_req->usernames[infp_setattr_req->index])); - sysdb_transaction_done(req, ret); - infp_return_failure(infp_setattr_req->infp_req, NULL); - talloc_free(infp_setattr_req); - } -} - -int infp_users_set_attr(DBusMessage *message, struct sbus_conn_ctx *sconn) -{ - TALLOC_CTX *dict_ctx; - DBusMessage *reply; - DBusMessageIter iter, array_iter, dict_array_iter; - DBusMessageIter dict_iter, variant_iter; - dbus_bool_t dbret; - char *domain_name; - char *einval_msg; - const char *recv_username; - const char *dict_key; - char *username; - char *val_key; - char *values; - char **attributes; - int user_count, change_count; - int change_map_count, dict_entry_count; - int added_entries; - int current_type; - int attr_type, variant_type; - int subtype; - struct infp_setattr_ctx *infp_setattr_req; - struct btreemap *username_map; - struct btreemap *value_map; - struct btreemap *change_map; - struct btreemap **change_array; - struct btreemap **tmp_array; - struct ldb_val *val; - int ret, i, j; - - /* Create a infp_setattr_ctx */ - infp_setattr_req = talloc_zero(NULL, struct infp_setattr_ctx); - if(infp_setattr_req == NULL) { - ret = ENOMEM; - goto error; - } - - /* Create an infp_req_ctx */ - infp_setattr_req->infp_req = infp_req_init(infp_setattr_req, - message, sconn); - if (infp_setattr_req->infp_req == NULL) { - ret = EIO; - goto error; - } - - /* Process the arguments to SetUserAttributes */ - dbret = dbus_message_iter_init(message, &iter); - if (!dbret) { - einval_msg = talloc_strdup(infp_setattr_req, "No arguments received."); - goto einval; - } - - /* Get the list of usernames to process */ - current_type = dbus_message_iter_get_arg_type(&iter); - if (current_type != DBUS_TYPE_ARRAY) { - einval_msg = talloc_strdup(infp_setattr_req, "Expected username list."); - goto einval; - } - if(dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING) { - einval_msg = talloc_strdup(infp_setattr_req, "Expected username list."); - goto einval; - } - /* Recurse into the array */ - user_count = 0; - dbus_message_iter_recurse(&iter, &array_iter); - username_map = NULL; - while((current_type=dbus_message_iter_get_arg_type(&array_iter)) != DBUS_TYPE_INVALID) { - dbus_message_iter_get_basic(&array_iter, &recv_username); - username = talloc_strdup(infp_setattr_req, recv_username); - if (username == NULL) { - ret = ENOMEM; - goto error; - } - ret = btreemap_set_value(infp_setattr_req, &username_map, - (const void *)username, NULL, username_comparator); - if (ret != EOK) goto error; - - user_count++; - dbus_message_iter_next(&array_iter); - } - - if (user_count == 0) { - /* No users passed in */ - einval_msg = talloc_strdup(infp_setattr_req, "No usernames provided."); - goto einval; - } - - ret = btreemap_get_keys(infp_setattr_req, username_map, - (const void ***)&infp_setattr_req->usernames, &infp_setattr_req->username_count); - if (ret != EOK) goto error; - - /* Verify that the usernames were all unique. - * If the count of usernames we added differs from the count we're - * getting back, then at least one was a duplicate. - */ - if (infp_setattr_req->username_count != user_count) { - einval_msg = talloc_strdup(infp_setattr_req, "Usernames were not unique."); - goto einval; - } - - /* Get the domain name */ - dbus_message_iter_next(&iter); - if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) { - einval_msg = talloc_strdup(infp_setattr_req, "No domain provided.\n"); - goto einval; - } - dbus_message_iter_get_basic(&iter, &domain_name); - - infp_setattr_req->infp_req->domain = - infp_get_domain_obj(infp_setattr_req->infp_req->infp, domain_name); - if (infp_setattr_req->infp_req->domain == NULL) { - einval_msg = talloc_strdup(infp_setattr_req, "Invalid domain."); - goto einval; - } - - /* Get the array of change DICT entries */ - dbus_message_iter_next(&iter); - current_type = dbus_message_iter_get_arg_type(&iter); - if (current_type != DBUS_TYPE_ARRAY) { - einval_msg = talloc_strdup(infp_setattr_req, "Expected change list."); - goto einval; - } - if(dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_ARRAY) { - einval_msg = talloc_strdup(infp_setattr_req, "Expected array of DICT entry arrays."); - goto einval; - } - - change_count = 0; - change_array = NULL; - dbus_message_iter_recurse(&iter, &array_iter); - if(dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_DICT_ENTRY) { - einval_msg = talloc_strdup(infp_setattr_req, "Expected array of DICT entries."); - goto einval; - } - while((current_type=dbus_message_iter_get_arg_type(&array_iter)) != DBUS_TYPE_INVALID) { - /* Descend into the DICT array */ - dbus_message_iter_recurse(&array_iter, &dict_array_iter); - - /* Create a new talloc context to contain the values from this DICT array */ - dict_ctx = talloc_new(infp_setattr_req); - if(dict_ctx == NULL) { - ret = ENOMEM; - goto error; - } - value_map = NULL; - dict_entry_count = 0; - - while((current_type=dbus_message_iter_get_arg_type(&dict_array_iter)) != DBUS_TYPE_INVALID) { - change_count++; - /* Descend into the DICT entry */ - dbus_message_iter_recurse(&dict_array_iter, &dict_iter); - /* Key must be a string */ - if (dbus_message_iter_get_arg_type(&dict_iter) != DBUS_TYPE_STRING) { - einval_msg = talloc_strdup(infp_setattr_req, "DICT entries must be keyed on strings."); - goto einval; - } - dbus_message_iter_get_basic(&dict_iter, &dict_key); - if((attr_type = infp_get_attribute_type(dict_key)) == INFP_ATTR_TYPE_INVALID) { - /* Continue to the next DICT entry (ignoring unrecognized attributes) */ - change_count--; /* Don't include ignored values in the count */ - dbus_message_iter_next(&dict_array_iter); - continue; - } - val_key = talloc_strdup(dict_ctx, dict_key); - if(val_key == NULL) { - ret = ENOMEM; - goto error; - } - - /* Value is a variant */ - variant_type = infp_get_user_attr_dbus_type(attr_type, &subtype); - if(variant_type == DBUS_TYPE_INVALID) { - /* This shouldn't happen since the attr_type is valid. - * If this failed, it's a coding error. - */ - DEBUG(0, ("Critical error, valid attribute type could not be paired with a D-BUS type.\n")); - ret = EIO; - goto error; - } - - dbus_message_iter_next(&dict_iter); - if (dbus_message_iter_get_arg_type(&dict_iter) != DBUS_TYPE_VARIANT) { - einval_msg = talloc_strdup(infp_setattr_req, "DICT value must be a variant."); - goto einval; - } - dbus_message_iter_recurse(&dict_iter, &variant_iter); - - if (dbus_message_iter_get_arg_type(&variant_iter) != variant_type) { - einval_msg = talloc_asprintf(infp_setattr_req, "DICT value did not match required type of key [%s]. Expected [%c], received [%c]\n", dict_key, variant_type, dbus_message_iter_get_arg_type(&dict_iter)); - goto einval; - } - - if(variant_type == DBUS_TYPE_ARRAY) { - current_type=dbus_message_iter_get_element_type(&variant_iter); - if (!sbus_is_dbus_fixed_type(current_type)) { - /* We only support fixed-type arrays right now */ - einval_msg = talloc_asprintf(infp_setattr_req, "Invalid array type."); - } - } - - ret = infp_get_ldb_val_from_dbus(dict_ctx, &variant_iter, &val, variant_type, subtype); - if (ret != EOK) { - /* Could not create an LDB val from this variant */ - DEBUG(0, ("Error, valid attribute type could not be converted to an ldb_val.\n")); - goto error; - } - - ret = btreemap_set_value(dict_ctx, &value_map, - (const void *)val_key, val, - attr_comparator); - if (ret != EOK) { - DEBUG(0, ("Could not add change value to the value map.\n")); - goto error; - } - - dict_entry_count++; - dbus_message_iter_next(&dict_array_iter); - } - - /* Verify that all of the dict entries were unique */ - ret = btreemap_get_keys(dict_ctx, value_map, - (const void ***)&values, &added_entries); - if (ret != EOK) goto error; - - if (added_entries != dict_entry_count) { - einval_msg = talloc_strdup(infp_setattr_req, "Attributes to change were not unique."); - goto einval; - } - - /* Add the map to an array */ - tmp_array = talloc_realloc(infp_setattr_req, change_array, struct btreemap *, change_count); - if(tmp_array == NULL) { - ret = ENOMEM; - goto error; - } - change_array = tmp_array; - change_array[change_count-1] = value_map; - - dbus_message_iter_next(&array_iter); - } - - if (change_count != infp_setattr_req->username_count && change_count != 1) { - /* Change counts must be one-to-one with the number of users, - * or else exactly one for all users. - */ - einval_msg = talloc_strdup(infp_setattr_req, "Count of change DICTs not equal to one or count of usernames."); - goto einval; - } - - /* Check permissions and create the sysdb_attrs change list */ - infp_setattr_req->changes = talloc_array(infp_setattr_req, struct sysdb_attrs *, infp_setattr_req->username_count); - for (i = 0; i < infp_setattr_req->username_count; i++) { - if (change_count == 1) - change_map = change_array[0]; - else - change_map = change_array[i]; - - ret = btreemap_get_keys(dict_ctx, change_map, - (const void ***)&attributes, &change_map_count); - if (ret != EOK) goto error; - - infp_setattr_req->changes[i] = sysdb_new_attrs(infp_setattr_req); - if (infp_setattr_req->changes[i] == NULL) { - ret = ENOMEM; - goto error; - } - for (j = 0; j < change_map_count; j++) { - /* Add it to the sydb_attrs change list if permission is granted */ - if (infp_get_permissions(infp_setattr_req->infp_req->caller, - infp_setattr_req->infp_req->domain, - INFP_OBJ_TYPE_USER, - infp_setattr_req->usernames[i], - INFP_ACTION_TYPE_MODIFY, - infp_get_attribute_type(attributes[j]))) - { - ret = sysdb_attrs_add_val(infp_setattr_req->changes[i], attributes[j], - btreemap_get_value(change_map, attributes[j])); - if (ret != EOK) { - goto error; - } - } - } - } - - infp_setattr_req->index = 0; - ret = sysdb_transaction(infp_setattr_req, infp_setattr_req->infp_req->infp->sysdb, - infp_do_user_set_attr, infp_setattr_req); - if (ret != EOK) { - DEBUG(0, ("Could not write to the cache database.\n")) - goto error; - } - - 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(infp_setattr_req); - return EOK; - -error: - if(infp_setattr_req) - infp_return_failure(infp_setattr_req->infp_req, NULL); - talloc_free(infp_setattr_req); - return ret; -} - -struct infp_setuid_ctx { - struct infp_req_ctx *infp_req; - struct sysdb_handle *handle; - struct sysdb_attrs *uid_attr; - char *username; -}; - -static void infp_do_user_set_uid_callback(void *ptr, int ldb_status, struct ldb_result *res) -{ - struct infp_setuid_ctx *infp_setuid_req = talloc_get_type(ptr, struct infp_setuid_ctx); - - /* Commit or cancel the transaction, based on the ldb_status */ - sysdb_transaction_done(infp_setuid_req->handle, sysdb_error_to_errno(ldb_status)); - - /* Check the LDB result */ - if (ldb_status != LDB_SUCCESS) { - DEBUG(0, ("Failed to store user uid to the sysdb\n")); - infp_return_failure(infp_setuid_req->infp_req, NULL); - talloc_free(infp_setuid_req); - return; - } - - /* Send reply ack */ - infp_return_success(infp_setuid_req->infp_req); - - talloc_free(infp_setuid_req); -} - -static void infp_do_user_set_uid(struct sysdb_handle *handle, void *pvt) -{ - int ret; - struct infp_setuid_ctx *infp_setuid_req; - - infp_setuid_req = talloc_get_type(pvt, struct infp_setuid_ctx); - infp_setuid_req->handle = handle; - - DEBUG(9, ("Setting UID for user [%s]\n", infp_setuid_req->username)); - ret = sysdb_set_user_attr(infp_setuid_req->handle, - infp_setuid_req->infp_req->domain, - infp_setuid_req->username, - infp_setuid_req->uid_attr, - infp_do_user_set_uid_callback, infp_setuid_req); - if (ret != EOK) { - DEBUG(0, ("Could not invoke sysdb_set_user_attr")); - sysdb_transaction_done(infp_setuid_req->handle, ret); - infp_return_failure(infp_setuid_req->infp_req, NULL); - talloc_free(infp_setuid_req); - return; - } -} - -int infp_users_set_uid(DBusMessage *message, struct sbus_conn_ctx *sconn) -{ - DBusMessage *reply; - DBusError error; - dbus_bool_t dbret; - char *einval_msg; - struct infp_setuid_ctx *infp_setuid_req; - int ret; - - /* Arguments */ - const char *arg_username; - const char *arg_domain; - const int arg_uid; - - infp_setuid_req = talloc_zero(NULL, struct infp_setuid_ctx); - if (infp_setuid_req == NULL) { - ret = ENOMEM; - goto error; - } - - /* Create an infp_req_ctx */ - infp_setuid_req->infp_req = infp_req_init(infp_setuid_req, - message, sconn); - if (infp_setuid_req->infp_req == NULL) { - ret = EIO; - goto error; - } - - dbus_error_init(&error); - dbret = dbus_message_get_args(message, &error, - DBUS_TYPE_STRING, &arg_username, - DBUS_TYPE_STRING, &arg_domain, - DBUS_TYPE_UINT32, &arg_uid, - DBUS_TYPE_INVALID); - if (!dbret) { - DEBUG(0, ("Parsing arguments to SetUserUID failed: %s:%s\n", error.name, error.message)); - einval_msg = talloc_strdup(infp_setuid_req, error.message); - dbus_error_free(&error); - goto einval; - } - - infp_setuid_req->username = talloc_strdup(infp_setuid_req, arg_username); - - infp_setuid_req->infp_req->domain = - infp_get_domain_obj(infp_setuid_req->infp_req->infp, arg_domain); - /* Check for a valid domain */ - if (infp_setuid_req->infp_req->domain == NULL) { - einval_msg = talloc_strdup(infp_setuid_req, "Invalid domain."); - goto einval; - } - - /* Check the domain MIN and MAX */ - if((arg_uid < infp_setuid_req->infp_req->domain->id_min) || /* Requested UID < than minimum */ - ((infp_setuid_req->infp_req->domain->id_max > infp_setuid_req->infp_req->domain->id_min) && /* Maximum exists and is greater than minimum */ - (arg_uid > infp_setuid_req->infp_req->domain->id_max))) { /* Requested UID > maximum */ - einval_msg = talloc_asprintf(infp_setuid_req, "UID out of range for this domain. Minimum: %u Maximum: %u\n", - infp_setuid_req->infp_req->domain->id_min, - infp_setuid_req->infp_req->domain->id_max?infp_setuid_req->infp_req->domain->id_max:(uid_t)-1); - goto einval; - } - - /* Check permissions */ - if(!infp_get_permissions(infp_setuid_req->infp_req->caller, - infp_setuid_req->infp_req->domain, - INFP_OBJ_TYPE_USER, - infp_setuid_req->username, - INFP_ACTION_TYPE_MODIFY, - INFP_ATTR_TYPE_USERID)) - { - 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(infp_setuid_req); - return EOK; - } - - infp_setuid_req->uid_attr = sysdb_new_attrs(infp_setuid_req); - if (infp_setuid_req->uid_attr == NULL) { - ret = ENOMEM; - goto error; - } - sysdb_attrs_add_long(infp_setuid_req->uid_attr, SYSDB_UIDNUM, arg_uid); - - ret = sysdb_transaction(infp_setuid_req, infp_setuid_req->infp_req->infp->sysdb, - infp_do_user_set_uid, infp_setuid_req); - if(ret != EOK) { - DEBUG(0, ("Could not write to the cache database.\n")); - goto error; - } - - return EOK; - -einval: - reply = dbus_message_new_error(message, DBUS_ERROR_NOT_SUPPORTED, einval_msg); - if(reply == NULL) { - ret = ENOMEM; - goto error; - } - - /* send reply */ - sbus_conn_send_reply(sconn, reply); - dbus_message_unref(reply); - - talloc_free(infp_setuid_req); - return EOK; - -error: - if(infp_setuid_req) - infp_return_failure(infp_setuid_req->infp_req, NULL); - talloc_free(infp_setuid_req); - return ret; -} |