From 7781c9e992da93f5d2f1ffe6d4866071502be983 Mon Sep 17 00:00:00 2001 From: Jakub Hrozek Date: Fri, 17 Nov 2017 18:06:26 +0100 Subject: [PATCH] Backport extended NSS API from upstream master branch --- 0002-sss_client-create-nss_common.h.patch | 142 +++ ...ss-like-calls-with-timeout-and-flags.patch | 900 ++++++++++++++++++ ...NSS-add-_EX-version-of-some-requests.patch | 605 ++++++++++++ ...support-for-SSS_NSS_EX_FLAG_NO_CACHE.patch | 148 +++ ...REQ-Add-cache_req_data_set_bypass_dp.patch | 111 +++ ...ss-make-memcache_delete_entry-public.patch | 48 + ...for-SSS_NSS_EX_FLAG_INVALIDATE_CACHE.patch | 364 +++++++ ...ESTS-add-unit-tests-for-_EX-requests.patch | 589 ++++++++++++ ...imeout-version-of-old-sss_nss_-calls.patch | 493 ++++++++++ ...empty-buffer-with-SSS_NSS_EX_FLAG_IN.patch | 183 ++++ sssd.spec | 16 +- 11 files changed, 3598 insertions(+), 1 deletion(-) create mode 100644 0002-sss_client-create-nss_common.h.patch create mode 100644 0003-nss-idmap-add-nss-like-calls-with-timeout-and-flags.patch create mode 100644 0004-NSS-add-_EX-version-of-some-requests.patch create mode 100644 0005-NSS-add-support-for-SSS_NSS_EX_FLAG_NO_CACHE.patch create mode 100644 0006-CACHE_REQ-Add-cache_req_data_set_bypass_dp.patch create mode 100644 0007-nss-make-memcache_delete_entry-public.patch create mode 100644 0008-NSS-add-support-for-SSS_NSS_EX_FLAG_INVALIDATE_CACHE.patch create mode 100644 0009-NSS-TESTS-add-unit-tests-for-_EX-requests.patch create mode 100644 0010-nss-idmap-add-timeout-version-of-old-sss_nss_-calls.patch create mode 100644 0011-nss-idmap-allow-empty-buffer-with-SSS_NSS_EX_FLAG_IN.patch diff --git a/0002-sss_client-create-nss_common.h.patch b/0002-sss_client-create-nss_common.h.patch new file mode 100644 index 0000000..5c15e32 --- /dev/null +++ b/0002-sss_client-create-nss_common.h.patch @@ -0,0 +1,142 @@ +From 7449b236523409cc8766fb957d6cba051fdfb483 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Fri, 29 Sep 2017 21:38:54 +0200 +Subject: [PATCH 02/11] sss_client: create nss_common.h + +This patch makes sss_nss_getpw_readrep() and sss_nss_getgr_readrep() +calls which parse SSSD's replies for user and group requests available +to other components. + +Related to https://pagure.io/SSSD/sssd/issue/2478 + +Reviewed-by: Jakub Hrozek +--- + Makefile.am | 1 + + src/sss_client/nss_common.h | 43 +++++++++++++++++++++++++++++++++++++++++++ + src/sss_client/nss_group.c | 10 +++------- + src/sss_client/nss_passwd.c | 11 +++-------- + 4 files changed, 50 insertions(+), 15 deletions(-) + create mode 100644 src/sss_client/nss_common.h + +diff --git a/Makefile.am b/Makefile.am +index 5483375167d99568e8313c9a0488900419be6ec3..dc2f4b1857ce5bd376544488348731be29b6b293 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -3623,6 +3623,7 @@ libnss_sss_la_SOURCES = \ + src/sss_client/nss_services.c \ + src/sss_client/sss_cli.h \ + src/sss_client/nss_compat.h \ ++ src/sss_client/nss_common.h \ + src/sss_client/nss_mc_common.c \ + src/util/io.c \ + src/util/murmurhash3.c \ +diff --git a/src/sss_client/nss_common.h b/src/sss_client/nss_common.h +new file mode 100644 +index 0000000000000000000000000000000000000000..e83b4f95a3136b5aa711194a4d37389eebfb607a +--- /dev/null ++++ b/src/sss_client/nss_common.h +@@ -0,0 +1,43 @@ ++/* ++ SSSD ++ ++ Common routines for classical and enhanced NSS interface ++ ++ Authors: ++ Sumit Bose ++ ++ Copyright (C) Red Hat, Inc 2007 ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU Lesser 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 Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public License ++ along with this program. If not, see . ++*/ ++ ++ ++ ++struct sss_nss_pw_rep { ++ struct passwd *result; ++ char *buffer; ++ size_t buflen; ++}; ++ ++int sss_nss_getpw_readrep(struct sss_nss_pw_rep *pr, ++ uint8_t *buf, size_t *len); ++ ++struct sss_nss_gr_rep { ++ struct group *result; ++ char *buffer; ++ size_t buflen; ++}; ++ ++int sss_nss_getgr_readrep(struct sss_nss_gr_rep *pr, ++ uint8_t *buf, size_t *len); +diff --git a/src/sss_client/nss_group.c b/src/sss_client/nss_group.c +index 0e686af43aeb84a5938315e3922e9fcf2fef4e83..42fba6242d23fc1d52cfd7be10cf10383010f091 100644 +--- a/src/sss_client/nss_group.c ++++ b/src/sss_client/nss_group.c +@@ -29,6 +29,7 @@ + #include + #include "sss_cli.h" + #include "nss_mc.h" ++#include "nss_common.h" + + static struct sss_nss_getgrent_data { + size_t len; +@@ -190,14 +191,9 @@ done: + * + * FIXME: do we need to pad so that each result is 32 bit aligned ? + */ +-struct sss_nss_gr_rep { +- struct group *result; +- char *buffer; +- size_t buflen; +-}; + +-static int sss_nss_getgr_readrep(struct sss_nss_gr_rep *pr, +- uint8_t *buf, size_t *len) ++int sss_nss_getgr_readrep(struct sss_nss_gr_rep *pr, ++ uint8_t *buf, size_t *len) + { + errno_t ret; + size_t i, l, slen, ptmem, pad, dlen, glen; +diff --git a/src/sss_client/nss_passwd.c b/src/sss_client/nss_passwd.c +index c43f9bc50f43599b541e97f5a5aa60de036a5cdf..61e2a567e684fbc7664b5d425e81cfa28a98e845 100644 +--- a/src/sss_client/nss_passwd.c ++++ b/src/sss_client/nss_passwd.c +@@ -28,6 +28,7 @@ + #include + #include "sss_cli.h" + #include "nss_mc.h" ++#include "nss_common.h" + + static struct sss_nss_getpwent_data { + size_t len; +@@ -63,14 +64,8 @@ static void sss_nss_getpwent_data_clean(void) { + * 8-X: sequence of 5, 0 terminated, strings (name, passwd, gecos, dir, shell) + */ + +-struct sss_nss_pw_rep { +- struct passwd *result; +- char *buffer; +- size_t buflen; +-}; +- +-static int sss_nss_getpw_readrep(struct sss_nss_pw_rep *pr, +- uint8_t *buf, size_t *len) ++int sss_nss_getpw_readrep(struct sss_nss_pw_rep *pr, ++ uint8_t *buf, size_t *len) + { + errno_t ret; + size_t i, slen, dlen; +-- +2.14.3 + diff --git a/0003-nss-idmap-add-nss-like-calls-with-timeout-and-flags.patch b/0003-nss-idmap-add-nss-like-calls-with-timeout-and-flags.patch new file mode 100644 index 0000000..e79a0ec --- /dev/null +++ b/0003-nss-idmap-add-nss-like-calls-with-timeout-and-flags.patch @@ -0,0 +1,900 @@ +From 5e6622722e84d594298a8324f3685a1bda2b5868 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Fri, 29 Sep 2017 16:16:01 +0200 +Subject: [PATCH 03/11] nss-idmap: add nss like calls with timeout and flags + +This patch adds new calls to libsss_nss_idmap to get NSS like user and +group information directly from SSSD without using the system's NSS +interfaces. + +Additionally a timeout and a flags options are added which are not +available for system's NSS. + +Related to https://pagure.io/SSSD/sssd/issue/2478 + +Reviewed-by: Jakub Hrozek +--- + Makefile.am | 22 +- + configure.ac | 13 + + src/sss_client/common.c | 9 +- + src/sss_client/common_private.h | 41 +++ + src/sss_client/idmap/common_ex.c | 105 +++++++ + src/sss_client/idmap/sss_nss_ex.c | 402 +++++++++++++++++++++++++++ + src/sss_client/idmap/sss_nss_idmap.exports | 10 + + src/sss_client/idmap/sss_nss_idmap.h | 135 +++++++++ + src/sss_client/idmap/sss_nss_idmap_private.h | 30 ++ + 9 files changed, 757 insertions(+), 10 deletions(-) + create mode 100644 src/sss_client/common_private.h + create mode 100644 src/sss_client/idmap/common_ex.c + create mode 100644 src/sss_client/idmap/sss_nss_ex.c + create mode 100644 src/sss_client/idmap/sss_nss_idmap_private.h + +diff --git a/Makefile.am b/Makefile.am +index dc2f4b1857ce5bd376544488348731be29b6b293..dd25d1f7ea1be66388aa1b393bac290c4d7501a2 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -1159,13 +1159,28 @@ pkgconfig_DATA += src/sss_client/idmap/sss_nss_idmap.pc + libsss_nss_idmap_la_DEPENDENCIES = src/sss_client/idmap/sss_nss_idmap.exports + libsss_nss_idmap_la_SOURCES = \ + src/sss_client/idmap/sss_nss_idmap.c \ ++ src/sss_client/idmap/sss_nss_ex.c \ ++ src/sss_client/idmap/sss_nss_idmap_private.h \ + src/sss_client/common.c \ +- src/util/strtonum.c ++ src/sss_client/idmap/common_ex.c \ ++ src/sss_client/nss_mc_passwd.c \ ++ src/sss_client/nss_passwd.c \ ++ src/sss_client/nss_mc_group.c \ ++ src/sss_client/nss_group.c \ ++ src/sss_client/nss_mc_initgr.c \ ++ src/sss_client/nss_mc_common.c \ ++ src/util/strtonum.c \ ++ src/util/murmurhash3.c \ ++ src/util/io.c \ ++ $(NULL) + libsss_nss_idmap_la_LIBADD = \ +- $(CLIENT_LIBS) ++ $(LIBCLOCK_GETTIME) \ ++ $(CLIENT_LIBS) \ ++ -lpthread \ ++ $(NULL) + libsss_nss_idmap_la_LDFLAGS = \ + -Wl,--version-script,$(srcdir)/src/sss_client/idmap/sss_nss_idmap.exports \ +- -version-info 3:0:3 ++ -version-info 4:0:4 + + dist_noinst_DATA += src/sss_client/idmap/sss_nss_idmap.exports + +@@ -3624,6 +3639,7 @@ libnss_sss_la_SOURCES = \ + src/sss_client/sss_cli.h \ + src/sss_client/nss_compat.h \ + src/sss_client/nss_common.h \ ++ src/sss_client/common_private.h \ + src/sss_client/nss_mc_common.c \ + src/util/io.c \ + src/util/murmurhash3.c \ +diff --git a/configure.ac b/configure.ac +index 7037927b5f7045b29d3774c85758e00e35e6def6..7e699d33e342c70d210d3f320c8a29a99e0c78a6 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -75,6 +75,19 @@ AC_SEARCH_LIBS([timer_create], [rt posix4], + AC_SUBST([LIBADD_TIMER]) + LIBS=$SAVE_LIBS + ++# Check library for the clock_gettime function ++SAVE_LIBS=$LIBS ++LIBS= ++LIBCLOCK_GETTIME= ++AC_SEARCH_LIBS([clock_gettime], [rt posix4], ++ [AC_DEFINE([HAVE_LIBRT], [1], ++ [Define if you have the librt library or equivalent.]) ++ LIBCLOCK_GETTIME="$LIBS"], ++ [AC_MSG_ERROR([unable to find library for the clock_gettime() function])]) ++ ++AC_SUBST([LIBCLOCK_GETTIME]) ++LIBS=$SAVE_LIBS ++ + # Check for presence of modern functions for setting file timestamps + AC_CHECK_FUNCS([ utimensat \ + futimens ]) +diff --git a/src/sss_client/common.c b/src/sss_client/common.c +index e5e0cbf854e4c977c03f9b1ca1ac90bfd8cbdb77..40252a35281dc4e94c712c3e7f8253af8b19b35a 100644 +--- a/src/sss_client/common.c ++++ b/src/sss_client/common.c +@@ -43,6 +43,7 @@ + #include + #define _(STRING) dgettext (PACKAGE, STRING) + #include "sss_cli.h" ++#include "common_private.h" + + #if HAVE_PTHREAD + #include +@@ -1113,13 +1114,7 @@ errno_t sss_strnlen(const char *str, size_t maxlen, size_t *len) + #if HAVE_PTHREAD + typedef void (*sss_mutex_init)(void); + +-struct sss_mutex { +- pthread_mutex_t mtx; +- +- int old_cancel_state; +-}; +- +-static struct sss_mutex sss_nss_mtx = { .mtx = PTHREAD_MUTEX_INITIALIZER }; ++struct sss_mutex sss_nss_mtx = { .mtx = PTHREAD_MUTEX_INITIALIZER }; + + static struct sss_mutex sss_pam_mtx = { .mtx = PTHREAD_MUTEX_INITIALIZER }; + +diff --git a/src/sss_client/common_private.h b/src/sss_client/common_private.h +new file mode 100644 +index 0000000000000000000000000000000000000000..a98d2c062caeecdbab02ecdaa6ae44d688a791bb +--- /dev/null ++++ b/src/sss_client/common_private.h +@@ -0,0 +1,41 @@ ++/* ++ SSSD ++ ++ SSS client - private calls ++ ++ Authors: ++ Sumit Bose ++ ++ Copyright (C) 2017 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 . ++*/ ++ ++#ifndef COMMON_PRIVATE_H_ ++#define COMMON_PRIVATE_H_ ++ ++#include "config.h" ++ ++#if HAVE_PTHREAD ++#include ++ ++struct sss_mutex { ++ pthread_mutex_t mtx; ++ ++ int old_cancel_state; ++}; ++ ++#endif /* HAVE_PTHREAD */ ++ ++#endif /* COMMON_PRIVATE_H_ */ +diff --git a/src/sss_client/idmap/common_ex.c b/src/sss_client/idmap/common_ex.c +new file mode 100644 +index 0000000000000000000000000000000000000000..5efe9fabed7896ce674615472dbb256c4eae2144 +--- /dev/null ++++ b/src/sss_client/idmap/common_ex.c +@@ -0,0 +1,105 @@ ++/* ++ Authors: ++ Sumit Bose ++ ++ Copyright (C) 2017 Red Hat ++ ++ SSSD's enhanced NSS API ++ ++ 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 . ++*/ ++ ++#include ++#include ++ ++#include "sss_cli.h" ++#include "common_private.h" ++ ++extern struct sss_mutex sss_nss_mtx; ++ ++#define SEC_FROM_MSEC(ms) ((ms) / 1000) ++#define NSEC_FROM_MSEC(ms) (((ms) % 1000) * 1000 * 1000) ++ ++/* adopted from timersub() defined in /usr/include/sys/time.h */ ++#define TIMESPECSUB(a, b, result) \ ++ do { \ ++ (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ ++ (result)->tv_nsec = (a)->tv_nsec - (b)->tv_nsec; \ ++ if ((result)->tv_nsec < 0) { \ ++ --(result)->tv_sec; \ ++ (result)->tv_nsec += 1000000000; \ ++ } \ ++ } while (0) ++ ++#define TIMESPEC_TO_MS(ts) ( ((ts)->tv_sec * 1000) \ ++ + ((ts)->tv_nsec) / (1000 * 1000) ) ++ ++static int sss_mt_timedlock(struct sss_mutex *m, struct timespec *endtime) ++{ ++ int ret; ++ ++ ret = pthread_mutex_timedlock(&m->mtx, endtime); ++ if (ret != 0) { ++ return ret; ++ } ++ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &m->old_cancel_state); ++ ++ return 0; ++} ++ ++int sss_nss_timedlock(unsigned int timeout_ms, int *time_left_ms) ++{ ++ int ret; ++ int left; ++ struct timespec starttime; ++ struct timespec endtime; ++ struct timespec diff; ++ ++ /* make sure there is no overrun when calculating the time left */ ++ if (timeout_ms > INT_MAX) { ++ timeout_ms = INT_MAX; ++ } ++ ++ ret = clock_gettime(CLOCK_REALTIME, &starttime); ++ if (ret != 0) { ++ return ret; ++ } ++ endtime.tv_sec = starttime.tv_sec + SEC_FROM_MSEC(timeout_ms); ++ endtime.tv_nsec = starttime.tv_nsec + NSEC_FROM_MSEC(timeout_ms); ++ ++ ret = sss_mt_timedlock(&sss_nss_mtx, &endtime); ++ ++ if (ret == 0) { ++ ret = clock_gettime(CLOCK_REALTIME, &endtime); ++ if (ret != 0) { ++ return ret; ++ } ++ ++ if (timeout_ms == 0) { ++ *time_left_ms = 0; ++ } else { ++ TIMESPECSUB(&endtime, &starttime, &diff); ++ left = timeout_ms - TIMESPEC_TO_MS(&diff); ++ if (left <= 0) { ++ return EIO; ++ } else if (left > SSS_CLI_SOCKET_TIMEOUT) { ++ *time_left_ms = SSS_CLI_SOCKET_TIMEOUT; ++ } else { ++ *time_left_ms = left; ++ } ++ } ++ } ++ ++ return ret; ++} +diff --git a/src/sss_client/idmap/sss_nss_ex.c b/src/sss_client/idmap/sss_nss_ex.c +new file mode 100644 +index 0000000000000000000000000000000000000000..582d1373ec35305cf128e04fd3d705457d304789 +--- /dev/null ++++ b/src/sss_client/idmap/sss_nss_ex.c +@@ -0,0 +1,402 @@ ++/* ++ SSSD ++ ++ Extended NSS Responder Interface ++ ++ Authors: ++ Sumit Bose ++ ++ Copyright (C) 2017 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 . ++*/ ++#include ++#include ++ ++#include /* for MIN() */ ++ ++#include "sss_client/sss_cli.h" ++#include "sss_client/nss_mc.h" ++#include "sss_client/nss_common.h" ++#include "sss_client/idmap/sss_nss_idmap.h" ++#include "sss_client/idmap/sss_nss_idmap_private.h" ++ ++#ifndef discard_const ++#define discard_const(ptr) ((void *)((uintptr_t)(ptr))) ++#endif ++ ++struct sss_nss_initgr_rep { ++ gid_t *groups; ++ long int *ngroups; ++ long int *start; ++}; ++ ++struct nss_input { ++ union { ++ const char *name; ++ uid_t uid; ++ gid_t gid; ++ } input; ++ struct sss_cli_req_data rd; ++ enum sss_cli_command cmd; ++ union { ++ struct sss_nss_pw_rep pwrep; ++ struct sss_nss_gr_rep grrep; ++ struct sss_nss_initgr_rep initgrrep; ++ } result; ++}; ++ ++errno_t sss_nss_mc_get(struct nss_input *inp) ++{ ++ switch(inp->cmd) { ++ case SSS_NSS_GETPWNAM: ++ return sss_nss_mc_getpwnam(inp->input.name, (inp->rd.len - 1), ++ inp->result.pwrep.result, ++ inp->result.pwrep.buffer, ++ inp->result.pwrep.buflen); ++ break; ++ case SSS_NSS_GETPWUID: ++ return sss_nss_mc_getpwuid(inp->input.uid, ++ inp->result.pwrep.result, ++ inp->result.pwrep.buffer, ++ inp->result.pwrep.buflen); ++ break; ++ case SSS_NSS_GETGRNAM: ++ return sss_nss_mc_getgrnam(inp->input.name, (inp->rd.len - 1), ++ inp->result.grrep.result, ++ inp->result.grrep.buffer, ++ inp->result.grrep.buflen); ++ break; ++ case SSS_NSS_GETGRGID: ++ return sss_nss_mc_getgrgid(inp->input.gid, ++ inp->result.grrep.result, ++ inp->result.grrep.buffer, ++ inp->result.grrep.buflen); ++ break; ++ case SSS_NSS_INITGR: ++ return sss_nss_mc_initgroups_dyn(inp->input.name, (inp->rd.len - 1), ++ -1 /* currently ignored */, ++ inp->result.initgrrep.start, ++ inp->result.initgrrep.ngroups, ++ &(inp->result.initgrrep.groups), ++ *(inp->result.initgrrep.ngroups)); ++ break; ++ default: ++ return EINVAL; ++ } ++} ++ ++int sss_get_ex(struct nss_input *inp, uint32_t flags, unsigned int timeout) ++{ ++ uint8_t *repbuf = NULL; ++ size_t replen; ++ size_t len; ++ uint32_t num_results; ++ int ret; ++ int time_left; ++ int errnop; ++ size_t c; ++ gid_t *new_groups; ++ size_t idx; ++ ++ ret = sss_nss_mc_get(inp); ++ switch (ret) { ++ case 0: ++ return 0; ++ case ERANGE: ++ return ERANGE; ++ case ENOENT: ++ /* fall through, we need to actively ask the parent ++ * if no entry is found */ ++ break; ++ default: ++ /* if using the mmaped cache failed, ++ * fall back to socket based comms */ ++ break; ++ } ++ ++ sss_nss_timedlock(timeout, &time_left); ++ ++ /* previous thread might already initialize entry in mmap cache */ ++ ret = sss_nss_mc_get(inp); ++ switch (ret) { ++ case 0: ++ ret = 0; ++ goto out; ++ case ERANGE: ++ ret = ERANGE; ++ goto out; ++ case ENOENT: ++ /* fall through, we need to actively ask the parent ++ * if no entry is found */ ++ break; ++ default: ++ /* if using the mmaped cache failed, ++ * fall back to socket based comms */ ++ break; ++ } ++ ++ ret = sss_nss_make_request_timeout(inp->cmd, &inp->rd, time_left, ++ &repbuf, &replen, &errnop); ++ if (ret != NSS_STATUS_SUCCESS) { ++ ret = errnop != 0 ? errnop : EIO; ++ goto out; ++ } ++ ++ /* Get number of results from repbuf. */ ++ SAFEALIGN_COPY_UINT32(&num_results, repbuf, NULL); ++ ++ /* no results if not found */ ++ if (num_results == 0) { ++ ret = ENOENT; ++ goto out; ++ } ++ ++ if (inp->cmd == SSS_NSS_INITGR) { ++ if ((*(inp->result.initgrrep.ngroups) - *(inp->result.initgrrep.start)) ++ < num_results) { ++ new_groups = realloc(inp->result.initgrrep.groups, ++ (num_results + *(inp->result.initgrrep.start)) ++ * sizeof(gid_t)); ++ if (new_groups == NULL) { ++ ret = ENOMEM; ++ goto out; ++ } ++ ++ inp->result.initgrrep.groups = new_groups; ++ } ++ *(inp->result.initgrrep.ngroups) = num_results ++ + *(inp->result.initgrrep.start); ++ ++ idx = 2 * sizeof(uint32_t); ++ for (c = 0; c < num_results; c++) { ++ SAFEALIGN_COPY_UINT32( ++ &(inp->result.initgrrep.groups[*(inp->result.initgrrep.start)]), ++ repbuf + idx, &idx); ++ *(inp->result.initgrrep.start) += 1; ++ } ++ ++ ret = 0; ++ goto out; ++ } ++ ++ /* only 1 result is accepted for this function */ ++ if (num_results != 1) { ++ ret = EBADMSG; ++ goto out; ++ } ++ ++ len = replen - 8; ++ if (inp->cmd == SSS_NSS_GETPWNAM || inp->cmd == SSS_NSS_GETPWUID) { ++ ret = sss_nss_getpw_readrep(&(inp->result.pwrep), repbuf+8, &len); ++ } else if (inp->cmd == SSS_NSS_GETGRNAM || inp->cmd == SSS_NSS_GETGRGID) { ++ ret = sss_nss_getgr_readrep(&(inp->result.grrep), repbuf+8, &len); ++ } else { ++ ret = EINVAL; ++ goto out; ++ } ++ if (ret) { ++ goto out; ++ } ++ ++ if (len == 0) { ++ /* no extra data */ ++ ret = 0; ++ goto out; ++ } ++ ++out: ++ free(repbuf); ++ ++ sss_nss_unlock(); ++ return ret; ++} ++ ++int sss_nss_getpwnam_timeout(const char *name, struct passwd *pwd, ++ char *buffer, size_t buflen, ++ struct passwd **result, ++ uint32_t flags, unsigned int timeout) ++{ ++ int ret; ++ struct nss_input inp = { ++ .input.name = name, ++ .cmd = SSS_NSS_GETPWNAM, ++ .rd.data = name, ++ .result.pwrep.result = pwd, ++ .result.pwrep.buffer = buffer, ++ .result.pwrep.buflen = buflen}; ++ ++ if (buffer == NULL || buflen == 0) { ++ return ERANGE; ++ } ++ ++ ret = sss_strnlen(name, SSS_NAME_MAX, &inp.rd.len); ++ if (ret != 0) { ++ return EINVAL; ++ } ++ inp.rd.len++; ++ ++ *result = NULL; ++ ++ ret = sss_get_ex(&inp, flags, timeout); ++ if (ret == 0) { ++ *result = inp.result.pwrep.result; ++ } ++ return ret; ++} ++ ++int sss_nss_getpwuid_timeout(uid_t uid, struct passwd *pwd, ++ char *buffer, size_t buflen, ++ struct passwd **result, ++ uint32_t flags, unsigned int timeout) ++{ ++ int ret; ++ uint32_t user_uid = uid; ++ struct nss_input inp = { ++ .input.uid = uid, ++ .cmd = SSS_NSS_GETPWUID, ++ .rd.len = sizeof(uint32_t), ++ .rd.data = &user_uid, ++ .result.pwrep.result = pwd, ++ .result.pwrep.buffer = buffer, ++ .result.pwrep.buflen = buflen}; ++ ++ if (buffer == NULL || buflen == 0) { ++ return ERANGE; ++ } ++ ++ *result = NULL; ++ ++ ret = sss_get_ex(&inp, flags, timeout); ++ if (ret == 0) { ++ *result = inp.result.pwrep.result; ++ } ++ return ret; ++} ++ ++int sss_nss_getgrnam_timeout(const char *name, struct group *grp, ++ char *buffer, size_t buflen, struct group **result, ++ uint32_t flags, unsigned int timeout) ++{ ++ int ret; ++ struct nss_input inp = { ++ .input.name = name, ++ .cmd = SSS_NSS_GETGRNAM, ++ .rd.data = name, ++ .result.grrep.result = grp, ++ .result.grrep.buffer = buffer, ++ .result.grrep.buflen = buflen}; ++ ++ if (buffer == NULL || buflen == 0) { ++ return ERANGE; ++ } ++ ++ ret = sss_strnlen(name, SSS_NAME_MAX, &inp.rd.len); ++ if (ret != 0) { ++ return EINVAL; ++ } ++ inp.rd.len++; ++ ++ *result = NULL; ++ ++ ret = sss_get_ex(&inp, flags, timeout); ++ if (ret == 0) { ++ *result = inp.result.grrep.result; ++ } ++ return ret; ++} ++ ++int sss_nss_getgrgid_timeout(gid_t gid, struct group *grp, ++ char *buffer, size_t buflen, struct group **result, ++ uint32_t flags, unsigned int timeout) ++{ ++ int ret; ++ uint32_t group_gid = gid; ++ struct nss_input inp = { ++ .input.gid = gid, ++ .cmd = SSS_NSS_GETGRGID, ++ .rd.len = sizeof(uint32_t), ++ .rd.data = &group_gid, ++ .result.grrep.result = grp, ++ .result.grrep.buffer = buffer, ++ .result.grrep.buflen = buflen}; ++ ++ if (buffer == NULL || buflen == 0) { ++ return ERANGE; ++ } ++ ++ *result = NULL; ++ ++ ret = sss_get_ex(&inp, flags, timeout); ++ if (ret == 0) { ++ *result = inp.result.grrep.result; ++ } ++ return ret; ++} ++ ++int sss_nss_getgrouplist_timeout(const char *name, gid_t group, ++ gid_t *groups, int *ngroups, ++ uint32_t flags, unsigned int timeout) ++{ ++ int ret; ++ gid_t *new_groups; ++ long int new_ngroups; ++ long int start = 1; ++ struct nss_input inp = { ++ .input.name = name, ++ .cmd = SSS_NSS_INITGR, ++ .rd.data = name}; ++ ++ if (groups == NULL || ngroups == NULL || *ngroups == 0) { ++ return EINVAL; ++ } ++ ++ ret = sss_strnlen(name, SSS_NAME_MAX, &inp.rd.len); ++ if (ret != 0) { ++ return ret; ++ } ++ inp.rd.len++; ++ ++ new_ngroups = MAX(1, *ngroups); ++ new_groups = malloc(new_ngroups * sizeof(gid_t)); ++ if (new_groups == NULL) { ++ free(discard_const(inp.rd.data)); ++ return ENOMEM; ++ } ++ new_groups[0] = group; ++ ++ inp.result.initgrrep.groups = new_groups, ++ inp.result.initgrrep.ngroups = &new_ngroups; ++ inp.result.initgrrep.start = &start; ++ ++ ++ ret = sss_get_ex(&inp, flags, timeout); ++ free(discard_const(inp.rd.data)); ++ if (ret != 0) { ++ free(new_groups); ++ return ret; ++ } ++ ++ memcpy(groups, new_groups, MIN(*ngroups, start) * sizeof(gid_t)); ++ free(new_groups); ++ ++ if (start > *ngroups) { ++ ret = ERANGE; ++ } else { ++ ret = 0; ++ } ++ *ngroups = start; ++ ++ return ret; ++} +diff --git a/src/sss_client/idmap/sss_nss_idmap.exports b/src/sss_client/idmap/sss_nss_idmap.exports +index 49dac6fc9351b0ca98cd46e83b85ec8ef0075a0d..788d05ecc3bd56fa88e68a98b9c8096cf7140a09 100644 +--- a/src/sss_client/idmap/sss_nss_idmap.exports ++++ b/src/sss_client/idmap/sss_nss_idmap.exports +@@ -31,3 +31,13 @@ SSS_NSS_IDMAP_0.3.0 { + global: + sss_nss_getlistbycert; + } SSS_NSS_IDMAP_0.2.0; ++ ++SSS_NSS_IDMAP_0.4.0 { ++ # public functions ++ global: ++ sss_nss_getpwnam_timeout; ++ sss_nss_getpwuid_timeout; ++ sss_nss_getgrnam_timeout; ++ sss_nss_getgrgid_timeout; ++ sss_nss_getgrouplist_timeout; ++} SSS_NSS_IDMAP_0.3.0; +diff --git a/src/sss_client/idmap/sss_nss_idmap.h b/src/sss_client/idmap/sss_nss_idmap.h +index cbf19479ff9ec6e0d6e07e1f7e48a1571e147740..2334b6cb3fb8ef62e4ce3a7187c7affaeaa034e7 100644 +--- a/src/sss_client/idmap/sss_nss_idmap.h ++++ b/src/sss_client/idmap/sss_nss_idmap.h +@@ -26,6 +26,9 @@ + #define SSS_NSS_IDMAP_H_ + + #include ++#include ++#include ++#include + + /** + * Object types +@@ -159,4 +162,136 @@ int sss_nss_getlistbycert(const char *cert, char ***fq_name, + * @param[in] kv_list Key-value list returned by sss_nss_getorigbyname(). + */ + void sss_nss_free_kv(struct sss_nss_kv *kv_list); ++ ++/** ++ * Flags to control the behavior and the results for sss_*_ex() calls ++ */ ++ ++#define SSS_NSS_EX_FLAG_NO_FLAGS 0 ++ ++#ifdef IPA_389DS_PLUGIN_HELPER_CALLS ++ ++/** ++ * @brief Return user information based on the user name ++ * ++ * @param[in] name same as for getpwnam_r(3) ++ * @param[in] pwd same as for getpwnam_r(3) ++ * @param[in] buffer same as for getpwnam_r(3) ++ * @param[in] buflen same as for getpwnam_r(3) ++ * @param[out] result same as for getpwnam_r(3) ++ * @param[in] flags flags to control the behavior and the results of the ++ * call ++ * @param[in] timeout timeout in milliseconds ++ * ++ * @return ++ * - 0: ++ * - ENOENT: no user with the given name found ++ * - ERANGE: Insufficient buffer space supplied ++ * - ETIME: request timed out but was send to SSSD ++ * - ETIMEDOUT: request timed out but was not send to SSSD ++ */ ++int sss_nss_getpwnam_timeout(const char *name, struct passwd *pwd, ++ char *buffer, size_t buflen, ++ struct passwd **result, ++ uint32_t flags, unsigned int timeout); ++ ++/** ++ * @brief Return user information based on the user uid ++ * ++ * @param[in] uid same as for getpwuid_r(3) ++ * @param[in] pwd same as for getpwuid_r(3) ++ * @param[in] buffer same as for getpwuid_r(3) ++ * @param[in] buflen same as for getpwuid_r(3) ++ * @param[out] result same as for getpwuid_r(3) ++ * @param[in] flags flags to control the behavior and the results of the ++ * call ++ * @param[in] timeout timeout in milliseconds ++ * ++ * @return ++ * - 0: ++ * - ENOENT: no user with the given uid found ++ * - ERANGE: Insufficient buffer space supplied ++ * - ETIME: request timed out but was send to SSSD ++ * - ETIMEDOUT: request timed out but was not send to SSSD ++ */ ++int sss_nss_getpwuid_timeout(uid_t uid, struct passwd *pwd, ++ char *buffer, size_t buflen, ++ struct passwd **result, ++ uint32_t flags, unsigned int timeout); ++ ++/** ++ * @brief Return group information based on the group name ++ * ++ * @param[in] name same as for getgrnam_r(3) ++ * @param[in] pwd same as for getgrnam_r(3) ++ * @param[in] buffer same as for getgrnam_r(3) ++ * @param[in] buflen same as for getgrnam_r(3) ++ * @param[out] result same as for getgrnam_r(3) ++ * @param[in] flags flags to control the behavior and the results of the ++ * call ++ * @param[in] timeout timeout in milliseconds ++ * ++ * @return ++ * - 0: ++ * - ENOENT: no group with the given name found ++ * - ERANGE: Insufficient buffer space supplied ++ * - ETIME: request timed out but was send to SSSD ++ * - ETIMEDOUT: request timed out but was not send to SSSD ++ */ ++int sss_nss_getgrnam_timeout(const char *name, struct group *grp, ++ char *buffer, size_t buflen, struct group **result, ++ uint32_t flags, unsigned int timeout); ++ ++/** ++ * @brief Return group information based on the group gid ++ * ++ * @param[in] gid same as for getgrgid_r(3) ++ * @param[in] pwd same as for getgrgid_r(3) ++ * @param[in] buffer same as for getgrgid_r(3) ++ * @param[in] buflen same as for getgrgid_r(3) ++ * @param[out] result same as for getgrgid_r(3) ++ * @param[in] flags flags to control the behavior and the results of the ++ * call ++ * @param[in] timeout timeout in milliseconds ++ * ++ * @return ++ * - 0: ++ * - ENOENT: no group with the given gid found ++ * - ERANGE: Insufficient buffer space supplied ++ * - ETIME: request timed out but was send to SSSD ++ * - ETIMEDOUT: request timed out but was not send to SSSD ++ */ ++int sss_nss_getgrgid_timeout(gid_t gid, struct group *grp, ++ char *buffer, size_t buflen, struct group **result, ++ uint32_t flags, unsigned int timeout); ++ ++/** ++ * @brief Return a list of groups to which a user belongs ++ * ++ * @param[in] name name of the user ++ * @param[in] group same as second argument of getgrouplist(3) ++ * @param[in] groups array of gid_t of size ngroups, will be filled ++ * with GIDs of groups the user belongs to ++ * @param[in,out] ngroups size of the groups array on input. On output it ++ * will contain the actual number of groups the ++ * user belongs to. With a return value of 0 the ++ * groups array was large enough to hold all group. ++ * With a return valu of ERANGE the array was not ++ * large enough and ngroups will have the needed ++ * size. ++ * @param[in] flags flags to control the behavior and the results of ++ * the call ++ * @param[in] timeout timeout in milliseconds ++ * ++ * @return ++ * - 0: success ++ * - ENOENT: no user with the given name found ++ * - ERANGE: Insufficient buffer space supplied ++ * - ETIME: request timed out but was send to SSSD ++ * - ETIMEDOUT: request timed out but was not send to SSSD ++ */ ++int sss_nss_getgrouplist_timeout(const char *name, gid_t group, ++ gid_t *groups, int *ngroups, ++ uint32_t flags, unsigned int timeout); ++#endif /* IPA_389DS_PLUGIN_HELPER_CALLS */ + #endif /* SSS_NSS_IDMAP_H_ */ +diff --git a/src/sss_client/idmap/sss_nss_idmap_private.h b/src/sss_client/idmap/sss_nss_idmap_private.h +new file mode 100644 +index 0000000000000000000000000000000000000000..afcd8e355981b9a2dc29a62bab143756b39ed654 +--- /dev/null ++++ b/src/sss_client/idmap/sss_nss_idmap_private.h +@@ -0,0 +1,30 @@ ++/* ++ SSSD ++ ++ NSS Responder ID-mapping interface - private calls ++ ++ Authors: ++ Sumit Bose ++ ++ Copyright (C) 2017 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 . ++*/ ++ ++#ifndef SSS_NSS_IDMAP_PRIVATE_H_ ++#define SSS_NSS_IDMAP_PRIVATE_H_ ++ ++int sss_nss_timedlock(unsigned int timeout_ms, int *time_left_ms); ++ ++#endif /* SSS_NSS_IDMAP_PRIVATE_H_ */ +-- +2.14.3 + diff --git a/0004-NSS-add-_EX-version-of-some-requests.patch b/0004-NSS-add-_EX-version-of-some-requests.patch new file mode 100644 index 0000000..7c096c9 --- /dev/null +++ b/0004-NSS-add-_EX-version-of-some-requests.patch @@ -0,0 +1,605 @@ +From cf93f7c2f2031078bbbff095dae01eb4f8deff85 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Wed, 11 Oct 2017 14:54:54 +0200 +Subject: [PATCH 04/11] NSS: add *_EX version of some requests + +To be able to send the flags to the SSSD responder new request types +with an _EX postfix are added which expect and additional 32bit flag +field after the name or the id of the requested object. + +Related to https://pagure.io/SSSD/sssd/issue/2478 + +Reviewed-by: Jakub Hrozek +--- + src/responder/nss/nss_cmd.c | 76 +++++++++++++++++++++----- + src/responder/nss/nss_protocol.c | 81 ++++++++++++++++++++++++++++ + src/responder/nss/nss_protocol.h | 8 +++ + src/sss_client/idmap/sss_nss_ex.c | 110 +++++++++++++++++++++++++++----------- + src/sss_client/sss_cli.h | 7 +++ + 5 files changed, 237 insertions(+), 45 deletions(-) + +diff --git a/src/responder/nss/nss_cmd.c b/src/responder/nss/nss_cmd.c +index ebf66dfe0444b83aed20d58d36ddf70d2f4fa1f9..974eaccc93cea3a330007735676da69eb9b84141 100644 +--- a/src/responder/nss/nss_cmd.c ++++ b/src/responder/nss/nss_cmd.c +@@ -54,6 +54,7 @@ static void nss_getby_done(struct tevent_req *subreq); + static void nss_getlistby_done(struct tevent_req *subreq); + + static errno_t nss_getby_name(struct cli_ctx *cli_ctx, ++ bool ex_version, + enum cache_req_type type, + const char **attrs, + enum sss_mc_type memcache, +@@ -64,6 +65,7 @@ static errno_t nss_getby_name(struct cli_ctx *cli_ctx, + struct tevent_req *subreq; + const char *rawname; + errno_t ret; ++ uint32_t flags = 0; + + cmd_ctx = nss_cmd_ctx_create(cli_ctx, cli_ctx, type, fill_fn); + if (cmd_ctx == NULL) { +@@ -71,7 +73,11 @@ static errno_t nss_getby_name(struct cli_ctx *cli_ctx, + goto done; + } + +- ret = nss_protocol_parse_name(cli_ctx, &rawname); ++ if (ex_version) { ++ ret = nss_protocol_parse_name_ex(cli_ctx, &rawname, &flags); ++ } else { ++ ret = nss_protocol_parse_name(cli_ctx, &rawname); ++ } + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Invalid request message!\n"); + goto done; +@@ -108,6 +114,7 @@ done: + } + + static errno_t nss_getby_id(struct cli_ctx *cli_ctx, ++ bool ex_version, + enum cache_req_type type, + const char **attrs, + enum sss_mc_type memcache, +@@ -118,6 +125,7 @@ static errno_t nss_getby_id(struct cli_ctx *cli_ctx, + struct tevent_req *subreq; + uint32_t id; + errno_t ret; ++ uint32_t flags = 0; + + cmd_ctx = nss_cmd_ctx_create(cli_ctx, cli_ctx, type, fill_fn); + if (cmd_ctx == NULL) { +@@ -125,7 +133,11 @@ static errno_t nss_getby_id(struct cli_ctx *cli_ctx, + goto done; + } + +- ret = nss_protocol_parse_id(cli_ctx, &id); ++ if (ex_version) { ++ ret = nss_protocol_parse_id_ex(cli_ctx, &id, &flags); ++ } else { ++ ret = nss_protocol_parse_id(cli_ctx, &id); ++ } + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Invalid request message!\n"); + goto done; +@@ -766,14 +778,26 @@ static errno_t nss_endent(struct cli_ctx *cli_ctx, + + static errno_t nss_cmd_getpwnam(struct cli_ctx *cli_ctx) + { +- return nss_getby_name(cli_ctx, CACHE_REQ_USER_BY_NAME, NULL, SSS_MC_PASSWD, +- nss_protocol_fill_pwent); ++ return nss_getby_name(cli_ctx, false, CACHE_REQ_USER_BY_NAME, NULL, ++ SSS_MC_PASSWD, nss_protocol_fill_pwent); + } + + static errno_t nss_cmd_getpwuid(struct cli_ctx *cli_ctx) + { +- return nss_getby_id(cli_ctx, CACHE_REQ_USER_BY_ID, NULL, SSS_MC_PASSWD, +- nss_protocol_fill_pwent); ++ return nss_getby_id(cli_ctx, false, CACHE_REQ_USER_BY_ID, NULL, ++ SSS_MC_PASSWD, nss_protocol_fill_pwent); ++} ++ ++static errno_t nss_cmd_getpwnam_ex(struct cli_ctx *cli_ctx) ++{ ++ return nss_getby_name(cli_ctx, true, CACHE_REQ_USER_BY_NAME, NULL, ++ SSS_MC_PASSWD, nss_protocol_fill_pwent); ++} ++ ++static errno_t nss_cmd_getpwuid_ex(struct cli_ctx *cli_ctx) ++{ ++ return nss_getby_id(cli_ctx, true, CACHE_REQ_USER_BY_ID, NULL, ++ SSS_MC_PASSWD, nss_protocol_fill_pwent); + } + + static errno_t nss_cmd_setpwent(struct cli_ctx *cli_ctx) +@@ -809,16 +833,29 @@ static errno_t nss_cmd_endpwent(struct cli_ctx *cli_ctx) + + static errno_t nss_cmd_getgrnam(struct cli_ctx *cli_ctx) + { +- return nss_getby_name(cli_ctx, CACHE_REQ_GROUP_BY_NAME, NULL, SSS_MC_GROUP, +- nss_protocol_fill_grent); ++ return nss_getby_name(cli_ctx, false, CACHE_REQ_GROUP_BY_NAME, NULL, ++ SSS_MC_GROUP, nss_protocol_fill_grent); + } + + static errno_t nss_cmd_getgrgid(struct cli_ctx *cli_ctx) + { +- return nss_getby_id(cli_ctx, CACHE_REQ_GROUP_BY_ID, NULL, SSS_MC_GROUP, +- nss_protocol_fill_grent); ++ return nss_getby_id(cli_ctx, false, CACHE_REQ_GROUP_BY_ID, NULL, ++ SSS_MC_GROUP, nss_protocol_fill_grent); + } + ++static errno_t nss_cmd_getgrnam_ex(struct cli_ctx *cli_ctx) ++{ ++ return nss_getby_name(cli_ctx, true, CACHE_REQ_GROUP_BY_NAME, NULL, ++ SSS_MC_GROUP, nss_protocol_fill_grent); ++} ++ ++static errno_t nss_cmd_getgrgid_ex(struct cli_ctx *cli_ctx) ++{ ++ return nss_getby_id(cli_ctx, true, CACHE_REQ_GROUP_BY_ID, NULL, ++ SSS_MC_GROUP, nss_protocol_fill_grent); ++} ++ ++ + static errno_t nss_cmd_setgrent(struct cli_ctx *cli_ctx) + { + struct nss_ctx *nss_ctx; +@@ -852,7 +889,13 @@ static errno_t nss_cmd_endgrent(struct cli_ctx *cli_ctx) + + static errno_t nss_cmd_initgroups(struct cli_ctx *cli_ctx) + { +- return nss_getby_name(cli_ctx, CACHE_REQ_INITGROUPS, NULL, ++ return nss_getby_name(cli_ctx, false, CACHE_REQ_INITGROUPS, NULL, ++ SSS_MC_INITGROUPS, nss_protocol_fill_initgr); ++} ++ ++static errno_t nss_cmd_initgroups_ex(struct cli_ctx *cli_ctx) ++{ ++ return nss_getby_name(cli_ctx, true, CACHE_REQ_INITGROUPS, NULL, + SSS_MC_INITGROUPS, nss_protocol_fill_initgr); + } + +@@ -943,7 +986,7 @@ static errno_t nss_cmd_getsidbyname(struct cli_ctx *cli_ctx) + { + const char *attrs[] = { SYSDB_SID_STR, NULL }; + +- return nss_getby_name(cli_ctx, CACHE_REQ_OBJECT_BY_NAME, attrs, ++ return nss_getby_name(cli_ctx, false, CACHE_REQ_OBJECT_BY_NAME, attrs, + SSS_MC_NONE, nss_protocol_fill_sid); + } + +@@ -951,7 +994,7 @@ static errno_t nss_cmd_getsidbyid(struct cli_ctx *cli_ctx) + { + const char *attrs[] = { SYSDB_SID_STR, NULL }; + +- return nss_getby_id(cli_ctx, CACHE_REQ_OBJECT_BY_ID, attrs, ++ return nss_getby_id(cli_ctx, false, CACHE_REQ_OBJECT_BY_ID, attrs, + SSS_MC_NONE, nss_protocol_fill_sid); + } + +@@ -1006,7 +1049,7 @@ static errno_t nss_cmd_getorigbyname(struct cli_ctx *cli_ctx) + attrs = defattrs; + } + +- return nss_getby_name(cli_ctx, CACHE_REQ_OBJECT_BY_NAME, attrs, ++ return nss_getby_name(cli_ctx, false, CACHE_REQ_OBJECT_BY_NAME, attrs, + SSS_MC_NONE, nss_protocol_fill_orig); + } + +@@ -1051,6 +1094,11 @@ struct sss_cmd_table *get_nss_cmds(void) + { SSS_NSS_GETORIGBYNAME, nss_cmd_getorigbyname }, + { SSS_NSS_GETNAMEBYCERT, nss_cmd_getnamebycert }, + { SSS_NSS_GETLISTBYCERT, nss_cmd_getlistbycert }, ++ { SSS_NSS_GETPWNAM_EX, nss_cmd_getpwnam_ex }, ++ { SSS_NSS_GETPWUID_EX, nss_cmd_getpwuid_ex }, ++ { SSS_NSS_GETGRNAM_EX, nss_cmd_getgrnam_ex }, ++ { SSS_NSS_GETGRGID_EX, nss_cmd_getgrgid_ex }, ++ { SSS_NSS_INITGR_EX, nss_cmd_initgroups_ex }, + { SSS_CLI_NULL, NULL } + }; + +diff --git a/src/responder/nss/nss_protocol.c b/src/responder/nss/nss_protocol.c +index 06fc4d00a7877a7990402f4f2633ddc0bd640b41..17bfc4f4e71960a72e9e04622eac95b94a865ec7 100644 +--- a/src/responder/nss/nss_protocol.c ++++ b/src/responder/nss/nss_protocol.c +@@ -133,6 +133,61 @@ nss_protocol_parse_name(struct cli_ctx *cli_ctx, const char **_rawname) + return EOK; + } + ++errno_t ++nss_protocol_parse_name_ex(struct cli_ctx *cli_ctx, const char **_rawname, ++ uint32_t *_flags) ++{ ++ struct cli_protocol *pctx; ++ const char *rawname; ++ uint8_t *body; ++ size_t blen; ++ uint8_t *p; ++ uint32_t flags; ++ ++ pctx = talloc_get_type(cli_ctx->protocol_ctx, struct cli_protocol); ++ ++ sss_packet_get_body(pctx->creq->in, &body, &blen); ++ ++ if (blen < 1 + sizeof(uint32_t)) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Body too short!\n"); ++ return EINVAL; ++ } ++ ++ /* If first argument not terminated fail. */ ++ if (body[blen - 1 - sizeof(uint32_t)] != '\0') { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Body is not null terminated!\n"); ++ return EINVAL; ++ } ++ ++ p = memchr(body, '\0', blen); ++ ++ /* If the body isn't valid UTF-8, fail */ ++ if (!sss_utf8_check(body, (p - body))) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "First argument is not UTF-8 string!\n"); ++ return EINVAL; ++ } ++ ++ rawname = (const char *)body; ++ if (rawname[0] == '\0') { ++ DEBUG(SSSDBG_CRIT_FAILURE, "An empty name was provided!\n"); ++ return EINVAL; ++ } ++ ++ p++; ++ if ((p - body) + sizeof(uint32_t) != blen) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Body has unexpected size!\n"); ++ return EINVAL; ++ } ++ ++ SAFEALIGN_COPY_UINT32(&flags, p, NULL); ++ p += sizeof(uint32_t); ++ ++ *_rawname = rawname; ++ *_flags = flags; ++ ++ return EOK; ++} ++ + errno_t + nss_protocol_parse_id(struct cli_ctx *cli_ctx, uint32_t *_id) + { +@@ -156,6 +211,32 @@ nss_protocol_parse_id(struct cli_ctx *cli_ctx, uint32_t *_id) + return EOK; + } + ++errno_t ++nss_protocol_parse_id_ex(struct cli_ctx *cli_ctx, uint32_t *_id, ++ uint32_t *_flags) ++{ ++ struct cli_protocol *pctx; ++ uint8_t *body; ++ size_t blen; ++ uint32_t id; ++ uint32_t flags; ++ ++ pctx = talloc_get_type(cli_ctx->protocol_ctx, struct cli_protocol); ++ ++ sss_packet_get_body(pctx->creq->in, &body, &blen); ++ ++ if (blen != 2 * sizeof(uint32_t)) { ++ return EINVAL; ++ } ++ ++ SAFEALIGN_COPY_UINT32(&id, body, NULL); ++ SAFEALIGN_COPY_UINT32(&flags, body + sizeof(uint32_t), NULL); ++ ++ *_id = id; ++ ++ return EOK; ++} ++ + errno_t + nss_protocol_parse_limit(struct cli_ctx *cli_ctx, uint32_t *_limit) + { +diff --git a/src/responder/nss/nss_protocol.h b/src/responder/nss/nss_protocol.h +index 417b0891615dcb8771d49f7b2f4d276342ca3150..ca5b040237dc18acdca9a7a3a7a7dbb64265aa95 100644 +--- a/src/responder/nss/nss_protocol.h ++++ b/src/responder/nss/nss_protocol.h +@@ -88,9 +88,17 @@ void nss_protocol_reply(struct cli_ctx *cli_ctx, + errno_t + nss_protocol_parse_name(struct cli_ctx *cli_ctx, const char **_rawname); + ++errno_t ++nss_protocol_parse_name_ex(struct cli_ctx *cli_ctx, const char **_rawname, ++ uint32_t *_flags); ++ + errno_t + nss_protocol_parse_id(struct cli_ctx *cli_ctx, uint32_t *_id); + ++errno_t ++nss_protocol_parse_id_ex(struct cli_ctx *cli_ctx, uint32_t *_id, ++ uint32_t *_flags); ++ + errno_t + nss_protocol_parse_limit(struct cli_ctx *cli_ctx, uint32_t *_limit); + +diff --git a/src/sss_client/idmap/sss_nss_ex.c b/src/sss_client/idmap/sss_nss_ex.c +index 582d1373ec35305cf128e04fd3d705457d304789..dc7610a4e528b5126f0d25d84cd3c1a22f683b75 100644 +--- a/src/sss_client/idmap/sss_nss_ex.c ++++ b/src/sss_client/idmap/sss_nss_ex.c +@@ -61,31 +61,37 @@ errno_t sss_nss_mc_get(struct nss_input *inp) + { + switch(inp->cmd) { + case SSS_NSS_GETPWNAM: +- return sss_nss_mc_getpwnam(inp->input.name, (inp->rd.len - 1), ++ case SSS_NSS_GETPWNAM_EX: ++ return sss_nss_mc_getpwnam(inp->input.name, strlen(inp->input.name), + inp->result.pwrep.result, + inp->result.pwrep.buffer, + inp->result.pwrep.buflen); + break; + case SSS_NSS_GETPWUID: ++ case SSS_NSS_GETPWUID_EX: + return sss_nss_mc_getpwuid(inp->input.uid, + inp->result.pwrep.result, + inp->result.pwrep.buffer, + inp->result.pwrep.buflen); + break; + case SSS_NSS_GETGRNAM: +- return sss_nss_mc_getgrnam(inp->input.name, (inp->rd.len - 1), ++ case SSS_NSS_GETGRNAM_EX: ++ return sss_nss_mc_getgrnam(inp->input.name, strlen(inp->input.name), + inp->result.grrep.result, + inp->result.grrep.buffer, + inp->result.grrep.buflen); + break; + case SSS_NSS_GETGRGID: ++ case SSS_NSS_GETGRGID_EX: + return sss_nss_mc_getgrgid(inp->input.gid, + inp->result.grrep.result, + inp->result.grrep.buffer, + inp->result.grrep.buflen); + break; + case SSS_NSS_INITGR: +- return sss_nss_mc_initgroups_dyn(inp->input.name, (inp->rd.len - 1), ++ case SSS_NSS_INITGR_EX: ++ return sss_nss_mc_initgroups_dyn(inp->input.name, ++ strlen(inp->input.name), + -1 /* currently ignored */, + inp->result.initgrrep.start, + inp->result.initgrrep.ngroups, +@@ -163,7 +169,7 @@ int sss_get_ex(struct nss_input *inp, uint32_t flags, unsigned int timeout) + goto out; + } + +- if (inp->cmd == SSS_NSS_INITGR) { ++ if (inp->cmd == SSS_NSS_INITGR || inp->cmd == SSS_NSS_INITGR_EX) { + if ((*(inp->result.initgrrep.ngroups) - *(inp->result.initgrrep.start)) + < num_results) { + new_groups = realloc(inp->result.initgrrep.groups, +@@ -198,15 +204,24 @@ int sss_get_ex(struct nss_input *inp, uint32_t flags, unsigned int timeout) + } + + len = replen - 8; +- if (inp->cmd == SSS_NSS_GETPWNAM || inp->cmd == SSS_NSS_GETPWUID) { ++ ++ switch(inp->cmd) { ++ case SSS_NSS_GETPWNAM: ++ case SSS_NSS_GETPWUID: ++ case SSS_NSS_GETPWNAM_EX: ++ case SSS_NSS_GETPWUID_EX: + ret = sss_nss_getpw_readrep(&(inp->result.pwrep), repbuf+8, &len); +- } else if (inp->cmd == SSS_NSS_GETGRNAM || inp->cmd == SSS_NSS_GETGRGID) { ++ break; ++ case SSS_NSS_GETGRNAM: ++ case SSS_NSS_GETGRGID: ++ case SSS_NSS_GETGRNAM_EX: ++ case SSS_NSS_GETGRGID_EX: + ret = sss_nss_getgr_readrep(&(inp->result.grrep), repbuf+8, &len); +- } else { ++ break; ++ default: + ret = EINVAL; +- goto out; + } +- if (ret) { ++ if (ret != 0) { + goto out; + } + +@@ -223,6 +238,39 @@ out: + return ret; + } + ++static int make_name_flag_req_data(const char *name, uint32_t flags, ++ struct sss_cli_req_data *rd) ++{ ++ size_t len; ++ size_t name_len; ++ uint8_t *data; ++ int ret; ++ ++ if (name == NULL) { ++ return EINVAL; ++ } ++ ++ ret = sss_strnlen(name, SSS_NAME_MAX, &name_len); ++ if (ret != 0) { ++ return ret; ++ } ++ name_len++; ++ ++ len = name_len + sizeof(uint32_t); ++ data = malloc(len); ++ if (data == NULL) { ++ return ENOMEM; ++ } ++ ++ memcpy(data, name, name_len); ++ SAFEALIGN_COPY_UINT32(data + name_len, &flags, NULL); ++ ++ rd->len = len; ++ rd->data = data; ++ ++ return 0; ++} ++ + int sss_nss_getpwnam_timeout(const char *name, struct passwd *pwd, + char *buffer, size_t buflen, + struct passwd **result, +@@ -231,8 +279,7 @@ int sss_nss_getpwnam_timeout(const char *name, struct passwd *pwd, + int ret; + struct nss_input inp = { + .input.name = name, +- .cmd = SSS_NSS_GETPWNAM, +- .rd.data = name, ++ .cmd = SSS_NSS_GETPWNAM_EX, + .result.pwrep.result = pwd, + .result.pwrep.buffer = buffer, + .result.pwrep.buflen = buflen}; +@@ -241,15 +288,15 @@ int sss_nss_getpwnam_timeout(const char *name, struct passwd *pwd, + return ERANGE; + } + +- ret = sss_strnlen(name, SSS_NAME_MAX, &inp.rd.len); ++ ret = make_name_flag_req_data(name, flags, &inp.rd); + if (ret != 0) { +- return EINVAL; ++ return ret; + } +- inp.rd.len++; + + *result = NULL; + + ret = sss_get_ex(&inp, flags, timeout); ++ free(discard_const(inp.rd.data)); + if (ret == 0) { + *result = inp.result.pwrep.result; + } +@@ -262,12 +309,12 @@ int sss_nss_getpwuid_timeout(uid_t uid, struct passwd *pwd, + uint32_t flags, unsigned int timeout) + { + int ret; +- uint32_t user_uid = uid; ++ uint32_t req_data[2]; + struct nss_input inp = { + .input.uid = uid, +- .cmd = SSS_NSS_GETPWUID, +- .rd.len = sizeof(uint32_t), +- .rd.data = &user_uid, ++ .cmd = SSS_NSS_GETPWUID_EX, ++ .rd.len = 2 * sizeof(uint32_t), ++ .rd.data = &req_data, + .result.pwrep.result = pwd, + .result.pwrep.buffer = buffer, + .result.pwrep.buflen = buflen}; +@@ -276,6 +323,8 @@ int sss_nss_getpwuid_timeout(uid_t uid, struct passwd *pwd, + return ERANGE; + } + ++ SAFEALIGN_COPY_UINT32(&req_data[0], &uid, NULL); ++ SAFEALIGN_COPY_UINT32(&req_data[1], &flags, NULL); + *result = NULL; + + ret = sss_get_ex(&inp, flags, timeout); +@@ -292,8 +341,7 @@ int sss_nss_getgrnam_timeout(const char *name, struct group *grp, + int ret; + struct nss_input inp = { + .input.name = name, +- .cmd = SSS_NSS_GETGRNAM, +- .rd.data = name, ++ .cmd = SSS_NSS_GETGRNAM_EX, + .result.grrep.result = grp, + .result.grrep.buffer = buffer, + .result.grrep.buflen = buflen}; +@@ -302,15 +350,15 @@ int sss_nss_getgrnam_timeout(const char *name, struct group *grp, + return ERANGE; + } + +- ret = sss_strnlen(name, SSS_NAME_MAX, &inp.rd.len); ++ ret = make_name_flag_req_data(name, flags, &inp.rd); + if (ret != 0) { +- return EINVAL; ++ return ret; + } +- inp.rd.len++; + + *result = NULL; + + ret = sss_get_ex(&inp, flags, timeout); ++ free(discard_const(inp.rd.data)); + if (ret == 0) { + *result = inp.result.grrep.result; + } +@@ -322,12 +370,12 @@ int sss_nss_getgrgid_timeout(gid_t gid, struct group *grp, + uint32_t flags, unsigned int timeout) + { + int ret; +- uint32_t group_gid = gid; ++ uint32_t req_data[2]; + struct nss_input inp = { + .input.gid = gid, +- .cmd = SSS_NSS_GETGRGID, +- .rd.len = sizeof(uint32_t), +- .rd.data = &group_gid, ++ .cmd = SSS_NSS_GETGRGID_EX, ++ .rd.len = 2 * sizeof(uint32_t), ++ .rd.data = &req_data, + .result.grrep.result = grp, + .result.grrep.buffer = buffer, + .result.grrep.buflen = buflen}; +@@ -336,6 +384,8 @@ int sss_nss_getgrgid_timeout(gid_t gid, struct group *grp, + return ERANGE; + } + ++ SAFEALIGN_COPY_UINT32(&req_data[0], &gid, NULL); ++ SAFEALIGN_COPY_UINT32(&req_data[1], &flags, NULL); + *result = NULL; + + ret = sss_get_ex(&inp, flags, timeout); +@@ -355,18 +405,16 @@ int sss_nss_getgrouplist_timeout(const char *name, gid_t group, + long int start = 1; + struct nss_input inp = { + .input.name = name, +- .cmd = SSS_NSS_INITGR, +- .rd.data = name}; ++ .cmd = SSS_NSS_INITGR_EX}; + + if (groups == NULL || ngroups == NULL || *ngroups == 0) { + return EINVAL; + } + +- ret = sss_strnlen(name, SSS_NAME_MAX, &inp.rd.len); ++ ret = make_name_flag_req_data(name, flags, &inp.rd); + if (ret != 0) { + return ret; + } +- inp.rd.len++; + + new_ngroups = MAX(1, *ngroups); + new_groups = malloc(new_ngroups * sizeof(gid_t)); +diff --git a/src/sss_client/sss_cli.h b/src/sss_client/sss_cli.h +index 5329651a9385d138b8ea7237cb5cf4e2b8e5f371..9d2cc00c9957f5680548461129e3e6b777da5091 100644 +--- a/src/sss_client/sss_cli.h ++++ b/src/sss_client/sss_cli.h +@@ -79,6 +79,9 @@ enum sss_cli_command { + SSS_NSS_GETPWENT = 0x0014, + SSS_NSS_ENDPWENT = 0x0015, + ++ SSS_NSS_GETPWNAM_EX = 0x0019, ++ SSS_NSS_GETPWUID_EX = 0x001A, ++ + /* group */ + + SSS_NSS_GETGRNAM = 0x0021, +@@ -88,6 +91,10 @@ enum sss_cli_command { + SSS_NSS_ENDGRENT = 0x0025, + SSS_NSS_INITGR = 0x0026, + ++ SSS_NSS_GETGRNAM_EX = 0x0029, ++ SSS_NSS_GETGRGID_EX = 0x002A, ++ SSS_NSS_INITGR_EX = 0x002E, ++ + #if 0 + /* aliases */ + +-- +2.14.3 + diff --git a/0005-NSS-add-support-for-SSS_NSS_EX_FLAG_NO_CACHE.patch b/0005-NSS-add-support-for-SSS_NSS_EX_FLAG_NO_CACHE.patch new file mode 100644 index 0000000..21775ae --- /dev/null +++ b/0005-NSS-add-support-for-SSS_NSS_EX_FLAG_NO_CACHE.patch @@ -0,0 +1,148 @@ +From ac6b267ff3df6d0417062a128ec16b184ea2c1b7 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Thu, 12 Oct 2017 10:42:41 +0200 +Subject: [PATCH 05/11] NSS: add support for SSS_NSS_EX_FLAG_NO_CACHE + +If SSS_NSS_EX_FLAG_NO_CACHE is set the object is refresh by directly +looking it up in the backend. + +Related to https://pagure.io/SSSD/sssd/issue/2478 + +Reviewed-by: Jakub Hrozek +--- + src/responder/nss/nss_cmd.c | 8 ++++ + src/sss_client/idmap/sss_nss_ex.c | 71 ++++++++++++++++++++---------------- + src/sss_client/idmap/sss_nss_idmap.h | 4 ++ + 3 files changed, 52 insertions(+), 31 deletions(-) + +diff --git a/src/responder/nss/nss_cmd.c b/src/responder/nss/nss_cmd.c +index 974eaccc93cea3a330007735676da69eb9b84141..c5ddd2f2cc2122cd169ea991b94a14eb5bad095f 100644 +--- a/src/responder/nss/nss_cmd.c ++++ b/src/responder/nss/nss_cmd.c +@@ -92,6 +92,10 @@ static errno_t nss_getby_name(struct cli_ctx *cli_ctx, + goto done; + } + ++ if ((flags & SSS_NSS_EX_FLAG_NO_CACHE) != 0) { ++ cache_req_data_set_bypass_cache(data, true); ++ } ++ + subreq = nss_get_object_send(cmd_ctx, cli_ctx->ev, cli_ctx, + data, memcache, rawname, 0); + if (subreq == NULL) { +@@ -152,6 +156,10 @@ static errno_t nss_getby_id(struct cli_ctx *cli_ctx, + goto done; + } + ++ if ((flags & SSS_NSS_EX_FLAG_NO_CACHE) != 0) { ++ cache_req_data_set_bypass_cache(data, true); ++ } ++ + subreq = nss_get_object_send(cmd_ctx, cli_ctx->ev, cli_ctx, + data, memcache, NULL, id); + if (subreq == NULL) { +diff --git a/src/sss_client/idmap/sss_nss_ex.c b/src/sss_client/idmap/sss_nss_ex.c +index dc7610a4e528b5126f0d25d84cd3c1a22f683b75..edb3ea652ef7032b76c8f815b9f83fe185a669ea 100644 +--- a/src/sss_client/idmap/sss_nss_ex.c ++++ b/src/sss_client/idmap/sss_nss_ex.c +@@ -115,42 +115,51 @@ int sss_get_ex(struct nss_input *inp, uint32_t flags, unsigned int timeout) + size_t c; + gid_t *new_groups; + size_t idx; ++ bool skip_mc = false; + +- ret = sss_nss_mc_get(inp); +- switch (ret) { +- case 0: +- return 0; +- case ERANGE: +- return ERANGE; +- case ENOENT: +- /* fall through, we need to actively ask the parent +- * if no entry is found */ +- break; +- default: +- /* if using the mmaped cache failed, +- * fall back to socket based comms */ +- break; ++ if ((flags & SSS_NSS_EX_FLAG_NO_CACHE) != 0) { ++ skip_mc = true; ++ } ++ ++ if (!skip_mc) { ++ ret = sss_nss_mc_get(inp); ++ switch (ret) { ++ case 0: ++ return 0; ++ case ERANGE: ++ return ERANGE; ++ case ENOENT: ++ /* fall through, we need to actively ask the parent ++ * if no entry is found */ ++ break; ++ default: ++ /* if using the mmaped cache failed, ++ * fall back to socket based comms */ ++ break; ++ } + } + + sss_nss_timedlock(timeout, &time_left); + +- /* previous thread might already initialize entry in mmap cache */ +- ret = sss_nss_mc_get(inp); +- switch (ret) { +- case 0: +- ret = 0; +- goto out; +- case ERANGE: +- ret = ERANGE; +- goto out; +- case ENOENT: +- /* fall through, we need to actively ask the parent +- * if no entry is found */ +- break; +- default: +- /* if using the mmaped cache failed, +- * fall back to socket based comms */ +- break; ++ if (!skip_mc) { ++ /* previous thread might already initialize entry in mmap cache */ ++ ret = sss_nss_mc_get(inp); ++ switch (ret) { ++ case 0: ++ ret = 0; ++ goto out; ++ case ERANGE: ++ ret = ERANGE; ++ goto out; ++ case ENOENT: ++ /* fall through, we need to actively ask the parent ++ * if no entry is found */ ++ break; ++ default: ++ /* if using the mmaped cache failed, ++ * fall back to socket based comms */ ++ break; ++ } + } + + ret = sss_nss_make_request_timeout(inp->cmd, &inp->rd, time_left, +diff --git a/src/sss_client/idmap/sss_nss_idmap.h b/src/sss_client/idmap/sss_nss_idmap.h +index 2334b6cb3fb8ef62e4ce3a7187c7affaeaa034e7..1649830afbb80c617fd339f054aef8bc8e585fb9 100644 +--- a/src/sss_client/idmap/sss_nss_idmap.h ++++ b/src/sss_client/idmap/sss_nss_idmap.h +@@ -169,6 +169,10 @@ void sss_nss_free_kv(struct sss_nss_kv *kv_list); + + #define SSS_NSS_EX_FLAG_NO_FLAGS 0 + ++/** Always request data from the server side, client must be privileged to do ++ * so, see nss_trusted_users option in man sssd.conf for details */ ++#define SSS_NSS_EX_FLAG_NO_CACHE (1 << 0) ++ + #ifdef IPA_389DS_PLUGIN_HELPER_CALLS + + /** +-- +2.14.3 + diff --git a/0006-CACHE_REQ-Add-cache_req_data_set_bypass_dp.patch b/0006-CACHE_REQ-Add-cache_req_data_set_bypass_dp.patch new file mode 100644 index 0000000..7a6247a --- /dev/null +++ b/0006-CACHE_REQ-Add-cache_req_data_set_bypass_dp.patch @@ -0,0 +1,111 @@ +From 52e675ec4b160720515c81ae8c0e5a95feb50c57 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 23 Oct 2017 18:26:55 +0200 +Subject: [PATCH 06/11] CACHE_REQ: Add cache_req_data_set_bypass_dp() + +Similar to cache_req_data_set_bypass_cache() +cache_req_data_set_bypass_dp() can be used to control how the cache_req +framework performs the lookup. If cache_req_data_set_bypass_dp() is used +with 'true' only a cache lookup is performed and no request is send to +the backend even if no entry was found. + +Related to https://pagure.io/SSSD/sssd/issue/2478 + +Reviewed-by: Jakub Hrozek +--- + src/responder/common/cache_req/cache_req.c | 15 +++++++++++++++ + src/responder/common/cache_req/cache_req.h | 3 +++ + src/responder/common/cache_req/cache_req_data.c | 12 ++++++++++++ + src/responder/common/cache_req/cache_req_private.h | 2 ++ + 4 files changed, 32 insertions(+) + +diff --git a/src/responder/common/cache_req/cache_req.c b/src/responder/common/cache_req/cache_req.c +index 5fed7a2ab8beded2fee91f679a12f9a0ff6013ec..110df561101be538e3f0496addfa2e14e42ea918 100644 +--- a/src/responder/common/cache_req/cache_req.c ++++ b/src/responder/common/cache_req/cache_req.c +@@ -142,6 +142,13 @@ cache_req_create(TALLOC_CTX *mem_ctx, + + cr->cache_first = rctx->cache_first; + cr->bypass_cache = cr->plugin->bypass_cache || cr->data->bypass_cache; ++ cr->bypass_dp = cr->data->bypass_dp; ++ if (cr->bypass_cache && cr->bypass_dp) { ++ CACHE_REQ_DEBUG(SSSDBG_CRIT_FAILURE, cr, ++ "Cannot bypass cache and dp at the same time!"); ++ talloc_free(cr); ++ return NULL; ++ } + + return cr; + } +@@ -658,6 +665,14 @@ static bool cache_req_search_schema(struct cache_req *cr, + bypass_cache = true; + bypass_dp = false; + ++ if (!first_iteration) { ++ return false; ++ } ++ } else if (cr->bypass_dp) { ++ /* The caller wants to lookup only in the cache */ ++ bypass_cache = false; ++ bypass_dp = true; ++ + if (!first_iteration) { + return false; + } +diff --git a/src/responder/common/cache_req/cache_req.h b/src/responder/common/cache_req/cache_req.h +index c04b2fba6f0445dcfcc9cfe1b5963ac975c39118..2c88853887fc816bba2182d9d9beaa32fa384158 100644 +--- a/src/responder/common/cache_req/cache_req.h ++++ b/src/responder/common/cache_req/cache_req.h +@@ -127,6 +127,9 @@ void + cache_req_data_set_bypass_cache(struct cache_req_data *data, + bool bypass_cache); + ++void ++cache_req_data_set_bypass_dp(struct cache_req_data *data, ++ bool bypass_dp); + /* Output data. */ + + struct cache_req_result { +diff --git a/src/responder/common/cache_req/cache_req_data.c b/src/responder/common/cache_req/cache_req_data.c +index 48264a321dc603f9708ba71c44542363b11a71ba..ed378274a9a0a68ede8ac99805f3ea4a041382e6 100644 +--- a/src/responder/common/cache_req/cache_req_data.c ++++ b/src/responder/common/cache_req/cache_req_data.c +@@ -365,3 +365,15 @@ cache_req_data_set_bypass_cache(struct cache_req_data *data, + + data->bypass_cache = bypass_cache; + } ++ ++void ++cache_req_data_set_bypass_dp(struct cache_req_data *data, ++ bool bypass_dp) ++{ ++ if (data == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "cache_req_data should never be NULL\n"); ++ return; ++ } ++ ++ data->bypass_dp = bypass_dp; ++} +diff --git a/src/responder/common/cache_req/cache_req_private.h b/src/responder/common/cache_req/cache_req_private.h +index 9b706ff7d678f543effb77089857a7e8a42a9c51..0f630542d38a277d1819063fa4134bd7d2525c90 100644 +--- a/src/responder/common/cache_req/cache_req_private.h ++++ b/src/responder/common/cache_req/cache_req_private.h +@@ -42,6 +42,7 @@ struct cache_req { + struct sss_domain_info *domain; + bool cache_first; + bool bypass_cache; ++ bool bypass_dp; + /* Only contact domains with this type */ + enum cache_req_dom_type req_dom_type; + +@@ -90,6 +91,7 @@ struct cache_req_data { + } svc; + + bool bypass_cache; ++ bool bypass_dp; + }; + + struct tevent_req * +-- +2.14.3 + diff --git a/0007-nss-make-memcache_delete_entry-public.patch b/0007-nss-make-memcache_delete_entry-public.patch new file mode 100644 index 0000000..157d3d9 --- /dev/null +++ b/0007-nss-make-memcache_delete_entry-public.patch @@ -0,0 +1,48 @@ +From a7d6ca275d6b2e5d396cbefb18d0ee880011e271 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Tue, 24 Oct 2017 12:50:43 +0200 +Subject: [PATCH 07/11] nss: make memcache_delete_entry() public + +Related to https://pagure.io/SSSD/sssd/issue/2478 + +Reviewed-by: Jakub Hrozek +--- + src/responder/nss/nss_get_object.c | 2 +- + src/responder/nss/nss_private.h | 8 ++++++++ + 2 files changed, 9 insertions(+), 1 deletion(-) + +diff --git a/src/responder/nss/nss_get_object.c b/src/responder/nss/nss_get_object.c +index e56480af5e3369963d2e8bb17d74d1603af8e014..15faced006f754134415e766284377f0c86af0ac 100644 +--- a/src/responder/nss/nss_get_object.c ++++ b/src/responder/nss/nss_get_object.c +@@ -86,7 +86,7 @@ memcache_delete_entry_by_id(struct nss_ctx *nss_ctx, + return ret; + } + +-static errno_t ++errno_t + memcache_delete_entry(struct nss_ctx *nss_ctx, + struct resp_ctx *rctx, + struct sss_domain_info *domain, +diff --git a/src/responder/nss/nss_private.h b/src/responder/nss/nss_private.h +index a0b573d6ecba2d8ba6f55db0adcd7ee29cbec991..5fc19d26be9adda4d967086e7b239e49a78866ee 100644 +--- a/src/responder/nss/nss_private.h ++++ b/src/responder/nss/nss_private.h +@@ -92,6 +92,14 @@ struct sss_cmd_table *get_nss_cmds(void); + + int nss_connection_setup(struct cli_ctx *cli_ctx); + ++errno_t ++memcache_delete_entry(struct nss_ctx *nss_ctx, ++ struct resp_ctx *rctx, ++ struct sss_domain_info *domain, ++ const char *name, ++ uint32_t id, ++ enum sss_mc_type type); ++ + struct tevent_req * + nss_get_object_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, +-- +2.14.3 + diff --git a/0008-NSS-add-support-for-SSS_NSS_EX_FLAG_INVALIDATE_CACHE.patch b/0008-NSS-add-support-for-SSS_NSS_EX_FLAG_INVALIDATE_CACHE.patch new file mode 100644 index 0000000..ca259e0 --- /dev/null +++ b/0008-NSS-add-support-for-SSS_NSS_EX_FLAG_INVALIDATE_CACHE.patch @@ -0,0 +1,364 @@ +From 55f7d8034d783c01789d76a2b9ffc901045e8af8 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Tue, 24 Oct 2017 14:10:53 +0200 +Subject: [PATCH 08/11] NSS: add support for SSS_NSS_EX_FLAG_INVALIDATE_CACHE + +The patch adds support for the SSS_NSS_EX_FLAG_INVALIDATE_CACHE flag and +makes the existing code more flexible and handle additional flags. + +If SSS_NSS_EX_FLAG_INVALIDATE_CACHE is set the requested object is only +looked up in the cache and if it was found on-disk and memory cache +entries will be invalidated. + +Related to https://pagure.io/SSSD/sssd/issue/2478 + +Reviewed-by: Jakub Hrozek +--- + src/responder/nss/nss_cmd.c | 141 +++++++++++++++++++++++++++++++-- + src/responder/nss/nss_protocol.c | 1 + + src/responder/nss/nss_protocol.h | 1 + + src/responder/nss/nss_protocol_grent.c | 9 ++- + src/responder/nss/nss_protocol_pwent.c | 6 +- + src/sss_client/idmap/sss_nss_ex.c | 20 ++++- + src/sss_client/idmap/sss_nss_idmap.h | 8 +- + 7 files changed, 171 insertions(+), 15 deletions(-) + +diff --git a/src/responder/nss/nss_cmd.c b/src/responder/nss/nss_cmd.c +index c5ddd2f2cc2122cd169ea991b94a14eb5bad095f..545257a0be7e91e9de767a57848bb77c5791db4e 100644 +--- a/src/responder/nss/nss_cmd.c ++++ b/src/responder/nss/nss_cmd.c +@@ -50,6 +50,26 @@ nss_cmd_ctx_create(TALLOC_CTX *mem_ctx, + return cmd_ctx; + } + ++static errno_t eval_flags(struct nss_cmd_ctx *cmd_ctx, ++ struct cache_req_data *data) ++{ ++ if ((cmd_ctx->flags & SSS_NSS_EX_FLAG_NO_CACHE) != 0 ++ && (cmd_ctx->flags & SSS_NSS_EX_FLAG_INVALIDATE_CACHE) != 0) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Flags SSS_NSS_EX_FLAG_NO_CACHE and " ++ "SSS_NSS_EX_FLAG_INVALIDATE_CACHE are " ++ "mutually exclusive.\n"); ++ return EINVAL; ++ } ++ ++ if ((cmd_ctx->flags & SSS_NSS_EX_FLAG_NO_CACHE) != 0) { ++ cache_req_data_set_bypass_cache(data, true); ++ } else if ((cmd_ctx->flags & SSS_NSS_EX_FLAG_INVALIDATE_CACHE) != 0) { ++ cache_req_data_set_bypass_dp(data, true); ++ } ++ ++ return EOK; ++} ++ + static void nss_getby_done(struct tevent_req *subreq); + static void nss_getlistby_done(struct tevent_req *subreq); + +@@ -65,7 +85,6 @@ static errno_t nss_getby_name(struct cli_ctx *cli_ctx, + struct tevent_req *subreq; + const char *rawname; + errno_t ret; +- uint32_t flags = 0; + + cmd_ctx = nss_cmd_ctx_create(cli_ctx, cli_ctx, type, fill_fn); + if (cmd_ctx == NULL) { +@@ -73,8 +92,9 @@ static errno_t nss_getby_name(struct cli_ctx *cli_ctx, + goto done; + } + ++ cmd_ctx->flags = 0; + if (ex_version) { +- ret = nss_protocol_parse_name_ex(cli_ctx, &rawname, &flags); ++ ret = nss_protocol_parse_name_ex(cli_ctx, &rawname, &cmd_ctx->flags); + } else { + ret = nss_protocol_parse_name(cli_ctx, &rawname); + } +@@ -92,8 +112,10 @@ static errno_t nss_getby_name(struct cli_ctx *cli_ctx, + goto done; + } + +- if ((flags & SSS_NSS_EX_FLAG_NO_CACHE) != 0) { +- cache_req_data_set_bypass_cache(data, true); ++ ret = eval_flags(cmd_ctx, data); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "eval_flags failed.\n"); ++ goto done; + } + + subreq = nss_get_object_send(cmd_ctx, cli_ctx->ev, cli_ctx, +@@ -129,7 +151,6 @@ static errno_t nss_getby_id(struct cli_ctx *cli_ctx, + struct tevent_req *subreq; + uint32_t id; + errno_t ret; +- uint32_t flags = 0; + + cmd_ctx = nss_cmd_ctx_create(cli_ctx, cli_ctx, type, fill_fn); + if (cmd_ctx == NULL) { +@@ -138,7 +159,7 @@ static errno_t nss_getby_id(struct cli_ctx *cli_ctx, + } + + if (ex_version) { +- ret = nss_protocol_parse_id_ex(cli_ctx, &id, &flags); ++ ret = nss_protocol_parse_id_ex(cli_ctx, &id, &cmd_ctx->flags); + } else { + ret = nss_protocol_parse_id(cli_ctx, &id); + } +@@ -156,8 +177,10 @@ static errno_t nss_getby_id(struct cli_ctx *cli_ctx, + goto done; + } + +- if ((flags & SSS_NSS_EX_FLAG_NO_CACHE) != 0) { +- cache_req_data_set_bypass_cache(data, true); ++ ret = eval_flags(cmd_ctx, data); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "eval_flags failed.\n"); ++ goto done; + } + + subreq = nss_get_object_send(cmd_ctx, cli_ctx->ev, cli_ctx, +@@ -425,6 +448,98 @@ done: + return EOK; + } + ++static errno_t invalidate_cache(struct nss_cmd_ctx *cmd_ctx, ++ struct cache_req_result *result) ++{ ++ int ret; ++ enum sss_mc_type memcache_type; ++ const char *name; ++ char *output_name = NULL; ++ bool is_user; ++ struct sysdb_attrs *attrs = NULL; ++ ++ switch (cmd_ctx->type) { ++ case CACHE_REQ_INITGROUPS: ++ case CACHE_REQ_INITGROUPS_BY_UPN: ++ memcache_type = SSS_MC_INITGROUPS; ++ is_user = true; ++ break; ++ case CACHE_REQ_USER_BY_NAME: ++ case CACHE_REQ_USER_BY_ID: ++ memcache_type = SSS_MC_PASSWD; ++ is_user = true; ++ break; ++ case CACHE_REQ_GROUP_BY_NAME: ++ case CACHE_REQ_GROUP_BY_ID: ++ memcache_type = SSS_MC_GROUP; ++ is_user = false; ++ break; ++ default: ++ /* nothing to do */ ++ return EOK; ++ } ++ ++ /* Find output name to invalidate memory cache entry*/ ++ name = sss_get_name_from_msg(result->domain, result->msgs[0]); ++ if (name == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Found object has no name.\n"); ++ return EINVAL; ++ } ++ ret = sss_output_fqname(cmd_ctx, result->domain, name, ++ cmd_ctx->nss_ctx->rctx->override_space, ++ &output_name); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "sss_output_fqname failed.\n"); ++ return ret; ++ } ++ ++ memcache_delete_entry(cmd_ctx->nss_ctx, cmd_ctx->nss_ctx->rctx, NULL, ++ output_name, 0, memcache_type); ++ if (memcache_type == SSS_MC_INITGROUPS) { ++ /* Invalidate the passwd data as well */ ++ memcache_delete_entry(cmd_ctx->nss_ctx, cmd_ctx->nss_ctx->rctx, ++ result->domain, output_name, 0, SSS_MC_PASSWD); ++ } ++ talloc_free(output_name); ++ ++ /* Use sysdb name to invalidate disk cache entry */ ++ name = ldb_msg_find_attr_as_string(result->msgs[0], SYSDB_NAME, NULL); ++ if (name == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Found object has no name.\n"); ++ return EINVAL; ++ } ++ ++ if (memcache_type == SSS_MC_INITGROUPS) { ++ attrs = sysdb_new_attrs(cmd_ctx); ++ if (attrs == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "sysdb_new_attrs failed.\n"); ++ return ENOMEM; ++ } ++ ++ ret = sysdb_attrs_add_time_t(attrs, SYSDB_INITGR_EXPIRE, 1); ++ if (ret != EOK) { ++ talloc_free(attrs); ++ DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_time_t failed.\n"); ++ return ret; ++ } ++ ++ ret = sysdb_set_user_attr(result->domain, name, attrs, SYSDB_MOD_REP); ++ talloc_free(attrs); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "sysdb_set_user_attr failed.\n"); ++ return ret; ++ } ++ } ++ ++ ret = sysdb_invalidate_cache_entry(result->domain, name, is_user); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "sysdb_invalidate_cache_entry failed.\n"); ++ return ret; ++ } ++ ++ return EOK; ++} ++ + static void nss_getby_done(struct tevent_req *subreq) + { + struct cache_req_result *result; +@@ -440,6 +555,16 @@ static void nss_getby_done(struct tevent_req *subreq) + goto done; + } + ++ if ((cmd_ctx->flags & SSS_NSS_EX_FLAG_INVALIDATE_CACHE) != 0) { ++ ret = invalidate_cache(cmd_ctx, result); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "Failed to invalidate cache for [%s].\n", ++ cmd_ctx->rawname); ++ nss_protocol_done(cmd_ctx->cli_ctx, ret); ++ goto done; ++ } ++ } ++ + nss_protocol_reply(cmd_ctx->cli_ctx, cmd_ctx->nss_ctx, cmd_ctx, + result, cmd_ctx->fill_fn); + +diff --git a/src/responder/nss/nss_protocol.c b/src/responder/nss/nss_protocol.c +index 17bfc4f4e71960a72e9e04622eac95b94a865ec7..2655386498754c46fbb363bdd1f976f9ded6a434 100644 +--- a/src/responder/nss/nss_protocol.c ++++ b/src/responder/nss/nss_protocol.c +@@ -233,6 +233,7 @@ nss_protocol_parse_id_ex(struct cli_ctx *cli_ctx, uint32_t *_id, + SAFEALIGN_COPY_UINT32(&flags, body + sizeof(uint32_t), NULL); + + *_id = id; ++ *_flags = flags; + + return EOK; + } +diff --git a/src/responder/nss/nss_protocol.h b/src/responder/nss/nss_protocol.h +index ca5b040237dc18acdca9a7a3a7a7dbb64265aa95..76724d2b2db7b11c9147fa927e39abab731328b2 100644 +--- a/src/responder/nss/nss_protocol.h ++++ b/src/responder/nss/nss_protocol.h +@@ -50,6 +50,7 @@ struct nss_cmd_ctx { + struct nss_ctx *nss_ctx; + struct nss_state_ctx *state_ctx; + nss_protocol_fill_packet_fn fill_fn; ++ uint32_t flags; + + /* For initgroups- */ + const char *rawname; +diff --git a/src/responder/nss/nss_protocol_grent.c b/src/responder/nss/nss_protocol_grent.c +index ee228c722a153a1ba7aa8a1b30a1e551108424bb..6f6ae57dd97b000ad3cf174b0f649d46981563e2 100644 +--- a/src/responder/nss/nss_protocol_grent.c ++++ b/src/responder/nss/nss_protocol_grent.c +@@ -274,8 +274,10 @@ nss_protocol_fill_grent(struct nss_ctx *nss_ctx, + + num_results++; + +- /* Do not store entry in memory cache during enumeration. */ +- if (!cmd_ctx->enumeration) { ++ /* Do not store entry in memory cache during enumeration or when ++ * requested. */ ++ if (!cmd_ctx->enumeration ++ && (cmd_ctx->flags & SSS_NSS_EX_FLAG_INVALIDATE_CACHE) == 0) { + members = (char *)&body[rp_members]; + members_size = body_len - rp_members; + ret = sss_mmap_cache_gr_store(&nss_ctx->grp_mc_ctx, name, &pwfield, +@@ -390,7 +392,8 @@ nss_protocol_fill_initgr(struct nss_ctx *nss_ctx, + num_results++; + } + +- if (nss_ctx->initgr_mc_ctx) { ++ if (nss_ctx->initgr_mc_ctx ++ && (cmd_ctx->flags & SSS_NSS_EX_FLAG_INVALIDATE_CACHE) == 0) { + to_sized_string(&rawname, cmd_ctx->rawname); + to_sized_string(&unique_name, result->lookup_name); + +diff --git a/src/responder/nss/nss_protocol_pwent.c b/src/responder/nss/nss_protocol_pwent.c +index db5c071e2ff172a2267c08c9817fecfbcc7cabc3..f449ec69b6a86a6db2aaed368e217c1a791faaa2 100644 +--- a/src/responder/nss/nss_protocol_pwent.c ++++ b/src/responder/nss/nss_protocol_pwent.c +@@ -295,8 +295,10 @@ nss_protocol_fill_pwent(struct nss_ctx *nss_ctx, + + num_results++; + +- /* Do not store entry in memory cache during enumeration. */ +- if (!cmd_ctx->enumeration) { ++ /* Do not store entry in memory cache during enumeration or when ++ * requested. */ ++ if (!cmd_ctx->enumeration ++ && (cmd_ctx->flags & SSS_NSS_EX_FLAG_INVALIDATE_CACHE) == 0) { + ret = sss_mmap_cache_pw_store(&nss_ctx->pwd_mc_ctx, name, &pwfield, + uid, gid, &gecos, &homedir, &shell); + if (ret != EOK) { +diff --git a/src/sss_client/idmap/sss_nss_ex.c b/src/sss_client/idmap/sss_nss_ex.c +index edb3ea652ef7032b76c8f815b9f83fe185a669ea..148eb7b35ec236b6272dd203a0035399cfdef73d 100644 +--- a/src/sss_client/idmap/sss_nss_ex.c ++++ b/src/sss_client/idmap/sss_nss_ex.c +@@ -103,6 +103,18 @@ errno_t sss_nss_mc_get(struct nss_input *inp) + } + } + ++static int check_flags(uint32_t flags) ++{ ++ /* SSS_NSS_EX_FLAG_NO_CACHE and SSS_NSS_EX_FLAG_INVALIDATE_CACHE are ++ * mutually exclusive */ ++ if ((flags & SSS_NSS_EX_FLAG_NO_CACHE) != 0 ++ && (flags & SSS_NSS_EX_FLAG_INVALIDATE_CACHE) != 0) { ++ return EINVAL; ++ } ++ ++ return 0; ++} ++ + int sss_get_ex(struct nss_input *inp, uint32_t flags, unsigned int timeout) + { + uint8_t *repbuf = NULL; +@@ -117,7 +129,13 @@ int sss_get_ex(struct nss_input *inp, uint32_t flags, unsigned int timeout) + size_t idx; + bool skip_mc = false; + +- if ((flags & SSS_NSS_EX_FLAG_NO_CACHE) != 0) { ++ ret = check_flags(flags); ++ if (ret != 0) { ++ return ret; ++ } ++ ++ if ((flags & SSS_NSS_EX_FLAG_NO_CACHE) != 0 ++ || (flags & SSS_NSS_EX_FLAG_INVALIDATE_CACHE) != 0) { + skip_mc = true; + } + +diff --git a/src/sss_client/idmap/sss_nss_idmap.h b/src/sss_client/idmap/sss_nss_idmap.h +index 1649830afbb80c617fd339f054aef8bc8e585fb9..3755643312f05a31d1cf1aa76dfc22848ef1e3ec 100644 +--- a/src/sss_client/idmap/sss_nss_idmap.h ++++ b/src/sss_client/idmap/sss_nss_idmap.h +@@ -170,9 +170,15 @@ void sss_nss_free_kv(struct sss_nss_kv *kv_list); + #define SSS_NSS_EX_FLAG_NO_FLAGS 0 + + /** Always request data from the server side, client must be privileged to do +- * so, see nss_trusted_users option in man sssd.conf for details */ ++ * so, see nss_trusted_users option in man sssd.conf for details. ++ * This flag cannot be used together with SSS_NSS_EX_FLAG_INVALIDATE_CACHE */ + #define SSS_NSS_EX_FLAG_NO_CACHE (1 << 0) + ++/** Invalidate the data in the caches, client must be privileged to do ++ * so, see nss_trusted_users option in man sssd.conf for details. ++ * This flag cannot be used together with SSS_NSS_EX_FLAG_NO_CACHE */ ++#define SSS_NSS_EX_FLAG_INVALIDATE_CACHE (1 << 1) ++ + #ifdef IPA_389DS_PLUGIN_HELPER_CALLS + + /** +-- +2.14.3 + diff --git a/0009-NSS-TESTS-add-unit-tests-for-_EX-requests.patch b/0009-NSS-TESTS-add-unit-tests-for-_EX-requests.patch new file mode 100644 index 0000000..3cf4745 --- /dev/null +++ b/0009-NSS-TESTS-add-unit-tests-for-_EX-requests.patch @@ -0,0 +1,589 @@ +From 85da8a5e90bffc8b0fef5e0ea364a8d3cb50de86 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Wed, 25 Oct 2017 21:31:54 +0200 +Subject: [PATCH 09/11] NSS/TESTS: add unit tests for *_EX requests + +The patch adds unit tests for the new *_EX requests with different input +types and flags. + +Related to https://pagure.io/SSSD/sssd/issue/2478 + +Reviewed-by: Jakub Hrozek +--- + src/tests/cmocka/test_nss_srv.c | 539 ++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 539 insertions(+) + +diff --git a/src/tests/cmocka/test_nss_srv.c b/src/tests/cmocka/test_nss_srv.c +index ccedf96beaecfaa4232bbe456d5e5a8394098483..6aa726153183b5a871a75d398727ea7132358ca6 100644 +--- a/src/tests/cmocka/test_nss_srv.c ++++ b/src/tests/cmocka/test_nss_srv.c +@@ -255,6 +255,45 @@ static void mock_input_user_or_group(const char *input) + mock_parse_inp(shortname, domname, EOK); + } + ++static void mock_input_user_or_group_ex(bool do_parse_inp, const char *input, ++ uint32_t flags) ++{ ++ const char *copy; ++ const char *shortname; ++ const char *domname; ++ char *separator; ++ uint8_t *data; ++ size_t len; ++ ++ len = strlen(input); ++ len++; ++ data = talloc_size(nss_test_ctx, len + sizeof(uint32_t)); ++ assert_non_null(data); ++ memcpy(data, input, len); ++ SAFEALIGN_COPY_UINT32(data + len, &flags, NULL); ++ ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_WRAPPER); ++ will_return(__wrap_sss_packet_get_body, data); ++ will_return(__wrap_sss_packet_get_body, len + sizeof(uint32_t)); ++ ++ if (do_parse_inp) { ++ copy = talloc_strdup(nss_test_ctx, input); ++ assert_non_null(copy); ++ ++ separator = strrchr(copy, '@'); ++ if (separator == NULL) { ++ shortname = input; ++ domname = NULL; ++ } else { ++ *separator = '\0'; ++ shortname = copy; ++ domname = separator + 1; ++ } ++ ++ mock_parse_inp(shortname, domname, EOK); ++ } ++} ++ + static void mock_input_upn(const char *upn) + { + will_return(__wrap_sss_packet_get_body, WRAP_CALL_WRAPPER); +@@ -291,6 +330,20 @@ static void mock_input_id(TALLOC_CTX *mem_ctx, uint32_t id) + will_return(__wrap_sss_packet_get_body, sizeof(uint32_t)); + } + ++static void mock_input_id_ex(TALLOC_CTX *mem_ctx, uint32_t id, uint32_t flags) ++{ ++ uint8_t *body; ++ ++ body = talloc_zero_array(mem_ctx, uint8_t, 8); ++ if (body == NULL) return; ++ ++ SAFEALIGN_SETMEM_UINT32(body, id, NULL); ++ SAFEALIGN_SETMEM_UINT32(body + sizeof(uint32_t), flags, NULL); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_WRAPPER); ++ will_return(__wrap_sss_packet_get_body, body); ++ will_return(__wrap_sss_packet_get_body, 2 * sizeof(uint32_t)); ++} ++ + static void mock_fill_user(void) + { + /* One packet for the entry and one for num entries */ +@@ -4143,6 +4196,482 @@ void test_nss_getsidbyname_neg(void **state) + assert_int_equal(ret, ENOENT); + } + ++static int test_nss_EINVAL_check(uint32_t status, uint8_t *body, size_t blen) ++{ ++ assert_int_equal(status, EINVAL); ++ assert_int_equal(blen, 0); ++ ++ return EOK; ++} ++ ++#define RESET_TCTX do { \ ++ nss_test_ctx->tctx->done = false; \ ++ nss_test_ctx->tctx->error = EIO; \ ++} while (0) ++ ++void test_nss_getpwnam_ex(void **state) ++{ ++ errno_t ret; ++ ++ ret = store_user(nss_test_ctx, nss_test_ctx->tctx->dom, ++ &getpwnam_usr, NULL, 0); ++ assert_int_equal(ret, EOK); ++ ++ mock_input_user_or_group_ex(true, "testuser", 0); ++ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETPWNAM_EX); ++ mock_fill_user(); ++ ++ /* Query for that user, call a callback when command finishes */ ++ set_cmd_cb(test_nss_getpwnam_check); ++ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETPWNAM_EX, ++ nss_test_ctx->nss_cmds); ++ assert_int_equal(ret, EOK); ++ ++ /* Wait until the test finishes with EOK */ ++ ret = test_ev_loop(nss_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++ RESET_TCTX; ++ ++ /* Use old input format, expect EINVAL */ ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_WRAPPER); ++ will_return(__wrap_sss_packet_get_body, "testuser"); ++ will_return(__wrap_sss_packet_get_body, 0); ++ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETPWNAM_EX); ++ ++ set_cmd_cb(test_nss_EINVAL_check); ++ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETPWNAM_EX, ++ nss_test_ctx->nss_cmds); ++ assert_int_equal(ret, EOK); ++ ++ ret = test_ev_loop(nss_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++ RESET_TCTX; ++ ++ /* Use unsupported flag combination, expect EINVAL */ ++ mock_input_user_or_group_ex(false, "testuser", ++ SSS_NSS_EX_FLAG_NO_CACHE ++ |SSS_NSS_EX_FLAG_INVALIDATE_CACHE); ++ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETPWNAM_EX); ++ ++ set_cmd_cb(test_nss_EINVAL_check); ++ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETPWNAM_EX, ++ nss_test_ctx->nss_cmds); ++ assert_int_equal(ret, EOK); ++ ++ /* Wait until the test finishes with EOK */ ++ ret = test_ev_loop(nss_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++ RESET_TCTX; ++ ++ /* Use flag SSS_NSS_EX_FLAG_NO_CACHE, ++ * will cause a backend lookup -> mock_account_recv_simple() */ ++ mock_input_user_or_group_ex(true, "testuser", SSS_NSS_EX_FLAG_NO_CACHE); ++ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETPWNAM_EX); ++ mock_fill_user(); ++ mock_account_recv_simple(); ++ ++ set_cmd_cb(test_nss_getpwnam_check); ++ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETPWNAM_EX, ++ nss_test_ctx->nss_cmds); ++ assert_int_equal(ret, EOK); ++ ++ /* Wait until the test finishes with EOK */ ++ ret = test_ev_loop(nss_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++ RESET_TCTX; ++ ++ /* Use flag SSS_NSS_EX_FLAG_INVALIDATE_CACHE */ ++ mock_input_user_or_group_ex(true, "testuser", ++ SSS_NSS_EX_FLAG_INVALIDATE_CACHE); ++ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETPWNAM_EX); ++ mock_fill_user(); ++ ++ set_cmd_cb(test_nss_getpwnam_check); ++ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETPWNAM_EX, ++ nss_test_ctx->nss_cmds); ++ assert_int_equal(ret, EOK); ++ ++ /* Wait until the test finishes with EOK */ ++ ret = test_ev_loop(nss_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++} ++ ++void test_nss_getpwuid_ex(void **state) ++{ ++ errno_t ret; ++ uint32_t id = 101; ++ ++ /* Prime the cache with a valid user */ ++ ret = store_user(nss_test_ctx, nss_test_ctx->tctx->dom, ++ &getpwuid_usr, NULL, 0); ++ assert_int_equal(ret, EOK); ++ ++ mock_input_id_ex(nss_test_ctx, id, 0); ++ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETPWUID_EX); ++ mock_fill_user(); ++ ++ /* Query for that id, call a callback when command finishes */ ++ set_cmd_cb(test_nss_getpwuid_check); ++ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETPWUID_EX, ++ nss_test_ctx->nss_cmds); ++ assert_int_equal(ret, EOK); ++ ++ /* Wait until the test finishes with EOK */ ++ ret = test_ev_loop(nss_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++ RESET_TCTX; ++ ++ /* Use old input format, expect failure */ ++ mock_input_id(nss_test_ctx, id); ++ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETPWUID_EX); ++ ++ set_cmd_cb(test_nss_EINVAL_check); ++ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETPWUID_EX, ++ nss_test_ctx->nss_cmds); ++ assert_int_equal(ret, EOK); ++ ++ /* Wait until the test finishes with EOK */ ++ ret = test_ev_loop(nss_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++ RESET_TCTX; ++ ++ /* Use unsupported flag combination, expect EINVAL */ ++ mock_input_id_ex(nss_test_ctx, id, SSS_NSS_EX_FLAG_NO_CACHE ++ |SSS_NSS_EX_FLAG_INVALIDATE_CACHE); ++ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETPWUID_EX); ++ ++ set_cmd_cb(test_nss_EINVAL_check); ++ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETPWUID_EX, ++ nss_test_ctx->nss_cmds); ++ assert_int_equal(ret, EOK); ++ ++ /* Wait until the test finishes with EOK */ ++ ret = test_ev_loop(nss_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++ RESET_TCTX; ++ ++ /* Use flag SSS_NSS_EX_FLAG_NO_CACHE, ++ * will cause a backend lookup -> mock_account_recv_simple() */ ++ mock_input_id_ex(nss_test_ctx, id, SSS_NSS_EX_FLAG_NO_CACHE); ++ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETPWUID_EX); ++ mock_fill_user(); ++ mock_account_recv_simple(); ++ ++ set_cmd_cb(test_nss_getpwuid_check); ++ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETPWUID_EX, ++ nss_test_ctx->nss_cmds); ++ assert_int_equal(ret, EOK); ++ ++ /* Wait until the test finishes with EOK */ ++ ret = test_ev_loop(nss_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++ RESET_TCTX; ++ ++ /* Use flag SSS_NSS_EX_FLAG_INVALIDATE_CACHE */ ++ mock_input_id_ex(nss_test_ctx, id, SSS_NSS_EX_FLAG_INVALIDATE_CACHE); ++ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETPWUID_EX); ++ mock_fill_user(); ++ ++ set_cmd_cb(test_nss_getpwuid_check); ++ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETPWUID_EX, ++ nss_test_ctx->nss_cmds); ++ assert_int_equal(ret, EOK); ++ ++ /* Wait until the test finishes with EOK */ ++ ret = test_ev_loop(nss_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++} ++ ++void test_nss_getgrnam_ex_no_members(void **state) ++{ ++ errno_t ret; ++ ++ /* Test group is still in the cache */ ++ ++ mock_input_user_or_group_ex(true, getgrnam_no_members.gr_name, 0); ++ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETGRNAM_EX); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ ++ /* Query for that group, call a callback when command finishes */ ++ set_cmd_cb(test_nss_getgrnam_no_members_check); ++ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETGRNAM_EX, ++ nss_test_ctx->nss_cmds); ++ assert_int_equal(ret, EOK); ++ ++ /* Wait until the test finishes with EOK */ ++ ret = test_ev_loop(nss_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++ RESET_TCTX; ++ ++ /* Use old input format, expect failure */ ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_WRAPPER); ++ will_return(__wrap_sss_packet_get_body, "testgroup"); ++ will_return(__wrap_sss_packet_get_body, 0); ++ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETGRNAM_EX); ++ ++ set_cmd_cb(test_nss_EINVAL_check); ++ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETGRNAM_EX, ++ nss_test_ctx->nss_cmds); ++ assert_int_equal(ret, EOK); ++ ++ ret = test_ev_loop(nss_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++ RESET_TCTX; ++ ++ /* Use unsupported flag combination, expect EINVAL */ ++ mock_input_user_or_group_ex(false, getgrnam_no_members.gr_name, ++ SSS_NSS_EX_FLAG_NO_CACHE ++ |SSS_NSS_EX_FLAG_INVALIDATE_CACHE); ++ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETGRNAM_EX); ++ ++ set_cmd_cb(test_nss_EINVAL_check); ++ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETGRNAM_EX, ++ nss_test_ctx->nss_cmds); ++ assert_int_equal(ret, EOK); ++ ++ /* Wait until the test finishes with EOK */ ++ ret = test_ev_loop(nss_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++ RESET_TCTX; ++ ++ /* Use flag SSS_NSS_EX_FLAG_NO_CACHE, ++ * will cause a backend lookup -> mock_account_recv_simple() */ ++ mock_input_user_or_group_ex(true, getgrnam_no_members.gr_name, ++ SSS_NSS_EX_FLAG_NO_CACHE); ++ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETGRNAM_EX); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ mock_account_recv_simple(); ++ ++ set_cmd_cb(test_nss_getgrnam_no_members_check); ++ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETGRNAM_EX, ++ nss_test_ctx->nss_cmds); ++ assert_int_equal(ret, EOK); ++ ++ /* Wait until the test finishes with EOK */ ++ ret = test_ev_loop(nss_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++ RESET_TCTX; ++ ++ /* Use flag SSS_NSS_EX_FLAG_INVALIDATE_CACHE */ ++ mock_input_user_or_group_ex(true, getgrnam_no_members.gr_name, ++ SSS_NSS_EX_FLAG_INVALIDATE_CACHE); ++ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETGRNAM_EX); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ ++ set_cmd_cb(test_nss_getgrnam_no_members_check); ++ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETGRNAM_EX, ++ nss_test_ctx->nss_cmds); ++ assert_int_equal(ret, EOK); ++ ++ /* Wait until the test finishes with EOK */ ++ ret = test_ev_loop(nss_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++} ++ ++void test_nss_getgrgid_ex_no_members(void **state) ++{ ++ errno_t ret; ++ ++ /* Test group is still in the cache */ ++ ++ mock_input_id_ex(nss_test_ctx, getgrnam_no_members.gr_gid, 0); ++ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETGRGID_EX); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ mock_account_recv_simple(); ++ ++ /* Query for that group, call a callback when command finishes */ ++ set_cmd_cb(test_nss_getgrnam_no_members_check); ++ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETGRGID_EX, ++ nss_test_ctx->nss_cmds); ++ assert_int_equal(ret, EOK); ++ ++ /* Wait until the test finishes with EOK */ ++ ret = test_ev_loop(nss_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++ RESET_TCTX; ++ ++ /* Use old input format, expect failure */ ++ mock_input_id(nss_test_ctx, getgrnam_no_members.gr_gid); ++ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETGRGID_EX); ++ ++ set_cmd_cb(test_nss_EINVAL_check); ++ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETGRGID_EX, ++ nss_test_ctx->nss_cmds); ++ assert_int_equal(ret, EOK); ++ ++ /* Wait until the test finishes with EOK */ ++ ret = test_ev_loop(nss_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++ RESET_TCTX; ++ ++ /* Use unsupported flag combination, expect EINVAL */ ++ mock_input_id_ex(nss_test_ctx, getgrnam_no_members.gr_gid, ++ SSS_NSS_EX_FLAG_NO_CACHE ++ |SSS_NSS_EX_FLAG_INVALIDATE_CACHE); ++ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETGRGID_EX); ++ ++ set_cmd_cb(test_nss_EINVAL_check); ++ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETGRGID_EX, ++ nss_test_ctx->nss_cmds); ++ assert_int_equal(ret, EOK); ++ ++ /* Wait until the test finishes with EOK */ ++ ret = test_ev_loop(nss_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++ RESET_TCTX; ++ ++ /* Use flag SSS_NSS_EX_FLAG_NO_CACHE, ++ * will cause a backend lookup -> mock_account_recv_simple() */ ++ mock_input_id_ex(nss_test_ctx, getgrnam_no_members.gr_gid, ++ SSS_NSS_EX_FLAG_NO_CACHE); ++ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETGRGID_EX); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ mock_account_recv_simple(); ++ mock_account_recv_simple(); ++ ++ set_cmd_cb(test_nss_getgrnam_no_members_check); ++ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETGRGID_EX, ++ nss_test_ctx->nss_cmds); ++ assert_int_equal(ret, EOK); ++ ++ /* Wait until the test finishes with EOK */ ++ ret = test_ev_loop(nss_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++ RESET_TCTX; ++ ++ /* Use flag SSS_NSS_EX_FLAG_INVALIDATE_CACHE */ ++ mock_input_id_ex(nss_test_ctx, getgrnam_no_members.gr_gid, ++ SSS_NSS_EX_FLAG_INVALIDATE_CACHE); ++ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETGRGID_EX); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ ++ set_cmd_cb(test_nss_getgrnam_no_members_check); ++ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETGRGID_EX, ++ nss_test_ctx->nss_cmds); ++ assert_int_equal(ret, EOK); ++ ++ /* Wait until the test finishes with EOK */ ++ ret = test_ev_loop(nss_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++} ++ ++void test_nss_initgroups_ex(void **state) ++{ ++ errno_t ret; ++ struct sysdb_attrs *attrs; ++ ++ attrs = sysdb_new_attrs(nss_test_ctx); ++ assert_non_null(attrs); ++ ++ ret = sysdb_attrs_add_time_t(attrs, SYSDB_INITGR_EXPIRE, ++ time(NULL) + 300); ++ assert_int_equal(ret, EOK); ++ ++ ret = sysdb_attrs_add_string(attrs, SYSDB_UPN, "upninitgr@upndomain.test"); ++ assert_int_equal(ret, EOK); ++ ++ ret = store_user(nss_test_ctx, nss_test_ctx->tctx->dom, ++ &testinitgr_usr, attrs, 0); ++ assert_int_equal(ret, EOK); ++ ++ mock_input_user_or_group_ex(true, "testinitgr", 0); ++ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_INITGR_EX); ++ mock_fill_user(); ++ ++ /* Query for that user, call a callback when command finishes */ ++ set_cmd_cb(test_nss_initgr_check); ++ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_INITGR_EX, ++ nss_test_ctx->nss_cmds); ++ assert_int_equal(ret, EOK); ++ ++ /* Wait until the test finishes with EOK */ ++ ret = test_ev_loop(nss_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++ RESET_TCTX; ++ ++ /* Use old input format, expect failure */ ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_WRAPPER); ++ will_return(__wrap_sss_packet_get_body, "testinitgr"); ++ will_return(__wrap_sss_packet_get_body, 0); ++ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_INITGR_EX); ++ ++ set_cmd_cb(test_nss_EINVAL_check); ++ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_INITGR_EX, ++ nss_test_ctx->nss_cmds); ++ assert_int_equal(ret, EOK); ++ ++ ret = test_ev_loop(nss_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++ RESET_TCTX; ++ ++ /* Use unsupported flag combination, expect EINVAL */ ++ mock_input_user_or_group_ex(false, "testinitgr", ++ SSS_NSS_EX_FLAG_NO_CACHE ++ |SSS_NSS_EX_FLAG_INVALIDATE_CACHE); ++ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_INITGR_EX); ++ ++ set_cmd_cb(test_nss_EINVAL_check); ++ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_INITGR_EX, ++ nss_test_ctx->nss_cmds); ++ assert_int_equal(ret, EOK); ++ ++ /* Wait until the test finishes with EOK */ ++ ret = test_ev_loop(nss_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++ RESET_TCTX; ++ ++ /* Use flag SSS_NSS_EX_FLAG_NO_CACHE, ++ * will cause a backend lookup -> mock_account_recv_simple() */ ++ mock_input_user_or_group_ex(true, "testinitgr", ++ SSS_NSS_EX_FLAG_NO_CACHE); ++ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_INITGR_EX); ++ mock_fill_user(); ++ mock_account_recv_simple(); ++ ++ set_cmd_cb(test_nss_initgr_check); ++ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_INITGR_EX, ++ nss_test_ctx->nss_cmds); ++ assert_int_equal(ret, EOK); ++ ++ /* Wait until the test finishes with EOK */ ++ ret = test_ev_loop(nss_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++ RESET_TCTX; ++ ++ /* Use flag SSS_NSS_EX_FLAG_INVALIDATE_CACHE */ ++ mock_input_user_or_group_ex(true, "testinitgr", ++ SSS_NSS_EX_FLAG_INVALIDATE_CACHE); ++ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_INITGR_EX); ++ mock_fill_user(); ++ ++ set_cmd_cb(test_nss_initgr_check); ++ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_INITGR_EX, ++ nss_test_ctx->nss_cmds); ++ assert_int_equal(ret, EOK); ++ ++ /* Wait until the test finishes with EOK */ ++ ret = test_ev_loop(nss_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++} ++ + int main(int argc, const char *argv[]) + { + int rv; +@@ -4288,6 +4817,16 @@ int main(int argc, const char *argv[]) + nss_test_setup, nss_test_teardown), + cmocka_unit_test_setup_teardown(test_nss_getsidbyname_neg, + nss_test_setup, nss_test_teardown), ++ cmocka_unit_test_setup_teardown(test_nss_getpwnam_ex, ++ nss_test_setup, nss_test_teardown), ++ cmocka_unit_test_setup_teardown(test_nss_getpwuid_ex, ++ nss_test_setup, nss_test_teardown), ++ cmocka_unit_test_setup_teardown(test_nss_getgrnam_ex_no_members, ++ nss_test_setup, nss_test_teardown), ++ cmocka_unit_test_setup_teardown(test_nss_getgrgid_ex_no_members, ++ nss_test_setup, nss_test_teardown), ++ cmocka_unit_test_setup_teardown(test_nss_initgroups_ex, ++ nss_test_setup, nss_test_teardown), + }; + + /* Set debug level to invalid value so we can deside if -d 0 was used. */ +-- +2.14.3 + diff --git a/0010-nss-idmap-add-timeout-version-of-old-sss_nss_-calls.patch b/0010-nss-idmap-add-timeout-version-of-old-sss_nss_-calls.patch new file mode 100644 index 0000000..e1c303a --- /dev/null +++ b/0010-nss-idmap-add-timeout-version-of-old-sss_nss_-calls.patch @@ -0,0 +1,493 @@ +From e54db68cbb9c12d8a6867f2c7766fb2115ab0997 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Thu, 2 Nov 2017 10:32:41 +0100 +Subject: [PATCH 10/11] nss-idmap: add timeout version of old sss_nss_* calls + +Reviewed-by: Jakub Hrozek +--- + Makefile.am | 2 +- + src/sss_client/idmap/sss_nss_idmap.c | 126 ++++++++++++++++++-------- + src/sss_client/idmap/sss_nss_idmap.exports | 7 ++ + src/sss_client/idmap/sss_nss_idmap.h | 124 +++++++++++++++++++++++++ + src/sss_client/idmap/sss_nss_idmap.unit_tests | 2 +- + src/tests/cmocka/sss_nss_idmap-tests.c | 13 +-- + 6 files changed, 229 insertions(+), 45 deletions(-) + +diff --git a/Makefile.am b/Makefile.am +index dd25d1f7ea1be66388aa1b393bac290c4d7501a2..286ba47e3c421864362717be5258de960efca9f2 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -2974,7 +2974,6 @@ test_sysdb_domain_resolution_order_LDADD = \ + + test_wbc_calls_SOURCES = \ + src/tests/cmocka/test_wbc_calls.c \ +- src/sss_client/idmap/sss_nss_idmap.c \ + src/sss_client/libwbclient/wbc_sid_sssd.c \ + src/sss_client/libwbclient/wbclient_common.c \ + src/sss_client/libwbclient/wbc_sid_common.c \ +@@ -2993,6 +2992,7 @@ test_wbc_calls_LDADD = \ + $(TALLOC_LIBS) \ + $(SSSD_INTERNAL_LTLIBS) \ + libsss_test_common.la \ ++ libsss_nss_idmap.la \ + $(NULL) + + test_be_ptask_SOURCES = \ +diff --git a/src/sss_client/idmap/sss_nss_idmap.c b/src/sss_client/idmap/sss_nss_idmap.c +index 6f3af267a1e763e7dce77e3862be377ae2bfe984..6e7685d2b1d80956b6a6668e9bbb146abd9e86ed 100644 +--- a/src/sss_client/idmap/sss_nss_idmap.c ++++ b/src/sss_client/idmap/sss_nss_idmap.c +@@ -28,10 +28,13 @@ + + #include "sss_client/sss_cli.h" + #include "sss_client/idmap/sss_nss_idmap.h" ++#include "sss_client/idmap/sss_nss_idmap_private.h" + #include "util/strtonum.h" + + #define DATA_START (3 * sizeof(uint32_t)) + #define LIST_START (2 * sizeof(uint32_t)) ++#define NO_TIMEOUT ((unsigned int) -1) ++ + union input { + const char *str; + uint32_t id; +@@ -198,8 +201,8 @@ done: + return ret; + } + +-static int sss_nss_getyyybyxxx(union input inp, enum sss_cli_command cmd , +- struct output *out) ++static int sss_nss_getyyybyxxx(union input inp, enum sss_cli_command cmd, ++ unsigned int timeout, struct output *out) + { + int ret; + size_t inp_len; +@@ -215,6 +218,7 @@ static int sss_nss_getyyybyxxx(union input inp, enum sss_cli_command cmd , + struct sss_nss_kv *kv_list; + char **names; + enum sss_id_type *types; ++ int time_left = SSS_CLI_SOCKET_TIMEOUT; + + switch (cmd) { + case SSS_NSS_GETSIDBYNAME: +@@ -250,9 +254,14 @@ static int sss_nss_getyyybyxxx(union input inp, enum sss_cli_command cmd , + return EINVAL; + } + +- sss_nss_lock(); ++ if (timeout == NO_TIMEOUT) { ++ sss_nss_lock(); ++ } else { ++ sss_nss_timedlock(timeout, &time_left); ++ } + +- nret = sss_nss_make_request(cmd, &rd, &repbuf, &replen, &errnop); ++ nret = sss_nss_make_request_timeout(cmd, &rd, time_left, &repbuf, &replen, ++ &errnop); + if (nret != NSS_STATUS_SUCCESS) { + ret = nss_status_to_errno(nret); + goto done; +@@ -347,8 +356,8 @@ done: + return ret; + } + +-int sss_nss_getsidbyname(const char *fq_name, char **sid, +- enum sss_id_type *type) ++int sss_nss_getsidbyname_timeout(const char *fq_name, unsigned int timeout, ++ char **sid, enum sss_id_type *type) + { + int ret; + union input inp; +@@ -360,7 +369,7 @@ int sss_nss_getsidbyname(const char *fq_name, char **sid, + + inp.str = fq_name; + +- ret = sss_nss_getyyybyxxx(inp, SSS_NSS_GETSIDBYNAME, &out); ++ ret = sss_nss_getyyybyxxx(inp, SSS_NSS_GETSIDBYNAME, timeout, &out); + if (ret == EOK) { + *sid = out.d.str; + *type = out.type; +@@ -369,7 +378,14 @@ int sss_nss_getsidbyname(const char *fq_name, char **sid, + return ret; + } + +-int sss_nss_getsidbyid(uint32_t id, char **sid, enum sss_id_type *type) ++int sss_nss_getsidbyname(const char *fq_name, char **sid, ++ enum sss_id_type *type) ++{ ++ return sss_nss_getsidbyname_timeout(fq_name, NO_TIMEOUT, sid, type); ++} ++ ++int sss_nss_getsidbyid_timeout(uint32_t id, unsigned int timeout, ++ char **sid, enum sss_id_type *type) + { + int ret; + union input inp; +@@ -381,7 +397,7 @@ int sss_nss_getsidbyid(uint32_t id, char **sid, enum sss_id_type *type) + + inp.id = id; + +- ret = sss_nss_getyyybyxxx(inp, SSS_NSS_GETSIDBYID, &out); ++ ret = sss_nss_getyyybyxxx(inp, SSS_NSS_GETSIDBYID, timeout, &out); + if (ret == EOK) { + *sid = out.d.str; + *type = out.type; +@@ -390,8 +406,13 @@ int sss_nss_getsidbyid(uint32_t id, char **sid, enum sss_id_type *type) + return ret; + } + +-int sss_nss_getnamebysid(const char *sid, char **fq_name, +- enum sss_id_type *type) ++int sss_nss_getsidbyid(uint32_t id, char **sid, enum sss_id_type *type) ++{ ++ return sss_nss_getsidbyid_timeout(id, NO_TIMEOUT, sid, type); ++} ++ ++int sss_nss_getnamebysid_timeout(const char *sid, unsigned int timeout, ++ char **fq_name, enum sss_id_type *type) + { + int ret; + union input inp; +@@ -403,7 +424,7 @@ int sss_nss_getnamebysid(const char *sid, char **fq_name, + + inp.str = sid; + +- ret = sss_nss_getyyybyxxx(inp, SSS_NSS_GETNAMEBYSID, &out); ++ ret = sss_nss_getyyybyxxx(inp, SSS_NSS_GETNAMEBYSID, timeout, &out); + if (ret == EOK) { + *fq_name = out.d.str; + *type = out.type; +@@ -412,7 +433,14 @@ int sss_nss_getnamebysid(const char *sid, char **fq_name, + return ret; + } + +-int sss_nss_getidbysid(const char *sid, uint32_t *id, enum sss_id_type *id_type) ++int sss_nss_getnamebysid(const char *sid, char **fq_name, ++ enum sss_id_type *type) ++{ ++ return sss_nss_getnamebysid_timeout(sid, NO_TIMEOUT, fq_name, type); ++} ++ ++int sss_nss_getidbysid_timeout(const char *sid, unsigned int timeout, ++ uint32_t *id, enum sss_id_type *id_type) + { + int ret; + union input inp; +@@ -424,7 +452,7 @@ int sss_nss_getidbysid(const char *sid, uint32_t *id, enum sss_id_type *id_type) + + inp.str = sid; + +- ret = sss_nss_getyyybyxxx(inp, SSS_NSS_GETIDBYSID, &out); ++ ret = sss_nss_getyyybyxxx(inp, SSS_NSS_GETIDBYSID, timeout, &out); + if (ret == EOK) { + *id = out.d.id; + *id_type = out.type; +@@ -433,8 +461,14 @@ 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 sss_nss_getidbysid(const char *sid, uint32_t *id, enum sss_id_type *id_type) ++{ ++ return sss_nss_getidbysid_timeout(sid, NO_TIMEOUT, id, id_type); ++} ++ ++int sss_nss_getorigbyname_timeout(const char *fq_name, unsigned int timeout, ++ struct sss_nss_kv **kv_list, ++ enum sss_id_type *type) + { + int ret; + union input inp; +@@ -446,7 +480,7 @@ int sss_nss_getorigbyname(const char *fq_name, struct sss_nss_kv **kv_list, + + inp.str = fq_name; + +- ret = sss_nss_getyyybyxxx(inp, SSS_NSS_GETORIGBYNAME, &out); ++ ret = sss_nss_getyyybyxxx(inp, SSS_NSS_GETORIGBYNAME, timeout, &out); + if (ret == EOK) { + *kv_list = out.d.kv_list; + *type = out.type; +@@ -455,30 +489,42 @@ int sss_nss_getorigbyname(const char *fq_name, struct sss_nss_kv **kv_list, + return ret; + } + ++int sss_nss_getorigbyname(const char *fq_name, struct sss_nss_kv **kv_list, ++ enum sss_id_type *type) ++{ ++ return sss_nss_getorigbyname_timeout(fq_name, NO_TIMEOUT, kv_list, type); ++} ++ ++int sss_nss_getnamebycert_timeout(const char *cert, unsigned int timeout, ++ char **fq_name, enum sss_id_type *type) ++{ ++ int ret; ++ union input inp; ++ struct output out; ++ ++ if (fq_name == NULL || cert == NULL || *cert == '\0') { ++ return EINVAL; ++ } ++ ++ inp.str = cert; ++ ++ ret = sss_nss_getyyybyxxx(inp, SSS_NSS_GETNAMEBYCERT, timeout, &out); ++ if (ret == EOK) { ++ *fq_name = out.d.str; ++ *type = out.type; ++ } ++ ++ return ret; ++} ++ + int sss_nss_getnamebycert(const char *cert, char **fq_name, + enum sss_id_type *type) + { +- int ret; +- union input inp; +- struct output out; +- +- if (fq_name == NULL || cert == NULL || *cert == '\0') { +- return EINVAL; +- } +- +- inp.str = cert; +- +- ret = sss_nss_getyyybyxxx(inp, SSS_NSS_GETNAMEBYCERT, &out); +- if (ret == EOK) { +- *fq_name = out.d.str; +- *type = out.type; +- } +- +- return ret; ++ return sss_nss_getnamebycert_timeout(cert, NO_TIMEOUT, fq_name, type); + } + +-int sss_nss_getlistbycert(const char *cert, char ***fq_name, +- enum sss_id_type **type) ++int sss_nss_getlistbycert_timeout(const char *cert, unsigned int timeout, ++ char ***fq_name, enum sss_id_type **type) + { + int ret; + union input inp; +@@ -490,7 +536,7 @@ int sss_nss_getlistbycert(const char *cert, char ***fq_name, + + inp.str = cert; + +- ret = sss_nss_getyyybyxxx(inp, SSS_NSS_GETLISTBYCERT, &out); ++ ret = sss_nss_getyyybyxxx(inp, SSS_NSS_GETLISTBYCERT, timeout, &out); + if (ret == EOK) { + *fq_name = out.d.names; + *type = out.types; +@@ -498,3 +544,9 @@ int sss_nss_getlistbycert(const char *cert, char ***fq_name, + + return ret; + } ++ ++int sss_nss_getlistbycert(const char *cert, char ***fq_name, ++ enum sss_id_type **type) ++{ ++ return sss_nss_getlistbycert_timeout(cert, NO_TIMEOUT, fq_name, type); ++} +diff --git a/src/sss_client/idmap/sss_nss_idmap.exports b/src/sss_client/idmap/sss_nss_idmap.exports +index 788d05ecc3bd56fa88e68a98b9c8096cf7140a09..8d0a24f42aa3fb3dd9c2ed125bf79e2c7792993f 100644 +--- a/src/sss_client/idmap/sss_nss_idmap.exports ++++ b/src/sss_client/idmap/sss_nss_idmap.exports +@@ -40,4 +40,11 @@ SSS_NSS_IDMAP_0.4.0 { + sss_nss_getgrnam_timeout; + sss_nss_getgrgid_timeout; + sss_nss_getgrouplist_timeout; ++ sss_nss_getsidbyname_timeout; ++ sss_nss_getsidbyid_timeout; ++ sss_nss_getnamebysid_timeout; ++ sss_nss_getidbysid_timeout; ++ sss_nss_getorigbyname_timeout; ++ sss_nss_getnamebycert_timeout; ++ sss_nss_getlistbycert_timeout; + } SSS_NSS_IDMAP_0.3.0; +diff --git a/src/sss_client/idmap/sss_nss_idmap.h b/src/sss_client/idmap/sss_nss_idmap.h +index 3755643312f05a31d1cf1aa76dfc22848ef1e3ec..125e72a6486f5916f90d37f27e1743d181bfa3e5 100644 +--- a/src/sss_client/idmap/sss_nss_idmap.h ++++ b/src/sss_client/idmap/sss_nss_idmap.h +@@ -303,5 +303,129 @@ int sss_nss_getgrgid_timeout(gid_t gid, struct group *grp, + int sss_nss_getgrouplist_timeout(const char *name, gid_t group, + gid_t *groups, int *ngroups, + uint32_t flags, unsigned int timeout); ++/** ++ * @brief Find SID by fully qualified name with timeout ++ * ++ * @param[in] fq_name Fully qualified name of a user or a group ++ * @param[in] timeout timeout in milliseconds ++ * @param[out] sid String representation of the SID of the requested user ++ * or group, must be freed by the caller ++ * @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 ++ * - ETIME: request timed out but was send to SSSD ++ * - ETIMEDOUT: request timed out but was not send to SSSD ++ */ ++int sss_nss_getsidbyname_timeout(const char *fq_name, unsigned int timeout, ++ char **sid, enum sss_id_type *type); ++ ++/** ++ * @brief Find SID by a POSIX UID or GID with timeout ++ * ++ * @param[in] id POSIX UID or GID ++ * @param[in] timeout timeout in milliseconds ++ * @param[out] sid String representation of the SID of the requested user ++ * or group, must be freed by the caller ++ * @param[out] type Type of the object related to the given ID ++ * ++ * @return ++ * - see #sss_nss_getsidbyname_timeout ++ */ ++int sss_nss_getsidbyid_timeout(uint32_t id, unsigned int timeout, ++ char **sid, enum sss_id_type *type); ++ ++/** ++ * @brief Return the fully qualified name for the given SID with timeout ++ * ++ * @param[in] sid String representation of the SID ++ * @param[in] timeout timeout in milliseconds ++ * @param[out] fq_name Fully qualified name of a user or a group, ++ * must be freed by the caller ++ * @param[out] type Type of the object related to the SID ++ * ++ * @return ++ * - see #sss_nss_getsidbyname_timeout ++ */ ++int sss_nss_getnamebysid_timeout(const char *sid, unsigned int timeout, ++ char **fq_name, enum sss_id_type *type); ++ ++/** ++ * @brief Return the POSIX ID for the given SID with timeout ++ * ++ * @param[in] sid String representation of the SID ++ * @param[in] timeout timeout in milliseconds ++ * @param[out] id POSIX ID related to the SID ++ * @param[out] id_type Type of the object related to the SID ++ * ++ * @return ++ * - see #sss_nss_getsidbyname_timeout ++ */ ++int sss_nss_getidbysid_timeout(const char *sid, unsigned int timeout, ++ uint32_t *id, enum sss_id_type *id_type); ++ ++/** ++ * @brief Find original data by fully qualified name with timeout ++ * ++ * @param[in] fq_name Fully qualified name of a user or a group ++ * @param[in] timeout timeout in milliseconds ++ * @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 ++ * - ETIME: request timed out but was send to SSSD ++ * - ETIMEDOUT: request timed out but was not send to SSSD ++ */ ++int sss_nss_getorigbyname_timeout(const char *fq_name, unsigned int timeout, ++ struct sss_nss_kv **kv_list, ++ enum sss_id_type *type); ++ ++/** ++ * @brief Return the fully qualified name for the given base64 encoded ++ * X.509 certificate in DER format with timeout ++ * ++ * @param[in] cert base64 encoded certificate ++ * @param[in] timeout timeout in milliseconds ++ * @param[out] fq_name Fully qualified name of a user or a group, ++ * must be freed by the caller ++ * @param[out] type Type of the object related to the cert ++ * ++ * @return ++ * - see #sss_nss_getsidbyname_timeout ++ */ ++int sss_nss_getnamebycert_timeout(const char *cert, unsigned int timeout, ++ char **fq_name, enum sss_id_type *type); ++ ++/** ++ * @brief Return a list of fully qualified names for the given base64 encoded ++ * X.509 certificate in DER format with timeout ++ * ++ * @param[in] cert base64 encoded certificate ++ * @param[in] timeout timeout in milliseconds ++ * @param[out] fq_name List of fully qualified name of users or groups, ++ * must be freed by the caller ++ * @param[out] type List of types of the objects related to the cert ++ * ++ * @return ++ * - see #sss_nss_getsidbyname_timeout ++ */ ++int sss_nss_getlistbycert_timeout(const char *cert, unsigned int timeout, ++ char ***fq_name, enum sss_id_type **type); ++ + #endif /* IPA_389DS_PLUGIN_HELPER_CALLS */ + #endif /* SSS_NSS_IDMAP_H_ */ +diff --git a/src/sss_client/idmap/sss_nss_idmap.unit_tests b/src/sss_client/idmap/sss_nss_idmap.unit_tests +index 361cc3b134ead52cf458afe27c055739d6728441..05c474f008e1d59aae5976acfd81613c3c3e6540 100644 +--- a/src/sss_client/idmap/sss_nss_idmap.unit_tests ++++ b/src/sss_client/idmap/sss_nss_idmap.unit_tests +@@ -2,5 +2,5 @@ + UNIT_TEST_ONLY { + # should not be part of installed library + global: +- sss_nss_make_request; ++ sss_nss_make_request_timeout; + }; +diff --git a/src/tests/cmocka/sss_nss_idmap-tests.c b/src/tests/cmocka/sss_nss_idmap-tests.c +index 8807eca619d7b07d919168e5629042cf38f654ac..2e37040d2d3523bea157804706685fa0b36df16a 100644 +--- a/src/tests/cmocka/sss_nss_idmap-tests.c ++++ b/src/tests/cmocka/sss_nss_idmap-tests.c +@@ -61,10 +61,11 @@ uint8_t buf_orig1[] = {0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0 + #error "unknow endianess" + #endif + +-enum nss_status sss_nss_make_request(enum sss_cli_command cmd, +- struct sss_cli_req_data *rd, +- uint8_t **repbuf, size_t *replen, +- int *errnop) ++enum nss_status sss_nss_make_request_timeout(enum sss_cli_command cmd, ++ struct sss_cli_req_data *rd, ++ int timeout, ++ uint8_t **repbuf, size_t *replen, ++ int *errnop) + { + struct sss_nss_make_request_test_data *d; + +@@ -114,7 +115,7 @@ void test_getsidbyname(void **state) + sid = NULL; + + for (c = 0; d[c].d.repbuf != NULL; c++) { +- will_return(sss_nss_make_request, &d[0].d); ++ will_return(sss_nss_make_request_timeout, &d[0].d); + + ret = sss_nss_getsidbyname("test", &sid, &type); + assert_int_equal(ret, d[0].ret); +@@ -134,7 +135,7 @@ void test_getorigbyname(void **state) + 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); ++ will_return(sss_nss_make_request_timeout, &d); + ret = sss_nss_getorigbyname("test", &kv_list, &type); + assert_int_equal(ret, EOK); + assert_int_equal(type, SSS_ID_TYPE_UID); +-- +2.14.3 + diff --git a/0011-nss-idmap-allow-empty-buffer-with-SSS_NSS_EX_FLAG_IN.patch b/0011-nss-idmap-allow-empty-buffer-with-SSS_NSS_EX_FLAG_IN.patch new file mode 100644 index 0000000..839ffc7 --- /dev/null +++ b/0011-nss-idmap-allow-empty-buffer-with-SSS_NSS_EX_FLAG_IN.patch @@ -0,0 +1,183 @@ +From 859bddc2bf51dc426a3dc56bd9f365e9c5722b65 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Thu, 2 Nov 2017 11:09:20 +0100 +Subject: [PATCH 11/11] nss-idmap: allow empty buffer with + SSS_NSS_EX_FLAG_INVALIDATE_CACHE + +Reviewed-by: Jakub Hrozek +--- + src/sss_client/idmap/sss_nss_ex.c | 89 ++++++++++++++++++++++++++------------- + 1 file changed, 60 insertions(+), 29 deletions(-) + +diff --git a/src/sss_client/idmap/sss_nss_ex.c b/src/sss_client/idmap/sss_nss_ex.c +index 148eb7b35ec236b6272dd203a0035399cfdef73d..dcd9619a8b07ced7498f61b7e809fa46ebffe09e 100644 +--- a/src/sss_client/idmap/sss_nss_ex.c ++++ b/src/sss_client/idmap/sss_nss_ex.c +@@ -103,8 +103,11 @@ errno_t sss_nss_mc_get(struct nss_input *inp) + } + } + +-static int check_flags(uint32_t flags) ++static int check_flags(struct nss_input *inp, uint32_t flags, ++ bool *skip_mc, bool *skip_data) + { ++ bool no_data = false; ++ + /* SSS_NSS_EX_FLAG_NO_CACHE and SSS_NSS_EX_FLAG_INVALIDATE_CACHE are + * mutually exclusive */ + if ((flags & SSS_NSS_EX_FLAG_NO_CACHE) != 0 +@@ -112,6 +115,52 @@ static int check_flags(uint32_t flags) + return EINVAL; + } + ++ *skip_mc = false; ++ if ((flags & SSS_NSS_EX_FLAG_NO_CACHE) != 0 ++ || (flags & SSS_NSS_EX_FLAG_INVALIDATE_CACHE) != 0) { ++ *skip_mc = true; ++ } ++ ++ switch(inp->cmd) { ++ case SSS_NSS_GETPWNAM: ++ case SSS_NSS_GETPWNAM_EX: ++ case SSS_NSS_GETPWUID: ++ case SSS_NSS_GETPWUID_EX: ++ if (inp->result.pwrep.buffer == NULL ++ || inp->result.pwrep.buflen == 0) { ++ no_data = true; ++ } ++ break; ++ case SSS_NSS_GETGRNAM: ++ case SSS_NSS_GETGRNAM_EX: ++ case SSS_NSS_GETGRGID: ++ case SSS_NSS_GETGRGID_EX: ++ if (inp->result.grrep.buffer == NULL ++ || inp->result.grrep.buflen == 0) { ++ no_data = true; ++ } ++ break; ++ case SSS_NSS_INITGR: ++ case SSS_NSS_INITGR_EX: ++ if (inp->result.initgrrep.ngroups == 0 ++ || inp->result.initgrrep.groups == NULL) { ++ return EINVAL; ++ } ++ break; ++ default: ++ return EINVAL; ++ } ++ ++ *skip_data = false; ++ /* Allow empty buffer with SSS_NSS_EX_FLAG_INVALIDATE_CACHE */ ++ if (no_data) { ++ if ((flags & SSS_NSS_EX_FLAG_INVALIDATE_CACHE) != 0) { ++ *skip_data = true; ++ } else { ++ return ERANGE; ++ } ++ } ++ + return 0; + } + +@@ -128,18 +177,14 @@ int sss_get_ex(struct nss_input *inp, uint32_t flags, unsigned int timeout) + gid_t *new_groups; + size_t idx; + bool skip_mc = false; ++ bool skip_data = false; + +- ret = check_flags(flags); ++ ret = check_flags(inp, flags, &skip_mc, &skip_data); + if (ret != 0) { + return ret; + } + +- if ((flags & SSS_NSS_EX_FLAG_NO_CACHE) != 0 +- || (flags & SSS_NSS_EX_FLAG_INVALIDATE_CACHE) != 0) { +- skip_mc = true; +- } +- +- if (!skip_mc) { ++ if (!skip_mc && !skip_data) { + ret = sss_nss_mc_get(inp); + switch (ret) { + case 0: +@@ -159,7 +204,7 @@ int sss_get_ex(struct nss_input *inp, uint32_t flags, unsigned int timeout) + + sss_nss_timedlock(timeout, &time_left); + +- if (!skip_mc) { ++ if (!skip_mc && !skip_data) { + /* previous thread might already initialize entry in mmap cache */ + ret = sss_nss_mc_get(inp); + switch (ret) { +@@ -196,6 +241,12 @@ int sss_get_ex(struct nss_input *inp, uint32_t flags, unsigned int timeout) + goto out; + } + ++ if (skip_data) { ++ /* No data requested, just return the return code */ ++ ret = 0; ++ goto out; ++ } ++ + if (inp->cmd == SSS_NSS_INITGR || inp->cmd == SSS_NSS_INITGR_EX) { + if ((*(inp->result.initgrrep.ngroups) - *(inp->result.initgrrep.start)) + < num_results) { +@@ -311,10 +362,6 @@ int sss_nss_getpwnam_timeout(const char *name, struct passwd *pwd, + .result.pwrep.buffer = buffer, + .result.pwrep.buflen = buflen}; + +- if (buffer == NULL || buflen == 0) { +- return ERANGE; +- } +- + ret = make_name_flag_req_data(name, flags, &inp.rd); + if (ret != 0) { + return ret; +@@ -346,10 +393,6 @@ int sss_nss_getpwuid_timeout(uid_t uid, struct passwd *pwd, + .result.pwrep.buffer = buffer, + .result.pwrep.buflen = buflen}; + +- if (buffer == NULL || buflen == 0) { +- return ERANGE; +- } +- + SAFEALIGN_COPY_UINT32(&req_data[0], &uid, NULL); + SAFEALIGN_COPY_UINT32(&req_data[1], &flags, NULL); + *result = NULL; +@@ -373,10 +416,6 @@ int sss_nss_getgrnam_timeout(const char *name, struct group *grp, + .result.grrep.buffer = buffer, + .result.grrep.buflen = buflen}; + +- if (buffer == NULL || buflen == 0) { +- return ERANGE; +- } +- + ret = make_name_flag_req_data(name, flags, &inp.rd); + if (ret != 0) { + return ret; +@@ -407,10 +446,6 @@ int sss_nss_getgrgid_timeout(gid_t gid, struct group *grp, + .result.grrep.buffer = buffer, + .result.grrep.buflen = buflen}; + +- if (buffer == NULL || buflen == 0) { +- return ERANGE; +- } +- + SAFEALIGN_COPY_UINT32(&req_data[0], &gid, NULL); + SAFEALIGN_COPY_UINT32(&req_data[1], &flags, NULL); + *result = NULL; +@@ -434,10 +469,6 @@ int sss_nss_getgrouplist_timeout(const char *name, gid_t group, + .input.name = name, + .cmd = SSS_NSS_INITGR_EX}; + +- if (groups == NULL || ngroups == NULL || *ngroups == 0) { +- return EINVAL; +- } +- + ret = make_name_flag_req_data(name, flags, &inp.rd); + if (ret != 0) { + return ret; +-- +2.14.3 + diff --git a/sssd.spec b/sssd.spec index dfd63d4..c81e4f7 100644 --- a/sssd.spec +++ b/sssd.spec @@ -29,7 +29,7 @@ Name: sssd Version: 1.16.0 -Release: 2%{?dist} +Release: 3%{?dist} Group: Applications/System Summary: System Security Services Daemon License: GPLv3+ @@ -39,6 +39,17 @@ BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX) ### Patches ### Patch0001: 0001-KCM-Fix-restart-during-after-upgrade.patch +Patch0002: 0002-sss_client-create-nss_common.h.patch +Patch0003: 0003-nss-idmap-add-nss-like-calls-with-timeout-and-flags.patch +Patch0004: 0004-NSS-add-_EX-version-of-some-requests.patch +Patch0005: 0005-NSS-add-support-for-SSS_NSS_EX_FLAG_NO_CACHE.patch +Patch0006: 0006-CACHE_REQ-Add-cache_req_data_set_bypass_dp.patch +Patch0007: 0007-nss-make-memcache_delete_entry-public.patch +Patch0008: 0008-NSS-add-support-for-SSS_NSS_EX_FLAG_INVALIDATE_CACHE.patch +Patch0009: 0009-NSS-TESTS-add-unit-tests-for-_EX-requests.patch +Patch0010: 0010-nss-idmap-add-timeout-version-of-old-sss_nss_-calls.patch +Patch0011: 0011-nss-idmap-allow-empty-buffer-with-SSS_NSS_EX_FLAG_IN.patch + Patch0502: 0502-SYSTEMD-Use-capabilities.patch Patch0503: 0503-Disable-stopping-idle-socket-activated-responders.patch Patch0600: 0600-tests-cmocka-Fix-unit-tests-with-libldb-1.3.0.patch @@ -1251,6 +1262,9 @@ fi %{_libdir}/%{name}/modules/libwbclient.so %changelog +* Fri Nov 17 2017 Jakub Hrozek - 1.16.0-3 +- Backport extended NSS API from upstream master branch + * Fri Nov 03 2017 Lukas Slebodnik - 1.16.0-2 - Resolves: upstream#3529 - sssd-kcm Fix restart during/after upgrade