r25406: Make the Linux nss client code thread-safe.
authorJeremy Allison <jra@samba.org>
Fri, 28 Sep 2007 18:12:22 +0000 (18:12 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 17:31:03 +0000 (12:31 -0500)
Fix originally inspired from code from boyang <yyyeer.bo@gmail.com>.
Jeremy.

source/Makefile.in
source/configure.in
source/nsswitch/winbind_nss_linux.c

index ffb5d93d50b43933cefbd3b8fc5134878306a12a..9de9ea2b787e90f26268c9dc0dfcd6942194bd43 100644 (file)
@@ -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 $@"
index 1aa34789193e7c51f0b707f03adfd862519301b4..df4d040b0fef38450b5b12406bee1a6095255a4a 100644 (file)
@@ -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)
index ac53979cedd5d612448b266738cfa76702c6ea94..6de419da5a21a584df92adeb135f77a509993721 100644 (file)
 
 #include "winbind_client.h"
 
+#if HAVE_PTHREAD_H
+#include <pthread.h>
+#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;
 }