diff options
author | Pavel Březina <pbrezina@redhat.com> | 2015-02-09 12:02:33 +0100 |
---|---|---|
committer | Jakub Hrozek <jhrozek@redhat.com> | 2015-05-22 15:57:14 +0200 |
commit | a1e4113a5388e34c08459c5b69679c82ac2bddc9 (patch) | |
tree | de092388bfceb31b3038ce3cfb056cff6f31bf65 /src | |
parent | c747b0c875785ce693f70b50bdda0237c4b04e35 (diff) | |
download | sssd-a1e4113a5388e34c08459c5b69679c82ac2bddc9.tar.gz sssd-a1e4113a5388e34c08459c5b69679c82ac2bddc9.tar.xz sssd-a1e4113a5388e34c08459c5b69679c82ac2bddc9.zip |
IFP: add org.freedesktop.sssd.infopipe.Users.User
Example calls:
dbus-send --print-reply --system --dest=org.freedesktop.sssd.infopipe /org/freedesktop/sssd/infopipe/Users/LDAP_2ePB/10001 org.freedesktop.DBus.Properties.Get string:org.freedesktop.sssd.infopipe.Users.User string:name
method return sender=:1.159 -> dest=:1.165 reply_serial=2
variant string "user-1"
Resolves:
https://fedorahosted.org/sssd/ticket/2150
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/responder/ifp/ifp_groups.c | 39 | ||||
-rw-r--r-- | src/responder/ifp/ifp_groups.h | 37 | ||||
-rw-r--r-- | src/responder/ifp/ifp_iface.c | 14 | ||||
-rw-r--r-- | src/responder/ifp/ifp_iface.xml | 15 | ||||
-rw-r--r-- | src/responder/ifp/ifp_iface_generated.c | 104 | ||||
-rw-r--r-- | src/responder/ifp/ifp_iface_generated.h | 70 | ||||
-rw-r--r-- | src/responder/ifp/ifp_private.h | 10 | ||||
-rw-r--r-- | src/responder/ifp/ifp_users.c | 459 | ||||
-rw-r--r-- | src/responder/ifp/ifp_users.h | 38 | ||||
-rw-r--r-- | src/responder/ifp/ifpsrv.c | 2 | ||||
-rw-r--r-- | src/responder/ifp/ifpsrv_util.c | 91 | ||||
-rw-r--r-- | src/responder/ifp/org.freedesktop.sssd.infopipe.conf | 1 | ||||
-rw-r--r-- | src/tests/cmocka/test_ifp.c | 14 |
13 files changed, 853 insertions, 41 deletions
diff --git a/src/responder/ifp/ifp_groups.c b/src/responder/ifp/ifp_groups.c new file mode 100644 index 000000000..533e6806d --- /dev/null +++ b/src/responder/ifp/ifp_groups.c @@ -0,0 +1,39 @@ +/* + Authors: + Pavel Březina <pbrezina@redhat.com> + + Copyright (C) 2015 Red Hat + + 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 <talloc.h> + +#include "db/sysdb.h" +#include "responder/ifp/ifp_groups.h" + +char * ifp_groups_build_path_from_msg(TALLOC_CTX *mem_ctx, + struct sss_domain_info *domain, + struct ldb_message *msg) +{ + const char *gid; + + gid = ldb_msg_find_attr_as_string(msg, SYSDB_GIDNUM, NULL); + + if (gid == NULL) { + return NULL; + } + + return sbus_opath_compose(mem_ctx, IFP_PATH_GROUPS, domain->name, gid); +} diff --git a/src/responder/ifp/ifp_groups.h b/src/responder/ifp/ifp_groups.h new file mode 100644 index 000000000..1bdaf3e0c --- /dev/null +++ b/src/responder/ifp/ifp_groups.h @@ -0,0 +1,37 @@ +/* + Authors: + Pavel Březina <pbrezina@redhat.com> + + Copyright (C) 2015 Red Hat + + 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/>. +*/ + +#ifndef IFP_GROUPS_H_ +#define IFP_GROUPS_H_ + +#include "responder/ifp/ifp_iface_generated.h" +#include "responder/ifp/ifp_private.h" + +#define IFP_PATH_GROUPS "/org/freedesktop/sssd/infopipe/Groups" +#define IFP_PATH_GROUPS_TREE IFP_PATH_GROUPS SBUS_SUBTREE_SUFFIX + +/* Utility functions */ + +char * ifp_groups_build_path_from_msg(TALLOC_CTX *mem_ctx, + struct sss_domain_info *domain, + struct ldb_message *msg); + + +#endif /* IFP_GROUPS_H_ */ diff --git a/src/responder/ifp/ifp_iface.c b/src/responder/ifp/ifp_iface.c index 753bad126..1878263c2 100644 --- a/src/responder/ifp/ifp_iface.c +++ b/src/responder/ifp/ifp_iface.c @@ -85,6 +85,19 @@ struct iface_ifp_users iface_ifp_users = { .ListByDomainAndName = ifp_users_list_by_domain_and_name }; +struct iface_ifp_users_user iface_ifp_users_user = { + { &iface_ifp_users_user_meta, 0 }, + .UpdateGroupsList = ifp_users_user_update_groups_list, + .get_name = ifp_users_user_get_name, + .get_uidNumber = ifp_users_user_get_uid_number, + .get_gidNumber = ifp_users_user_get_gid_number, + .get_gecos = ifp_users_user_get_gecos, + .get_homeDirectory = ifp_users_user_get_home_directory, + .get_loginShell = ifp_users_user_get_login_shell, + .get_groups = ifp_users_user_get_groups, + .get_extraAttributes = ifp_users_user_get_extra_attributes +}; + struct iface_map { const char *path; struct sbus_vtable *vtable; @@ -95,6 +108,7 @@ static struct iface_map iface_map[] = { { IFP_PATH_DOMAINS_TREE, &iface_ifp_domains.vtable }, { IFP_PATH_COMPONENTS_TREE, &iface_ifp_components.vtable }, { IFP_PATH_USERS, &iface_ifp_users.vtable }, + { IFP_PATH_USERS_TREE, &iface_ifp_users_user.vtable }, { NULL, NULL }, }; diff --git a/src/responder/ifp/ifp_iface.xml b/src/responder/ifp/ifp_iface.xml index d0c835949..2c15fddea 100644 --- a/src/responder/ifp/ifp_iface.xml +++ b/src/responder/ifp/ifp_iface.xml @@ -125,4 +125,19 @@ <arg name="result" type="ao" direction="out"/> </method> </interface> + + <interface name="org.freedesktop.sssd.infopipe.Users.User"> + <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="iface_ifp_users_user"/> + + <method name="UpdateGroupsList" /> + + <property name="name" type="s" access="read" /> + <property name="uidNumber" type="u" access="read" /> + <property name="gidNumber" type="u" access="read" /> + <property name="gecos" type="s" access="read" /> + <property name="homeDirectory" type="s" access="read" /> + <property name="loginShell" type="s" access="read" /> + <property name="groups" type="ao" access="read" /> + <property name="extraAttributes" type="a{sas}" access="read" /> + </interface> </node> diff --git a/src/responder/ifp/ifp_iface_generated.c b/src/responder/ifp/ifp_iface_generated.c index 40a416bc4..1f6c7ba1d 100644 --- a/src/responder/ifp/ifp_iface_generated.c +++ b/src/responder/ifp/ifp_iface_generated.c @@ -652,6 +652,110 @@ const struct sbus_interface_meta iface_ifp_users_meta = { sbus_invoke_get_all, /* GetAll invoker */ }; +int iface_ifp_users_user_UpdateGroupsList_finish(struct sbus_request *req) +{ + return sbus_request_return_and_finish(req, + DBUS_TYPE_INVALID); +} + +/* methods for org.freedesktop.sssd.infopipe.Users.User */ +const struct sbus_method_meta iface_ifp_users_user__methods[] = { + { + "UpdateGroupsList", /* name */ + NULL, /* no in_args */ + NULL, /* no out_args */ + offsetof(struct iface_ifp_users_user, UpdateGroupsList), + NULL, /* no invoker */ + }, + { NULL, } +}; + +/* property info for org.freedesktop.sssd.infopipe.Users.User */ +const struct sbus_property_meta iface_ifp_users_user__properties[] = { + { + "name", /* name */ + "s", /* type */ + SBUS_PROPERTY_READABLE, + offsetof(struct iface_ifp_users_user, get_name), + sbus_invoke_get_s, + 0, /* not writable */ + NULL, /* no invoker */ + }, + { + "uidNumber", /* name */ + "u", /* type */ + SBUS_PROPERTY_READABLE, + offsetof(struct iface_ifp_users_user, get_uidNumber), + sbus_invoke_get_u, + 0, /* not writable */ + NULL, /* no invoker */ + }, + { + "gidNumber", /* name */ + "u", /* type */ + SBUS_PROPERTY_READABLE, + offsetof(struct iface_ifp_users_user, get_gidNumber), + sbus_invoke_get_u, + 0, /* not writable */ + NULL, /* no invoker */ + }, + { + "gecos", /* name */ + "s", /* type */ + SBUS_PROPERTY_READABLE, + offsetof(struct iface_ifp_users_user, get_gecos), + sbus_invoke_get_s, + 0, /* not writable */ + NULL, /* no invoker */ + }, + { + "homeDirectory", /* name */ + "s", /* type */ + SBUS_PROPERTY_READABLE, + offsetof(struct iface_ifp_users_user, get_homeDirectory), + sbus_invoke_get_s, + 0, /* not writable */ + NULL, /* no invoker */ + }, + { + "loginShell", /* name */ + "s", /* type */ + SBUS_PROPERTY_READABLE, + offsetof(struct iface_ifp_users_user, get_loginShell), + sbus_invoke_get_s, + 0, /* not writable */ + NULL, /* no invoker */ + }, + { + "groups", /* name */ + "ao", /* type */ + SBUS_PROPERTY_READABLE, + offsetof(struct iface_ifp_users_user, get_groups), + sbus_invoke_get_ao, + 0, /* not writable */ + NULL, /* no invoker */ + }, + { + "extraAttributes", /* name */ + "a{sas}", /* type */ + SBUS_PROPERTY_READABLE, + offsetof(struct iface_ifp_users_user, get_extraAttributes), + sbus_invoke_get_aDOsasDE, + 0, /* not writable */ + NULL, /* no invoker */ + }, + { NULL, } +}; + +/* interface info for org.freedesktop.sssd.infopipe.Users.User */ +const struct sbus_interface_meta iface_ifp_users_user_meta = { + "org.freedesktop.sssd.infopipe.Users.User", /* name */ + iface_ifp_users_user__methods, + NULL, /* no signals */ + iface_ifp_users_user__properties, + sbus_invoke_get_all, /* GetAll invoker */ +}; + /* invokes a handler with a 'ssu' DBus signature */ static int invoke_ssu_method(struct sbus_request *dbus_req, void *function_ptr) { diff --git a/src/responder/ifp/ifp_iface_generated.h b/src/responder/ifp/ifp_iface_generated.h index 83ac75b06..609bd40e6 100644 --- a/src/responder/ifp/ifp_iface_generated.h +++ b/src/responder/ifp/ifp_iface_generated.h @@ -61,6 +61,18 @@ #define IFACE_IFP_USERS_LISTBYNAME "ListByName" #define IFACE_IFP_USERS_LISTBYDOMAINANDNAME "ListByDomainAndName" +/* constants for org.freedesktop.sssd.infopipe.Users.User */ +#define IFACE_IFP_USERS_USER "org.freedesktop.sssd.infopipe.Users.User" +#define IFACE_IFP_USERS_USER_UPDATEGROUPSLIST "UpdateGroupsList" +#define IFACE_IFP_USERS_USER_NAME "name" +#define IFACE_IFP_USERS_USER_UIDNUMBER "uidNumber" +#define IFACE_IFP_USERS_USER_GIDNUMBER "gidNumber" +#define IFACE_IFP_USERS_USER_GECOS "gecos" +#define IFACE_IFP_USERS_USER_HOMEDIRECTORY "homeDirectory" +#define IFACE_IFP_USERS_USER_LOGINSHELL "loginShell" +#define IFACE_IFP_USERS_USER_GROUPS "groups" +#define IFACE_IFP_USERS_USER_EXTRAATTRIBUTES "extraAttributes" + /* ------------------------------------------------------------------------ * DBus handlers * @@ -129,11 +141,11 @@ struct iface_ifp_components { int (*Disable)(struct sbus_request *req, void *data); int (*ChangeDebugLevel)(struct sbus_request *req, void *data, uint32_t arg_new_level); int (*ChangeDebugLevelTemporarily)(struct sbus_request *req, void *data, uint32_t arg_new_level); - void (*get_name)(struct sbus_request *, void *data, const char * *); - void (*get_debug_level)(struct sbus_request *, void *data, uint32_t *); - void (*get_enabled)(struct sbus_request *, void *data, bool *); - void (*get_type)(struct sbus_request *, void *data, const char * *); - void (*get_providers)(struct sbus_request *, void *data, const char * * *, int *); + void (*get_name)(struct sbus_request *, void *data, const char **); + void (*get_debug_level)(struct sbus_request *, void *data, uint32_t*); + void (*get_enabled)(struct sbus_request *, void *data, bool*); + void (*get_type)(struct sbus_request *, void *data, const char **); + void (*get_providers)(struct sbus_request *, void *data, const char ***, int *); }; /* finish function for Enable */ @@ -151,20 +163,20 @@ int iface_ifp_components_ChangeDebugLevelTemporarily_finish(struct sbus_request /* vtable for org.freedesktop.sssd.infopipe.Domains */ struct iface_ifp_domains { struct sbus_vtable vtable; /* derive from sbus_vtable */ - void (*get_name)(struct sbus_request *, void *data, const char * *); - void (*get_provider)(struct sbus_request *, void *data, const char * *); - void (*get_primary_servers)(struct sbus_request *, void *data, const char * * *, int *); - void (*get_backup_servers)(struct sbus_request *, void *data, const char * * *, int *); - void (*get_min_id)(struct sbus_request *, void *data, uint32_t *); - void (*get_max_id)(struct sbus_request *, void *data, uint32_t *); - void (*get_realm)(struct sbus_request *, void *data, const char * *); - void (*get_forest)(struct sbus_request *, void *data, const char * *); - void (*get_login_format)(struct sbus_request *, void *data, const char * *); - void (*get_fully_qualified_name_format)(struct sbus_request *, void *data, const char * *); - void (*get_enumerable)(struct sbus_request *, void *data, bool *); - void (*get_use_fully_qualified_names)(struct sbus_request *, void *data, bool *); - void (*get_subdomain)(struct sbus_request *, void *data, bool *); - void (*get_parent_domain)(struct sbus_request *, void *data, const char * *); + void (*get_name)(struct sbus_request *, void *data, const char **); + void (*get_provider)(struct sbus_request *, void *data, const char **); + void (*get_primary_servers)(struct sbus_request *, void *data, const char ***, int *); + void (*get_backup_servers)(struct sbus_request *, void *data, const char ***, int *); + void (*get_min_id)(struct sbus_request *, void *data, uint32_t*); + void (*get_max_id)(struct sbus_request *, void *data, uint32_t*); + void (*get_realm)(struct sbus_request *, void *data, const char **); + void (*get_forest)(struct sbus_request *, void *data, const char **); + void (*get_login_format)(struct sbus_request *, void *data, const char **); + void (*get_fully_qualified_name_format)(struct sbus_request *, void *data, const char **); + void (*get_enumerable)(struct sbus_request *, void *data, bool*); + void (*get_use_fully_qualified_names)(struct sbus_request *, void *data, bool*); + void (*get_subdomain)(struct sbus_request *, void *data, bool*); + void (*get_parent_domain)(struct sbus_request *, void *data, const char **); }; /* vtable for org.freedesktop.sssd.infopipe.Users */ @@ -188,6 +200,23 @@ int iface_ifp_users_ListByName_finish(struct sbus_request *req, const char *arg_ /* finish function for ListByDomainAndName */ int iface_ifp_users_ListByDomainAndName_finish(struct sbus_request *req, const char *arg_result[], int len_result); +/* vtable for org.freedesktop.sssd.infopipe.Users.User */ +struct iface_ifp_users_user { + struct sbus_vtable vtable; /* derive from sbus_vtable */ + int (*UpdateGroupsList)(struct sbus_request *req, void *data); + void (*get_name)(struct sbus_request *, void *data, const char **); + void (*get_uidNumber)(struct sbus_request *, void *data, uint32_t*); + void (*get_gidNumber)(struct sbus_request *, void *data, uint32_t*); + void (*get_gecos)(struct sbus_request *, void *data, const char **); + void (*get_homeDirectory)(struct sbus_request *, void *data, const char **); + void (*get_loginShell)(struct sbus_request *, void *data, const char **); + void (*get_groups)(struct sbus_request *, void *data, const char ***, int *); + void (*get_extraAttributes)(struct sbus_request *, void *data, hash_table_t **); +}; + +/* finish function for UpdateGroupsList */ +int iface_ifp_users_user_UpdateGroupsList_finish(struct sbus_request *req); + /* ------------------------------------------------------------------------ * DBus Interface Metadata * @@ -210,4 +239,7 @@ extern const struct sbus_interface_meta iface_ifp_domains_meta; /* interface info for org.freedesktop.sssd.infopipe.Users */ extern const struct sbus_interface_meta iface_ifp_users_meta; +/* interface info for org.freedesktop.sssd.infopipe.Users.User */ +extern const struct sbus_interface_meta iface_ifp_users_user_meta; + #endif /* __IFP_IFACE_XML__ */ diff --git a/src/responder/ifp/ifp_private.h b/src/responder/ifp/ifp_private.h index f76655fa1..94c9a4b85 100644 --- a/src/responder/ifp/ifp_private.h +++ b/src/responder/ifp/ifp_private.h @@ -73,9 +73,13 @@ int ifp_req_create_handle_failure(struct sbus_request *dbus_req, errno_t err); errno_t ifp_add_ldb_el_to_dict(DBusMessageIter *iter_dict, struct ldb_message_element *el); -const char **ifp_parse_attr_list(TALLOC_CTX *mem_ctx, const char *conf_str); const char ** -ifp_parse_attr_list_ex(TALLOC_CTX *mem_ctx, const char *conf_str, - const char **defaults); +ifp_parse_user_attr_list(TALLOC_CTX *mem_ctx, const char *conf_str); + +const char ** +ifp_get_user_extra_attributes(TALLOC_CTX *mem_ctx, struct ifp_ctx *ifp_ctx); + bool ifp_attr_allowed(const char *whitelist[], const char *attr); +bool ifp_is_user_attr_allowed(struct ifp_ctx *ifp_ctx, const char *attr); + #endif /* _IFPSRV_PRIVATE_H_ */ diff --git a/src/responder/ifp/ifp_users.c b/src/responder/ifp/ifp_users.c index 04fabf77b..26c1aa696 100644 --- a/src/responder/ifp/ifp_users.c +++ b/src/responder/ifp/ifp_users.c @@ -24,10 +24,12 @@ #include "db/sysdb.h" #include "util/util.h" +#include "util/strtonum.h" #include "sbus/sssd_dbus_errors.h" #include "responder/common/responder.h" #include "responder/common/responder_cache_req.h" #include "responder/ifp/ifp_users.h" +#include "responder/ifp/ifp_groups.h" char * ifp_users_build_path_from_msg(TALLOC_CTX *mem_ctx, struct sss_domain_info *domain, @@ -44,6 +46,41 @@ char * ifp_users_build_path_from_msg(TALLOC_CTX *mem_ctx, return sbus_opath_compose(mem_ctx, IFP_PATH_USERS, domain->name, uid); } +static errno_t ifp_users_decompose_path(struct sss_domain_info *domains, + const char *path, + struct sss_domain_info **_domain, + uid_t *_uid) +{ + char **parts = NULL; + struct sss_domain_info *domain; + uid_t uid; + errno_t ret; + + ret = sbus_opath_decompose_exact(NULL, path, IFP_PATH_USERS, 2, &parts); + if (ret != EOK) { + return ret; + } + + domain = find_domain_by_name(domains, parts[0], false); + if (domain == NULL) { + ret = ERR_DOMAIN_NOT_FOUND; + goto done; + } + + uid = strtouint32(parts[1], NULL, 10); + if (errno != 0) { + ret = errno; + goto done; + } + + *_domain = domain; + *_uid = uid; + +done: + talloc_free(parts); + return ret; +} + static void ifp_users_find_by_name_done(struct tevent_req *req); int ifp_users_find_by_name(struct sbus_request *sbus_req, @@ -200,3 +237,425 @@ int ifp_users_list_by_domain_and_name(struct sbus_request *sbus_req, { return EOK; } + +static errno_t +ifp_users_user_get(struct sbus_request *sbus_req, + struct ifp_ctx *ifp_ctx, + uid_t *_uid, + struct sss_domain_info **_domain, + struct ldb_message **_user) +{ + struct sss_domain_info *domain; + struct ldb_result *res; + uid_t uid; + errno_t ret; + + ret = ifp_users_decompose_path(ifp_ctx->rctx->domains, sbus_req->path, + &domain, &uid); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to decompose object path" + "[%s] [%d]: %s\n", sbus_req->path, ret, sss_strerror(ret)); + return ret; + } + + if (_user != NULL) { + ret = sysdb_getpwuid_with_views(sbus_req, domain, uid, &res); + if (ret == EOK && res->count == 0) { + *_user = NULL; + ret = ENOENT; + } + + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to lookup user %u@%s [%d]: %s\n", + uid, domain->name, ret, sss_strerror(ret)); + } else { + *_user = res->msgs[0]; + } + } + + if (ret == EOK || ret == ENOENT) { + if (_uid != NULL) { + *_uid = uid; + } + + if (_domain != NULL) { + *_domain = domain; + } + } + + return ret; +} + +static void ifp_users_get_as_string(struct sbus_request *sbus_req, + void *data, + const char *attr, + const char **_out) +{ + struct ifp_ctx *ifp_ctx; + struct ldb_message *msg; + struct sss_domain_info *domain; + errno_t ret; + + *_out = NULL; + + ifp_ctx = talloc_get_type(data, struct ifp_ctx); + if (ifp_ctx == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Invalid pointer!\n"); + return; + } + + if (!ifp_is_user_attr_allowed(ifp_ctx, attr)) { + DEBUG(SSSDBG_TRACE_ALL, "Attribute %s is not allowed\n", attr); + return; + } + + ret = ifp_users_user_get(sbus_req, ifp_ctx, NULL, &domain, &msg); + if (ret != EOK) { + return; + } + + *_out = sss_view_ldb_msg_find_attr_as_string(domain, msg, attr, NULL); + + return; +} + +static void ifp_users_get_as_uint32(struct sbus_request *sbus_req, + void *data, + const char *attr, + uint32_t *_out) +{ + struct ifp_ctx *ifp_ctx; + struct ldb_message *msg; + struct sss_domain_info *domain; + errno_t ret; + + *_out = 0; + + ifp_ctx = talloc_get_type(data, struct ifp_ctx); + if (ifp_ctx == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Invalid pointer!\n"); + return; + } + + if (!ifp_is_user_attr_allowed(ifp_ctx, attr)) { + DEBUG(SSSDBG_TRACE_ALL, "Attribute %s is not allowed\n", attr); + return; + } + + ret = ifp_users_user_get(sbus_req, ifp_ctx, NULL, &domain, &msg); + if (ret != EOK) { + return; + } + + *_out = sss_view_ldb_msg_find_attr_as_uint64(domain, msg, attr, 0); + + return; +} + +static void ifp_users_user_update_groups_list_done(struct tevent_req *req); + +int ifp_users_user_update_groups_list(struct sbus_request *sbus_req, + void *data) +{ + struct tevent_req *req; + struct ifp_ctx *ctx; + struct sss_domain_info *domain; + const char *username; + struct ldb_message *user; + errno_t ret; + + ctx = talloc_get_type(data, struct ifp_ctx); + if (ctx == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Invalid pointer!\n"); + return ERR_INTERNAL; + } + + ret = ifp_users_user_get(sbus_req, data, NULL, &domain, &user); + if (ret != EOK) { + return ret; + } + + username = ldb_msg_find_attr_as_string(user, SYSDB_NAME, NULL); + if (username == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "User name is empty!\n"); + return ERR_INTERNAL; + } + + req = cache_req_initgr_by_name_send(sbus_req, ctx->rctx->ev, ctx->rctx, + ctx->ncache, ctx->neg_timeout, 0, + domain->name, username); + if (req == NULL) { + return ENOMEM; + } + + tevent_req_set_callback(req, ifp_users_user_update_groups_list_done, + sbus_req); + + return EOK; +} + +static void ifp_users_user_update_groups_list_done(struct tevent_req *req) +{ + DBusError *error; + struct sbus_request *sbus_req; + errno_t ret; + + sbus_req = tevent_req_callback_data(req, struct sbus_request); + + ret = cache_req_initgr_by_name_recv(sbus_req, req, NULL, NULL, NULL); + talloc_zfree(req); + if (ret == ENOENT) { + error = sbus_error_new(sbus_req, SBUS_ERROR_NOT_FOUND, + "User not found"); + goto done; + } else if (ret != EOK) { + error = sbus_error_new(sbus_req, DBUS_ERROR_FAILED, "Failed to fetch " + "user [%d]: %s\n", ret, sss_strerror(ret)); + goto done; + } + +done: + if (ret != EOK) { + sbus_request_fail_and_finish(sbus_req, error); + return; + } + + iface_ifp_users_user_UpdateGroupsList_finish(sbus_req); + return; +} + +void ifp_users_user_get_name(struct sbus_request *sbus_req, + void *data, + const char **_out) +{ + ifp_users_get_as_string(sbus_req, data, SYSDB_NAME, _out); +} + +void ifp_users_user_get_uid_number(struct sbus_request *sbus_req, + void *data, + uint32_t *_out) +{ + ifp_users_get_as_uint32(sbus_req, data, SYSDB_UIDNUM, _out); +} + +void ifp_users_user_get_gid_number(struct sbus_request *sbus_req, + void *data, + uint32_t *_out) +{ + ifp_users_get_as_uint32(sbus_req, data, SYSDB_GIDNUM, _out); +} + +void ifp_users_user_get_gecos(struct sbus_request *sbus_req, + void *data, + const char **_out) +{ + ifp_users_get_as_string(sbus_req, data, SYSDB_GECOS, _out); +} + +void ifp_users_user_get_home_directory(struct sbus_request *sbus_req, + void *data, + const char **_out) +{ + ifp_users_get_as_string(sbus_req, data, SYSDB_HOMEDIR, _out); +} + +void ifp_users_user_get_login_shell(struct sbus_request *sbus_req, + void *data, + const char **_out) +{ + ifp_users_get_as_string(sbus_req, data, SYSDB_SHELL, _out); +} + +void ifp_users_user_get_groups(struct sbus_request *sbus_req, + void *data, + const char ***_out, + int *_size) +{ + struct ifp_ctx *ifp_ctx; + struct sss_domain_info *domain; + const char *username; + struct ldb_message *user; + struct ldb_result *res; + const char **out; + int num_groups; + gid_t gid; + errno_t ret; + int i; + + *_out = NULL; + *_size = 0; + + ifp_ctx = talloc_get_type(data, struct ifp_ctx); + if (ifp_ctx == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Invalid pointer!\n"); + return; + } + + if (!ifp_is_user_attr_allowed(ifp_ctx, "groups")) { + DEBUG(SSSDBG_TRACE_ALL, "Attribute %s is not allowed\n", + SYSDB_MEMBEROF); + return; + } + + ret = ifp_users_user_get(sbus_req, ifp_ctx, NULL, &domain, &user); + if (ret != EOK) { + return; + } + + username = ldb_msg_find_attr_as_string(user, SYSDB_NAME, NULL); + if (username == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "User name is empty!\n"); + return; + } + + /* Run initgroups. */ + ret = sysdb_initgroups_with_views(sbus_req, domain, username, &res); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get groups for %s@%s [%d]: %s\n", + username, domain->name, ret, sss_strerror(ret)); + return; + } + + if (res->count == 0) { + return; + } + + out = talloc_zero_array(sbus_req, const char *, res->count); + if (out == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero_array() failed\n"); + return; + } + + num_groups = 0; + for (i = 0; i < res->count; i++) { + gid = sss_view_ldb_msg_find_attr_as_uint64(domain, res->msgs[i], + SYSDB_GIDNUM, 0); + if (gid == 0) { + continue; + } + + out[i] = ifp_groups_build_path_from_msg(out, domain, res->msgs[i]); + if (out[i] == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "ifp_groups_build_path() failed\n"); + return; + } + + num_groups++; + } + + *_out = out; + *_size = num_groups; +} + +void ifp_users_user_get_extra_attributes(struct sbus_request *sbus_req, + void *data, + hash_table_t **_out) +{ + struct ifp_ctx *ifp_ctx; + struct sss_domain_info *domain; + struct ldb_message **user; + struct ldb_message_element *el; + struct ldb_dn *basedn; + size_t count; + uid_t uid; + const char *filter; + const char **extra; + hash_table_t *table; + hash_key_t key; + hash_value_t value; + const char **values; + errno_t ret; + int hret; + int i; + + *_out = NULL; + + ifp_ctx = talloc_get_type(data, struct ifp_ctx); + if (ifp_ctx == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Invalid pointer!\n"); + return; + } + + extra = ifp_get_user_extra_attributes(sbus_req, ifp_ctx); + if (extra == NULL || extra[0] == NULL) { + DEBUG(SSSDBG_TRACE_ALL, "No extra attributes to return\n"); + return; + } + + ret = ifp_users_user_get(sbus_req, data, &uid, &domain, NULL); + if (ret != EOK) { + return; + } + + basedn = sysdb_user_base_dn(sbus_req, domain); + if (basedn == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_user_base_dn() failed\n"); + return; + } + + filter = talloc_asprintf(sbus_req, "(&(%s=%s)(%s=%u))", + SYSDB_OBJECTCLASS, SYSDB_USER_CLASS, + SYSDB_UIDNUM, uid); + if (filter == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf() failed\n"); + return; + } + + ret = sysdb_search_entry(sbus_req, domain->sysdb, basedn, + LDB_SCOPE_ONELEVEL, filter, + extra, &count, &user); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to lookup user [%d]: %s\n", + ret, sss_strerror(ret)); + return; + } + + if (count == 0) { + DEBUG(SSSDBG_TRACE_FUNC, "User %u not found!\n", uid); + return; + } else if (count > 1) { + DEBUG(SSSDBG_CRIT_FAILURE, "More than one entry found!\n"); + return; + } + + ret = sss_hash_create(sbus_req, 10, &table); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create hash table!\n"); + return; + } + + /* Read each extra attribute. */ + for (i = 0; extra[i] != NULL; i++) { + el = ldb_msg_find_element(user[0], extra[i]); + if (el == NULL) { + DEBUG(SSSDBG_TRACE_ALL, "Attribute %s not found, skipping...\n", + extra[i]); + continue; + } + + values = sss_ldb_el_to_string_list(table, el); + if (values == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "sss_ldb_el_to_string_list() failed\n"); + return; + } + + key.type = HASH_KEY_STRING; + key.str = talloc_strdup(table, extra[i]); + if (key.str == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup() failed\n"); + return; + } + + value.type = HASH_VALUE_PTR; + value.ptr = values; + + hret = hash_enter(table, &key, &value); + if (hret != HASH_SUCCESS) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to insert entry " + "into hash table: %d\n", hret); + return; + } + } + + *_out = table; +} diff --git a/src/responder/ifp/ifp_users.h b/src/responder/ifp/ifp_users.h index a0a079f48..7027ef14e 100644 --- a/src/responder/ifp/ifp_users.h +++ b/src/responder/ifp/ifp_users.h @@ -54,4 +54,42 @@ int ifp_users_list_by_domain_and_name(struct sbus_request *sbus_req, const char *filter, uint32_t limit); +/* org.freedesktop.sssd.infopipe.Users.User */ + +int ifp_users_user_update_groups_list(struct sbus_request *req, + void *data); + +void ifp_users_user_get_name(struct sbus_request *sbus_req, + void *data, + const char **_out); + +void ifp_users_user_get_uid_number(struct sbus_request *sbus_req, + void *data, + uint32_t *_out); + +void ifp_users_user_get_gid_number(struct sbus_request *sbus_req, + void *data, + uint32_t *_out); + +void ifp_users_user_get_gecos(struct sbus_request *sbus_req, + void *data, + const char **_out); + +void ifp_users_user_get_home_directory(struct sbus_request *sbus_req, + void *data, + const char **_out); + +void ifp_users_user_get_login_shell(struct sbus_request *sbus_req, + void *data, + const char **_out); + +void ifp_users_user_get_groups(struct sbus_request *sbus_req, + void *data, + const char ***_out, + int *_size); + +void ifp_users_user_get_extra_attributes(struct sbus_request *sbus_req, + void *data, + hash_table_t **_out); + #endif /* IFP_USERS_H_ */ diff --git a/src/responder/ifp/ifpsrv.c b/src/responder/ifp/ifpsrv.c index 3f5444186..f804ea197 100644 --- a/src/responder/ifp/ifpsrv.c +++ b/src/responder/ifp/ifpsrv.c @@ -300,7 +300,7 @@ int ifp_process_init(TALLOC_CTX *mem_ctx, goto fail; } - ifp_ctx->user_whitelist = ifp_parse_attr_list(ifp_ctx, attr_list_str); + ifp_ctx->user_whitelist = ifp_parse_user_attr_list(ifp_ctx, attr_list_str); talloc_free(attr_list_str); if (ifp_ctx->user_whitelist == NULL) { DEBUG(SSSDBG_FATAL_FAILURE, diff --git a/src/responder/ifp/ifpsrv_util.c b/src/responder/ifp/ifpsrv_util.c index b6a0b168b..674165ee4 100644 --- a/src/responder/ifp/ifpsrv_util.c +++ b/src/responder/ifp/ifpsrv_util.c @@ -24,10 +24,11 @@ #include "db/sysdb.h" #include "responder/ifp/ifp_private.h" -#define IFP_DEFAULT_ATTRS {SYSDB_NAME, SYSDB_UIDNUM, \ - SYSDB_GIDNUM, SYSDB_GECOS, \ - SYSDB_HOMEDIR, SYSDB_SHELL, \ - NULL} +#define IFP_USER_DEFAULT_ATTRS {SYSDB_NAME, SYSDB_UIDNUM, \ + SYSDB_GIDNUM, SYSDB_GECOS, \ + SYSDB_HOMEDIR, SYSDB_SHELL, \ + "groups", \ + NULL} errno_t ifp_req_create(struct sbus_request *dbus_req, struct ifp_ctx *ifp_ctx, @@ -175,13 +176,6 @@ errno_t ifp_add_ldb_el_to_dict(DBusMessageIter *iter_dict, return EOK; } -const char ** -ifp_parse_attr_list(TALLOC_CTX *mem_ctx, const char *conf_str) -{ - const char *defaults[] = IFP_DEFAULT_ATTRS; - - return parse_attr_list_ex(mem_ctx, conf_str, defaults); -} bool ifp_attr_allowed(const char *whitelist[], const char *attr) @@ -200,3 +194,78 @@ ifp_attr_allowed(const char *whitelist[], const char *attr) return (whitelist[i]) ? true : false; } + +const char ** +ifp_parse_user_attr_list(TALLOC_CTX *mem_ctx, const char *csv) +{ + static const char *defaults[] = IFP_USER_DEFAULT_ATTRS; + + return parse_attr_list_ex(mem_ctx, csv, defaults); +} + +const char ** +ifp_get_user_extra_attributes(TALLOC_CTX *mem_ctx, struct ifp_ctx *ifp_ctx) +{ + TALLOC_CTX *tmp_ctx = NULL; + const char *std[] = IFP_USER_DEFAULT_ATTRS; + const char **whitelist = ifp_ctx->user_whitelist; + const char **extra; + bool found; + int extra_num; + int i, j; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n"); + return NULL; + } + + for (i = 0; whitelist[i] != NULL; i++) { + /* Just count number of attributes in whitelist. */ + } + + extra = talloc_zero_array(tmp_ctx, const char *, i + 1); + if (extra == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero_array() failed\n"); + goto fail; + } + + extra_num = 0; + for (i = 0; whitelist[i] != NULL; i++) { + found = false; + for (j = 0; std[j] != NULL; j++) { + if (strcmp(whitelist[i], std[j]) == 0) { + found = true; + break; + } + } + + if (!found) { + extra[extra_num] = talloc_strdup(extra, whitelist[i]); + if (extra[extra_num] == NULL) { + goto fail; + } + + extra_num++; + } + } + + extra = talloc_realloc(tmp_ctx, extra, const char *, extra_num + 1); + if (extra == NULL) { + goto fail; + } + + talloc_steal(mem_ctx, extra); + talloc_free(tmp_ctx); + return extra; + +fail: + talloc_free(tmp_ctx); + return NULL; +} + +bool +ifp_is_user_attr_allowed(struct ifp_ctx *ifp_ctx, const char *attr) +{ + return ifp_attr_allowed(ifp_ctx->user_whitelist, attr); +} diff --git a/src/responder/ifp/org.freedesktop.sssd.infopipe.conf b/src/responder/ifp/org.freedesktop.sssd.infopipe.conf index 195e73aa9..79160bbcc 100644 --- a/src/responder/ifp/org.freedesktop.sssd.infopipe.conf +++ b/src/responder/ifp/org.freedesktop.sssd.infopipe.conf @@ -31,6 +31,7 @@ <allow send_interface="org.freedesktop.sssd.infopipe"/> <allow send_interface="org.freedesktop.sssd.infopipe.Users"/> + <allow send_interface="org.freedesktop.sssd.infopipe.Users.User"/> </policy> <policy user="root"> diff --git a/src/tests/cmocka/test_ifp.c b/src/tests/cmocka/test_ifp.c index a0fb5883c..21c5475d1 100644 --- a/src/tests/cmocka/test_ifp.c +++ b/src/tests/cmocka/test_ifp.c @@ -226,7 +226,7 @@ static void attr_parse_test(const char *expected[], const char *input) test_ctx = talloc_new(NULL); assert_non_null(test_ctx); - res = ifp_parse_attr_list(test_ctx, input); + res = ifp_parse_user_attr_list(test_ctx, input); if (expected) { /* Positive test */ @@ -269,7 +269,7 @@ void test_attr_acl(void **state) const char *exp_defaults[] = { SYSDB_NAME, SYSDB_UIDNUM, SYSDB_GIDNUM, SYSDB_GECOS, SYSDB_HOMEDIR, SYSDB_SHELL, - NULL }; + "groups", NULL }; attr_parse_test(exp_defaults, NULL); /* Test adding some attributes to the defaults */ @@ -277,13 +277,13 @@ void test_attr_acl(void **state) SYSDB_NAME, SYSDB_UIDNUM, SYSDB_GIDNUM, SYSDB_GECOS, SYSDB_HOMEDIR, SYSDB_SHELL, - NULL }; + "groups", NULL }; attr_parse_test(exp_add, "+telephoneNumber, +streetAddress"); /* Test removing some attributes to the defaults */ const char *exp_rm[] = { SYSDB_NAME, SYSDB_GIDNUM, SYSDB_GECOS, - SYSDB_HOMEDIR, + SYSDB_HOMEDIR, "groups", NULL }; attr_parse_test(exp_rm, "-"SYSDB_SHELL ",-"SYSDB_UIDNUM); @@ -291,7 +291,7 @@ void test_attr_acl(void **state) const char *exp_add_rm[] = { "telephoneNumber", SYSDB_NAME, SYSDB_UIDNUM, SYSDB_GIDNUM, SYSDB_GECOS, - SYSDB_HOMEDIR, + SYSDB_HOMEDIR, "groups", NULL }; attr_parse_test(exp_add_rm, "+telephoneNumber, -"SYSDB_SHELL); @@ -299,7 +299,7 @@ void test_attr_acl(void **state) const char *exp_add_rm_override[] = { SYSDB_NAME, SYSDB_UIDNUM, SYSDB_GIDNUM, SYSDB_GECOS, SYSDB_HOMEDIR, SYSDB_SHELL, - NULL }; + "groups", NULL }; attr_parse_test(exp_add_rm_override, "+telephoneNumber, -telephoneNumber, +telephoneNumber"); @@ -307,7 +307,7 @@ void test_attr_acl(void **state) const char *rm_all[] = { NULL }; attr_parse_test(rm_all, "-"SYSDB_NAME ", -"SYSDB_UIDNUM ", -"SYSDB_GIDNUM ", -"SYSDB_GECOS - ", -"SYSDB_HOMEDIR ", -"SYSDB_SHELL); + ", -"SYSDB_HOMEDIR ", -"SYSDB_SHELL", -groups"); /* Malformed list */ attr_parse_test(NULL, "missing_plus_or_minus"); |