source: branches/samba-3.0/source/nsswitch/winbind_nss_linux.c

Last change on this file was 1, checked in by Paul Smedley, 19 years ago

Initial code import

File size: 28.7 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3
4 Windows NT Domain nsswitch module
5
6 Copyright (C) Tim Potter 2000
7
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.
12
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.
17
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.
22*/
23
24#include "winbind_client.h"
25
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. */
29
30#define MAX_GETPWENT_USERS 250
31#define MAX_GETGRENT_USERS 250
32
33NSS_STATUS _nss_winbind_setpwent(void);
34NSS_STATUS _nss_winbind_endpwent(void);
35NSS_STATUS _nss_winbind_getpwent_r(struct passwd *result, char *buffer,
36 size_t buflen, int *errnop);
37NSS_STATUS _nss_winbind_getpwuid_r(uid_t uid, struct passwd *result,
38 char *buffer, size_t buflen, int *errnop);
39NSS_STATUS _nss_winbind_getpwnam_r(const char *name, struct passwd *result,
40 char *buffer, size_t buflen, int *errnop);
41NSS_STATUS _nss_winbind_setgrent(void);
42NSS_STATUS _nss_winbind_endgrent(void);
43NSS_STATUS _nss_winbind_getgrent_r(struct group *result, char *buffer,
44 size_t buflen, int *errnop);
45NSS_STATUS _nss_winbind_getgrlst_r(struct group *result, char *buffer,
46 size_t buflen, int *errnop);
47NSS_STATUS _nss_winbind_getgrnam_r(const char *name, struct group *result,
48 char *buffer, size_t buflen, int *errnop);
49NSS_STATUS _nss_winbind_getgrgid_r(gid_t gid, struct group *result, char *buffer,
50 size_t buflen, int *errnop);
51NSS_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);
54NSS_STATUS _nss_winbind_getusersids(const char *user_sid, char **group_sids,
55 int *num_groups, char *buffer, size_t buf_size,
56 int *errnop);
57NSS_STATUS _nss_winbind_nametosid(const char *name, char **sid, char *buffer,
58 size_t buflen, int *errnop);
59NSS_STATUS _nss_winbind_sidtoname(const char *sid, char **name, char *buffer,
60 size_t buflen, int *errnop);
61NSS_STATUS _nss_winbind_sidtouid(const char *sid, uid_t *uid, int *errnop);
62NSS_STATUS _nss_winbind_sidtogid(const char *sid, gid_t *gid, int *errnop);
63NSS_STATUS _nss_winbind_uidtosid(uid_t uid, char **sid, char *buffer,
64 size_t buflen, int *errnop);
65NSS_STATUS _nss_winbind_gidtosid(gid_t gid, char **sid, char *buffer,
66 size_t buflen, int *errnop);
67
68/* Prototypes from wb_common.c */
69
70extern int winbindd_fd;
71
72#ifdef DEBUG_NSS
73static 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!!!!!!!";
87 }
88}
89#endif
90
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. */
94
95static char *get_static(char **buffer, size_t *buflen, size_t len)
96{
97 char *result;
98
99 /* Error check. We return false if things aren't set up right, or
100 there isn't enough buffer space left. */
101
102 if ((buffer == NULL) || (buflen == NULL) || (*buflen < len)) {
103 return NULL;
104 }
105
106 /* Return an index into the static buffer */
107
108 result = *buffer;
109 *buffer += len;
110 *buflen -= len;
111
112 return result;
113}
114
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. */
118
119static BOOL next_token(char **ptr,char *buff,const char *sep, size_t bufsize)
120{
121 char *s;
122 BOOL quoted;
123 size_t len=1;
124
125 if (!ptr) return(False);
126
127 s = *ptr;
128
129 /* default to simple separators */
130 if (!sep) sep = " \t\n\r";
131
132 /* find the first non sep char */
133 while (*s && strchr(sep,*s)) s++;
134
135 /* nothing left? */
136 if (! *s) return(False);
137
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;
145 }
146 }
147
148 *ptr = (*s) ? s+1 : s;
149 *buff = 0;
150
151 return(True);
152}
153
154
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. */
158
159static NSS_STATUS fill_pwent(struct passwd *result,
160 struct winbindd_pw *pw,
161 char **buffer, size_t *buflen)
162{
163 /* User name */
164
165 if ((result->pw_name =
166 get_static(buffer, buflen, strlen(pw->pw_name) + 1)) == NULL) {
167
168 /* Out of memory */
169
170 return NSS_STATUS_TRYAGAIN;
171 }
172
173 strcpy(result->pw_name, pw->pw_name);
174
175 /* Password */
176
177 if ((result->pw_passwd =
178 get_static(buffer, buflen, strlen(pw->pw_passwd) + 1)) == NULL) {
179
180 /* Out of memory */
181
182 return NSS_STATUS_TRYAGAIN;
183 }
184
185 strcpy(result->pw_passwd, pw->pw_passwd);
186
187 /* [ug]id */
188
189 result->pw_uid = pw->pw_uid;
190 result->pw_gid = pw->pw_gid;
191
192 /* GECOS */
193
194 if ((result->pw_gecos =
195 get_static(buffer, buflen, strlen(pw->pw_gecos) + 1)) == NULL) {
196
197 /* Out of memory */
198
199 return NSS_STATUS_TRYAGAIN;
200 }
201
202 strcpy(result->pw_gecos, pw->pw_gecos);
203
204 /* Home directory */
205
206 if ((result->pw_dir =
207 get_static(buffer, buflen, strlen(pw->pw_dir) + 1)) == NULL) {
208
209 /* Out of memory */
210
211 return NSS_STATUS_TRYAGAIN;
212 }
213
214 strcpy(result->pw_dir, pw->pw_dir);
215
216 /* Logon shell */
217
218 if ((result->pw_shell =
219 get_static(buffer, buflen, strlen(pw->pw_shell) + 1)) == NULL) {
220
221 /* Out of memory */
222
223 return NSS_STATUS_TRYAGAIN;
224 }
225
226 strcpy(result->pw_shell, pw->pw_shell);
227
228 /* The struct passwd for Solaris has some extra fields which must
229 be initialised or nscd crashes. */
230
231#if HAVE_PASSWD_PW_COMMENT
232 result->pw_comment = "";
233#endif
234
235#if HAVE_PASSWD_PW_AGE
236 result->pw_age = "";
237#endif
238
239 return NSS_STATUS_SUCCESS;
240}
241
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. */
245
246static NSS_STATUS fill_grent(struct group *result, struct winbindd_gr *gr,
247 char *gr_mem, char **buffer, size_t *buflen)
248{
249 fstring name;
250 int i;
251 char *tst;
252
253 /* Group name */
254
255 if ((result->gr_name =
256 get_static(buffer, buflen, strlen(gr->gr_name) + 1)) == NULL) {
257
258 /* Out of memory */
259
260 return NSS_STATUS_TRYAGAIN;
261 }
262
263 strcpy(result->gr_name, gr->gr_name);
264
265 /* Password */
266
267 if ((result->gr_passwd =
268 get_static(buffer, buflen, strlen(gr->gr_passwd) + 1)) == NULL) {
269
270 /* Out of memory */
271
272 return NSS_STATUS_TRYAGAIN;
273 }
274
275 strcpy(result->gr_passwd, gr->gr_passwd);
276
277 /* gid */
278
279 result->gr_gid = gr->gr_gid;
280
281 /* Group membership */
282
283 if ((gr->num_gr_mem < 0) || !gr_mem) {
284 gr->num_gr_mem = 0;
285 }
286
287 /* this next value is a pointer to a pointer so let's align it */
288
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;
292
293 if ((tst = get_static(buffer, buflen, ((gr->num_gr_mem + 1) *
294 sizeof(char *)+i))) == NULL) {
295
296 /* Out of memory */
297
298 return NSS_STATUS_TRYAGAIN;
299 }
300 result->gr_mem = (char **)(tst + i);
301
302 if (gr->num_gr_mem == 0) {
303
304 /* Group is empty */
305
306 *(result->gr_mem) = NULL;
307 return NSS_STATUS_SUCCESS;
308 }
309
310 /* Start looking at extra data */
311
312 i = 0;
313
314 while(next_token((char **)&gr_mem, name, ",", sizeof(fstring))) {
315
316 /* Allocate space for member */
317
318 if (((result->gr_mem)[i] =
319 get_static(buffer, buflen, strlen(name) + 1)) == NULL) {
320
321 /* Out of memory */
322
323 return NSS_STATUS_TRYAGAIN;
324 }
325
326 strcpy((result->gr_mem)[i], name);
327 i++;
328 }
329
330 /* Terminate list */
331
332 (result->gr_mem)[i] = NULL;
333
334 return NSS_STATUS_SUCCESS;
335}
336
337/*
338 * NSS user functions
339 */
340
341static struct winbindd_response getpwent_response;
342
343static int ndx_pw_cache; /* Current index into pwd cache */
344static int num_pw_cache; /* Current size of pwd cache */
345
346/* Rewind "file pointer" to start of ntdom password database */
347
348NSS_STATUS
349_nss_winbind_setpwent(void)
350{
351 NSS_STATUS ret;
352#ifdef DEBUG_NSS
353 fprintf(stderr, "[%5d]: setpwent\n", getpid());
354#endif
355
356 if (num_pw_cache > 0) {
357 ndx_pw_cache = num_pw_cache = 0;
358 free_response(&getpwent_response);
359 }
360
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;
367}
368
369/* Close ntdom password database "file pointer" */
370
371NSS_STATUS
372_nss_winbind_endpwent(void)
373{
374 NSS_STATUS ret;
375#ifdef DEBUG_NSS
376 fprintf(stderr, "[%5d]: endpwent\n", getpid());
377#endif
378
379 if (num_pw_cache > 0) {
380 ndx_pw_cache = num_pw_cache = 0;
381 free_response(&getpwent_response);
382 }
383
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;
390}
391
392/* Fetch the next password entry from ntdom password database */
393
394NSS_STATUS
395_nss_winbind_getpwent_r(struct passwd *result, char *buffer,
396 size_t buflen, int *errnop)
397{
398 NSS_STATUS ret;
399 struct winbindd_request request;
400 static int called_again;
401
402#ifdef DEBUG_NSS
403 fprintf(stderr, "[%5d]: getpwent\n", getpid());
404#endif
405
406 /* Return an entry from the cache if we have one, or if we are
407 called again because we exceeded our static buffer. */
408
409 if ((ndx_pw_cache < num_pw_cache) || called_again) {
410 goto return_result;
411 }
412
413 /* Else call winbindd to get a bunch of entries */
414
415 if (num_pw_cache > 0) {
416 free_response(&getpwent_response);
417 }
418
419 ZERO_STRUCT(request);
420 ZERO_STRUCT(getpwent_response);
421
422 request.data.num_entries = MAX_GETPWENT_USERS;
423
424 ret = winbindd_request_response(WINBINDD_GETPWENT, &request,
425 &getpwent_response);
426
427 if (ret == NSS_STATUS_SUCCESS) {
428 struct winbindd_pw *pw_cache;
429
430 /* Fill cache */
431
432 ndx_pw_cache = 0;
433 num_pw_cache = getpwent_response.data.num_entries;
434
435 /* Return a result */
436
437 return_result:
438
439 pw_cache = (struct winbindd_pw *)
440 getpwent_response.extra_data.data;
441
442 /* Check data is valid */
443
444 if (pw_cache == NULL) {
445 ret = NSS_STATUS_NOTFOUND;
446 goto done;
447 }
448
449 ret = fill_pwent(result, &pw_cache[ndx_pw_cache],
450 &buffer, &buflen);
451
452 /* Out of memory - try again */
453
454 if (ret == NSS_STATUS_TRYAGAIN) {
455 called_again = True;
456 *errnop = errno = ERANGE;
457 goto done;
458 }
459
460 *errnop = errno = 0;
461 called_again = False;
462 ndx_pw_cache++;
463
464 /* If we've finished with this lot of results free cache */
465
466 if (ndx_pw_cache == num_pw_cache) {
467 ndx_pw_cache = num_pw_cache = 0;
468 free_response(&getpwent_response);
469 }
470 }
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;
477}
478
479/* Return passwd struct from uid */
480
481NSS_STATUS
482_nss_winbind_getpwuid_r(uid_t uid, struct passwd *result, char *buffer,
483 size_t buflen, int *errnop)
484{
485 NSS_STATUS ret;
486 static struct winbindd_response response;
487 struct winbindd_request request;
488 static int keep_response=0;
489
490#ifdef DEBUG_NSS
491 fprintf(stderr, "[%5d]: getpwuid %d\n", getpid(), (unsigned int)uid);
492#endif
493
494 /* If our static buffer needs to be expanded we are called again */
495 if (!keep_response) {
496
497 /* Call for the first time */
498
499 ZERO_STRUCT(response);
500 ZERO_STRUCT(request);
501
502 request.data.uid = uid;
503
504 ret = winbindd_request_response(WINBINDD_GETPWUID, &request, &response);
505
506 if (ret == NSS_STATUS_SUCCESS) {
507 ret = fill_pwent(result, &response.data.pw,
508 &buffer, &buflen);
509
510 if (ret == NSS_STATUS_TRYAGAIN) {
511 keep_response = True;
512 *errnop = errno = ERANGE;
513 goto done;
514 }
515 }
516
517 } else {
518
519 /* We've been called again */
520
521 ret = fill_pwent(result, &response.data.pw, &buffer, &buflen);
522
523 if (ret == NSS_STATUS_TRYAGAIN) {
524 keep_response = True;
525 *errnop = errno = ERANGE;
526 goto done;
527 }
528
529 keep_response = False;
530 *errnop = errno = 0;
531 }
532
533 free_response(&response);
534 done:
535
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;
541}
542
543/* Return passwd struct from username */
544NSS_STATUS
545_nss_winbind_getpwnam_r(const char *name, struct passwd *result, char *buffer,
546 size_t buflen, int *errnop)
547{
548 NSS_STATUS ret;
549 static struct winbindd_response response;
550 struct winbindd_request request;
551 static int keep_response;
552
553#ifdef DEBUG_NSS
554 fprintf(stderr, "[%5d]: getpwnam %s\n", getpid(), name);
555#endif
556
557 /* If our static buffer needs to be expanded we are called again */
558
559 if (!keep_response) {
560
561 /* Call for the first time */
562
563 ZERO_STRUCT(response);
564 ZERO_STRUCT(request);
565
566 strncpy(request.data.username, name,
567 sizeof(request.data.username) - 1);
568 request.data.username
569 [sizeof(request.data.username) - 1] = '\0';
570
571 ret = winbindd_request_response(WINBINDD_GETPWNAM, &request, &response);
572
573 if (ret == NSS_STATUS_SUCCESS) {
574 ret = fill_pwent(result, &response.data.pw, &buffer,
575 &buflen);
576
577 if (ret == NSS_STATUS_TRYAGAIN) {
578 keep_response = True;
579 *errnop = errno = ERANGE;
580 goto done;
581 }
582 }
583
584 } else {
585
586 /* We've been called again */
587
588 ret = fill_pwent(result, &response.data.pw, &buffer, &buflen);
589
590 if (ret == NSS_STATUS_TRYAGAIN) {
591 keep_response = True;
592 *errnop = errno = ERANGE;
593 goto done;
594 }
595
596 keep_response = False;
597 *errnop = errno = 0;
598 }
599
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;
607}
608
609/*
610 * NSS group functions
611 */
612
613static struct winbindd_response getgrent_response;
614
615static int ndx_gr_cache; /* Current index into grp cache */
616static int num_gr_cache; /* Current size of grp cache */
617
618/* Rewind "file pointer" to start of ntdom group database */
619
620NSS_STATUS
621_nss_winbind_setgrent(void)
622{
623 NSS_STATUS ret;
624#ifdef DEBUG_NSS
625 fprintf(stderr, "[%5d]: setgrent\n", getpid());
626#endif
627
628 if (num_gr_cache > 0) {
629 ndx_gr_cache = num_gr_cache = 0;
630 free_response(&getgrent_response);
631 }
632
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;
639}
640
641/* Close "file pointer" for ntdom group database */
642
643NSS_STATUS
644_nss_winbind_endgrent(void)
645{
646 NSS_STATUS ret;
647#ifdef DEBUG_NSS
648 fprintf(stderr, "[%5d]: endgrent\n", getpid());
649#endif
650
651 if (num_gr_cache > 0) {
652 ndx_gr_cache = num_gr_cache = 0;
653 free_response(&getgrent_response);
654 }
655
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;
662}
663
664/* Get next entry from ntdom group database */
665
666static NSS_STATUS
667winbind_getgrent(enum winbindd_cmd cmd,
668 struct group *result,
669 char *buffer, size_t buflen, int *errnop)
670{
671 NSS_STATUS ret;
672 static struct winbindd_request request;
673 static int called_again;
674
675
676#ifdef DEBUG_NSS
677 fprintf(stderr, "[%5d]: getgrent\n", getpid());
678#endif
679
680 /* Return an entry from the cache if we have one, or if we are
681 called again because we exceeded our static buffer. */
682
683 if ((ndx_gr_cache < num_gr_cache) || called_again) {
684 goto return_result;
685 }
686
687 /* Else call winbindd to get a bunch of entries */
688
689 if (num_gr_cache > 0) {
690 free_response(&getgrent_response);
691 }
692
693 ZERO_STRUCT(request);
694 ZERO_STRUCT(getgrent_response);
695
696 request.data.num_entries = MAX_GETGRENT_USERS;
697
698 ret = winbindd_request_response(cmd, &request,
699 &getgrent_response);
700
701 if (ret == NSS_STATUS_SUCCESS) {
702 struct winbindd_gr *gr_cache;
703 int mem_ofs;
704
705 /* Fill cache */
706
707 ndx_gr_cache = 0;
708 num_gr_cache = getgrent_response.data.num_entries;
709
710 /* Return a result */
711
712 return_result:
713
714 gr_cache = (struct winbindd_gr *)
715 getgrent_response.extra_data.data;
716
717 /* Check data is valid */
718
719 if (gr_cache == NULL) {
720 ret = NSS_STATUS_NOTFOUND;
721 goto done;
722 }
723
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. */
727
728 mem_ofs = gr_cache[ndx_gr_cache].gr_mem_ofs +
729 num_gr_cache * sizeof(struct winbindd_gr);
730
731 ret = fill_grent(result, &gr_cache[ndx_gr_cache],
732 ((char *)getgrent_response.extra_data.data)+mem_ofs,
733 &buffer, &buflen);
734
735 /* Out of memory - try again */
736
737 if (ret == NSS_STATUS_TRYAGAIN) {
738 called_again = True;
739 *errnop = errno = ERANGE;
740 goto done;
741 }
742
743 *errnop = 0;
744 called_again = False;
745 ndx_gr_cache++;
746
747 /* If we've finished with this lot of results free cache */
748
749 if (ndx_gr_cache == num_gr_cache) {
750 ndx_gr_cache = num_gr_cache = 0;
751 free_response(&getgrent_response);
752 }
753 }
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;
760}
761
762
763NSS_STATUS
764_nss_winbind_getgrent_r(struct group *result,
765 char *buffer, size_t buflen, int *errnop)
766{
767 return winbind_getgrent(WINBINDD_GETGRENT, result, buffer, buflen, errnop);
768}
769
770NSS_STATUS
771_nss_winbind_getgrlst_r(struct group *result,
772 char *buffer, size_t buflen, int *errnop)
773{
774 return winbind_getgrent(WINBINDD_GETGRLST, result, buffer, buflen, errnop);
775}
776
777/* Return group struct from group name */
778
779NSS_STATUS
780_nss_winbind_getgrnam_r(const char *name,
781 struct group *result, char *buffer,
782 size_t buflen, int *errnop)
783{
784 NSS_STATUS ret;
785 static struct winbindd_response response;
786 struct winbindd_request request;
787 static int keep_response;
788
789#ifdef DEBUG_NSS
790 fprintf(stderr, "[%5d]: getgrnam %s\n", getpid(), name);
791#endif
792
793 /* If our static buffer needs to be expanded we are called again */
794
795 if (!keep_response) {
796
797 /* Call for the first time */
798
799 ZERO_STRUCT(request);
800 ZERO_STRUCT(response);
801
802 strncpy(request.data.groupname, name,
803 sizeof(request.data.groupname));
804 request.data.groupname
805 [sizeof(request.data.groupname) - 1] = '\0';
806
807 ret = winbindd_request_response(WINBINDD_GETGRNAM, &request, &response);
808
809 if (ret == NSS_STATUS_SUCCESS) {
810 ret = fill_grent(result, &response.data.gr,
811 (char *)response.extra_data.data,
812 &buffer, &buflen);
813
814 if (ret == NSS_STATUS_TRYAGAIN) {
815 keep_response = True;
816 *errnop = errno = ERANGE;
817 goto done;
818 }
819 }
820
821 } else {
822
823 /* We've been called again */
824
825 ret = fill_grent(result, &response.data.gr,
826 (char *)response.extra_data.data, &buffer,
827 &buflen);
828
829 if (ret == NSS_STATUS_TRYAGAIN) {
830 keep_response = True;
831 *errnop = errno = ERANGE;
832 goto done;
833 }
834
835 keep_response = False;
836 *errnop = 0;
837 }
838
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;
846}
847
848/* Return group struct from gid */
849
850NSS_STATUS
851_nss_winbind_getgrgid_r(gid_t gid,
852 struct group *result, char *buffer,
853 size_t buflen, int *errnop)
854{
855 NSS_STATUS ret;
856 static struct winbindd_response response;
857 struct winbindd_request request;
858 static int keep_response;
859
860#ifdef DEBUG_NSS
861 fprintf(stderr, "[%5d]: getgrgid %d\n", getpid(), gid);
862#endif
863
864 /* If our static buffer needs to be expanded we are called again */
865
866 if (!keep_response) {
867
868 /* Call for the first time */
869
870 ZERO_STRUCT(request);
871 ZERO_STRUCT(response);
872
873 request.data.gid = gid;
874
875 ret = winbindd_request_response(WINBINDD_GETGRGID, &request, &response);
876
877 if (ret == NSS_STATUS_SUCCESS) {
878
879 ret = fill_grent(result, &response.data.gr,
880 (char *)response.extra_data.data,
881 &buffer, &buflen);
882
883 if (ret == NSS_STATUS_TRYAGAIN) {
884 keep_response = True;
885 *errnop = errno = ERANGE;
886 goto done;
887 }
888 }
889
890 } else {
891
892 /* We've been called again */
893
894 ret = fill_grent(result, &response.data.gr,
895 (char *)response.extra_data.data, &buffer,
896 &buflen);
897
898 if (ret == NSS_STATUS_TRYAGAIN) {
899 keep_response = True;
900 *errnop = errno = ERANGE;
901 goto done;
902 }
903
904 keep_response = False;
905 *errnop = 0;
906 }
907
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;
915}
916
917/* Initialise supplementary groups */
918
919NSS_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)
923{
924 NSS_STATUS ret;
925 struct winbindd_request request;
926 struct winbindd_response response;
927 int i;
928
929#ifdef DEBUG_NSS
930 fprintf(stderr, "[%5d]: initgroups %s (%d)\n", getpid(),
931 user, group);
932#endif
933
934 ZERO_STRUCT(request);
935 ZERO_STRUCT(response);
936
937 strncpy(request.data.username, user,
938 sizeof(request.data.username) - 1);
939
940 ret = winbindd_request_response(WINBINDD_GETGROUPS, &request, &response);
941
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;
945
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;
954 }
955
956 /* Copy group list to client */
957
958 for (i = 0; i < num_gids; i++) {
959
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
965
966 /* Skip primary group */
967
968 if (gid_list[i] == group) {
969 continue;
970 }
971
972 /* Filled buffer ? If so, resize. */
973
974 if (*start == *size) {
975 long int newsize;
976 gid_t *newgroups;
977
978 newsize = 2 * (*size);
979 if (limit > 0) {
980 if (*size == limit) {
981 goto done;
982 }
983 if (newsize > limit) {
984 newsize = limit;
985 }
986 }
987
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;
995 }
996 *groups = newgroups;
997 *size = newsize;
998 }
999
1000 /* Add to buffer */
1001
1002 (*groups)[*start] = gid_list[i];
1003 *start += 1;
1004 }
1005 }
1006
1007 /* Back to your regularly scheduled programming */
1008
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;
1015}
1016
1017
1018/* return a list of group SIDs for a user SID */
1019NSS_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)
1023{
1024 NSS_STATUS ret;
1025 struct winbindd_request request;
1026 struct winbindd_response response;
1027
1028#ifdef DEBUG_NSS
1029 fprintf(stderr, "[%5d]: getusersids %s\n", getpid(), user_sid);
1030#endif
1031
1032 ZERO_STRUCT(request);
1033 ZERO_STRUCT(response);
1034
1035 strncpy(request.data.sid, user_sid,sizeof(request.data.sid) - 1);
1036 request.data.sid[sizeof(request.data.sid) - 1] = '\0';
1037
1038 ret = winbindd_request_response(WINBINDD_GETUSERSIDS, &request, &response);
1039
1040 if (ret != NSS_STATUS_SUCCESS) {
1041 goto done;
1042 }
1043
1044 if (buf_size < response.length - sizeof(response)) {
1045 ret = NSS_STATUS_TRYAGAIN;
1046 errno = *errnop = ERANGE;
1047 goto done;
1048 }
1049
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;
1054
1055 done:
1056 free_response(&response);
1057 return ret;
1058}
1059
1060
1061/* map a user or group name to a SID string */
1062NSS_STATUS
1063_nss_winbind_nametosid(const char *name, char **sid, char *buffer,
1064 size_t buflen, int *errnop)
1065{
1066 NSS_STATUS ret;
1067 struct winbindd_response response;
1068 struct winbindd_request request;
1069
1070#ifdef DEBUG_NSS
1071 fprintf(stderr, "[%5d]: nametosid %s\n", getpid(), name);
1072#endif
1073
1074 ZERO_STRUCT(response);
1075 ZERO_STRUCT(request);
1076
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';
1080
1081 ret = winbindd_request_response(WINBINDD_LOOKUPNAME, &request, &response);
1082 if (ret != NSS_STATUS_SUCCESS) {
1083 *errnop = errno = EINVAL;
1084 goto failed;
1085 }
1086
1087 if (buflen < strlen(response.data.sid.sid)+1) {
1088 ret = NSS_STATUS_TRYAGAIN;
1089 *errnop = errno = ERANGE;
1090 goto failed;
1091 }
1092
1093 *errnop = errno = 0;
1094 *sid = buffer;
1095 strcpy(*sid, response.data.sid.sid);
1096
1097failed:
1098 free_response(&response);
1099 return ret;
1100}
1101
1102/* map a sid string to a user or group name */
1103NSS_STATUS
1104_nss_winbind_sidtoname(const char *sid, char **name, char *buffer,
1105 size_t buflen, int *errnop)
1106{
1107 NSS_STATUS ret;
1108 struct winbindd_response response;
1109 struct winbindd_request request;
1110 static char sep_char;
1111 unsigned needed;
1112
1113#ifdef DEBUG_NSS
1114 fprintf(stderr, "[%5d]: sidtoname %s\n", getpid(), sid);
1115#endif
1116
1117 ZERO_STRUCT(response);
1118 ZERO_STRUCT(request);
1119
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;
1126 }
1127
1128 sep_char = response.data.info.winbind_separator;
1129 free_response(&response);
1130 }
1131
1132
1133 strncpy(request.data.sid, sid,
1134 sizeof(request.data.sid) - 1);
1135 request.data.sid[sizeof(request.data.sid) - 1] = '\0';
1136
1137 ret = winbindd_request_response(WINBINDD_LOOKUPSID, &request, &response);
1138 if (ret != NSS_STATUS_SUCCESS) {
1139 *errnop = errno = EINVAL;
1140 goto failed;
1141 }
1142
1143 needed =
1144 strlen(response.data.name.dom_name) +
1145 strlen(response.data.name.name) + 2;
1146
1147 if (buflen < needed) {
1148 ret = NSS_STATUS_TRYAGAIN;
1149 *errnop = errno = ERANGE;
1150 goto failed;
1151 }
1152
1153 snprintf(buffer, needed, "%s%c%s",
1154 response.data.name.dom_name,
1155 sep_char,
1156 response.data.name.name);
1157
1158 *name = buffer;
1159 *errnop = errno = 0;
1160
1161failed:
1162 free_response(&response);
1163 return ret;
1164}
1165
1166/* map a sid to a uid */
1167NSS_STATUS
1168_nss_winbind_sidtouid(const char *sid, uid_t *uid, int *errnop)
1169{
1170 NSS_STATUS ret;
1171 struct winbindd_response response;
1172 struct winbindd_request request;
1173
1174#ifdef DEBUG_NSS
1175 fprintf(stderr, "[%5d]: sidtouid %s\n", getpid(), sid);
1176#endif
1177
1178 ZERO_STRUCT(request);
1179 ZERO_STRUCT(response);
1180
1181 strncpy(request.data.sid, sid, sizeof(request.data.sid) - 1);
1182 request.data.sid[sizeof(request.data.sid) - 1] = '\0';
1183
1184 ret = winbindd_request_response(WINBINDD_SID_TO_UID, &request, &response);
1185 if (ret != NSS_STATUS_SUCCESS) {
1186 *errnop = errno = EINVAL;
1187 goto failed;
1188 }
1189
1190 *uid = response.data.uid;
1191
1192failed:
1193 return ret;
1194}
1195
1196/* map a sid to a gid */
1197NSS_STATUS
1198_nss_winbind_sidtogid(const char *sid, gid_t *gid, int *errnop)
1199{
1200 NSS_STATUS ret;
1201 struct winbindd_response response;
1202 struct winbindd_request request;
1203
1204#ifdef DEBUG_NSS
1205 fprintf(stderr, "[%5d]: sidtogid %s\n", getpid(), sid);
1206#endif
1207
1208 ZERO_STRUCT(request);
1209 ZERO_STRUCT(response);
1210
1211 strncpy(request.data.sid, sid, sizeof(request.data.sid) - 1);
1212 request.data.sid[sizeof(request.data.sid) - 1] = '\0';
1213
1214 ret = winbindd_request_response(WINBINDD_SID_TO_GID, &request, &response);
1215 if (ret != NSS_STATUS_SUCCESS) {
1216 *errnop = errno = EINVAL;
1217 goto failed;
1218 }
1219
1220 *gid = response.data.gid;
1221
1222failed:
1223 return ret;
1224}
1225
1226/* map a uid to a SID string */
1227NSS_STATUS
1228_nss_winbind_uidtosid(uid_t uid, char **sid, char *buffer,
1229 size_t buflen, int *errnop)
1230{
1231 NSS_STATUS ret;
1232 struct winbindd_response response;
1233 struct winbindd_request request;
1234
1235#ifdef DEBUG_NSS
1236 fprintf(stderr, "[%5u]: uidtosid %u\n", (unsigned int)getpid(), (unsigned int)uid);
1237#endif
1238
1239 ZERO_STRUCT(response);
1240 ZERO_STRUCT(request);
1241
1242 request.data.uid = uid;
1243
1244 ret = winbindd_request_response(WINBINDD_UID_TO_SID, &request, &response);
1245 if (ret != NSS_STATUS_SUCCESS) {
1246 *errnop = errno = EINVAL;
1247 goto failed;
1248 }
1249
1250 if (buflen < strlen(response.data.sid.sid)+1) {
1251 ret = NSS_STATUS_TRYAGAIN;
1252 *errnop = errno = ERANGE;
1253 goto failed;
1254 }
1255
1256 *errnop = errno = 0;
1257 *sid = buffer;
1258 strcpy(*sid, response.data.sid.sid);
1259
1260failed:
1261 free_response(&response);
1262 return ret;
1263}
1264
1265/* map a gid to a SID string */
1266NSS_STATUS
1267_nss_winbind_gidtosid(gid_t gid, char **sid, char *buffer,
1268 size_t buflen, int *errnop)
1269{
1270 NSS_STATUS ret;
1271 struct winbindd_response response;
1272 struct winbindd_request request;
1273
1274#ifdef DEBUG_NSS
1275 fprintf(stderr, "[%5u]: gidtosid %u\n", (unsigned int)getpid(), (unsigned int)gid);
1276#endif
1277
1278 ZERO_STRUCT(response);
1279 ZERO_STRUCT(request);
1280
1281 request.data.gid = gid;
1282
1283 ret = winbindd_request_response(WINBINDD_GID_TO_SID, &request, &response);
1284 if (ret != NSS_STATUS_SUCCESS) {
1285 *errnop = errno = EINVAL;
1286 goto failed;
1287 }
1288
1289 if (buflen < strlen(response.data.sid.sid)+1) {
1290 ret = NSS_STATUS_TRYAGAIN;
1291 *errnop = errno = ERANGE;
1292 goto failed;
1293 }
1294
1295 *errnop = errno = 0;
1296 *sid = buffer;
1297 strcpy(*sid, response.data.sid.sid);
1298
1299failed:
1300 free_response(&response);
1301 return ret;
1302}
Note: See TracBrowser for help on using the repository browser.