2 Unix SMB/CIFS implementation.
4 Windows NT Domain nsswitch module
6 Copyright (C) Tim Potter 2000
8 This library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Lesser General Public
10 License as published by the Free Software Foundation; either
11 version 3 of the License, or (at your option) any later version.
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Library General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "winbind_client.h"
29 static pthread_mutex_t winbind_nss_mutex = PTHREAD_MUTEX_INITIALIZER;
32 /* Maximum number of users to pass back over the unix domain socket
33 per call. This is not a static limit on the total number of users
34 or groups returned in total. */
36 #define MAX_GETPWENT_USERS 250
37 #define MAX_GETGRENT_USERS 250
39 NSS_STATUS _nss_winbind_setpwent(void);
40 NSS_STATUS _nss_winbind_endpwent(void);
41 NSS_STATUS _nss_winbind_getpwent_r(struct passwd *result, char *buffer,
42 size_t buflen, int *errnop);
43 NSS_STATUS _nss_winbind_getpwuid_r(uid_t uid, struct passwd *result,
44 char *buffer, size_t buflen, int *errnop);
45 NSS_STATUS _nss_winbind_getpwnam_r(const char *name, struct passwd *result,
46 char *buffer, size_t buflen, int *errnop);
47 NSS_STATUS _nss_winbind_setgrent(void);
48 NSS_STATUS _nss_winbind_endgrent(void);
49 NSS_STATUS _nss_winbind_getgrent_r(struct group *result, char *buffer,
50 size_t buflen, int *errnop);
51 NSS_STATUS _nss_winbind_getgrlst_r(struct group *result, char *buffer,
52 size_t buflen, int *errnop);
53 NSS_STATUS _nss_winbind_getgrnam_r(const char *name, struct group *result,
54 char *buffer, size_t buflen, int *errnop);
55 NSS_STATUS _nss_winbind_getgrgid_r(gid_t gid, struct group *result, char *buffer,
56 size_t buflen, int *errnop);
57 NSS_STATUS _nss_winbind_initgroups_dyn(char *user, gid_t group, long int *start,
58 long int *size, gid_t **groups,
59 long int limit, int *errnop);
61 /*************************************************************************
62 ************************************************************************/
65 static const char *nss_err_str(NSS_STATUS ret)
68 case NSS_STATUS_TRYAGAIN:
69 return "NSS_STATUS_TRYAGAIN";
70 case NSS_STATUS_SUCCESS:
71 return "NSS_STATUS_SUCCESS";
72 case NSS_STATUS_NOTFOUND:
73 return "NSS_STATUS_NOTFOUND";
74 case NSS_STATUS_UNAVAIL:
75 return "NSS_STATUS_UNAVAIL";
76 #ifdef NSS_STATUS_RETURN
77 case NSS_STATUS_RETURN:
78 return "NSS_STATUS_RETURN";
81 return "UNKNOWN RETURN CODE!!!!!!!";
86 /* Prototypes from wb_common.c */
88 /* Allocate some space from the nss static buffer. The buffer and buflen
89 are the pointers passed in by the C library to the _nss_ntdom_*
92 static char *get_static(char **buffer, size_t *buflen, size_t len)
96 /* Error check. We return false if things aren't set up right, or
97 there isn't enough buffer space left. */
99 if ((buffer == NULL) || (buflen == NULL) || (*buflen < len)) {
103 /* Return an index into the static buffer */
112 /* I've copied the strtok() replacement function next_token_Xalloc() from
113 lib/util_str.c as I really don't want to have to link in any other
114 objects if I can possibly avoid it. */
116 static bool next_token_alloc(const char **ptr,
133 /* default to simple separators */
138 /* find the first non sep char */
139 while (*s && strchr(sep,*s)) {
148 /* When restarting we need to go from here. */
151 /* Work out the length needed. */
152 for (quoted = false; *s &&
153 (quoted || !strchr(sep,*s)); s++) {
161 /* We started with len = 1 so we have space for the nul. */
162 *pp_buff = (char *)malloc(len);
167 /* copy over the token */
170 for (quoted = false; *s &&
171 (quoted || !strchr(sep,*s)); s++) {
179 *ptr = (*s) ? s+1 : s;
185 /* Fill a pwent structure from a winbindd_response structure. We use
186 the static data passed to us by libc to put strings and stuff in.
187 Return NSS_STATUS_TRYAGAIN if we run out of memory. */
189 static NSS_STATUS fill_pwent(struct passwd *result,
190 struct winbindd_pw *pw,
191 char **buffer, size_t *buflen)
196 len = strlen(pw->pw_name) + 1;
198 if ((result->pw_name =
199 get_static(buffer, buflen, len)) == NULL) {
203 return NSS_STATUS_TRYAGAIN;
206 memcpy(result->pw_name, pw->pw_name, len);
209 len = strlen(pw->pw_passwd) + 1;
211 if ((result->pw_passwd =
212 get_static(buffer, buflen, len)) == NULL) {
216 return NSS_STATUS_TRYAGAIN;
219 memcpy(result->pw_passwd, pw->pw_passwd, len);
223 result->pw_uid = pw->pw_uid;
224 result->pw_gid = pw->pw_gid;
227 len = strlen(pw->pw_gecos) + 1;
229 if ((result->pw_gecos =
230 get_static(buffer, buflen, len)) == NULL) {
234 return NSS_STATUS_TRYAGAIN;
237 memcpy(result->pw_gecos, pw->pw_gecos, len);
240 len = strlen(pw->pw_dir) + 1;
242 if ((result->pw_dir =
243 get_static(buffer, buflen, len)) == NULL) {
247 return NSS_STATUS_TRYAGAIN;
250 memcpy(result->pw_dir, pw->pw_dir, len);
253 len = strlen(pw->pw_shell) + 1;
255 if ((result->pw_shell =
256 get_static(buffer, buflen, len)) == NULL) {
260 return NSS_STATUS_TRYAGAIN;
263 memcpy(result->pw_shell, pw->pw_shell, len);
265 /* The struct passwd for Solaris has some extra fields which must
266 be initialised or nscd crashes. */
268 #if HAVE_PASSWD_PW_COMMENT
269 result->pw_comment = "";
272 #if HAVE_PASSWD_PW_AGE
276 return NSS_STATUS_SUCCESS;
279 /* Fill a grent structure from a winbindd_response structure. We use
280 the static data passed to us by libc to put strings and stuff in.
281 Return NSS_STATUS_TRYAGAIN if we run out of memory. */
283 static NSS_STATUS fill_grent(struct group *result, struct winbindd_gr *gr,
284 const char *gr_mem, char **buffer, size_t *buflen)
292 len = strlen(gr->gr_name) + 1;
294 if ((result->gr_name =
295 get_static(buffer, buflen, len)) == NULL) {
299 return NSS_STATUS_TRYAGAIN;
302 memcpy(result->gr_name, gr->gr_name, len);
305 len = strlen(gr->gr_passwd) + 1;
307 if ((result->gr_passwd =
308 get_static(buffer, buflen, len)) == NULL) {
311 return NSS_STATUS_TRYAGAIN;
314 memcpy(result->gr_passwd, gr->gr_passwd, len);
318 result->gr_gid = gr->gr_gid;
320 /* Group membership */
326 /* this next value is a pointer to a pointer so let's align it */
328 /* Calculate number of extra bytes needed to align on pointer size boundry */
329 if ((i = (unsigned long)(*buffer) % sizeof(char*)) != 0)
330 i = sizeof(char*) - i;
332 if ((tst = get_static(buffer, buflen, ((gr->num_gr_mem + 1) *
333 sizeof(char *)+i))) == NULL) {
337 return NSS_STATUS_TRYAGAIN;
339 result->gr_mem = (char **)(tst + i);
341 if (gr->num_gr_mem == 0) {
345 *(result->gr_mem) = NULL;
346 return NSS_STATUS_SUCCESS;
349 /* Start looking at extra data */
353 while(next_token_alloc((const char **)&gr_mem, &name, ",")) {
354 /* Allocate space for member */
355 len = strlen(name) + 1;
357 if (((result->gr_mem)[i] =
358 get_static(buffer, buflen, len)) == NULL) {
361 return NSS_STATUS_TRYAGAIN;
363 memcpy((result->gr_mem)[i], name, len);
370 (result->gr_mem)[i] = NULL;
372 return NSS_STATUS_SUCCESS;
379 static struct winbindd_response getpwent_response;
381 static int ndx_pw_cache; /* Current index into pwd cache */
382 static int num_pw_cache; /* Current size of pwd cache */
384 /* Rewind "file pointer" to start of ntdom password database */
387 _nss_winbind_setpwent(void)
391 fprintf(stderr, "[%5d]: setpwent\n", getpid());
395 pthread_mutex_lock(&winbind_nss_mutex);
398 if (num_pw_cache > 0) {
399 ndx_pw_cache = num_pw_cache = 0;
400 winbindd_free_response(&getpwent_response);
403 ret = winbindd_request_response(NULL, WINBINDD_SETPWENT, NULL, NULL);
405 fprintf(stderr, "[%5d]: setpwent returns %s (%d)\n", getpid(),
406 nss_err_str(ret), ret);
410 pthread_mutex_unlock(&winbind_nss_mutex);
415 /* Close ntdom password database "file pointer" */
418 _nss_winbind_endpwent(void)
422 fprintf(stderr, "[%5d]: endpwent\n", getpid());
426 pthread_mutex_lock(&winbind_nss_mutex);
429 if (num_pw_cache > 0) {
430 ndx_pw_cache = num_pw_cache = 0;
431 winbindd_free_response(&getpwent_response);
434 ret = winbindd_request_response(NULL, WINBINDD_ENDPWENT, NULL, NULL);
436 fprintf(stderr, "[%5d]: endpwent returns %s (%d)\n", getpid(),
437 nss_err_str(ret), ret);
441 pthread_mutex_unlock(&winbind_nss_mutex);
447 /* Fetch the next password entry from ntdom password database */
450 _nss_winbind_getpwent_r(struct passwd *result, char *buffer,
451 size_t buflen, int *errnop)
454 struct winbindd_request request;
455 static int called_again;
458 fprintf(stderr, "[%5d]: getpwent\n", getpid());
462 pthread_mutex_lock(&winbind_nss_mutex);
465 /* Return an entry from the cache if we have one, or if we are
466 called again because we exceeded our static buffer. */
468 if ((ndx_pw_cache < num_pw_cache) || called_again) {
472 /* Else call winbindd to get a bunch of entries */
474 if (num_pw_cache > 0) {
475 winbindd_free_response(&getpwent_response);
478 ZERO_STRUCT(request);
479 ZERO_STRUCT(getpwent_response);
481 request.data.num_entries = MAX_GETPWENT_USERS;
483 ret = winbindd_request_response(NULL, WINBINDD_GETPWENT, &request,
486 if (ret == NSS_STATUS_SUCCESS) {
487 struct winbindd_pw *pw_cache;
492 num_pw_cache = getpwent_response.data.num_entries;
494 /* Return a result */
498 pw_cache = (struct winbindd_pw *)
499 getpwent_response.extra_data.data;
501 /* Check data is valid */
503 if (pw_cache == NULL) {
504 ret = NSS_STATUS_NOTFOUND;
508 ret = fill_pwent(result, &pw_cache[ndx_pw_cache],
511 /* Out of memory - try again */
513 if (ret == NSS_STATUS_TRYAGAIN) {
515 *errnop = errno = ERANGE;
520 called_again = false;
523 /* If we've finished with this lot of results free cache */
525 if (ndx_pw_cache == num_pw_cache) {
526 ndx_pw_cache = num_pw_cache = 0;
527 winbindd_free_response(&getpwent_response);
532 fprintf(stderr, "[%5d]: getpwent returns %s (%d)\n", getpid(),
533 nss_err_str(ret), ret);
537 pthread_mutex_unlock(&winbind_nss_mutex);
542 /* Return passwd struct from uid */
545 _nss_winbind_getpwuid_r(uid_t uid, struct passwd *result, char *buffer,
546 size_t buflen, int *errnop)
549 static struct winbindd_response response;
550 struct winbindd_request request;
551 static int keep_response;
554 fprintf(stderr, "[%5d]: getpwuid_r %d\n", getpid(), (unsigned int)uid);
558 pthread_mutex_lock(&winbind_nss_mutex);
561 /* If our static buffer needs to be expanded we are called again */
562 if (!keep_response || uid != response.data.pw.pw_uid) {
564 /* Call for the first time */
566 ZERO_STRUCT(response);
567 ZERO_STRUCT(request);
569 request.data.uid = uid;
571 ret = winbindd_request_response(NULL, WINBINDD_GETPWUID, &request, &response);
573 if (ret == NSS_STATUS_SUCCESS) {
574 ret = fill_pwent(result, &response.data.pw,
577 if (ret == NSS_STATUS_TRYAGAIN) {
578 keep_response = true;
579 *errnop = errno = ERANGE;
586 /* We've been called again */
588 ret = fill_pwent(result, &response.data.pw, &buffer, &buflen);
590 if (ret == NSS_STATUS_TRYAGAIN) {
591 *errnop = errno = ERANGE;
595 keep_response = false;
599 winbindd_free_response(&response);
604 fprintf(stderr, "[%5d]: getpwuid %d returns %s (%d)\n", getpid(),
605 (unsigned int)uid, nss_err_str(ret), ret);
609 pthread_mutex_unlock(&winbind_nss_mutex);
615 /* Return passwd struct from username */
617 _nss_winbind_getpwnam_r(const char *name, struct passwd *result, char *buffer,
618 size_t buflen, int *errnop)
621 static struct winbindd_response response;
622 struct winbindd_request request;
623 static int keep_response;
626 fprintf(stderr, "[%5d]: getpwnam_r %s\n", getpid(), name);
630 pthread_mutex_lock(&winbind_nss_mutex);
633 /* If our static buffer needs to be expanded we are called again */
635 if (!keep_response || strcmp(name,response.data.pw.pw_name) != 0) {
637 /* Call for the first time */
639 ZERO_STRUCT(response);
640 ZERO_STRUCT(request);
642 strncpy(request.data.username, name,
643 sizeof(request.data.username) - 1);
644 request.data.username
645 [sizeof(request.data.username) - 1] = '\0';
647 ret = winbindd_request_response(NULL, WINBINDD_GETPWNAM, &request, &response);
649 if (ret == NSS_STATUS_SUCCESS) {
650 ret = fill_pwent(result, &response.data.pw, &buffer,
653 if (ret == NSS_STATUS_TRYAGAIN) {
654 keep_response = true;
655 *errnop = errno = ERANGE;
662 /* We've been called again */
664 ret = fill_pwent(result, &response.data.pw, &buffer, &buflen);
666 if (ret == NSS_STATUS_TRYAGAIN) {
667 keep_response = true;
668 *errnop = errno = ERANGE;
672 keep_response = false;
676 winbindd_free_response(&response);
679 fprintf(stderr, "[%5d]: getpwnam %s returns %s (%d)\n", getpid(),
680 name, nss_err_str(ret), ret);
684 pthread_mutex_unlock(&winbind_nss_mutex);
691 * NSS group functions
694 static struct winbindd_response getgrent_response;
696 static int ndx_gr_cache; /* Current index into grp cache */
697 static int num_gr_cache; /* Current size of grp cache */
699 /* Rewind "file pointer" to start of ntdom group database */
702 _nss_winbind_setgrent(void)
706 fprintf(stderr, "[%5d]: setgrent\n", getpid());
710 pthread_mutex_lock(&winbind_nss_mutex);
713 if (num_gr_cache > 0) {
714 ndx_gr_cache = num_gr_cache = 0;
715 winbindd_free_response(&getgrent_response);
718 ret = winbindd_request_response(NULL, WINBINDD_SETGRENT, NULL, NULL);
720 fprintf(stderr, "[%5d]: setgrent returns %s (%d)\n", getpid(),
721 nss_err_str(ret), ret);
725 pthread_mutex_unlock(&winbind_nss_mutex);
731 /* Close "file pointer" for ntdom group database */
734 _nss_winbind_endgrent(void)
738 fprintf(stderr, "[%5d]: endgrent\n", getpid());
742 pthread_mutex_lock(&winbind_nss_mutex);
745 if (num_gr_cache > 0) {
746 ndx_gr_cache = num_gr_cache = 0;
747 winbindd_free_response(&getgrent_response);
750 ret = winbindd_request_response(NULL, WINBINDD_ENDGRENT, NULL, NULL);
752 fprintf(stderr, "[%5d]: endgrent returns %s (%d)\n", getpid(),
753 nss_err_str(ret), ret);
757 pthread_mutex_unlock(&winbind_nss_mutex);
763 /* Get next entry from ntdom group database */
766 winbind_getgrent(enum winbindd_cmd cmd,
767 struct group *result,
768 char *buffer, size_t buflen, int *errnop)
771 static struct winbindd_request request;
772 static int called_again;
776 fprintf(stderr, "[%5d]: getgrent\n", getpid());
780 pthread_mutex_lock(&winbind_nss_mutex);
783 /* Return an entry from the cache if we have one, or if we are
784 called again because we exceeded our static buffer. */
786 if ((ndx_gr_cache < num_gr_cache) || called_again) {
790 /* Else call winbindd to get a bunch of entries */
792 if (num_gr_cache > 0) {
793 winbindd_free_response(&getgrent_response);
796 ZERO_STRUCT(request);
797 ZERO_STRUCT(getgrent_response);
799 request.data.num_entries = MAX_GETGRENT_USERS;
801 ret = winbindd_request_response(NULL, cmd, &request,
804 if (ret == NSS_STATUS_SUCCESS) {
805 struct winbindd_gr *gr_cache;
811 num_gr_cache = getgrent_response.data.num_entries;
813 /* Return a result */
817 gr_cache = (struct winbindd_gr *)
818 getgrent_response.extra_data.data;
820 /* Check data is valid */
822 if (gr_cache == NULL) {
823 ret = NSS_STATUS_NOTFOUND;
827 /* Fill group membership. The offset into the extra data
828 for the group membership is the reported offset plus the
829 size of all the winbindd_gr records returned. */
831 mem_ofs = gr_cache[ndx_gr_cache].gr_mem_ofs +
832 num_gr_cache * sizeof(struct winbindd_gr);
834 ret = fill_grent(result, &gr_cache[ndx_gr_cache],
835 ((char *)getgrent_response.extra_data.data)+mem_ofs,
838 /* Out of memory - try again */
840 if (ret == NSS_STATUS_TRYAGAIN) {
842 *errnop = errno = ERANGE;
847 called_again = false;
850 /* If we've finished with this lot of results free cache */
852 if (ndx_gr_cache == num_gr_cache) {
853 ndx_gr_cache = num_gr_cache = 0;
854 winbindd_free_response(&getgrent_response);
859 fprintf(stderr, "[%5d]: getgrent returns %s (%d)\n", getpid(),
860 nss_err_str(ret), ret);
864 pthread_mutex_unlock(&winbind_nss_mutex);
872 _nss_winbind_getgrent_r(struct group *result,
873 char *buffer, size_t buflen, int *errnop)
875 return winbind_getgrent(WINBINDD_GETGRENT, result, buffer, buflen, errnop);
879 _nss_winbind_getgrlst_r(struct group *result,
880 char *buffer, size_t buflen, int *errnop)
882 return winbind_getgrent(WINBINDD_GETGRLST, result, buffer, buflen, errnop);
885 /* Return group struct from group name */
888 _nss_winbind_getgrnam_r(const char *name,
889 struct group *result, char *buffer,
890 size_t buflen, int *errnop)
893 static struct winbindd_response response;
894 struct winbindd_request request;
895 static int keep_response;
898 fprintf(stderr, "[%5d]: getgrnam %s\n", getpid(), name);
902 pthread_mutex_lock(&winbind_nss_mutex);
905 /* If our static buffer needs to be expanded we are called again */
906 /* Or if the stored response group name differs from the request. */
908 if (!keep_response || strcmp(name,response.data.gr.gr_name) != 0) {
910 /* Call for the first time */
912 ZERO_STRUCT(request);
913 ZERO_STRUCT(response);
915 strncpy(request.data.groupname, name,
916 sizeof(request.data.groupname));
917 request.data.groupname
918 [sizeof(request.data.groupname) - 1] = '\0';
920 ret = winbindd_request_response(NULL, WINBINDD_GETGRNAM,
921 &request, &response);
923 if (ret == NSS_STATUS_SUCCESS) {
924 ret = fill_grent(result, &response.data.gr,
925 (char *)response.extra_data.data,
928 if (ret == NSS_STATUS_TRYAGAIN) {
929 keep_response = true;
930 *errnop = errno = ERANGE;
937 /* We've been called again */
939 ret = fill_grent(result, &response.data.gr,
940 (char *)response.extra_data.data, &buffer,
943 if (ret == NSS_STATUS_TRYAGAIN) {
944 keep_response = true;
945 *errnop = errno = ERANGE;
949 keep_response = false;
953 winbindd_free_response(&response);
956 fprintf(stderr, "[%5d]: getgrnam %s returns %s (%d)\n", getpid(),
957 name, nss_err_str(ret), ret);
961 pthread_mutex_unlock(&winbind_nss_mutex);
967 /* Return group struct from gid */
970 _nss_winbind_getgrgid_r(gid_t gid,
971 struct group *result, char *buffer,
972 size_t buflen, int *errnop)
975 static struct winbindd_response response;
976 struct winbindd_request request;
977 static int keep_response;
980 fprintf(stderr, "[%5d]: getgrgid %d\n", getpid(), gid);
984 pthread_mutex_lock(&winbind_nss_mutex);
987 /* If our static buffer needs to be expanded we are called again */
988 /* Or if the stored response group name differs from the request. */
990 if (!keep_response || gid != response.data.gr.gr_gid) {
992 /* Call for the first time */
994 ZERO_STRUCT(request);
995 ZERO_STRUCT(response);
997 request.data.gid = gid;
999 ret = winbindd_request_response(NULL, WINBINDD_GETGRGID,
1000 &request, &response);
1002 if (ret == NSS_STATUS_SUCCESS) {
1004 ret = fill_grent(result, &response.data.gr,
1005 (char *)response.extra_data.data,
1008 if (ret == NSS_STATUS_TRYAGAIN) {
1009 keep_response = true;
1010 *errnop = errno = ERANGE;
1017 /* We've been called again */
1019 ret = fill_grent(result, &response.data.gr,
1020 (char *)response.extra_data.data, &buffer,
1023 if (ret == NSS_STATUS_TRYAGAIN) {
1024 keep_response = true;
1025 *errnop = errno = ERANGE;
1029 keep_response = false;
1033 winbindd_free_response(&response);
1036 fprintf(stderr, "[%5d]: getgrgid %d returns %s (%d)\n", getpid(),
1037 (unsigned int)gid, nss_err_str(ret), ret);
1041 pthread_mutex_unlock(&winbind_nss_mutex);
1046 /* Initialise supplementary groups */
1049 _nss_winbind_initgroups_dyn(char *user, gid_t group, long int *start,
1050 long int *size, gid_t **groups, long int limit,
1054 struct winbindd_request request;
1055 struct winbindd_response response;
1059 fprintf(stderr, "[%5d]: initgroups %s (%d)\n", getpid(),
1064 pthread_mutex_lock(&winbind_nss_mutex);
1067 ZERO_STRUCT(request);
1068 ZERO_STRUCT(response);
1070 strncpy(request.data.username, user,
1071 sizeof(request.data.username) - 1);
1073 ret = winbindd_request_response(NULL, WINBINDD_GETGROUPS,
1074 &request, &response);
1076 if (ret == NSS_STATUS_SUCCESS) {
1077 int num_gids = response.data.num_entries;
1078 gid_t *gid_list = (gid_t *)response.extra_data.data;
1081 fprintf(stderr, "[%5d]: initgroups %s: got NSS_STATUS_SUCCESS "
1082 "and %d gids\n", getpid(),
1085 if (gid_list == NULL) {
1086 ret = NSS_STATUS_NOTFOUND;
1090 /* Copy group list to client */
1092 for (i = 0; i < num_gids; i++) {
1095 fprintf(stderr, "[%5d]: initgroups %s (%d): "
1096 "processing gid %d \n", getpid(),
1097 user, group, gid_list[i]);
1100 /* Skip primary group */
1102 if (gid_list[i] == group) {
1106 /* Skip groups without a mapping */
1107 if (gid_list[i] == (uid_t)-1) {
1111 /* Filled buffer ? If so, resize. */
1113 if (*start == *size) {
1117 newsize = 2 * (*size);
1119 if (*size == limit) {
1122 if (newsize > limit) {
1127 newgroups = (gid_t *)
1129 newsize * sizeof(**groups));
1132 ret = NSS_STATUS_NOTFOUND;
1135 *groups = newgroups;
1141 (*groups)[*start] = gid_list[i];
1146 /* Back to your regularly scheduled programming */
1150 fprintf(stderr, "[%5d]: initgroups %s returns %s (%d)\n", getpid(),
1151 user, nss_err_str(ret), ret);
1155 pthread_mutex_unlock(&winbind_nss_mutex);