From f0a3aa67c0dbf8ca4e606f9e4e2a65d72341e037 Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Thu, 9 Oct 2014 21:05:34 +0200 Subject: [PATCH 2/2] sss_nss_idmap: add sss_nss_getorigbyname() This patch adds an interface to the new SSS_NSS_GETORIGBYNAME request of the nss responder to libsss_nss_idmap. The main use case for this new call is to replace sss_nss_getsidbyname() in the extdom plugin on the FreeIPA server to get more information about the given object than just the SID which is not available with the default POSIX interfaces. --- Makefile.am | 2 +- src/sss_client/idmap/sss_nss_idmap.c | 113 +++++++++++++++++++++++++++++ src/sss_client/idmap/sss_nss_idmap.exports | 7 ++ src/sss_client/idmap/sss_nss_idmap.h | 32 ++++++++ src/tests/cmocka/sss_nss_idmap-tests.c | 26 ++++++- 5 files changed, 178 insertions(+), 2 deletions(-) diff --git a/Makefile.am b/Makefile.am index ee6e39b..4ee7eb9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -791,7 +791,7 @@ libsss_nss_idmap_la_LIBADD = \ $(CLIENT_LIBS) libsss_nss_idmap_la_LDFLAGS = \ -Wl,--version-script,$(srcdir)/src/sss_client/idmap/sss_nss_idmap.exports \ - -version-info 0:1:0 + -version-info 1:0:1 dist_noinst_DATA += src/sss_client/idmap/sss_nss_idmap.exports diff --git a/src/sss_client/idmap/sss_nss_idmap.c b/src/sss_client/idmap/sss_nss_idmap.c index adb5889..55d8043 100644 --- a/src/sss_client/idmap/sss_nss_idmap.c +++ b/src/sss_client/idmap/sss_nss_idmap.c @@ -41,6 +41,7 @@ struct output { union { char *str; uint32_t id; + struct sss_nss_kv *kv_list; } d; }; @@ -58,6 +59,85 @@ int nss_status_to_errno(enum nss_status nret) { return EINVAL; } +void sss_nss_free_kv(struct sss_nss_kv *kv_list) +{ + size_t c; + + if (kv_list != NULL) { + for (c = 0; kv_list[c].key != NULL; c++) { + free(kv_list[c].key); + free(kv_list[c].value); + } + free(kv_list); + } +} + +static int buf_to_kv_list(uint8_t *buf, size_t buf_len, + struct sss_nss_kv **kv_list) +{ + size_t c; + size_t count = 0; + struct sss_nss_kv *list; + uint8_t *p; + int ret; + + for (c = 0; c < buf_len; c++) { + if (buf[c] == '\0') { + count++; + } + } + + if ((count % 2) != 0) { + return EINVAL; + } + count /= 2; + + list = calloc((count + 1), sizeof(struct sss_nss_kv)); + if (list == NULL) { + return ENOMEM; + } + + p = buf; + for (c = 0; c < count; c++) { + list[c].key = strdup((char *) p); + if (list[c].key == NULL) { + ret = ENOMEM; + goto done; + } + + p = memchr(p, '\0', buf_len - (p - buf)); + if (p == NULL) { + ret = EINVAL; + goto done; + } + p++; + + list[c].value = strdup((char *) p); + if (list[c].value == NULL) { + ret = ENOMEM; + goto done; + } + + p = memchr(p, '\0', buf_len - (p - buf)); + if (p == NULL) { + ret = EINVAL; + goto done; + } + p++; + } + + *kv_list = list; + + ret = EOK; + +done: + if (ret != EOK) { + sss_nss_free_kv(list); + } + + return ret; +} + static int sss_nss_getyyybyxxx(union input inp, enum sss_cli_command cmd , struct output *out) { @@ -72,11 +152,13 @@ static int sss_nss_getyyybyxxx(union input inp, enum sss_cli_command cmd , char *str = NULL; size_t data_len; uint32_t c; + struct sss_nss_kv *kv_list; switch (cmd) { case SSS_NSS_GETSIDBYNAME: case SSS_NSS_GETNAMEBYSID: case SSS_NSS_GETIDBYSID: + case SSS_NSS_GETORIGBYNAME: ret = sss_strnlen(inp.str, SSS_NAME_MAX, &inp_len); if (ret != EOK) { return EINVAL; @@ -153,6 +235,15 @@ static int sss_nss_getyyybyxxx(union input inp, enum sss_cli_command cmd , out->d.id = c; break; + case SSS_NSS_GETORIGBYNAME: + ret = buf_to_kv_list(repbuf + DATA_START, data_len, &kv_list); + if (ret != EOK) { + goto done; + } + + out->d.kv_list = kv_list; + + break; default: ret = EINVAL; goto done; @@ -255,3 +346,25 @@ int sss_nss_getidbysid(const char *sid, uint32_t *id, enum sss_id_type *id_type) return ret; } + +int sss_nss_getorigbyname(const char *fq_name, struct sss_nss_kv **kv_list, + enum sss_id_type *type) +{ + int ret; + union input inp; + struct output out; + + if (kv_list == NULL || fq_name == NULL || *fq_name == '\0') { + return EINVAL; + } + + inp.str = fq_name; + + ret = sss_nss_getyyybyxxx(inp, SSS_NSS_GETORIGBYNAME, &out); + if (ret == EOK) { + *kv_list = out.d.kv_list; + *type = out.type; + } + + return ret; +} diff --git a/src/sss_client/idmap/sss_nss_idmap.exports b/src/sss_client/idmap/sss_nss_idmap.exports index 7b8488b..8aa4702 100644 --- a/src/sss_client/idmap/sss_nss_idmap.exports +++ b/src/sss_client/idmap/sss_nss_idmap.exports @@ -12,3 +12,10 @@ SSS_NSS_IDMAP_0.0.1 { local: *; }; + +SSS_NSS_IDMAP_0.1.0 { + # public functions + global: + sss_nss_getorigbyname; + sss_nss_free_kv; +} SSS_NSS_IDMAP_0.0.1; diff --git a/src/sss_client/idmap/sss_nss_idmap.h b/src/sss_client/idmap/sss_nss_idmap.h index 79dacfb..78a8a11 100644 --- a/src/sss_client/idmap/sss_nss_idmap.h +++ b/src/sss_client/idmap/sss_nss_idmap.h @@ -37,6 +37,11 @@ enum sss_id_type { SSS_ID_TYPE_BOTH /* used for user or magic private groups */ }; +struct sss_nss_kv { + char *key; + char *value; +}; + /** * @brief Find SID by fully qualified name * @@ -97,4 +102,31 @@ int sss_nss_getnamebysid(const char *sid, char **fq_name, int sss_nss_getidbysid(const char *sid, uint32_t *id, enum sss_id_type *id_type); +/** + * @brief Find original data by fully qualified name + * + * @param[in] fq_name Fully qualified name of a user or a group + * @param[out] kv_list A NULL terminate list of key-value pairs where the key + * is the attribute name in the cache of SSSD, + * must be freed by the caller with sss_nss_free_kv() + * @param[out] type Type of the object related to the given name + * + * @return + * - 0 (EOK): success, sid contains the requested SID + * - ENOENT: requested object was not found in the domain extracted from the given name + * - ENETUNREACH: SSSD does not know how to handle the domain extracted from the given name + * - ENOSYS: this call is not supported by the configured provider + * - EINVAL: input cannot be parsed + * - EIO: remote servers cannot be reached + * - EFAULT: any other error + */ +int sss_nss_getorigbyname(const char *fq_name, struct sss_nss_kv **kv_list, + enum sss_id_type *type); + +/** + * @brief Free key-value list returned by sss_nss_getorigbyname() + * + * @param[in] kv_list Key-value list returned by sss_nss_getorigbyname(). + */ +void sss_nss_free_kv(struct sss_nss_kv *kv_list); #endif /* SSS_NSS_IDMAP_H_ */ diff --git a/src/tests/cmocka/sss_nss_idmap-tests.c b/src/tests/cmocka/sss_nss_idmap-tests.c index 034f3a1..4141a32 100644 --- a/src/tests/cmocka/sss_nss_idmap-tests.c +++ b/src/tests/cmocka/sss_nss_idmap-tests.c @@ -46,6 +46,9 @@ uint8_t buf1[] = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x uint8_t buf2[] = {0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 't', 'e', 's', 't', 0x00}; uint8_t buf3[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 't', 'e', 's', 't', 0x00}; uint8_t buf4[] = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 't', 'e', 's', 't', 'x'}; + +uint8_t buf_orig1[] = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 'k', 'e', 'y', 0x00, 'v', 'a', 'l', 'u', 'e', 0x00}; + enum nss_status sss_nss_make_request(enum sss_cli_command cmd, struct sss_cli_req_data *rd, uint8_t **repbuf, size_t *replen, @@ -68,7 +71,8 @@ enum nss_status sss_nss_make_request(enum sss_cli_command cmd, return d->nss_status; } -void test_getsidbyname(void **state) { +void test_getsidbyname(void **state) +{ int ret; char *sid = NULL; size_t c; @@ -111,11 +115,31 @@ void test_getsidbyname(void **state) { } } +void test_getorigbyname(void **state) +{ + int ret; + struct sss_nss_kv *kv_list; + enum sss_id_type type; + struct sss_nss_make_request_test_data d = {buf_orig1, sizeof(buf_orig1), 0, NSS_STATUS_SUCCESS}; + + will_return(sss_nss_make_request, &d); + ret = sss_nss_getorigbyname("test", &kv_list, &type); + assert_int_equal(ret, EOK); + assert_int_equal(type, SSS_ID_TYPE_UID); + assert_string_equal(kv_list[0].key, "key"); + assert_string_equal(kv_list[0].value, "value"); + assert_null(kv_list[1].key); + assert_null(kv_list[1].value); + + sss_nss_free_kv(kv_list); +} + int main(int argc, const char *argv[]) { const UnitTest tests[] = { unit_test(test_getsidbyname), + unit_test(test_getorigbyname), }; return run_tests(tests); -- 1.8.3.1