From cc19c0ace43a3613f6290fa4bc4f68c964563743 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 28 Sep 2007 18:12:22 +0000 Subject: [PATCH] r25406: Make the Linux nss client code thread-safe. Fix originally inspired from code from boyang . Jeremy. --- source/Makefile.in | 2 +- source/configure.in | 6 +- source/nsswitch/winbind_nss_linux.c | 193 ++++++++++++++++++++++++++-- 3 files changed, 187 insertions(+), 14 deletions(-) diff --git a/source/Makefile.in b/source/Makefile.in index ffb5d93d50b..9de9ea2b787 100644 --- a/source/Makefile.in +++ b/source/Makefile.in @@ -1489,7 +1489,7 @@ bin/winbindd@EXEEXT@: $(BINARY_PREREQS) $(WINBINDD_OBJ) @BUILD_POPT@ @WINBIND_NSS@: $(BINARY_PREREQS) $(WINBIND_NSS_OBJ) @echo "Linking $@" @$(SHLD) $(WINBIND_NSS_LDSHFLAGS) -o $@ $(WINBIND_NSS_OBJ) \ - @WINBIND_NSS_EXTRA_LIBS@ @SONAMEFLAG@`basename $@`@NSSSONAMEVERSIONSUFFIX@ + @WINBIND_NSS_EXTRA_LIBS@ @WINBIND_NSS_PTHREAD@ @SONAMEFLAG@`basename $@`@NSSSONAMEVERSIONSUFFIX@ @WINBIND_WINS_NSS@: $(BINARY_PREREQS) $(WINBIND_WINS_NSS_OBJ) @echo "Linking $@" diff --git a/source/configure.in b/source/configure.in index 1aa34789193..df4d040b0fe 100644 --- a/source/configure.in +++ b/source/configure.in @@ -991,7 +991,7 @@ LIBS="${LIBS} ${LIBDL}" AC_CHECK_HEADERS(aio.h arpa/inet.h sys/fcntl.h sys/select.h fcntl.h sys/time.h sys/unistd.h rpc/nettype.h) AC_CHECK_HEADERS(unistd.h utime.h grp.h sys/id.h memory.h alloca.h) -AC_CHECK_HEADERS(limits.h float.h) +AC_CHECK_HEADERS(limits.h float.h pthread.h) AC_CHECK_HEADERS(rpc/rpc.h rpcsvc/nis.h rpcsvc/ypclnt.h) AC_CHECK_HEADERS(sys/param.h ctype.h sys/wait.h sys/resource.h sys/ioctl.h sys/ipc.h sys/prctl.h) AC_CHECK_HEADERS(sys/mman.h sys/filio.h sys/priv.h sys/shm.h string.h strings.h stdlib.h sys/socket.h) @@ -5984,6 +5984,7 @@ WINBIND_NSS="nsswitch/libnss_winbind.$SHLIBEXT" WINBIND_WINS_NSS="nsswitch/libnss_wins.$SHLIBEXT" WINBIND_NSS_LDSHFLAGS=$LDSHFLAGS NSSSONAMEVERSIONSUFFIX="" +WINBIND_NSS_PTHREAD="" case "$host_os" in linux*-gnu* | gnu* | k*bsd*-gnu) @@ -6047,6 +6048,9 @@ case "$host_os" in ;; esac +AC_CHECK_LIB(pthread, pthread_mutex_lock, [WINBIND_NSS_PTHREAD="-lpthread" + AC_DEFINE(HAVE_PTHREAD, 1, [whether pthread exists])]) +AC_SUBST(WINBIND_NSS_PTHREAD) AC_SUBST(WINBIND_NSS) AC_SUBST(WINBIND_WINS_NSS) AC_SUBST(WINBIND_NSS_LDSHFLAGS) diff --git a/source/nsswitch/winbind_nss_linux.c b/source/nsswitch/winbind_nss_linux.c index ac53979cedd..6de419da5a2 100644 --- a/source/nsswitch/winbind_nss_linux.c +++ b/source/nsswitch/winbind_nss_linux.c @@ -21,6 +21,14 @@ #include "winbind_client.h" +#if HAVE_PTHREAD_H +#include +#endif + +#if HAVE_PTHREAD +static pthread_mutex_t winbind_nss_mutex = PTHREAD_MUTEX_INITIALIZER; +#endif + /* Maximum number of users to pass back over the unix domain socket per call. This is not a static limit on the total number of users or groups returned in total. */ @@ -332,6 +340,10 @@ _nss_winbind_setpwent(void) fprintf(stderr, "[%5d]: setpwent\n", getpid()); #endif +#if HAVE_PTHREAD + pthread_mutex_lock(&winbind_nss_mutex); +#endif + if (num_pw_cache > 0) { ndx_pw_cache = num_pw_cache = 0; winbindd_free_response(&getpwent_response); @@ -342,6 +354,10 @@ _nss_winbind_setpwent(void) fprintf(stderr, "[%5d]: setpwent returns %s (%d)\n", getpid(), nss_err_str(ret), ret); #endif + +#if HAVE_PTHREAD + pthread_mutex_unlock(&winbind_nss_mutex); +#endif return ret; } @@ -355,6 +371,10 @@ _nss_winbind_endpwent(void) fprintf(stderr, "[%5d]: endpwent\n", getpid()); #endif +#if HAVE_PTHREAD + pthread_mutex_lock(&winbind_nss_mutex); +#endif + if (num_pw_cache > 0) { ndx_pw_cache = num_pw_cache = 0; winbindd_free_response(&getpwent_response); @@ -365,6 +385,11 @@ _nss_winbind_endpwent(void) fprintf(stderr, "[%5d]: endpwent returns %s (%d)\n", getpid(), nss_err_str(ret), ret); #endif + +#if HAVE_PTHREAD + pthread_mutex_unlock(&winbind_nss_mutex); +#endif + return ret; } @@ -382,6 +407,10 @@ _nss_winbind_getpwent_r(struct passwd *result, char *buffer, fprintf(stderr, "[%5d]: getpwent\n", getpid()); #endif +#if HAVE_PTHREAD + pthread_mutex_lock(&winbind_nss_mutex); +#endif + /* Return an entry from the cache if we have one, or if we are called again because we exceeded our static buffer. */ @@ -452,6 +481,10 @@ _nss_winbind_getpwent_r(struct passwd *result, char *buffer, fprintf(stderr, "[%5d]: getpwent returns %s (%d)\n", getpid(), nss_err_str(ret), ret); #endif + +#if HAVE_PTHREAD + pthread_mutex_unlock(&winbind_nss_mutex); +#endif return ret; } @@ -464,14 +497,18 @@ _nss_winbind_getpwuid_r(uid_t uid, struct passwd *result, char *buffer, NSS_STATUS ret; static struct winbindd_response response; struct winbindd_request request; - static int keep_response=0; + static int keep_response; #ifdef DEBUG_NSS - fprintf(stderr, "[%5d]: getpwuid %d\n", getpid(), (unsigned int)uid); + fprintf(stderr, "[%5d]: getpwuid_r %d\n", getpid(), (unsigned int)uid); +#endif + +#if HAVE_PTHREAD + pthread_mutex_lock(&winbind_nss_mutex); #endif /* If our static buffer needs to be expanded we are called again */ - if (!keep_response) { + if (!keep_response || uid != response.data.pw.pw_uid) { /* Call for the first time */ @@ -500,7 +537,6 @@ _nss_winbind_getpwuid_r(uid_t uid, struct passwd *result, char *buffer, ret = fill_pwent(result, &response.data.pw, &buffer, &buflen); if (ret == NSS_STATUS_TRYAGAIN) { - keep_response = true; *errnop = errno = ERANGE; goto done; } @@ -510,12 +546,18 @@ _nss_winbind_getpwuid_r(uid_t uid, struct passwd *result, char *buffer, } winbindd_free_response(&response); + done: #ifdef DEBUG_NSS fprintf(stderr, "[%5d]: getpwuid %d returns %s (%d)\n", getpid(), (unsigned int)uid, nss_err_str(ret), ret); #endif + +#if HAVE_PTHREAD + pthread_mutex_unlock(&winbind_nss_mutex); +#endif + return ret; } @@ -530,12 +572,16 @@ _nss_winbind_getpwnam_r(const char *name, struct passwd *result, char *buffer, static int keep_response; #ifdef DEBUG_NSS - fprintf(stderr, "[%5d]: getpwnam %s\n", getpid(), name); + fprintf(stderr, "[%5d]: getpwnam_r %s\n", getpid(), name); +#endif + +#if HAVE_PTHREAD + pthread_mutex_lock(&winbind_nss_mutex); #endif /* If our static buffer needs to be expanded we are called again */ - if (!keep_response) { + if (!keep_response || strcmp(name,response.data.pw.pw_name) != 0) { /* Call for the first time */ @@ -582,6 +628,11 @@ _nss_winbind_getpwnam_r(const char *name, struct passwd *result, char *buffer, fprintf(stderr, "[%5d]: getpwnam %s returns %s (%d)\n", getpid(), name, nss_err_str(ret), ret); #endif + +#if HAVE_PTHREAD + pthread_mutex_unlock(&winbind_nss_mutex); +#endif + return ret; } @@ -604,6 +655,10 @@ _nss_winbind_setgrent(void) fprintf(stderr, "[%5d]: setgrent\n", getpid()); #endif +#if HAVE_PTHREAD + pthread_mutex_lock(&winbind_nss_mutex); +#endif + if (num_gr_cache > 0) { ndx_gr_cache = num_gr_cache = 0; winbindd_free_response(&getgrent_response); @@ -614,6 +669,11 @@ _nss_winbind_setgrent(void) fprintf(stderr, "[%5d]: setgrent returns %s (%d)\n", getpid(), nss_err_str(ret), ret); #endif + +#if HAVE_PTHREAD + pthread_mutex_unlock(&winbind_nss_mutex); +#endif + return ret; } @@ -627,6 +687,10 @@ _nss_winbind_endgrent(void) fprintf(stderr, "[%5d]: endgrent\n", getpid()); #endif +#if HAVE_PTHREAD + pthread_mutex_lock(&winbind_nss_mutex); +#endif + if (num_gr_cache > 0) { ndx_gr_cache = num_gr_cache = 0; winbindd_free_response(&getgrent_response); @@ -637,6 +701,11 @@ _nss_winbind_endgrent(void) fprintf(stderr, "[%5d]: endgrent returns %s (%d)\n", getpid(), nss_err_str(ret), ret); #endif + +#if HAVE_PTHREAD + pthread_mutex_unlock(&winbind_nss_mutex); +#endif + return ret; } @@ -656,6 +725,10 @@ winbind_getgrent(enum winbindd_cmd cmd, fprintf(stderr, "[%5d]: getgrent\n", getpid()); #endif +#if HAVE_PTHREAD + pthread_mutex_lock(&winbind_nss_mutex); +#endif + /* Return an entry from the cache if we have one, or if we are called again because we exceeded our static buffer. */ @@ -735,6 +808,11 @@ winbind_getgrent(enum winbindd_cmd cmd, fprintf(stderr, "[%5d]: getgrent returns %s (%d)\n", getpid(), nss_err_str(ret), ret); #endif + +#if HAVE_PTHREAD + pthread_mutex_unlock(&winbind_nss_mutex); +#endif + return ret; } @@ -769,9 +847,14 @@ _nss_winbind_getgrnam_r(const char *name, fprintf(stderr, "[%5d]: getgrnam %s\n", getpid(), name); #endif +#if HAVE_PTHREAD + pthread_mutex_lock(&winbind_nss_mutex); +#endif + /* If our static buffer needs to be expanded we are called again */ - - if (!keep_response) { + /* Or if the stored response group name differs from the request. */ + + if (!keep_response || strcmp(name,response.data.gr.gr_name) != 0) { /* Call for the first time */ @@ -798,13 +881,13 @@ _nss_winbind_getgrnam_r(const char *name, } } else { - + /* We've been called again */ - + ret = fill_grent(result, &response.data.gr, (char *)response.extra_data.data, &buffer, &buflen); - + if (ret == NSS_STATUS_TRYAGAIN) { keep_response = true; *errnop = errno = ERANGE; @@ -821,6 +904,11 @@ _nss_winbind_getgrnam_r(const char *name, fprintf(stderr, "[%5d]: getgrnam %s returns %s (%d)\n", getpid(), name, nss_err_str(ret), ret); #endif + +#if HAVE_PTHREAD + pthread_mutex_unlock(&winbind_nss_mutex); +#endif + return ret; } @@ -840,9 +928,14 @@ _nss_winbind_getgrgid_r(gid_t gid, fprintf(stderr, "[%5d]: getgrgid %d\n", getpid(), gid); #endif +#if HAVE_PTHREAD + pthread_mutex_lock(&winbind_nss_mutex); +#endif + /* If our static buffer needs to be expanded we are called again */ + /* Or if the stored response group name differs from the request. */ - if (!keep_response) { + if (!keep_response || gid != response.data.gr.gr_gid) { /* Call for the first time */ @@ -890,6 +983,10 @@ _nss_winbind_getgrgid_r(gid_t gid, fprintf(stderr, "[%5d]: getgrgid %d returns %s (%d)\n", getpid(), (unsigned int)gid, nss_err_str(ret), ret); #endif + +#if HAVE_PTHREAD + pthread_mutex_unlock(&winbind_nss_mutex); +#endif return ret; } @@ -910,6 +1007,10 @@ _nss_winbind_initgroups_dyn(char *user, gid_t group, long int *start, user, group); #endif +#if HAVE_PTHREAD + pthread_mutex_lock(&winbind_nss_mutex); +#endif + ZERO_STRUCT(request); ZERO_STRUCT(response); @@ -990,6 +1091,11 @@ _nss_winbind_initgroups_dyn(char *user, gid_t group, long int *start, fprintf(stderr, "[%5d]: initgroups %s returns %s (%d)\n", getpid(), user, nss_err_str(ret), ret); #endif + +#if HAVE_PTHREAD + pthread_mutex_unlock(&winbind_nss_mutex); +#endif + return ret; } @@ -1008,6 +1114,10 @@ _nss_winbind_getusersids(const char *user_sid, char **group_sids, fprintf(stderr, "[%5d]: getusersids %s\n", getpid(), user_sid); #endif +#if HAVE_PTHREAD + pthread_mutex_lock(&winbind_nss_mutex); +#endif + ZERO_STRUCT(request); ZERO_STRUCT(response); @@ -1033,6 +1143,11 @@ _nss_winbind_getusersids(const char *user_sid, char **group_sids, done: winbindd_free_response(&response); + +#if HAVE_PTHREAD + pthread_mutex_unlock(&winbind_nss_mutex); +#endif + return ret; } @@ -1050,6 +1165,10 @@ _nss_winbind_nametosid(const char *name, char **sid, char *buffer, fprintf(stderr, "[%5d]: nametosid %s\n", getpid(), name); #endif +#if HAVE_PTHREAD + pthread_mutex_lock(&winbind_nss_mutex); +#endif + ZERO_STRUCT(response); ZERO_STRUCT(request); @@ -1075,6 +1194,11 @@ _nss_winbind_nametosid(const char *name, char **sid, char *buffer, failed: winbindd_free_response(&response); + +#if HAVE_PTHREAD + pthread_mutex_unlock(&winbind_nss_mutex); +#endif + return ret; } @@ -1093,6 +1217,10 @@ _nss_winbind_sidtoname(const char *sid, char **name, char *buffer, fprintf(stderr, "[%5d]: sidtoname %s\n", getpid(), sid); #endif +#if HAVE_PTHREAD + pthread_mutex_lock(&winbind_nss_mutex); +#endif + ZERO_STRUCT(response); ZERO_STRUCT(request); @@ -1139,6 +1267,11 @@ _nss_winbind_sidtoname(const char *sid, char **name, char *buffer, failed: winbindd_free_response(&response); + +#if HAVE_PTHREAD + pthread_mutex_unlock(&winbind_nss_mutex); +#endif + return ret; } @@ -1154,6 +1287,10 @@ _nss_winbind_sidtouid(const char *sid, uid_t *uid, int *errnop) fprintf(stderr, "[%5d]: sidtouid %s\n", getpid(), sid); #endif +#if HAVE_PTHREAD + pthread_mutex_lock(&winbind_nss_mutex); +#endif + ZERO_STRUCT(request); ZERO_STRUCT(response); @@ -1169,6 +1306,11 @@ _nss_winbind_sidtouid(const char *sid, uid_t *uid, int *errnop) *uid = response.data.uid; failed: + +#if HAVE_PTHREAD + pthread_mutex_unlock(&winbind_nss_mutex); +#endif + return ret; } @@ -1184,6 +1326,10 @@ _nss_winbind_sidtogid(const char *sid, gid_t *gid, int *errnop) fprintf(stderr, "[%5d]: sidtogid %s\n", getpid(), sid); #endif +#if HAVE_PTHREAD + pthread_mutex_lock(&winbind_nss_mutex); +#endif + ZERO_STRUCT(request); ZERO_STRUCT(response); @@ -1199,6 +1345,11 @@ _nss_winbind_sidtogid(const char *sid, gid_t *gid, int *errnop) *gid = response.data.gid; failed: + +#if HAVE_PTHREAD + pthread_mutex_lock(&winbind_nss_mutex); +#endif + return ret; } @@ -1215,6 +1366,10 @@ _nss_winbind_uidtosid(uid_t uid, char **sid, char *buffer, fprintf(stderr, "[%5u]: uidtosid %u\n", (unsigned int)getpid(), (unsigned int)uid); #endif +#if HAVE_PTHREAD + pthread_mutex_lock(&winbind_nss_mutex); +#endif + ZERO_STRUCT(response); ZERO_STRUCT(request); @@ -1238,6 +1393,11 @@ _nss_winbind_uidtosid(uid_t uid, char **sid, char *buffer, failed: winbindd_free_response(&response); + +#if HAVE_PTHREAD + pthread_mutex_unlock(&winbind_nss_mutex); +#endif + return ret; } @@ -1254,6 +1414,10 @@ _nss_winbind_gidtosid(gid_t gid, char **sid, char *buffer, fprintf(stderr, "[%5u]: gidtosid %u\n", (unsigned int)getpid(), (unsigned int)gid); #endif +#if HAVE_PTHREAD + pthread_mutex_lock(&winbind_nss_mutex); +#endif + ZERO_STRUCT(response); ZERO_STRUCT(request); @@ -1277,5 +1441,10 @@ _nss_winbind_gidtosid(gid_t gid, char **sid, char *buffer, failed: winbindd_free_response(&response); + +#if HAVE_PTHREAD + pthread_mutex_unlock(&winbind_nss_mutex); +#endif + return ret; } -- 2.34.1