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
);