Deal with c_req send errors asynchronously
[Samba/vfs_proxy.git] / source4 / nsswitch / winbind_nss_linux.c
blobac53979cedd5d612448b266738cfa76702c6ea94
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 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"
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 /* Allocate some space from the nss static buffer. The buffer and buflen
71 are the pointers passed in by the C library to the _nss_ntdom_*
72 functions. */
74 static char *get_static(char **buffer, size_t *buflen, size_t len)
76 char *result;
78 /* Error check. We return false if things aren't set up right, or
79 there isn't enough buffer space left. */
81 if ((buffer == NULL) || (buflen == NULL) || (*buflen < len)) {
82 return NULL;
85 /* Return an index into the static buffer */
87 result = *buffer;
88 *buffer += len;
89 *buflen -= len;
91 return result;
94 /* I've copied the strtok() replacement function next_token() from
95 lib/util_str.c as I really don't want to have to link in any other
96 objects if I can possibly avoid it. */
98 static bool next_token(char **ptr,char *buff,const char *sep, size_t bufsize)
100 char *s;
101 bool quoted;
102 size_t len=1;
104 if (!ptr) return false;
106 s = *ptr;
108 /* default to simple separators */
109 if (!sep) sep = " \t\n\r";
111 /* find the first non sep char */
112 while (*s && strchr(sep,*s)) s++;
114 /* nothing left? */
115 if (! *s) return false;
117 /* copy over the token */
118 for (quoted = false; len < bufsize && *s && (quoted || !strchr(sep,*s)); s++) {
119 if (*s == '\"') {
120 quoted = !quoted;
121 } else {
122 len++;
123 *buff++ = *s;
127 *ptr = (*s) ? s+1 : s;
128 *buff = 0;
130 return true;
134 /* Fill a pwent structure from a winbindd_response structure. We use
135 the static data passed to us by libc to put strings and stuff in.
136 Return NSS_STATUS_TRYAGAIN if we run out of memory. */
138 static NSS_STATUS fill_pwent(struct passwd *result,
139 struct winbindd_pw *pw,
140 char **buffer, size_t *buflen)
142 /* User name */
144 if ((result->pw_name =
145 get_static(buffer, buflen, strlen(pw->pw_name) + 1)) == NULL) {
147 /* Out of memory */
149 return NSS_STATUS_TRYAGAIN;
152 strcpy(result->pw_name, pw->pw_name);
154 /* Password */
156 if ((result->pw_passwd =
157 get_static(buffer, buflen, strlen(pw->pw_passwd) + 1)) == NULL) {
159 /* Out of memory */
161 return NSS_STATUS_TRYAGAIN;
164 strcpy(result->pw_passwd, pw->pw_passwd);
166 /* [ug]id */
168 result->pw_uid = pw->pw_uid;
169 result->pw_gid = pw->pw_gid;
171 /* GECOS */
173 if ((result->pw_gecos =
174 get_static(buffer, buflen, strlen(pw->pw_gecos) + 1)) == NULL) {
176 /* Out of memory */
178 return NSS_STATUS_TRYAGAIN;
181 strcpy(result->pw_gecos, pw->pw_gecos);
183 /* Home directory */
185 if ((result->pw_dir =
186 get_static(buffer, buflen, strlen(pw->pw_dir) + 1)) == NULL) {
188 /* Out of memory */
190 return NSS_STATUS_TRYAGAIN;
193 strcpy(result->pw_dir, pw->pw_dir);
195 /* Logon shell */
197 if ((result->pw_shell =
198 get_static(buffer, buflen, strlen(pw->pw_shell) + 1)) == NULL) {
200 /* Out of memory */
202 return NSS_STATUS_TRYAGAIN;
205 strcpy(result->pw_shell, pw->pw_shell);
207 /* The struct passwd for Solaris has some extra fields which must
208 be initialised or nscd crashes. */
210 #if HAVE_PASSWD_PW_COMMENT
211 result->pw_comment = "";
212 #endif
214 #if HAVE_PASSWD_PW_AGE
215 result->pw_age = "";
216 #endif
218 return NSS_STATUS_SUCCESS;
221 /* Fill a grent structure from a winbindd_response structure. We use
222 the static data passed to us by libc to put strings and stuff in.
223 Return NSS_STATUS_TRYAGAIN if we run out of memory. */
225 static NSS_STATUS fill_grent(struct group *result, struct winbindd_gr *gr,
226 char *gr_mem, char **buffer, size_t *buflen)
228 fstring name;
229 int i;
230 char *tst;
232 /* Group name */
234 if ((result->gr_name =
235 get_static(buffer, buflen, strlen(gr->gr_name) + 1)) == NULL) {
237 /* Out of memory */
239 return NSS_STATUS_TRYAGAIN;
242 strcpy(result->gr_name, gr->gr_name);
244 /* Password */
246 if ((result->gr_passwd =
247 get_static(buffer, buflen, strlen(gr->gr_passwd) + 1)) == NULL) {
249 /* Out of memory */
251 return NSS_STATUS_TRYAGAIN;
254 strcpy(result->gr_passwd, gr->gr_passwd);
256 /* gid */
258 result->gr_gid = gr->gr_gid;
260 /* Group membership */
262 if ((gr->num_gr_mem < 0) || !gr_mem) {
263 gr->num_gr_mem = 0;
266 /* this next value is a pointer to a pointer so let's align it */
268 /* Calculate number of extra bytes needed to align on pointer size boundry */
269 if ((i = (unsigned long)(*buffer) % sizeof(char*)) != 0)
270 i = sizeof(char*) - i;
272 if ((tst = get_static(buffer, buflen, ((gr->num_gr_mem + 1) *
273 sizeof(char *)+i))) == NULL) {
275 /* Out of memory */
277 return NSS_STATUS_TRYAGAIN;
279 result->gr_mem = (char **)(tst + i);
281 if (gr->num_gr_mem == 0) {
283 /* Group is empty */
285 *(result->gr_mem) = NULL;
286 return NSS_STATUS_SUCCESS;
289 /* Start looking at extra data */
291 i = 0;
293 while(next_token((char **)&gr_mem, name, ",", sizeof(fstring))) {
295 /* Allocate space for member */
297 if (((result->gr_mem)[i] =
298 get_static(buffer, buflen, strlen(name) + 1)) == NULL) {
300 /* Out of memory */
302 return NSS_STATUS_TRYAGAIN;
305 strcpy((result->gr_mem)[i], name);
306 i++;
309 /* Terminate list */
311 (result->gr_mem)[i] = NULL;
313 return NSS_STATUS_SUCCESS;
317 * NSS user functions
320 static struct winbindd_response getpwent_response;
322 static int ndx_pw_cache; /* Current index into pwd cache */
323 static int num_pw_cache; /* Current size of pwd cache */
325 /* Rewind "file pointer" to start of ntdom password database */
327 NSS_STATUS
328 _nss_winbind_setpwent(void)
330 NSS_STATUS ret;
331 #ifdef DEBUG_NSS
332 fprintf(stderr, "[%5d]: setpwent\n", getpid());
333 #endif
335 if (num_pw_cache > 0) {
336 ndx_pw_cache = num_pw_cache = 0;
337 winbindd_free_response(&getpwent_response);
340 ret = winbindd_request_response(WINBINDD_SETPWENT, NULL, NULL);
341 #ifdef DEBUG_NSS
342 fprintf(stderr, "[%5d]: setpwent returns %s (%d)\n", getpid(),
343 nss_err_str(ret), ret);
344 #endif
345 return ret;
348 /* Close ntdom password database "file pointer" */
350 NSS_STATUS
351 _nss_winbind_endpwent(void)
353 NSS_STATUS ret;
354 #ifdef DEBUG_NSS
355 fprintf(stderr, "[%5d]: endpwent\n", getpid());
356 #endif
358 if (num_pw_cache > 0) {
359 ndx_pw_cache = num_pw_cache = 0;
360 winbindd_free_response(&getpwent_response);
363 ret = winbindd_request_response(WINBINDD_ENDPWENT, NULL, NULL);
364 #ifdef DEBUG_NSS
365 fprintf(stderr, "[%5d]: endpwent returns %s (%d)\n", getpid(),
366 nss_err_str(ret), ret);
367 #endif
368 return ret;
371 /* Fetch the next password entry from ntdom password database */
373 NSS_STATUS
374 _nss_winbind_getpwent_r(struct passwd *result, char *buffer,
375 size_t buflen, int *errnop)
377 NSS_STATUS ret;
378 struct winbindd_request request;
379 static int called_again;
381 #ifdef DEBUG_NSS
382 fprintf(stderr, "[%5d]: getpwent\n", getpid());
383 #endif
385 /* Return an entry from the cache if we have one, or if we are
386 called again because we exceeded our static buffer. */
388 if ((ndx_pw_cache < num_pw_cache) || called_again) {
389 goto return_result;
392 /* Else call winbindd to get a bunch of entries */
394 if (num_pw_cache > 0) {
395 winbindd_free_response(&getpwent_response);
398 ZERO_STRUCT(request);
399 ZERO_STRUCT(getpwent_response);
401 request.data.num_entries = MAX_GETPWENT_USERS;
403 ret = winbindd_request_response(WINBINDD_GETPWENT, &request,
404 &getpwent_response);
406 if (ret == NSS_STATUS_SUCCESS) {
407 struct winbindd_pw *pw_cache;
409 /* Fill cache */
411 ndx_pw_cache = 0;
412 num_pw_cache = getpwent_response.data.num_entries;
414 /* Return a result */
416 return_result:
418 pw_cache = (struct winbindd_pw *)
419 getpwent_response.extra_data.data;
421 /* Check data is valid */
423 if (pw_cache == NULL) {
424 ret = NSS_STATUS_NOTFOUND;
425 goto done;
428 ret = fill_pwent(result, &pw_cache[ndx_pw_cache],
429 &buffer, &buflen);
431 /* Out of memory - try again */
433 if (ret == NSS_STATUS_TRYAGAIN) {
434 called_again = true;
435 *errnop = errno = ERANGE;
436 goto done;
439 *errnop = errno = 0;
440 called_again = false;
441 ndx_pw_cache++;
443 /* If we've finished with this lot of results free cache */
445 if (ndx_pw_cache == num_pw_cache) {
446 ndx_pw_cache = num_pw_cache = 0;
447 winbindd_free_response(&getpwent_response);
450 done:
451 #ifdef DEBUG_NSS
452 fprintf(stderr, "[%5d]: getpwent returns %s (%d)\n", getpid(),
453 nss_err_str(ret), ret);
454 #endif
455 return ret;
458 /* Return passwd struct from uid */
460 NSS_STATUS
461 _nss_winbind_getpwuid_r(uid_t uid, struct passwd *result, char *buffer,
462 size_t buflen, int *errnop)
464 NSS_STATUS ret;
465 static struct winbindd_response response;
466 struct winbindd_request request;
467 static int keep_response=0;
469 #ifdef DEBUG_NSS
470 fprintf(stderr, "[%5d]: getpwuid %d\n", getpid(), (unsigned int)uid);
471 #endif
473 /* If our static buffer needs to be expanded we are called again */
474 if (!keep_response) {
476 /* Call for the first time */
478 ZERO_STRUCT(response);
479 ZERO_STRUCT(request);
481 request.data.uid = uid;
483 ret = winbindd_request_response(WINBINDD_GETPWUID, &request, &response);
485 if (ret == NSS_STATUS_SUCCESS) {
486 ret = fill_pwent(result, &response.data.pw,
487 &buffer, &buflen);
489 if (ret == NSS_STATUS_TRYAGAIN) {
490 keep_response = true;
491 *errnop = errno = ERANGE;
492 goto done;
496 } else {
498 /* We've been called again */
500 ret = fill_pwent(result, &response.data.pw, &buffer, &buflen);
502 if (ret == NSS_STATUS_TRYAGAIN) {
503 keep_response = true;
504 *errnop = errno = ERANGE;
505 goto done;
508 keep_response = false;
509 *errnop = errno = 0;
512 winbindd_free_response(&response);
513 done:
515 #ifdef DEBUG_NSS
516 fprintf(stderr, "[%5d]: getpwuid %d returns %s (%d)\n", getpid(),
517 (unsigned int)uid, nss_err_str(ret), ret);
518 #endif
519 return ret;
522 /* Return passwd struct from username */
523 NSS_STATUS
524 _nss_winbind_getpwnam_r(const char *name, struct passwd *result, char *buffer,
525 size_t buflen, int *errnop)
527 NSS_STATUS ret;
528 static struct winbindd_response response;
529 struct winbindd_request request;
530 static int keep_response;
532 #ifdef DEBUG_NSS
533 fprintf(stderr, "[%5d]: getpwnam %s\n", getpid(), name);
534 #endif
536 /* If our static buffer needs to be expanded we are called again */
538 if (!keep_response) {
540 /* Call for the first time */
542 ZERO_STRUCT(response);
543 ZERO_STRUCT(request);
545 strncpy(request.data.username, name,
546 sizeof(request.data.username) - 1);
547 request.data.username
548 [sizeof(request.data.username) - 1] = '\0';
550 ret = winbindd_request_response(WINBINDD_GETPWNAM, &request, &response);
552 if (ret == NSS_STATUS_SUCCESS) {
553 ret = fill_pwent(result, &response.data.pw, &buffer,
554 &buflen);
556 if (ret == NSS_STATUS_TRYAGAIN) {
557 keep_response = true;
558 *errnop = errno = ERANGE;
559 goto done;
563 } else {
565 /* We've been called again */
567 ret = fill_pwent(result, &response.data.pw, &buffer, &buflen);
569 if (ret == NSS_STATUS_TRYAGAIN) {
570 keep_response = true;
571 *errnop = errno = ERANGE;
572 goto done;
575 keep_response = false;
576 *errnop = errno = 0;
579 winbindd_free_response(&response);
580 done:
581 #ifdef DEBUG_NSS
582 fprintf(stderr, "[%5d]: getpwnam %s returns %s (%d)\n", getpid(),
583 name, nss_err_str(ret), ret);
584 #endif
585 return ret;
589 * NSS group functions
592 static struct winbindd_response getgrent_response;
594 static int ndx_gr_cache; /* Current index into grp cache */
595 static int num_gr_cache; /* Current size of grp cache */
597 /* Rewind "file pointer" to start of ntdom group database */
599 NSS_STATUS
600 _nss_winbind_setgrent(void)
602 NSS_STATUS ret;
603 #ifdef DEBUG_NSS
604 fprintf(stderr, "[%5d]: setgrent\n", getpid());
605 #endif
607 if (num_gr_cache > 0) {
608 ndx_gr_cache = num_gr_cache = 0;
609 winbindd_free_response(&getgrent_response);
612 ret = winbindd_request_response(WINBINDD_SETGRENT, NULL, NULL);
613 #ifdef DEBUG_NSS
614 fprintf(stderr, "[%5d]: setgrent returns %s (%d)\n", getpid(),
615 nss_err_str(ret), ret);
616 #endif
617 return ret;
620 /* Close "file pointer" for ntdom group database */
622 NSS_STATUS
623 _nss_winbind_endgrent(void)
625 NSS_STATUS ret;
626 #ifdef DEBUG_NSS
627 fprintf(stderr, "[%5d]: endgrent\n", getpid());
628 #endif
630 if (num_gr_cache > 0) {
631 ndx_gr_cache = num_gr_cache = 0;
632 winbindd_free_response(&getgrent_response);
635 ret = winbindd_request_response(WINBINDD_ENDGRENT, NULL, NULL);
636 #ifdef DEBUG_NSS
637 fprintf(stderr, "[%5d]: endgrent returns %s (%d)\n", getpid(),
638 nss_err_str(ret), ret);
639 #endif
640 return ret;
643 /* Get next entry from ntdom group database */
645 static NSS_STATUS
646 winbind_getgrent(enum winbindd_cmd cmd,
647 struct group *result,
648 char *buffer, size_t buflen, int *errnop)
650 NSS_STATUS ret;
651 static struct winbindd_request request;
652 static int called_again;
655 #ifdef DEBUG_NSS
656 fprintf(stderr, "[%5d]: getgrent\n", getpid());
657 #endif
659 /* Return an entry from the cache if we have one, or if we are
660 called again because we exceeded our static buffer. */
662 if ((ndx_gr_cache < num_gr_cache) || called_again) {
663 goto return_result;
666 /* Else call winbindd to get a bunch of entries */
668 if (num_gr_cache > 0) {
669 winbindd_free_response(&getgrent_response);
672 ZERO_STRUCT(request);
673 ZERO_STRUCT(getgrent_response);
675 request.data.num_entries = MAX_GETGRENT_USERS;
677 ret = winbindd_request_response(cmd, &request,
678 &getgrent_response);
680 if (ret == NSS_STATUS_SUCCESS) {
681 struct winbindd_gr *gr_cache;
682 int mem_ofs;
684 /* Fill cache */
686 ndx_gr_cache = 0;
687 num_gr_cache = getgrent_response.data.num_entries;
689 /* Return a result */
691 return_result:
693 gr_cache = (struct winbindd_gr *)
694 getgrent_response.extra_data.data;
696 /* Check data is valid */
698 if (gr_cache == NULL) {
699 ret = NSS_STATUS_NOTFOUND;
700 goto done;
703 /* Fill group membership. The offset into the extra data
704 for the group membership is the reported offset plus the
705 size of all the winbindd_gr records returned. */
707 mem_ofs = gr_cache[ndx_gr_cache].gr_mem_ofs +
708 num_gr_cache * sizeof(struct winbindd_gr);
710 ret = fill_grent(result, &gr_cache[ndx_gr_cache],
711 ((char *)getgrent_response.extra_data.data)+mem_ofs,
712 &buffer, &buflen);
714 /* Out of memory - try again */
716 if (ret == NSS_STATUS_TRYAGAIN) {
717 called_again = true;
718 *errnop = errno = ERANGE;
719 goto done;
722 *errnop = 0;
723 called_again = false;
724 ndx_gr_cache++;
726 /* If we've finished with this lot of results free cache */
728 if (ndx_gr_cache == num_gr_cache) {
729 ndx_gr_cache = num_gr_cache = 0;
730 winbindd_free_response(&getgrent_response);
733 done:
734 #ifdef DEBUG_NSS
735 fprintf(stderr, "[%5d]: getgrent returns %s (%d)\n", getpid(),
736 nss_err_str(ret), ret);
737 #endif
738 return ret;
742 NSS_STATUS
743 _nss_winbind_getgrent_r(struct group *result,
744 char *buffer, size_t buflen, int *errnop)
746 return winbind_getgrent(WINBINDD_GETGRENT, result, buffer, buflen, errnop);
749 NSS_STATUS
750 _nss_winbind_getgrlst_r(struct group *result,
751 char *buffer, size_t buflen, int *errnop)
753 return winbind_getgrent(WINBINDD_GETGRLST, result, buffer, buflen, errnop);
756 /* Return group struct from group name */
758 NSS_STATUS
759 _nss_winbind_getgrnam_r(const char *name,
760 struct group *result, char *buffer,
761 size_t buflen, int *errnop)
763 NSS_STATUS ret;
764 static struct winbindd_response response;
765 struct winbindd_request request;
766 static int keep_response;
768 #ifdef DEBUG_NSS
769 fprintf(stderr, "[%5d]: getgrnam %s\n", getpid(), name);
770 #endif
772 /* If our static buffer needs to be expanded we are called again */
774 if (!keep_response) {
776 /* Call for the first time */
778 ZERO_STRUCT(request);
779 ZERO_STRUCT(response);
781 strncpy(request.data.groupname, name,
782 sizeof(request.data.groupname));
783 request.data.groupname
784 [sizeof(request.data.groupname) - 1] = '\0';
786 ret = winbindd_request_response(WINBINDD_GETGRNAM, &request, &response);
788 if (ret == NSS_STATUS_SUCCESS) {
789 ret = fill_grent(result, &response.data.gr,
790 (char *)response.extra_data.data,
791 &buffer, &buflen);
793 if (ret == NSS_STATUS_TRYAGAIN) {
794 keep_response = true;
795 *errnop = errno = ERANGE;
796 goto done;
800 } else {
802 /* We've been called again */
804 ret = fill_grent(result, &response.data.gr,
805 (char *)response.extra_data.data, &buffer,
806 &buflen);
808 if (ret == NSS_STATUS_TRYAGAIN) {
809 keep_response = true;
810 *errnop = errno = ERANGE;
811 goto done;
814 keep_response = false;
815 *errnop = 0;
818 winbindd_free_response(&response);
819 done:
820 #ifdef DEBUG_NSS
821 fprintf(stderr, "[%5d]: getgrnam %s returns %s (%d)\n", getpid(),
822 name, nss_err_str(ret), ret);
823 #endif
824 return ret;
827 /* Return group struct from gid */
829 NSS_STATUS
830 _nss_winbind_getgrgid_r(gid_t gid,
831 struct group *result, char *buffer,
832 size_t buflen, int *errnop)
834 NSS_STATUS ret;
835 static struct winbindd_response response;
836 struct winbindd_request request;
837 static int keep_response;
839 #ifdef DEBUG_NSS
840 fprintf(stderr, "[%5d]: getgrgid %d\n", getpid(), gid);
841 #endif
843 /* If our static buffer needs to be expanded we are called again */
845 if (!keep_response) {
847 /* Call for the first time */
849 ZERO_STRUCT(request);
850 ZERO_STRUCT(response);
852 request.data.gid = gid;
854 ret = winbindd_request_response(WINBINDD_GETGRGID, &request, &response);
856 if (ret == NSS_STATUS_SUCCESS) {
858 ret = fill_grent(result, &response.data.gr,
859 (char *)response.extra_data.data,
860 &buffer, &buflen);
862 if (ret == NSS_STATUS_TRYAGAIN) {
863 keep_response = true;
864 *errnop = errno = ERANGE;
865 goto done;
869 } else {
871 /* We've been called again */
873 ret = fill_grent(result, &response.data.gr,
874 (char *)response.extra_data.data, &buffer,
875 &buflen);
877 if (ret == NSS_STATUS_TRYAGAIN) {
878 keep_response = true;
879 *errnop = errno = ERANGE;
880 goto done;
883 keep_response = false;
884 *errnop = 0;
887 winbindd_free_response(&response);
888 done:
889 #ifdef DEBUG_NSS
890 fprintf(stderr, "[%5d]: getgrgid %d returns %s (%d)\n", getpid(),
891 (unsigned int)gid, nss_err_str(ret), ret);
892 #endif
893 return ret;
896 /* Initialise supplementary groups */
898 NSS_STATUS
899 _nss_winbind_initgroups_dyn(char *user, gid_t group, long int *start,
900 long int *size, gid_t **groups, long int limit,
901 int *errnop)
903 NSS_STATUS ret;
904 struct winbindd_request request;
905 struct winbindd_response response;
906 int i;
908 #ifdef DEBUG_NSS
909 fprintf(stderr, "[%5d]: initgroups %s (%d)\n", getpid(),
910 user, group);
911 #endif
913 ZERO_STRUCT(request);
914 ZERO_STRUCT(response);
916 strncpy(request.data.username, user,
917 sizeof(request.data.username) - 1);
919 ret = winbindd_request_response(WINBINDD_GETGROUPS, &request, &response);
921 if (ret == NSS_STATUS_SUCCESS) {
922 int num_gids = response.data.num_entries;
923 gid_t *gid_list = (gid_t *)response.extra_data.data;
925 #ifdef DEBUG_NSS
926 fprintf(stderr, "[%5d]: initgroups %s: got NSS_STATUS_SUCCESS "
927 "and %d gids\n", getpid(),
928 user, num_gids);
929 #endif
930 if (gid_list == NULL) {
931 ret = NSS_STATUS_NOTFOUND;
932 goto done;
935 /* Copy group list to client */
937 for (i = 0; i < num_gids; i++) {
939 #ifdef DEBUG_NSS
940 fprintf(stderr, "[%5d]: initgroups %s (%d): "
941 "processing gid %d \n", getpid(),
942 user, group, gid_list[i]);
943 #endif
945 /* Skip primary group */
947 if (gid_list[i] == group) {
948 continue;
951 /* Filled buffer ? If so, resize. */
953 if (*start == *size) {
954 long int newsize;
955 gid_t *newgroups;
957 newsize = 2 * (*size);
958 if (limit > 0) {
959 if (*size == limit) {
960 goto done;
962 if (newsize > limit) {
963 newsize = limit;
967 newgroups = (gid_t *)
968 realloc((*groups),
969 newsize * sizeof(**groups));
970 if (!newgroups) {
971 *errnop = ENOMEM;
972 ret = NSS_STATUS_NOTFOUND;
973 goto done;
975 *groups = newgroups;
976 *size = newsize;
979 /* Add to buffer */
981 (*groups)[*start] = gid_list[i];
982 *start += 1;
986 /* Back to your regularly scheduled programming */
988 done:
989 #ifdef DEBUG_NSS
990 fprintf(stderr, "[%5d]: initgroups %s returns %s (%d)\n", getpid(),
991 user, nss_err_str(ret), ret);
992 #endif
993 return ret;
997 /* return a list of group SIDs for a user SID */
998 NSS_STATUS
999 _nss_winbind_getusersids(const char *user_sid, char **group_sids,
1000 int *num_groups,
1001 char *buffer, size_t buf_size, int *errnop)
1003 NSS_STATUS ret;
1004 struct winbindd_request request;
1005 struct winbindd_response response;
1007 #ifdef DEBUG_NSS
1008 fprintf(stderr, "[%5d]: getusersids %s\n", getpid(), user_sid);
1009 #endif
1011 ZERO_STRUCT(request);
1012 ZERO_STRUCT(response);
1014 strncpy(request.data.sid, user_sid,sizeof(request.data.sid) - 1);
1015 request.data.sid[sizeof(request.data.sid) - 1] = '\0';
1017 ret = winbindd_request_response(WINBINDD_GETUSERSIDS, &request, &response);
1019 if (ret != NSS_STATUS_SUCCESS) {
1020 goto done;
1023 if (buf_size < response.length - sizeof(response)) {
1024 ret = NSS_STATUS_TRYAGAIN;
1025 errno = *errnop = ERANGE;
1026 goto done;
1029 *num_groups = response.data.num_entries;
1030 *group_sids = buffer;
1031 memcpy(buffer, response.extra_data.data, response.length - sizeof(response));
1032 errno = *errnop = 0;
1034 done:
1035 winbindd_free_response(&response);
1036 return ret;
1040 /* map a user or group name to a SID string */
1041 NSS_STATUS
1042 _nss_winbind_nametosid(const char *name, char **sid, char *buffer,
1043 size_t buflen, int *errnop)
1045 NSS_STATUS ret;
1046 struct winbindd_response response;
1047 struct winbindd_request request;
1049 #ifdef DEBUG_NSS
1050 fprintf(stderr, "[%5d]: nametosid %s\n", getpid(), name);
1051 #endif
1053 ZERO_STRUCT(response);
1054 ZERO_STRUCT(request);
1056 strncpy(request.data.name.name, name,
1057 sizeof(request.data.name.name) - 1);
1058 request.data.name.name[sizeof(request.data.name.name) - 1] = '\0';
1060 ret = winbindd_request_response(WINBINDD_LOOKUPNAME, &request, &response);
1061 if (ret != NSS_STATUS_SUCCESS) {
1062 *errnop = errno = EINVAL;
1063 goto failed;
1066 if (buflen < strlen(response.data.sid.sid)+1) {
1067 ret = NSS_STATUS_TRYAGAIN;
1068 *errnop = errno = ERANGE;
1069 goto failed;
1072 *errnop = errno = 0;
1073 *sid = buffer;
1074 strcpy(*sid, response.data.sid.sid);
1076 failed:
1077 winbindd_free_response(&response);
1078 return ret;
1081 /* map a sid string to a user or group name */
1082 NSS_STATUS
1083 _nss_winbind_sidtoname(const char *sid, char **name, char *buffer,
1084 size_t buflen, int *errnop)
1086 NSS_STATUS ret;
1087 struct winbindd_response response;
1088 struct winbindd_request request;
1089 static char sep_char;
1090 unsigned needed;
1092 #ifdef DEBUG_NSS
1093 fprintf(stderr, "[%5d]: sidtoname %s\n", getpid(), sid);
1094 #endif
1096 ZERO_STRUCT(response);
1097 ZERO_STRUCT(request);
1099 /* we need to fetch the separator first time through */
1100 if (!sep_char) {
1101 ret = winbindd_request_response(WINBINDD_INFO, &request, &response);
1102 if (ret != NSS_STATUS_SUCCESS) {
1103 *errnop = errno = EINVAL;
1104 goto failed;
1107 sep_char = response.data.info.winbind_separator;
1108 winbindd_free_response(&response);
1112 strncpy(request.data.sid, sid,
1113 sizeof(request.data.sid) - 1);
1114 request.data.sid[sizeof(request.data.sid) - 1] = '\0';
1116 ret = winbindd_request_response(WINBINDD_LOOKUPSID, &request, &response);
1117 if (ret != NSS_STATUS_SUCCESS) {
1118 *errnop = errno = EINVAL;
1119 goto failed;
1122 needed =
1123 strlen(response.data.name.dom_name) +
1124 strlen(response.data.name.name) + 2;
1126 if (buflen < needed) {
1127 ret = NSS_STATUS_TRYAGAIN;
1128 *errnop = errno = ERANGE;
1129 goto failed;
1132 snprintf(buffer, needed, "%s%c%s",
1133 response.data.name.dom_name,
1134 sep_char,
1135 response.data.name.name);
1137 *name = buffer;
1138 *errnop = errno = 0;
1140 failed:
1141 winbindd_free_response(&response);
1142 return ret;
1145 /* map a sid to a uid */
1146 NSS_STATUS
1147 _nss_winbind_sidtouid(const char *sid, uid_t *uid, int *errnop)
1149 NSS_STATUS ret;
1150 struct winbindd_response response;
1151 struct winbindd_request request;
1153 #ifdef DEBUG_NSS
1154 fprintf(stderr, "[%5d]: sidtouid %s\n", getpid(), sid);
1155 #endif
1157 ZERO_STRUCT(request);
1158 ZERO_STRUCT(response);
1160 strncpy(request.data.sid, sid, sizeof(request.data.sid) - 1);
1161 request.data.sid[sizeof(request.data.sid) - 1] = '\0';
1163 ret = winbindd_request_response(WINBINDD_SID_TO_UID, &request, &response);
1164 if (ret != NSS_STATUS_SUCCESS) {
1165 *errnop = errno = EINVAL;
1166 goto failed;
1169 *uid = response.data.uid;
1171 failed:
1172 return ret;
1175 /* map a sid to a gid */
1176 NSS_STATUS
1177 _nss_winbind_sidtogid(const char *sid, gid_t *gid, int *errnop)
1179 NSS_STATUS ret;
1180 struct winbindd_response response;
1181 struct winbindd_request request;
1183 #ifdef DEBUG_NSS
1184 fprintf(stderr, "[%5d]: sidtogid %s\n", getpid(), sid);
1185 #endif
1187 ZERO_STRUCT(request);
1188 ZERO_STRUCT(response);
1190 strncpy(request.data.sid, sid, sizeof(request.data.sid) - 1);
1191 request.data.sid[sizeof(request.data.sid) - 1] = '\0';
1193 ret = winbindd_request_response(WINBINDD_SID_TO_GID, &request, &response);
1194 if (ret != NSS_STATUS_SUCCESS) {
1195 *errnop = errno = EINVAL;
1196 goto failed;
1199 *gid = response.data.gid;
1201 failed:
1202 return ret;
1205 /* map a uid to a SID string */
1206 NSS_STATUS
1207 _nss_winbind_uidtosid(uid_t uid, char **sid, char *buffer,
1208 size_t buflen, int *errnop)
1210 NSS_STATUS ret;
1211 struct winbindd_response response;
1212 struct winbindd_request request;
1214 #ifdef DEBUG_NSS
1215 fprintf(stderr, "[%5u]: uidtosid %u\n", (unsigned int)getpid(), (unsigned int)uid);
1216 #endif
1218 ZERO_STRUCT(response);
1219 ZERO_STRUCT(request);
1221 request.data.uid = uid;
1223 ret = winbindd_request_response(WINBINDD_UID_TO_SID, &request, &response);
1224 if (ret != NSS_STATUS_SUCCESS) {
1225 *errnop = errno = EINVAL;
1226 goto failed;
1229 if (buflen < strlen(response.data.sid.sid)+1) {
1230 ret = NSS_STATUS_TRYAGAIN;
1231 *errnop = errno = ERANGE;
1232 goto failed;
1235 *errnop = errno = 0;
1236 *sid = buffer;
1237 strcpy(*sid, response.data.sid.sid);
1239 failed:
1240 winbindd_free_response(&response);
1241 return ret;
1244 /* map a gid to a SID string */
1245 NSS_STATUS
1246 _nss_winbind_gidtosid(gid_t gid, char **sid, char *buffer,
1247 size_t buflen, int *errnop)
1249 NSS_STATUS ret;
1250 struct winbindd_response response;
1251 struct winbindd_request request;
1253 #ifdef DEBUG_NSS
1254 fprintf(stderr, "[%5u]: gidtosid %u\n", (unsigned int)getpid(), (unsigned int)gid);
1255 #endif
1257 ZERO_STRUCT(response);
1258 ZERO_STRUCT(request);
1260 request.data.gid = gid;
1262 ret = winbindd_request_response(WINBINDD_GID_TO_SID, &request, &response);
1263 if (ret != NSS_STATUS_SUCCESS) {
1264 *errnop = errno = EINVAL;
1265 goto failed;
1268 if (buflen < strlen(response.data.sid.sid)+1) {
1269 ret = NSS_STATUS_TRYAGAIN;
1270 *errnop = errno = ERANGE;
1271 goto failed;
1274 *errnop = errno = 0;
1275 *sid = buffer;
1276 strcpy(*sid, response.data.sid.sid);
1278 failed:
1279 winbindd_free_response(&response);
1280 return ret;