VERSION: Raise version number up to 3.0.36.
[Samba.git] / source / nsswitch / winbind_nss_linux.c
blobfa74194aa9d7ec47ee31590aa4fb4904faacecdf
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 2 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
19 License along with this library; if not, write to the
20 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 Boston, MA 02111-1307, USA.
24 #include "winbind_client.h"
26 /* Maximum number of users to pass back over the unix domain socket
27 per call. This is not a static limit on the total number of users
28 or groups returned in total. */
30 #define MAX_GETPWENT_USERS 250
31 #define MAX_GETGRENT_USERS 250
33 NSS_STATUS _nss_winbind_setpwent(void);
34 NSS_STATUS _nss_winbind_endpwent(void);
35 NSS_STATUS _nss_winbind_getpwent_r(struct passwd *result, char *buffer,
36 size_t buflen, int *errnop);
37 NSS_STATUS _nss_winbind_getpwuid_r(uid_t uid, struct passwd *result,
38 char *buffer, size_t buflen, int *errnop);
39 NSS_STATUS _nss_winbind_getpwnam_r(const char *name, struct passwd *result,
40 char *buffer, size_t buflen, int *errnop);
41 NSS_STATUS _nss_winbind_setgrent(void);
42 NSS_STATUS _nss_winbind_endgrent(void);
43 NSS_STATUS _nss_winbind_getgrent_r(struct group *result, char *buffer,
44 size_t buflen, int *errnop);
45 NSS_STATUS _nss_winbind_getgrlst_r(struct group *result, char *buffer,
46 size_t buflen, int *errnop);
47 NSS_STATUS _nss_winbind_getgrnam_r(const char *name, struct group *result,
48 char *buffer, size_t buflen, int *errnop);
49 NSS_STATUS _nss_winbind_getgrgid_r(gid_t gid, struct group *result, char *buffer,
50 size_t buflen, int *errnop);
51 NSS_STATUS _nss_winbind_initgroups_dyn(char *user, gid_t group, long int *start,
52 long int *size, gid_t **groups,
53 long int limit, int *errnop);
54 NSS_STATUS _nss_winbind_getusersids(const char *user_sid, char **group_sids,
55 int *num_groups, char *buffer, size_t buf_size,
56 int *errnop);
57 NSS_STATUS _nss_winbind_nametosid(const char *name, char **sid, char *buffer,
58 size_t buflen, int *errnop);
59 NSS_STATUS _nss_winbind_sidtoname(const char *sid, char **name, char *buffer,
60 size_t buflen, int *errnop);
61 NSS_STATUS _nss_winbind_sidtouid(const char *sid, uid_t *uid, int *errnop);
62 NSS_STATUS _nss_winbind_sidtogid(const char *sid, gid_t *gid, int *errnop);
63 NSS_STATUS _nss_winbind_uidtosid(uid_t uid, char **sid, char *buffer,
64 size_t buflen, int *errnop);
65 NSS_STATUS _nss_winbind_gidtosid(gid_t gid, char **sid, char *buffer,
66 size_t buflen, int *errnop);
68 /* Prototypes from wb_common.c */
70 extern int winbindd_fd;
72 #ifdef DEBUG_NSS
73 static const char *nss_err_str(NSS_STATUS ret) {
74 switch (ret) {
75 case NSS_STATUS_TRYAGAIN:
76 return "NSS_STATUS_TRYAGAIN";
77 case NSS_STATUS_SUCCESS:
78 return "NSS_STATUS_SUCCESS";
79 case NSS_STATUS_NOTFOUND:
80 return "NSS_STATUS_NOTFOUND";
81 case NSS_STATUS_UNAVAIL:
82 return "NSS_STATUS_UNAVAIL";
83 case NSS_STATUS_RETURN:
84 return "NSS_STATUS_RETURN";
85 default:
86 return "UNKNOWN RETURN CODE!!!!!!!";
89 #endif
91 /* Allocate some space from the nss static buffer. The buffer and buflen
92 are the pointers passed in by the C library to the _nss_ntdom_*
93 functions. */
95 static char *get_static(char **buffer, size_t *buflen, size_t len)
97 char *result;
99 /* Error check. We return false if things aren't set up right, or
100 there isn't enough buffer space left. */
102 if ((buffer == NULL) || (buflen == NULL) || (*buflen < len)) {
103 return NULL;
106 /* Return an index into the static buffer */
108 result = *buffer;
109 *buffer += len;
110 *buflen -= len;
112 return result;
115 /* I've copied the strtok() replacement function next_token() from
116 lib/util_str.c as I really don't want to have to link in any other
117 objects if I can possibly avoid it. */
119 static BOOL next_token(char **ptr,char *buff,const char *sep, size_t bufsize)
121 char *s;
122 BOOL quoted;
123 size_t len=1;
125 if (!ptr) return(False);
127 s = *ptr;
129 /* default to simple separators */
130 if (!sep) sep = " \t\n\r";
132 /* find the first non sep char */
133 while (*s && strchr(sep,*s)) s++;
135 /* nothing left? */
136 if (! *s) return(False);
138 /* copy over the token */
139 for (quoted = False; len < bufsize && *s && (quoted || !strchr(sep,*s)); s++) {
140 if (*s == '\"') {
141 quoted = !quoted;
142 } else {
143 len++;
144 *buff++ = *s;
148 *ptr = (*s) ? s+1 : s;
149 *buff = 0;
151 return(True);
155 /* Fill a pwent structure from a winbindd_response structure. We use
156 the static data passed to us by libc to put strings and stuff in.
157 Return NSS_STATUS_TRYAGAIN if we run out of memory. */
159 static NSS_STATUS fill_pwent(struct passwd *result,
160 struct winbindd_pw *pw,
161 char **buffer, size_t *buflen)
163 /* User name */
165 if ((result->pw_name =
166 get_static(buffer, buflen, strlen(pw->pw_name) + 1)) == NULL) {
168 /* Out of memory */
170 return NSS_STATUS_TRYAGAIN;
173 strcpy(result->pw_name, pw->pw_name);
175 /* Password */
177 if ((result->pw_passwd =
178 get_static(buffer, buflen, strlen(pw->pw_passwd) + 1)) == NULL) {
180 /* Out of memory */
182 return NSS_STATUS_TRYAGAIN;
185 strcpy(result->pw_passwd, pw->pw_passwd);
187 /* [ug]id */
189 result->pw_uid = pw->pw_uid;
190 result->pw_gid = pw->pw_gid;
192 /* GECOS */
194 if ((result->pw_gecos =
195 get_static(buffer, buflen, strlen(pw->pw_gecos) + 1)) == NULL) {
197 /* Out of memory */
199 return NSS_STATUS_TRYAGAIN;
202 strcpy(result->pw_gecos, pw->pw_gecos);
204 /* Home directory */
206 if ((result->pw_dir =
207 get_static(buffer, buflen, strlen(pw->pw_dir) + 1)) == NULL) {
209 /* Out of memory */
211 return NSS_STATUS_TRYAGAIN;
214 strcpy(result->pw_dir, pw->pw_dir);
216 /* Logon shell */
218 if ((result->pw_shell =
219 get_static(buffer, buflen, strlen(pw->pw_shell) + 1)) == NULL) {
221 /* Out of memory */
223 return NSS_STATUS_TRYAGAIN;
226 strcpy(result->pw_shell, pw->pw_shell);
228 /* The struct passwd for Solaris has some extra fields which must
229 be initialised or nscd crashes. */
231 #if HAVE_PASSWD_PW_COMMENT
232 result->pw_comment = "";
233 #endif
235 #if HAVE_PASSWD_PW_AGE
236 result->pw_age = "";
237 #endif
239 return NSS_STATUS_SUCCESS;
242 /* Fill a grent structure from a winbindd_response structure. We use
243 the static data passed to us by libc to put strings and stuff in.
244 Return NSS_STATUS_TRYAGAIN if we run out of memory. */
246 static NSS_STATUS fill_grent(struct group *result, struct winbindd_gr *gr,
247 char *gr_mem, char **buffer, size_t *buflen)
249 fstring name;
250 int i;
251 char *tst;
253 /* Group name */
255 if ((result->gr_name =
256 get_static(buffer, buflen, strlen(gr->gr_name) + 1)) == NULL) {
258 /* Out of memory */
260 return NSS_STATUS_TRYAGAIN;
263 strcpy(result->gr_name, gr->gr_name);
265 /* Password */
267 if ((result->gr_passwd =
268 get_static(buffer, buflen, strlen(gr->gr_passwd) + 1)) == NULL) {
270 /* Out of memory */
272 return NSS_STATUS_TRYAGAIN;
275 strcpy(result->gr_passwd, gr->gr_passwd);
277 /* gid */
279 result->gr_gid = gr->gr_gid;
281 /* Group membership */
283 if ((gr->num_gr_mem < 0) || !gr_mem) {
284 gr->num_gr_mem = 0;
287 /* this next value is a pointer to a pointer so let's align it */
289 /* Calculate number of extra bytes needed to align on pointer size boundry */
290 if ((i = (unsigned long)(*buffer) % sizeof(char*)) != 0)
291 i = sizeof(char*) - i;
293 if ((tst = get_static(buffer, buflen, ((gr->num_gr_mem + 1) *
294 sizeof(char *)+i))) == NULL) {
296 /* Out of memory */
298 return NSS_STATUS_TRYAGAIN;
300 result->gr_mem = (char **)(tst + i);
302 if (gr->num_gr_mem == 0) {
304 /* Group is empty */
306 *(result->gr_mem) = NULL;
307 return NSS_STATUS_SUCCESS;
310 /* Start looking at extra data */
312 i = 0;
314 while(next_token((char **)&gr_mem, name, ",", sizeof(fstring))) {
316 /* Allocate space for member */
318 if (((result->gr_mem)[i] =
319 get_static(buffer, buflen, strlen(name) + 1)) == NULL) {
321 /* Out of memory */
323 return NSS_STATUS_TRYAGAIN;
326 strcpy((result->gr_mem)[i], name);
327 i++;
330 /* Terminate list */
332 (result->gr_mem)[i] = NULL;
334 return NSS_STATUS_SUCCESS;
338 * NSS user functions
341 static struct winbindd_response getpwent_response;
343 static int ndx_pw_cache; /* Current index into pwd cache */
344 static int num_pw_cache; /* Current size of pwd cache */
346 /* Rewind "file pointer" to start of ntdom password database */
348 NSS_STATUS
349 _nss_winbind_setpwent(void)
351 NSS_STATUS ret;
352 #ifdef DEBUG_NSS
353 fprintf(stderr, "[%5d]: setpwent\n", getpid());
354 #endif
356 if (num_pw_cache > 0) {
357 ndx_pw_cache = num_pw_cache = 0;
358 free_response(&getpwent_response);
361 ret = winbindd_request_response(WINBINDD_SETPWENT, NULL, NULL);
362 #ifdef DEBUG_NSS
363 fprintf(stderr, "[%5d]: setpwent returns %s (%d)\n", getpid(),
364 nss_err_str(ret), ret);
365 #endif
366 return ret;
369 /* Close ntdom password database "file pointer" */
371 NSS_STATUS
372 _nss_winbind_endpwent(void)
374 NSS_STATUS ret;
375 #ifdef DEBUG_NSS
376 fprintf(stderr, "[%5d]: endpwent\n", getpid());
377 #endif
379 if (num_pw_cache > 0) {
380 ndx_pw_cache = num_pw_cache = 0;
381 free_response(&getpwent_response);
384 ret = winbindd_request_response(WINBINDD_ENDPWENT, NULL, NULL);
385 #ifdef DEBUG_NSS
386 fprintf(stderr, "[%5d]: endpwent returns %s (%d)\n", getpid(),
387 nss_err_str(ret), ret);
388 #endif
389 return ret;
392 /* Fetch the next password entry from ntdom password database */
394 NSS_STATUS
395 _nss_winbind_getpwent_r(struct passwd *result, char *buffer,
396 size_t buflen, int *errnop)
398 NSS_STATUS ret;
399 struct winbindd_request request;
400 static int called_again;
402 #ifdef DEBUG_NSS
403 fprintf(stderr, "[%5d]: getpwent\n", getpid());
404 #endif
406 /* Return an entry from the cache if we have one, or if we are
407 called again because we exceeded our static buffer. */
409 if ((ndx_pw_cache < num_pw_cache) || called_again) {
410 goto return_result;
413 /* Else call winbindd to get a bunch of entries */
415 if (num_pw_cache > 0) {
416 free_response(&getpwent_response);
419 ZERO_STRUCT(request);
420 ZERO_STRUCT(getpwent_response);
422 request.data.num_entries = MAX_GETPWENT_USERS;
424 ret = winbindd_request_response(WINBINDD_GETPWENT, &request,
425 &getpwent_response);
427 if (ret == NSS_STATUS_SUCCESS) {
428 struct winbindd_pw *pw_cache;
430 /* Fill cache */
432 ndx_pw_cache = 0;
433 num_pw_cache = getpwent_response.data.num_entries;
435 /* Return a result */
437 return_result:
439 pw_cache = (struct winbindd_pw *)
440 getpwent_response.extra_data.data;
442 /* Check data is valid */
444 if (pw_cache == NULL) {
445 ret = NSS_STATUS_NOTFOUND;
446 goto done;
449 ret = fill_pwent(result, &pw_cache[ndx_pw_cache],
450 &buffer, &buflen);
452 /* Out of memory - try again */
454 if (ret == NSS_STATUS_TRYAGAIN) {
455 called_again = True;
456 *errnop = errno = ERANGE;
457 goto done;
460 *errnop = errno = 0;
461 called_again = False;
462 ndx_pw_cache++;
464 /* If we've finished with this lot of results free cache */
466 if (ndx_pw_cache == num_pw_cache) {
467 ndx_pw_cache = num_pw_cache = 0;
468 free_response(&getpwent_response);
471 done:
472 #ifdef DEBUG_NSS
473 fprintf(stderr, "[%5d]: getpwent returns %s (%d)\n", getpid(),
474 nss_err_str(ret), ret);
475 #endif
476 return ret;
479 /* Return passwd struct from uid */
481 NSS_STATUS
482 _nss_winbind_getpwuid_r(uid_t uid, struct passwd *result, char *buffer,
483 size_t buflen, int *errnop)
485 NSS_STATUS ret;
486 static struct winbindd_response response;
487 struct winbindd_request request;
488 static int keep_response=0;
490 #ifdef DEBUG_NSS
491 fprintf(stderr, "[%5d]: getpwuid %d\n", getpid(), (unsigned int)uid);
492 #endif
494 /* If our static buffer needs to be expanded we are called again */
495 if (!keep_response) {
497 /* Call for the first time */
499 ZERO_STRUCT(response);
500 ZERO_STRUCT(request);
502 request.data.uid = uid;
504 ret = winbindd_request_response(WINBINDD_GETPWUID, &request, &response);
506 if (ret == NSS_STATUS_SUCCESS) {
507 ret = fill_pwent(result, &response.data.pw,
508 &buffer, &buflen);
510 if (ret == NSS_STATUS_TRYAGAIN) {
511 keep_response = True;
512 *errnop = errno = ERANGE;
513 goto done;
517 } else {
519 /* We've been called again */
521 ret = fill_pwent(result, &response.data.pw, &buffer, &buflen);
523 if (ret == NSS_STATUS_TRYAGAIN) {
524 keep_response = True;
525 *errnop = errno = ERANGE;
526 goto done;
529 keep_response = False;
530 *errnop = errno = 0;
533 free_response(&response);
534 done:
536 #ifdef DEBUG_NSS
537 fprintf(stderr, "[%5d]: getpwuid %d returns %s (%d)\n", getpid(),
538 (unsigned int)uid, nss_err_str(ret), ret);
539 #endif
540 return ret;
543 /* Return passwd struct from username */
544 NSS_STATUS
545 _nss_winbind_getpwnam_r(const char *name, struct passwd *result, char *buffer,
546 size_t buflen, int *errnop)
548 NSS_STATUS ret;
549 static struct winbindd_response response;
550 struct winbindd_request request;
551 static int keep_response;
553 #ifdef DEBUG_NSS
554 fprintf(stderr, "[%5d]: getpwnam %s\n", getpid(), name);
555 #endif
557 /* If our static buffer needs to be expanded we are called again */
559 if (!keep_response) {
561 /* Call for the first time */
563 ZERO_STRUCT(response);
564 ZERO_STRUCT(request);
566 strncpy(request.data.username, name,
567 sizeof(request.data.username) - 1);
568 request.data.username
569 [sizeof(request.data.username) - 1] = '\0';
571 ret = winbindd_request_response(WINBINDD_GETPWNAM, &request, &response);
573 if (ret == NSS_STATUS_SUCCESS) {
574 ret = fill_pwent(result, &response.data.pw, &buffer,
575 &buflen);
577 if (ret == NSS_STATUS_TRYAGAIN) {
578 keep_response = True;
579 *errnop = errno = ERANGE;
580 goto done;
584 } else {
586 /* We've been called again */
588 ret = fill_pwent(result, &response.data.pw, &buffer, &buflen);
590 if (ret == NSS_STATUS_TRYAGAIN) {
591 keep_response = True;
592 *errnop = errno = ERANGE;
593 goto done;
596 keep_response = False;
597 *errnop = errno = 0;
600 free_response(&response);
601 done:
602 #ifdef DEBUG_NSS
603 fprintf(stderr, "[%5d]: getpwnam %s returns %s (%d)\n", getpid(),
604 name, nss_err_str(ret), ret);
605 #endif
606 return ret;
610 * NSS group functions
613 static struct winbindd_response getgrent_response;
615 static int ndx_gr_cache; /* Current index into grp cache */
616 static int num_gr_cache; /* Current size of grp cache */
618 /* Rewind "file pointer" to start of ntdom group database */
620 NSS_STATUS
621 _nss_winbind_setgrent(void)
623 NSS_STATUS ret;
624 #ifdef DEBUG_NSS
625 fprintf(stderr, "[%5d]: setgrent\n", getpid());
626 #endif
628 if (num_gr_cache > 0) {
629 ndx_gr_cache = num_gr_cache = 0;
630 free_response(&getgrent_response);
633 ret = winbindd_request_response(WINBINDD_SETGRENT, NULL, NULL);
634 #ifdef DEBUG_NSS
635 fprintf(stderr, "[%5d]: setgrent returns %s (%d)\n", getpid(),
636 nss_err_str(ret), ret);
637 #endif
638 return ret;
641 /* Close "file pointer" for ntdom group database */
643 NSS_STATUS
644 _nss_winbind_endgrent(void)
646 NSS_STATUS ret;
647 #ifdef DEBUG_NSS
648 fprintf(stderr, "[%5d]: endgrent\n", getpid());
649 #endif
651 if (num_gr_cache > 0) {
652 ndx_gr_cache = num_gr_cache = 0;
653 free_response(&getgrent_response);
656 ret = winbindd_request_response(WINBINDD_ENDGRENT, NULL, NULL);
657 #ifdef DEBUG_NSS
658 fprintf(stderr, "[%5d]: endgrent returns %s (%d)\n", getpid(),
659 nss_err_str(ret), ret);
660 #endif
661 return ret;
664 /* Get next entry from ntdom group database */
666 static NSS_STATUS
667 winbind_getgrent(enum winbindd_cmd cmd,
668 struct group *result,
669 char *buffer, size_t buflen, int *errnop)
671 NSS_STATUS ret;
672 static struct winbindd_request request;
673 static int called_again;
676 #ifdef DEBUG_NSS
677 fprintf(stderr, "[%5d]: getgrent\n", getpid());
678 #endif
680 /* Return an entry from the cache if we have one, or if we are
681 called again because we exceeded our static buffer. */
683 if ((ndx_gr_cache < num_gr_cache) || called_again) {
684 goto return_result;
687 /* Else call winbindd to get a bunch of entries */
689 if (num_gr_cache > 0) {
690 free_response(&getgrent_response);
693 ZERO_STRUCT(request);
694 ZERO_STRUCT(getgrent_response);
696 request.data.num_entries = MAX_GETGRENT_USERS;
698 ret = winbindd_request_response(cmd, &request,
699 &getgrent_response);
701 if (ret == NSS_STATUS_SUCCESS) {
702 struct winbindd_gr *gr_cache;
703 int mem_ofs;
705 /* Fill cache */
707 ndx_gr_cache = 0;
708 num_gr_cache = getgrent_response.data.num_entries;
710 /* Return a result */
712 return_result:
714 gr_cache = (struct winbindd_gr *)
715 getgrent_response.extra_data.data;
717 /* Check data is valid */
719 if (gr_cache == NULL) {
720 ret = NSS_STATUS_NOTFOUND;
721 goto done;
724 /* Fill group membership. The offset into the extra data
725 for the group membership is the reported offset plus the
726 size of all the winbindd_gr records returned. */
728 mem_ofs = gr_cache[ndx_gr_cache].gr_mem_ofs +
729 num_gr_cache * sizeof(struct winbindd_gr);
731 ret = fill_grent(result, &gr_cache[ndx_gr_cache],
732 ((char *)getgrent_response.extra_data.data)+mem_ofs,
733 &buffer, &buflen);
735 /* Out of memory - try again */
737 if (ret == NSS_STATUS_TRYAGAIN) {
738 called_again = True;
739 *errnop = errno = ERANGE;
740 goto done;
743 *errnop = 0;
744 called_again = False;
745 ndx_gr_cache++;
747 /* If we've finished with this lot of results free cache */
749 if (ndx_gr_cache == num_gr_cache) {
750 ndx_gr_cache = num_gr_cache = 0;
751 free_response(&getgrent_response);
754 done:
755 #ifdef DEBUG_NSS
756 fprintf(stderr, "[%5d]: getgrent returns %s (%d)\n", getpid(),
757 nss_err_str(ret), ret);
758 #endif
759 return ret;
763 NSS_STATUS
764 _nss_winbind_getgrent_r(struct group *result,
765 char *buffer, size_t buflen, int *errnop)
767 return winbind_getgrent(WINBINDD_GETGRENT, result, buffer, buflen, errnop);
770 NSS_STATUS
771 _nss_winbind_getgrlst_r(struct group *result,
772 char *buffer, size_t buflen, int *errnop)
774 return winbind_getgrent(WINBINDD_GETGRLST, result, buffer, buflen, errnop);
777 /* Return group struct from group name */
779 NSS_STATUS
780 _nss_winbind_getgrnam_r(const char *name,
781 struct group *result, char *buffer,
782 size_t buflen, int *errnop)
784 NSS_STATUS ret;
785 static struct winbindd_response response;
786 struct winbindd_request request;
787 static int keep_response;
789 #ifdef DEBUG_NSS
790 fprintf(stderr, "[%5d]: getgrnam %s\n", getpid(), name);
791 #endif
793 /* If our static buffer needs to be expanded we are called again */
795 if (!keep_response) {
797 /* Call for the first time */
799 ZERO_STRUCT(request);
800 ZERO_STRUCT(response);
802 strncpy(request.data.groupname, name,
803 sizeof(request.data.groupname));
804 request.data.groupname
805 [sizeof(request.data.groupname) - 1] = '\0';
807 ret = winbindd_request_response(WINBINDD_GETGRNAM, &request, &response);
809 if (ret == NSS_STATUS_SUCCESS) {
810 ret = fill_grent(result, &response.data.gr,
811 (char *)response.extra_data.data,
812 &buffer, &buflen);
814 if (ret == NSS_STATUS_TRYAGAIN) {
815 keep_response = True;
816 *errnop = errno = ERANGE;
817 goto done;
821 } else {
823 /* We've been called again */
825 ret = fill_grent(result, &response.data.gr,
826 (char *)response.extra_data.data, &buffer,
827 &buflen);
829 if (ret == NSS_STATUS_TRYAGAIN) {
830 keep_response = True;
831 *errnop = errno = ERANGE;
832 goto done;
835 keep_response = False;
836 *errnop = 0;
839 free_response(&response);
840 done:
841 #ifdef DEBUG_NSS
842 fprintf(stderr, "[%5d]: getgrnam %s returns %s (%d)\n", getpid(),
843 name, nss_err_str(ret), ret);
844 #endif
845 return ret;
848 /* Return group struct from gid */
850 NSS_STATUS
851 _nss_winbind_getgrgid_r(gid_t gid,
852 struct group *result, char *buffer,
853 size_t buflen, int *errnop)
855 NSS_STATUS ret;
856 static struct winbindd_response response;
857 struct winbindd_request request;
858 static int keep_response;
860 #ifdef DEBUG_NSS
861 fprintf(stderr, "[%5d]: getgrgid %d\n", getpid(), gid);
862 #endif
864 /* If our static buffer needs to be expanded we are called again */
866 if (!keep_response) {
868 /* Call for the first time */
870 ZERO_STRUCT(request);
871 ZERO_STRUCT(response);
873 request.data.gid = gid;
875 ret = winbindd_request_response(WINBINDD_GETGRGID, &request, &response);
877 if (ret == NSS_STATUS_SUCCESS) {
879 ret = fill_grent(result, &response.data.gr,
880 (char *)response.extra_data.data,
881 &buffer, &buflen);
883 if (ret == NSS_STATUS_TRYAGAIN) {
884 keep_response = True;
885 *errnop = errno = ERANGE;
886 goto done;
890 } else {
892 /* We've been called again */
894 ret = fill_grent(result, &response.data.gr,
895 (char *)response.extra_data.data, &buffer,
896 &buflen);
898 if (ret == NSS_STATUS_TRYAGAIN) {
899 keep_response = True;
900 *errnop = errno = ERANGE;
901 goto done;
904 keep_response = False;
905 *errnop = 0;
908 free_response(&response);
909 done:
910 #ifdef DEBUG_NSS
911 fprintf(stderr, "[%5d]: getgrgid %d returns %s (%d)\n", getpid(),
912 (unsigned int)gid, nss_err_str(ret), ret);
913 #endif
914 return ret;
917 /* Initialise supplementary groups */
919 NSS_STATUS
920 _nss_winbind_initgroups_dyn(char *user, gid_t group, long int *start,
921 long int *size, gid_t **groups, long int limit,
922 int *errnop)
924 NSS_STATUS ret;
925 struct winbindd_request request;
926 struct winbindd_response response;
927 int i;
929 #ifdef DEBUG_NSS
930 fprintf(stderr, "[%5d]: initgroups %s (%d)\n", getpid(),
931 user, group);
932 #endif
934 ZERO_STRUCT(request);
935 ZERO_STRUCT(response);
937 strncpy(request.data.username, user,
938 sizeof(request.data.username) - 1);
940 ret = winbindd_request_response(WINBINDD_GETGROUPS, &request, &response);
942 if (ret == NSS_STATUS_SUCCESS) {
943 int num_gids = response.data.num_entries;
944 gid_t *gid_list = (gid_t *)response.extra_data.data;
946 #ifdef DEBUG_NSS
947 fprintf(stderr, "[%5d]: initgroups %s: got NSS_STATUS_SUCCESS "
948 "and %d gids\n", getpid(),
949 user, num_gids);
950 #endif
951 if (gid_list == NULL) {
952 ret = NSS_STATUS_NOTFOUND;
953 goto done;
956 /* Copy group list to client */
958 for (i = 0; i < num_gids; i++) {
960 #ifdef DEBUG_NSS
961 fprintf(stderr, "[%5d]: initgroups %s (%d): "
962 "processing gid %d \n", getpid(),
963 user, group, gid_list[i]);
964 #endif
966 /* Skip primary group */
968 if (gid_list[i] == group) {
969 continue;
972 /* Filled buffer ? If so, resize. */
974 if (*start == *size) {
975 long int newsize;
976 gid_t *newgroups;
978 newsize = 2 * (*size);
979 if (limit > 0) {
980 if (*size == limit) {
981 goto done;
983 if (newsize > limit) {
984 newsize = limit;
988 newgroups = (gid_t *)
989 realloc((*groups),
990 newsize * sizeof(**groups));
991 if (!newgroups) {
992 *errnop = ENOMEM;
993 ret = NSS_STATUS_NOTFOUND;
994 goto done;
996 *groups = newgroups;
997 *size = newsize;
1000 /* Add to buffer */
1002 (*groups)[*start] = gid_list[i];
1003 *start += 1;
1007 /* Back to your regularly scheduled programming */
1009 done:
1010 #ifdef DEBUG_NSS
1011 fprintf(stderr, "[%5d]: initgroups %s returns %s (%d)\n", getpid(),
1012 user, nss_err_str(ret), ret);
1013 #endif
1014 return ret;
1018 /* return a list of group SIDs for a user SID */
1019 NSS_STATUS
1020 _nss_winbind_getusersids(const char *user_sid, char **group_sids,
1021 int *num_groups,
1022 char *buffer, size_t buf_size, int *errnop)
1024 NSS_STATUS ret;
1025 struct winbindd_request request;
1026 struct winbindd_response response;
1028 #ifdef DEBUG_NSS
1029 fprintf(stderr, "[%5d]: getusersids %s\n", getpid(), user_sid);
1030 #endif
1032 ZERO_STRUCT(request);
1033 ZERO_STRUCT(response);
1035 strncpy(request.data.sid, user_sid,sizeof(request.data.sid) - 1);
1036 request.data.sid[sizeof(request.data.sid) - 1] = '\0';
1038 ret = winbindd_request_response(WINBINDD_GETUSERSIDS, &request, &response);
1040 if (ret != NSS_STATUS_SUCCESS) {
1041 goto done;
1044 if (buf_size < response.length - sizeof(response)) {
1045 ret = NSS_STATUS_TRYAGAIN;
1046 errno = *errnop = ERANGE;
1047 goto done;
1050 *num_groups = response.data.num_entries;
1051 *group_sids = buffer;
1052 memcpy(buffer, response.extra_data.data, response.length - sizeof(response));
1053 errno = *errnop = 0;
1055 done:
1056 free_response(&response);
1057 return ret;
1061 /* map a user or group name to a SID string */
1062 NSS_STATUS
1063 _nss_winbind_nametosid(const char *name, char **sid, char *buffer,
1064 size_t buflen, int *errnop)
1066 NSS_STATUS ret;
1067 struct winbindd_response response;
1068 struct winbindd_request request;
1070 #ifdef DEBUG_NSS
1071 fprintf(stderr, "[%5d]: nametosid %s\n", getpid(), name);
1072 #endif
1074 ZERO_STRUCT(response);
1075 ZERO_STRUCT(request);
1077 strncpy(request.data.name.name, name,
1078 sizeof(request.data.name.name) - 1);
1079 request.data.name.name[sizeof(request.data.name.name) - 1] = '\0';
1081 ret = winbindd_request_response(WINBINDD_LOOKUPNAME, &request, &response);
1082 if (ret != NSS_STATUS_SUCCESS) {
1083 *errnop = errno = EINVAL;
1084 goto failed;
1087 if (buflen < strlen(response.data.sid.sid)+1) {
1088 ret = NSS_STATUS_TRYAGAIN;
1089 *errnop = errno = ERANGE;
1090 goto failed;
1093 *errnop = errno = 0;
1094 *sid = buffer;
1095 strcpy(*sid, response.data.sid.sid);
1097 failed:
1098 free_response(&response);
1099 return ret;
1102 /* map a sid string to a user or group name */
1103 NSS_STATUS
1104 _nss_winbind_sidtoname(const char *sid, char **name, char *buffer,
1105 size_t buflen, int *errnop)
1107 NSS_STATUS ret;
1108 struct winbindd_response response;
1109 struct winbindd_request request;
1110 static char sep_char;
1111 unsigned needed;
1113 #ifdef DEBUG_NSS
1114 fprintf(stderr, "[%5d]: sidtoname %s\n", getpid(), sid);
1115 #endif
1117 ZERO_STRUCT(response);
1118 ZERO_STRUCT(request);
1120 /* we need to fetch the separator first time through */
1121 if (!sep_char) {
1122 ret = winbindd_request_response(WINBINDD_INFO, &request, &response);
1123 if (ret != NSS_STATUS_SUCCESS) {
1124 *errnop = errno = EINVAL;
1125 goto failed;
1128 sep_char = response.data.info.winbind_separator;
1129 free_response(&response);
1133 strncpy(request.data.sid, sid,
1134 sizeof(request.data.sid) - 1);
1135 request.data.sid[sizeof(request.data.sid) - 1] = '\0';
1137 ret = winbindd_request_response(WINBINDD_LOOKUPSID, &request, &response);
1138 if (ret != NSS_STATUS_SUCCESS) {
1139 *errnop = errno = EINVAL;
1140 goto failed;
1143 needed =
1144 strlen(response.data.name.dom_name) +
1145 strlen(response.data.name.name) + 2;
1147 if (buflen < needed) {
1148 ret = NSS_STATUS_TRYAGAIN;
1149 *errnop = errno = ERANGE;
1150 goto failed;
1153 snprintf(buffer, needed, "%s%c%s",
1154 response.data.name.dom_name,
1155 sep_char,
1156 response.data.name.name);
1158 *name = buffer;
1159 *errnop = errno = 0;
1161 failed:
1162 free_response(&response);
1163 return ret;
1166 /* map a sid to a uid */
1167 NSS_STATUS
1168 _nss_winbind_sidtouid(const char *sid, uid_t *uid, int *errnop)
1170 NSS_STATUS ret;
1171 struct winbindd_response response;
1172 struct winbindd_request request;
1174 #ifdef DEBUG_NSS
1175 fprintf(stderr, "[%5d]: sidtouid %s\n", getpid(), sid);
1176 #endif
1178 ZERO_STRUCT(request);
1179 ZERO_STRUCT(response);
1181 strncpy(request.data.sid, sid, sizeof(request.data.sid) - 1);
1182 request.data.sid[sizeof(request.data.sid) - 1] = '\0';
1184 ret = winbindd_request_response(WINBINDD_SID_TO_UID, &request, &response);
1185 if (ret != NSS_STATUS_SUCCESS) {
1186 *errnop = errno = EINVAL;
1187 goto failed;
1190 *uid = response.data.uid;
1192 failed:
1193 return ret;
1196 /* map a sid to a gid */
1197 NSS_STATUS
1198 _nss_winbind_sidtogid(const char *sid, gid_t *gid, int *errnop)
1200 NSS_STATUS ret;
1201 struct winbindd_response response;
1202 struct winbindd_request request;
1204 #ifdef DEBUG_NSS
1205 fprintf(stderr, "[%5d]: sidtogid %s\n", getpid(), sid);
1206 #endif
1208 ZERO_STRUCT(request);
1209 ZERO_STRUCT(response);
1211 strncpy(request.data.sid, sid, sizeof(request.data.sid) - 1);
1212 request.data.sid[sizeof(request.data.sid) - 1] = '\0';
1214 ret = winbindd_request_response(WINBINDD_SID_TO_GID, &request, &response);
1215 if (ret != NSS_STATUS_SUCCESS) {
1216 *errnop = errno = EINVAL;
1217 goto failed;
1220 *gid = response.data.gid;
1222 failed:
1223 return ret;
1226 /* map a uid to a SID string */
1227 NSS_STATUS
1228 _nss_winbind_uidtosid(uid_t uid, char **sid, char *buffer,
1229 size_t buflen, int *errnop)
1231 NSS_STATUS ret;
1232 struct winbindd_response response;
1233 struct winbindd_request request;
1235 #ifdef DEBUG_NSS
1236 fprintf(stderr, "[%5u]: uidtosid %u\n", (unsigned int)getpid(), (unsigned int)uid);
1237 #endif
1239 ZERO_STRUCT(response);
1240 ZERO_STRUCT(request);
1242 request.data.uid = uid;
1244 ret = winbindd_request_response(WINBINDD_UID_TO_SID, &request, &response);
1245 if (ret != NSS_STATUS_SUCCESS) {
1246 *errnop = errno = EINVAL;
1247 goto failed;
1250 if (buflen < strlen(response.data.sid.sid)+1) {
1251 ret = NSS_STATUS_TRYAGAIN;
1252 *errnop = errno = ERANGE;
1253 goto failed;
1256 *errnop = errno = 0;
1257 *sid = buffer;
1258 strcpy(*sid, response.data.sid.sid);
1260 failed:
1261 free_response(&response);
1262 return ret;
1265 /* map a gid to a SID string */
1266 NSS_STATUS
1267 _nss_winbind_gidtosid(gid_t gid, char **sid, char *buffer,
1268 size_t buflen, int *errnop)
1270 NSS_STATUS ret;
1271 struct winbindd_response response;
1272 struct winbindd_request request;
1274 #ifdef DEBUG_NSS
1275 fprintf(stderr, "[%5u]: gidtosid %u\n", (unsigned int)getpid(), (unsigned int)gid);
1276 #endif
1278 ZERO_STRUCT(response);
1279 ZERO_STRUCT(request);
1281 request.data.gid = gid;
1283 ret = winbindd_request_response(WINBINDD_GID_TO_SID, &request, &response);
1284 if (ret != NSS_STATUS_SUCCESS) {
1285 *errnop = errno = EINVAL;
1286 goto failed;
1289 if (buflen < strlen(response.data.sid.sid)+1) {
1290 ret = NSS_STATUS_TRYAGAIN;
1291 *errnop = errno = ERANGE;
1292 goto failed;
1295 *errnop = errno = 0;
1296 *sid = buffer;
1297 strcpy(*sid, response.data.sid.sid);
1299 failed:
1300 free_response(&response);
1301 return ret;