r23794: convert more code from LGPLv2+ to LGPLv3+
[Samba/bb.git] / source / nsswitch / winbind_nss_linux.c
blob47dec70102b5806d3d64aaf1a9d6048a1b2acb12
1 /*
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 Library 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 Library General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "winbind_client.h"
24 /* Maximum number of users to pass back over the unix domain socket
25 per call. This is not a static limit on the total number of users
26 or groups returned in total. */
28 #define MAX_GETPWENT_USERS 250
29 #define MAX_GETGRENT_USERS 250
31 NSS_STATUS _nss_winbind_setpwent(void);
32 NSS_STATUS _nss_winbind_endpwent(void);
33 NSS_STATUS _nss_winbind_getpwent_r(struct passwd *result, char *buffer,
34 size_t buflen, int *errnop);
35 NSS_STATUS _nss_winbind_getpwuid_r(uid_t uid, struct passwd *result,
36 char *buffer, size_t buflen, int *errnop);
37 NSS_STATUS _nss_winbind_getpwnam_r(const char *name, struct passwd *result,
38 char *buffer, size_t buflen, int *errnop);
39 NSS_STATUS _nss_winbind_setgrent(void);
40 NSS_STATUS _nss_winbind_endgrent(void);
41 NSS_STATUS _nss_winbind_getgrent_r(struct group *result, char *buffer,
42 size_t buflen, int *errnop);
43 NSS_STATUS _nss_winbind_getgrlst_r(struct group *result, char *buffer,
44 size_t buflen, int *errnop);
45 NSS_STATUS _nss_winbind_getgrnam_r(const char *name, struct group *result,
46 char *buffer, size_t buflen, int *errnop);
47 NSS_STATUS _nss_winbind_getgrgid_r(gid_t gid, struct group *result, char *buffer,
48 size_t buflen, int *errnop);
49 NSS_STATUS _nss_winbind_initgroups_dyn(char *user, gid_t group, long int *start,
50 long int *size, gid_t **groups,
51 long int limit, int *errnop);
52 NSS_STATUS _nss_winbind_getusersids(const char *user_sid, char **group_sids,
53 int *num_groups, char *buffer, size_t buf_size,
54 int *errnop);
55 NSS_STATUS _nss_winbind_nametosid(const char *name, char **sid, char *buffer,
56 size_t buflen, int *errnop);
57 NSS_STATUS _nss_winbind_sidtoname(const char *sid, char **name, char *buffer,
58 size_t buflen, int *errnop);
59 NSS_STATUS _nss_winbind_sidtouid(const char *sid, uid_t *uid, int *errnop);
60 NSS_STATUS _nss_winbind_sidtogid(const char *sid, gid_t *gid, int *errnop);
61 NSS_STATUS _nss_winbind_uidtosid(uid_t uid, char **sid, char *buffer,
62 size_t buflen, int *errnop);
63 NSS_STATUS _nss_winbind_gidtosid(gid_t gid, char **sid, char *buffer,
64 size_t buflen, int *errnop);
66 /* Prototypes from wb_common.c */
68 extern int winbindd_fd;
70 #ifdef DEBUG_NSS
71 static const char *nss_err_str(NSS_STATUS ret) {
72 switch (ret) {
73 case NSS_STATUS_TRYAGAIN:
74 return "NSS_STATUS_TRYAGAIN";
75 case NSS_STATUS_SUCCESS:
76 return "NSS_STATUS_SUCCESS";
77 case NSS_STATUS_NOTFOUND:
78 return "NSS_STATUS_NOTFOUND";
79 case NSS_STATUS_UNAVAIL:
80 return "NSS_STATUS_UNAVAIL";
81 case NSS_STATUS_RETURN:
82 return "NSS_STATUS_RETURN";
83 default:
84 return "UNKNOWN RETURN CODE!!!!!!!";
87 #endif
89 /* Allocate some space from the nss static buffer. The buffer and buflen
90 are the pointers passed in by the C library to the _nss_ntdom_*
91 functions. */
93 static char *get_static(char **buffer, size_t *buflen, size_t len)
95 char *result;
97 /* Error check. We return false if things aren't set up right, or
98 there isn't enough buffer space left. */
100 if ((buffer == NULL) || (buflen == NULL) || (*buflen < len)) {
101 return NULL;
104 /* Return an index into the static buffer */
106 result = *buffer;
107 *buffer += len;
108 *buflen -= len;
110 return result;
113 /* I've copied the strtok() replacement function next_token() from
114 lib/util_str.c as I really don't want to have to link in any other
115 objects if I can possibly avoid it. */
117 static BOOL next_token(char **ptr,char *buff,const char *sep, size_t bufsize)
119 char *s;
120 BOOL quoted;
121 size_t len=1;
123 if (!ptr) return(False);
125 s = *ptr;
127 /* default to simple separators */
128 if (!sep) sep = " \t\n\r";
130 /* find the first non sep char */
131 while (*s && strchr(sep,*s)) s++;
133 /* nothing left? */
134 if (! *s) return(False);
136 /* copy over the token */
137 for (quoted = False; len < bufsize && *s && (quoted || !strchr(sep,*s)); s++) {
138 if (*s == '\"') {
139 quoted = !quoted;
140 } else {
141 len++;
142 *buff++ = *s;
146 *ptr = (*s) ? s+1 : s;
147 *buff = 0;
149 return(True);
153 /* Fill a pwent structure from a winbindd_response structure. We use
154 the static data passed to us by libc to put strings and stuff in.
155 Return NSS_STATUS_TRYAGAIN if we run out of memory. */
157 static NSS_STATUS fill_pwent(struct passwd *result,
158 struct winbindd_pw *pw,
159 char **buffer, size_t *buflen)
161 /* User name */
163 if ((result->pw_name =
164 get_static(buffer, buflen, strlen(pw->pw_name) + 1)) == NULL) {
166 /* Out of memory */
168 return NSS_STATUS_TRYAGAIN;
171 strcpy(result->pw_name, pw->pw_name);
173 /* Password */
175 if ((result->pw_passwd =
176 get_static(buffer, buflen, strlen(pw->pw_passwd) + 1)) == NULL) {
178 /* Out of memory */
180 return NSS_STATUS_TRYAGAIN;
183 strcpy(result->pw_passwd, pw->pw_passwd);
185 /* [ug]id */
187 result->pw_uid = pw->pw_uid;
188 result->pw_gid = pw->pw_gid;
190 /* GECOS */
192 if ((result->pw_gecos =
193 get_static(buffer, buflen, strlen(pw->pw_gecos) + 1)) == NULL) {
195 /* Out of memory */
197 return NSS_STATUS_TRYAGAIN;
200 strcpy(result->pw_gecos, pw->pw_gecos);
202 /* Home directory */
204 if ((result->pw_dir =
205 get_static(buffer, buflen, strlen(pw->pw_dir) + 1)) == NULL) {
207 /* Out of memory */
209 return NSS_STATUS_TRYAGAIN;
212 strcpy(result->pw_dir, pw->pw_dir);
214 /* Logon shell */
216 if ((result->pw_shell =
217 get_static(buffer, buflen, strlen(pw->pw_shell) + 1)) == NULL) {
219 /* Out of memory */
221 return NSS_STATUS_TRYAGAIN;
224 strcpy(result->pw_shell, pw->pw_shell);
226 /* The struct passwd for Solaris has some extra fields which must
227 be initialised or nscd crashes. */
229 #if HAVE_PASSWD_PW_COMMENT
230 result->pw_comment = "";
231 #endif
233 #if HAVE_PASSWD_PW_AGE
234 result->pw_age = "";
235 #endif
237 return NSS_STATUS_SUCCESS;
240 /* Fill a grent structure from a winbindd_response structure. We use
241 the static data passed to us by libc to put strings and stuff in.
242 Return NSS_STATUS_TRYAGAIN if we run out of memory. */
244 static NSS_STATUS fill_grent(struct group *result, struct winbindd_gr *gr,
245 char *gr_mem, char **buffer, size_t *buflen)
247 fstring name;
248 int i;
249 char *tst;
251 /* Group name */
253 if ((result->gr_name =
254 get_static(buffer, buflen, strlen(gr->gr_name) + 1)) == NULL) {
256 /* Out of memory */
258 return NSS_STATUS_TRYAGAIN;
261 strcpy(result->gr_name, gr->gr_name);
263 /* Password */
265 if ((result->gr_passwd =
266 get_static(buffer, buflen, strlen(gr->gr_passwd) + 1)) == NULL) {
268 /* Out of memory */
270 return NSS_STATUS_TRYAGAIN;
273 strcpy(result->gr_passwd, gr->gr_passwd);
275 /* gid */
277 result->gr_gid = gr->gr_gid;
279 /* Group membership */
281 if ((gr->num_gr_mem < 0) || !gr_mem) {
282 gr->num_gr_mem = 0;
285 /* this next value is a pointer to a pointer so let's align it */
287 /* Calculate number of extra bytes needed to align on pointer size boundry */
288 if ((i = (unsigned long)(*buffer) % sizeof(char*)) != 0)
289 i = sizeof(char*) - i;
291 if ((tst = get_static(buffer, buflen, ((gr->num_gr_mem + 1) *
292 sizeof(char *)+i))) == NULL) {
294 /* Out of memory */
296 return NSS_STATUS_TRYAGAIN;
298 result->gr_mem = (char **)(tst + i);
300 if (gr->num_gr_mem == 0) {
302 /* Group is empty */
304 *(result->gr_mem) = NULL;
305 return NSS_STATUS_SUCCESS;
308 /* Start looking at extra data */
310 i = 0;
312 while(next_token((char **)&gr_mem, name, ",", sizeof(fstring))) {
314 /* Allocate space for member */
316 if (((result->gr_mem)[i] =
317 get_static(buffer, buflen, strlen(name) + 1)) == NULL) {
319 /* Out of memory */
321 return NSS_STATUS_TRYAGAIN;
324 strcpy((result->gr_mem)[i], name);
325 i++;
328 /* Terminate list */
330 (result->gr_mem)[i] = NULL;
332 return NSS_STATUS_SUCCESS;
336 * NSS user functions
339 static struct winbindd_response getpwent_response;
341 static int ndx_pw_cache; /* Current index into pwd cache */
342 static int num_pw_cache; /* Current size of pwd cache */
344 /* Rewind "file pointer" to start of ntdom password database */
346 NSS_STATUS
347 _nss_winbind_setpwent(void)
349 NSS_STATUS ret;
350 #ifdef DEBUG_NSS
351 fprintf(stderr, "[%5d]: setpwent\n", getpid());
352 #endif
354 if (num_pw_cache > 0) {
355 ndx_pw_cache = num_pw_cache = 0;
356 free_response(&getpwent_response);
359 ret = winbindd_request_response(WINBINDD_SETPWENT, NULL, NULL);
360 #ifdef DEBUG_NSS
361 fprintf(stderr, "[%5d]: setpwent returns %s (%d)\n", getpid(),
362 nss_err_str(ret), ret);
363 #endif
364 return ret;
367 /* Close ntdom password database "file pointer" */
369 NSS_STATUS
370 _nss_winbind_endpwent(void)
372 NSS_STATUS ret;
373 #ifdef DEBUG_NSS
374 fprintf(stderr, "[%5d]: endpwent\n", getpid());
375 #endif
377 if (num_pw_cache > 0) {
378 ndx_pw_cache = num_pw_cache = 0;
379 free_response(&getpwent_response);
382 ret = winbindd_request_response(WINBINDD_ENDPWENT, NULL, NULL);
383 #ifdef DEBUG_NSS
384 fprintf(stderr, "[%5d]: endpwent returns %s (%d)\n", getpid(),
385 nss_err_str(ret), ret);
386 #endif
387 return ret;
390 /* Fetch the next password entry from ntdom password database */
392 NSS_STATUS
393 _nss_winbind_getpwent_r(struct passwd *result, char *buffer,
394 size_t buflen, int *errnop)
396 NSS_STATUS ret;
397 struct winbindd_request request;
398 static int called_again;
400 #ifdef DEBUG_NSS
401 fprintf(stderr, "[%5d]: getpwent\n", getpid());
402 #endif
404 /* Return an entry from the cache if we have one, or if we are
405 called again because we exceeded our static buffer. */
407 if ((ndx_pw_cache < num_pw_cache) || called_again) {
408 goto return_result;
411 /* Else call winbindd to get a bunch of entries */
413 if (num_pw_cache > 0) {
414 free_response(&getpwent_response);
417 ZERO_STRUCT(request);
418 ZERO_STRUCT(getpwent_response);
420 request.data.num_entries = MAX_GETPWENT_USERS;
422 ret = winbindd_request_response(WINBINDD_GETPWENT, &request,
423 &getpwent_response);
425 if (ret == NSS_STATUS_SUCCESS) {
426 struct winbindd_pw *pw_cache;
428 /* Fill cache */
430 ndx_pw_cache = 0;
431 num_pw_cache = getpwent_response.data.num_entries;
433 /* Return a result */
435 return_result:
437 pw_cache = (struct winbindd_pw *)
438 getpwent_response.extra_data.data;
440 /* Check data is valid */
442 if (pw_cache == NULL) {
443 ret = NSS_STATUS_NOTFOUND;
444 goto done;
447 ret = fill_pwent(result, &pw_cache[ndx_pw_cache],
448 &buffer, &buflen);
450 /* Out of memory - try again */
452 if (ret == NSS_STATUS_TRYAGAIN) {
453 called_again = True;
454 *errnop = errno = ERANGE;
455 goto done;
458 *errnop = errno = 0;
459 called_again = False;
460 ndx_pw_cache++;
462 /* If we've finished with this lot of results free cache */
464 if (ndx_pw_cache == num_pw_cache) {
465 ndx_pw_cache = num_pw_cache = 0;
466 free_response(&getpwent_response);
469 done:
470 #ifdef DEBUG_NSS
471 fprintf(stderr, "[%5d]: getpwent returns %s (%d)\n", getpid(),
472 nss_err_str(ret), ret);
473 #endif
474 return ret;
477 /* Return passwd struct from uid */
479 NSS_STATUS
480 _nss_winbind_getpwuid_r(uid_t uid, struct passwd *result, char *buffer,
481 size_t buflen, int *errnop)
483 NSS_STATUS ret;
484 static struct winbindd_response response;
485 struct winbindd_request request;
486 static int keep_response=0;
488 #ifdef DEBUG_NSS
489 fprintf(stderr, "[%5d]: getpwuid %d\n", getpid(), (unsigned int)uid);
490 #endif
492 /* If our static buffer needs to be expanded we are called again */
493 if (!keep_response) {
495 /* Call for the first time */
497 ZERO_STRUCT(response);
498 ZERO_STRUCT(request);
500 request.data.uid = uid;
502 ret = winbindd_request_response(WINBINDD_GETPWUID, &request, &response);
504 if (ret == NSS_STATUS_SUCCESS) {
505 ret = fill_pwent(result, &response.data.pw,
506 &buffer, &buflen);
508 if (ret == NSS_STATUS_TRYAGAIN) {
509 keep_response = True;
510 *errnop = errno = ERANGE;
511 goto done;
515 } else {
517 /* We've been called again */
519 ret = fill_pwent(result, &response.data.pw, &buffer, &buflen);
521 if (ret == NSS_STATUS_TRYAGAIN) {
522 keep_response = True;
523 *errnop = errno = ERANGE;
524 goto done;
527 keep_response = False;
528 *errnop = errno = 0;
531 free_response(&response);
532 done:
534 #ifdef DEBUG_NSS
535 fprintf(stderr, "[%5d]: getpwuid %d returns %s (%d)\n", getpid(),
536 (unsigned int)uid, nss_err_str(ret), ret);
537 #endif
538 return ret;
541 /* Return passwd struct from username */
542 NSS_STATUS
543 _nss_winbind_getpwnam_r(const char *name, struct passwd *result, char *buffer,
544 size_t buflen, int *errnop)
546 NSS_STATUS ret;
547 static struct winbindd_response response;
548 struct winbindd_request request;
549 static int keep_response;
551 #ifdef DEBUG_NSS
552 fprintf(stderr, "[%5d]: getpwnam %s\n", getpid(), name);
553 #endif
555 /* If our static buffer needs to be expanded we are called again */
557 if (!keep_response) {
559 /* Call for the first time */
561 ZERO_STRUCT(response);
562 ZERO_STRUCT(request);
564 strncpy(request.data.username, name,
565 sizeof(request.data.username) - 1);
566 request.data.username
567 [sizeof(request.data.username) - 1] = '\0';
569 ret = winbindd_request_response(WINBINDD_GETPWNAM, &request, &response);
571 if (ret == NSS_STATUS_SUCCESS) {
572 ret = fill_pwent(result, &response.data.pw, &buffer,
573 &buflen);
575 if (ret == NSS_STATUS_TRYAGAIN) {
576 keep_response = True;
577 *errnop = errno = ERANGE;
578 goto done;
582 } else {
584 /* We've been called again */
586 ret = fill_pwent(result, &response.data.pw, &buffer, &buflen);
588 if (ret == NSS_STATUS_TRYAGAIN) {
589 keep_response = True;
590 *errnop = errno = ERANGE;
591 goto done;
594 keep_response = False;
595 *errnop = errno = 0;
598 free_response(&response);
599 done:
600 #ifdef DEBUG_NSS
601 fprintf(stderr, "[%5d]: getpwnam %s returns %s (%d)\n", getpid(),
602 name, nss_err_str(ret), ret);
603 #endif
604 return ret;
608 * NSS group functions
611 static struct winbindd_response getgrent_response;
613 static int ndx_gr_cache; /* Current index into grp cache */
614 static int num_gr_cache; /* Current size of grp cache */
616 /* Rewind "file pointer" to start of ntdom group database */
618 NSS_STATUS
619 _nss_winbind_setgrent(void)
621 NSS_STATUS ret;
622 #ifdef DEBUG_NSS
623 fprintf(stderr, "[%5d]: setgrent\n", getpid());
624 #endif
626 if (num_gr_cache > 0) {
627 ndx_gr_cache = num_gr_cache = 0;
628 free_response(&getgrent_response);
631 ret = winbindd_request_response(WINBINDD_SETGRENT, NULL, NULL);
632 #ifdef DEBUG_NSS
633 fprintf(stderr, "[%5d]: setgrent returns %s (%d)\n", getpid(),
634 nss_err_str(ret), ret);
635 #endif
636 return ret;
639 /* Close "file pointer" for ntdom group database */
641 NSS_STATUS
642 _nss_winbind_endgrent(void)
644 NSS_STATUS ret;
645 #ifdef DEBUG_NSS
646 fprintf(stderr, "[%5d]: endgrent\n", getpid());
647 #endif
649 if (num_gr_cache > 0) {
650 ndx_gr_cache = num_gr_cache = 0;
651 free_response(&getgrent_response);
654 ret = winbindd_request_response(WINBINDD_ENDGRENT, NULL, NULL);
655 #ifdef DEBUG_NSS
656 fprintf(stderr, "[%5d]: endgrent returns %s (%d)\n", getpid(),
657 nss_err_str(ret), ret);
658 #endif
659 return ret;
662 /* Get next entry from ntdom group database */
664 static NSS_STATUS
665 winbind_getgrent(enum winbindd_cmd cmd,
666 struct group *result,
667 char *buffer, size_t buflen, int *errnop)
669 NSS_STATUS ret;
670 static struct winbindd_request request;
671 static int called_again;
674 #ifdef DEBUG_NSS
675 fprintf(stderr, "[%5d]: getgrent\n", getpid());
676 #endif
678 /* Return an entry from the cache if we have one, or if we are
679 called again because we exceeded our static buffer. */
681 if ((ndx_gr_cache < num_gr_cache) || called_again) {
682 goto return_result;
685 /* Else call winbindd to get a bunch of entries */
687 if (num_gr_cache > 0) {
688 free_response(&getgrent_response);
691 ZERO_STRUCT(request);
692 ZERO_STRUCT(getgrent_response);
694 request.data.num_entries = MAX_GETGRENT_USERS;
696 ret = winbindd_request_response(cmd, &request,
697 &getgrent_response);
699 if (ret == NSS_STATUS_SUCCESS) {
700 struct winbindd_gr *gr_cache;
701 int mem_ofs;
703 /* Fill cache */
705 ndx_gr_cache = 0;
706 num_gr_cache = getgrent_response.data.num_entries;
708 /* Return a result */
710 return_result:
712 gr_cache = (struct winbindd_gr *)
713 getgrent_response.extra_data.data;
715 /* Check data is valid */
717 if (gr_cache == NULL) {
718 ret = NSS_STATUS_NOTFOUND;
719 goto done;
722 /* Fill group membership. The offset into the extra data
723 for the group membership is the reported offset plus the
724 size of all the winbindd_gr records returned. */
726 mem_ofs = gr_cache[ndx_gr_cache].gr_mem_ofs +
727 num_gr_cache * sizeof(struct winbindd_gr);
729 ret = fill_grent(result, &gr_cache[ndx_gr_cache],
730 ((char *)getgrent_response.extra_data.data)+mem_ofs,
731 &buffer, &buflen);
733 /* Out of memory - try again */
735 if (ret == NSS_STATUS_TRYAGAIN) {
736 called_again = True;
737 *errnop = errno = ERANGE;
738 goto done;
741 *errnop = 0;
742 called_again = False;
743 ndx_gr_cache++;
745 /* If we've finished with this lot of results free cache */
747 if (ndx_gr_cache == num_gr_cache) {
748 ndx_gr_cache = num_gr_cache = 0;
749 free_response(&getgrent_response);
752 done:
753 #ifdef DEBUG_NSS
754 fprintf(stderr, "[%5d]: getgrent returns %s (%d)\n", getpid(),
755 nss_err_str(ret), ret);
756 #endif
757 return ret;
761 NSS_STATUS
762 _nss_winbind_getgrent_r(struct group *result,
763 char *buffer, size_t buflen, int *errnop)
765 return winbind_getgrent(WINBINDD_GETGRENT, result, buffer, buflen, errnop);
768 NSS_STATUS
769 _nss_winbind_getgrlst_r(struct group *result,
770 char *buffer, size_t buflen, int *errnop)
772 return winbind_getgrent(WINBINDD_GETGRLST, result, buffer, buflen, errnop);
775 /* Return group struct from group name */
777 NSS_STATUS
778 _nss_winbind_getgrnam_r(const char *name,
779 struct group *result, char *buffer,
780 size_t buflen, int *errnop)
782 NSS_STATUS ret;
783 static struct winbindd_response response;
784 struct winbindd_request request;
785 static int keep_response;
787 #ifdef DEBUG_NSS
788 fprintf(stderr, "[%5d]: getgrnam %s\n", getpid(), name);
789 #endif
791 /* If our static buffer needs to be expanded we are called again */
793 if (!keep_response) {
795 /* Call for the first time */
797 ZERO_STRUCT(request);
798 ZERO_STRUCT(response);
800 strncpy(request.data.groupname, name,
801 sizeof(request.data.groupname));
802 request.data.groupname
803 [sizeof(request.data.groupname) - 1] = '\0';
805 ret = winbindd_request_response(WINBINDD_GETGRNAM, &request, &response);
807 if (ret == NSS_STATUS_SUCCESS) {
808 ret = fill_grent(result, &response.data.gr,
809 (char *)response.extra_data.data,
810 &buffer, &buflen);
812 if (ret == NSS_STATUS_TRYAGAIN) {
813 keep_response = True;
814 *errnop = errno = ERANGE;
815 goto done;
819 } else {
821 /* We've been called again */
823 ret = fill_grent(result, &response.data.gr,
824 (char *)response.extra_data.data, &buffer,
825 &buflen);
827 if (ret == NSS_STATUS_TRYAGAIN) {
828 keep_response = True;
829 *errnop = errno = ERANGE;
830 goto done;
833 keep_response = False;
834 *errnop = 0;
837 free_response(&response);
838 done:
839 #ifdef DEBUG_NSS
840 fprintf(stderr, "[%5d]: getgrnam %s returns %s (%d)\n", getpid(),
841 name, nss_err_str(ret), ret);
842 #endif
843 return ret;
846 /* Return group struct from gid */
848 NSS_STATUS
849 _nss_winbind_getgrgid_r(gid_t gid,
850 struct group *result, char *buffer,
851 size_t buflen, int *errnop)
853 NSS_STATUS ret;
854 static struct winbindd_response response;
855 struct winbindd_request request;
856 static int keep_response;
858 #ifdef DEBUG_NSS
859 fprintf(stderr, "[%5d]: getgrgid %d\n", getpid(), gid);
860 #endif
862 /* If our static buffer needs to be expanded we are called again */
864 if (!keep_response) {
866 /* Call for the first time */
868 ZERO_STRUCT(request);
869 ZERO_STRUCT(response);
871 request.data.gid = gid;
873 ret = winbindd_request_response(WINBINDD_GETGRGID, &request, &response);
875 if (ret == NSS_STATUS_SUCCESS) {
877 ret = fill_grent(result, &response.data.gr,
878 (char *)response.extra_data.data,
879 &buffer, &buflen);
881 if (ret == NSS_STATUS_TRYAGAIN) {
882 keep_response = True;
883 *errnop = errno = ERANGE;
884 goto done;
888 } else {
890 /* We've been called again */
892 ret = fill_grent(result, &response.data.gr,
893 (char *)response.extra_data.data, &buffer,
894 &buflen);
896 if (ret == NSS_STATUS_TRYAGAIN) {
897 keep_response = True;
898 *errnop = errno = ERANGE;
899 goto done;
902 keep_response = False;
903 *errnop = 0;
906 free_response(&response);
907 done:
908 #ifdef DEBUG_NSS
909 fprintf(stderr, "[%5d]: getgrgid %d returns %s (%d)\n", getpid(),
910 (unsigned int)gid, nss_err_str(ret), ret);
911 #endif
912 return ret;
915 /* Initialise supplementary groups */
917 NSS_STATUS
918 _nss_winbind_initgroups_dyn(char *user, gid_t group, long int *start,
919 long int *size, gid_t **groups, long int limit,
920 int *errnop)
922 NSS_STATUS ret;
923 struct winbindd_request request;
924 struct winbindd_response response;
925 int i;
927 #ifdef DEBUG_NSS
928 fprintf(stderr, "[%5d]: initgroups %s (%d)\n", getpid(),
929 user, group);
930 #endif
932 ZERO_STRUCT(request);
933 ZERO_STRUCT(response);
935 strncpy(request.data.username, user,
936 sizeof(request.data.username) - 1);
938 ret = winbindd_request_response(WINBINDD_GETGROUPS, &request, &response);
940 if (ret == NSS_STATUS_SUCCESS) {
941 int num_gids = response.data.num_entries;
942 gid_t *gid_list = (gid_t *)response.extra_data.data;
944 #ifdef DEBUG_NSS
945 fprintf(stderr, "[%5d]: initgroups %s: got NSS_STATUS_SUCCESS "
946 "and %d gids\n", getpid(),
947 user, num_gids);
948 #endif
949 if (gid_list == NULL) {
950 ret = NSS_STATUS_NOTFOUND;
951 goto done;
954 /* Copy group list to client */
956 for (i = 0; i < num_gids; i++) {
958 #ifdef DEBUG_NSS
959 fprintf(stderr, "[%5d]: initgroups %s (%d): "
960 "processing gid %d \n", getpid(),
961 user, group, gid_list[i]);
962 #endif
964 /* Skip primary group */
966 if (gid_list[i] == group) {
967 continue;
970 /* Filled buffer ? If so, resize. */
972 if (*start == *size) {
973 long int newsize;
974 gid_t *newgroups;
976 newsize = 2 * (*size);
977 if (limit > 0) {
978 if (*size == limit) {
979 goto done;
981 if (newsize > limit) {
982 newsize = limit;
986 newgroups = (gid_t *)
987 realloc((*groups),
988 newsize * sizeof(**groups));
989 if (!newgroups) {
990 *errnop = ENOMEM;
991 ret = NSS_STATUS_NOTFOUND;
992 goto done;
994 *groups = newgroups;
995 *size = newsize;
998 /* Add to buffer */
1000 (*groups)[*start] = gid_list[i];
1001 *start += 1;
1005 /* Back to your regularly scheduled programming */
1007 done:
1008 #ifdef DEBUG_NSS
1009 fprintf(stderr, "[%5d]: initgroups %s returns %s (%d)\n", getpid(),
1010 user, nss_err_str(ret), ret);
1011 #endif
1012 return ret;
1016 /* return a list of group SIDs for a user SID */
1017 NSS_STATUS
1018 _nss_winbind_getusersids(const char *user_sid, char **group_sids,
1019 int *num_groups,
1020 char *buffer, size_t buf_size, int *errnop)
1022 NSS_STATUS ret;
1023 struct winbindd_request request;
1024 struct winbindd_response response;
1026 #ifdef DEBUG_NSS
1027 fprintf(stderr, "[%5d]: getusersids %s\n", getpid(), user_sid);
1028 #endif
1030 ZERO_STRUCT(request);
1031 ZERO_STRUCT(response);
1033 strncpy(request.data.sid, user_sid,sizeof(request.data.sid) - 1);
1034 request.data.sid[sizeof(request.data.sid) - 1] = '\0';
1036 ret = winbindd_request_response(WINBINDD_GETUSERSIDS, &request, &response);
1038 if (ret != NSS_STATUS_SUCCESS) {
1039 goto done;
1042 if (buf_size < response.length - sizeof(response)) {
1043 ret = NSS_STATUS_TRYAGAIN;
1044 errno = *errnop = ERANGE;
1045 goto done;
1048 *num_groups = response.data.num_entries;
1049 *group_sids = buffer;
1050 memcpy(buffer, response.extra_data.data, response.length - sizeof(response));
1051 errno = *errnop = 0;
1053 done:
1054 free_response(&response);
1055 return ret;
1059 /* map a user or group name to a SID string */
1060 NSS_STATUS
1061 _nss_winbind_nametosid(const char *name, char **sid, char *buffer,
1062 size_t buflen, int *errnop)
1064 NSS_STATUS ret;
1065 struct winbindd_response response;
1066 struct winbindd_request request;
1068 #ifdef DEBUG_NSS
1069 fprintf(stderr, "[%5d]: nametosid %s\n", getpid(), name);
1070 #endif
1072 ZERO_STRUCT(response);
1073 ZERO_STRUCT(request);
1075 strncpy(request.data.name.name, name,
1076 sizeof(request.data.name.name) - 1);
1077 request.data.name.name[sizeof(request.data.name.name) - 1] = '\0';
1079 ret = winbindd_request_response(WINBINDD_LOOKUPNAME, &request, &response);
1080 if (ret != NSS_STATUS_SUCCESS) {
1081 *errnop = errno = EINVAL;
1082 goto failed;
1085 if (buflen < strlen(response.data.sid.sid)+1) {
1086 ret = NSS_STATUS_TRYAGAIN;
1087 *errnop = errno = ERANGE;
1088 goto failed;
1091 *errnop = errno = 0;
1092 *sid = buffer;
1093 strcpy(*sid, response.data.sid.sid);
1095 failed:
1096 free_response(&response);
1097 return ret;
1100 /* map a sid string to a user or group name */
1101 NSS_STATUS
1102 _nss_winbind_sidtoname(const char *sid, char **name, char *buffer,
1103 size_t buflen, int *errnop)
1105 NSS_STATUS ret;
1106 struct winbindd_response response;
1107 struct winbindd_request request;
1108 static char sep_char;
1109 unsigned needed;
1111 #ifdef DEBUG_NSS
1112 fprintf(stderr, "[%5d]: sidtoname %s\n", getpid(), sid);
1113 #endif
1115 ZERO_STRUCT(response);
1116 ZERO_STRUCT(request);
1118 /* we need to fetch the separator first time through */
1119 if (!sep_char) {
1120 ret = winbindd_request_response(WINBINDD_INFO, &request, &response);
1121 if (ret != NSS_STATUS_SUCCESS) {
1122 *errnop = errno = EINVAL;
1123 goto failed;
1126 sep_char = response.data.info.winbind_separator;
1127 free_response(&response);
1131 strncpy(request.data.sid, sid,
1132 sizeof(request.data.sid) - 1);
1133 request.data.sid[sizeof(request.data.sid) - 1] = '\0';
1135 ret = winbindd_request_response(WINBINDD_LOOKUPSID, &request, &response);
1136 if (ret != NSS_STATUS_SUCCESS) {
1137 *errnop = errno = EINVAL;
1138 goto failed;
1141 needed =
1142 strlen(response.data.name.dom_name) +
1143 strlen(response.data.name.name) + 2;
1145 if (buflen < needed) {
1146 ret = NSS_STATUS_TRYAGAIN;
1147 *errnop = errno = ERANGE;
1148 goto failed;
1151 snprintf(buffer, needed, "%s%c%s",
1152 response.data.name.dom_name,
1153 sep_char,
1154 response.data.name.name);
1156 *name = buffer;
1157 *errnop = errno = 0;
1159 failed:
1160 free_response(&response);
1161 return ret;
1164 /* map a sid to a uid */
1165 NSS_STATUS
1166 _nss_winbind_sidtouid(const char *sid, uid_t *uid, int *errnop)
1168 NSS_STATUS ret;
1169 struct winbindd_response response;
1170 struct winbindd_request request;
1172 #ifdef DEBUG_NSS
1173 fprintf(stderr, "[%5d]: sidtouid %s\n", getpid(), sid);
1174 #endif
1176 ZERO_STRUCT(request);
1177 ZERO_STRUCT(response);
1179 strncpy(request.data.sid, sid, sizeof(request.data.sid) - 1);
1180 request.data.sid[sizeof(request.data.sid) - 1] = '\0';
1182 ret = winbindd_request_response(WINBINDD_SID_TO_UID, &request, &response);
1183 if (ret != NSS_STATUS_SUCCESS) {
1184 *errnop = errno = EINVAL;
1185 goto failed;
1188 *uid = response.data.uid;
1190 failed:
1191 return ret;
1194 /* map a sid to a gid */
1195 NSS_STATUS
1196 _nss_winbind_sidtogid(const char *sid, gid_t *gid, int *errnop)
1198 NSS_STATUS ret;
1199 struct winbindd_response response;
1200 struct winbindd_request request;
1202 #ifdef DEBUG_NSS
1203 fprintf(stderr, "[%5d]: sidtogid %s\n", getpid(), sid);
1204 #endif
1206 ZERO_STRUCT(request);
1207 ZERO_STRUCT(response);
1209 strncpy(request.data.sid, sid, sizeof(request.data.sid) - 1);
1210 request.data.sid[sizeof(request.data.sid) - 1] = '\0';
1212 ret = winbindd_request_response(WINBINDD_SID_TO_GID, &request, &response);
1213 if (ret != NSS_STATUS_SUCCESS) {
1214 *errnop = errno = EINVAL;
1215 goto failed;
1218 *gid = response.data.gid;
1220 failed:
1221 return ret;
1224 /* map a uid to a SID string */
1225 NSS_STATUS
1226 _nss_winbind_uidtosid(uid_t uid, char **sid, char *buffer,
1227 size_t buflen, int *errnop)
1229 NSS_STATUS ret;
1230 struct winbindd_response response;
1231 struct winbindd_request request;
1233 #ifdef DEBUG_NSS
1234 fprintf(stderr, "[%5u]: uidtosid %u\n", (unsigned int)getpid(), (unsigned int)uid);
1235 #endif
1237 ZERO_STRUCT(response);
1238 ZERO_STRUCT(request);
1240 request.data.uid = uid;
1242 ret = winbindd_request_response(WINBINDD_UID_TO_SID, &request, &response);
1243 if (ret != NSS_STATUS_SUCCESS) {
1244 *errnop = errno = EINVAL;
1245 goto failed;
1248 if (buflen < strlen(response.data.sid.sid)+1) {
1249 ret = NSS_STATUS_TRYAGAIN;
1250 *errnop = errno = ERANGE;
1251 goto failed;
1254 *errnop = errno = 0;
1255 *sid = buffer;
1256 strcpy(*sid, response.data.sid.sid);
1258 failed:
1259 free_response(&response);
1260 return ret;
1263 /* map a gid to a SID string */
1264 NSS_STATUS
1265 _nss_winbind_gidtosid(gid_t gid, char **sid, char *buffer,
1266 size_t buflen, int *errnop)
1268 NSS_STATUS ret;
1269 struct winbindd_response response;
1270 struct winbindd_request request;
1272 #ifdef DEBUG_NSS
1273 fprintf(stderr, "[%5u]: gidtosid %u\n", (unsigned int)getpid(), (unsigned int)gid);
1274 #endif
1276 ZERO_STRUCT(response);
1277 ZERO_STRUCT(request);
1279 request.data.gid = gid;
1281 ret = winbindd_request_response(WINBINDD_GID_TO_SID, &request, &response);
1282 if (ret != NSS_STATUS_SUCCESS) {
1283 *errnop = errno = EINVAL;
1284 goto failed;
1287 if (buflen < strlen(response.data.sid.sid)+1) {
1288 ret = NSS_STATUS_TRYAGAIN;
1289 *errnop = errno = ERANGE;
1290 goto failed;
1293 *errnop = errno = 0;
1294 *sid = buffer;
1295 strcpy(*sid, response.data.sid.sid);
1297 failed:
1298 free_response(&response);
1299 return ret;