Line data Source code
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 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.
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 Lesser General Public License
19 : along with this program. If not, see <http://www.gnu.org/licenses/>.
20 : */
21 :
22 : #include "winbind_client.h"
23 :
24 : #ifdef HAVE_PTHREAD_H
25 : #include <pthread.h>
26 : #endif
27 :
28 : #ifdef HAVE_PTHREAD
29 : static pthread_mutex_t winbind_nss_mutex = PTHREAD_MUTEX_INITIALIZER;
30 : #endif
31 :
32 : /* Maximum number of users to pass back over the unix domain socket
33 : per call. This is not a static limit on the total number of users
34 : or groups returned in total. */
35 :
36 : #define MAX_GETPWENT_USERS 250
37 : #define MAX_GETGRENT_USERS 250
38 :
39 : /*************************************************************************
40 : ************************************************************************/
41 :
42 : #ifdef DEBUG_NSS
43 : static const char *nss_err_str(NSS_STATUS ret)
44 : {
45 : switch (ret) {
46 : case NSS_STATUS_TRYAGAIN:
47 : return "NSS_STATUS_TRYAGAIN";
48 : case NSS_STATUS_SUCCESS:
49 : return "NSS_STATUS_SUCCESS";
50 : case NSS_STATUS_NOTFOUND:
51 : return "NSS_STATUS_NOTFOUND";
52 : case NSS_STATUS_UNAVAIL:
53 : return "NSS_STATUS_UNAVAIL";
54 : #ifdef NSS_STATUS_RETURN
55 : case NSS_STATUS_RETURN:
56 : return "NSS_STATUS_RETURN";
57 : #endif
58 : default:
59 : return "UNKNOWN RETURN CODE!!!!!!!";
60 : }
61 : }
62 : #endif
63 :
64 : /* Prototypes from wb_common.c */
65 :
66 : /* Allocate some space from the nss static buffer. The buffer and buflen
67 : are the pointers passed in by the C library to the _nss_ntdom_*
68 : functions. */
69 :
70 40846 : static char *get_static(char **buffer, size_t *buflen, size_t len)
71 : {
72 : char *result;
73 :
74 : /* Error check. We return false if things aren't set up right, or
75 : there isn't enough buffer space left. */
76 :
77 40846 : if ((buffer == NULL) || (buflen == NULL) || (*buflen < len)) {
78 0 : return NULL;
79 : }
80 :
81 : /* Return an index into the static buffer */
82 :
83 40846 : result = *buffer;
84 40846 : *buffer += len;
85 40846 : *buflen -= len;
86 :
87 40846 : return result;
88 : }
89 :
90 : /* I've copied the strtok() replacement function next_token_Xalloc() from
91 : lib/util_str.c as I really don't want to have to link in any other
92 : objects if I can possibly avoid it. */
93 :
94 16 : static bool next_token_alloc(const char **ptr,
95 : char **pp_buff,
96 : const char *sep)
97 : {
98 : const char *s;
99 : const char *saved_s;
100 : char *pbuf;
101 : bool quoted;
102 16 : size_t len=1;
103 :
104 16 : *pp_buff = NULL;
105 16 : if (!ptr) {
106 0 : return(false);
107 : }
108 :
109 16 : s = *ptr;
110 :
111 : /* default to simple separators */
112 16 : if (!sep) {
113 0 : sep = " \t\n\r";
114 : }
115 :
116 : /* find the first non sep char */
117 24 : while (*s && strchr(sep,*s)) {
118 0 : s++;
119 : }
120 :
121 : /* nothing left? */
122 16 : if (!*s) {
123 8 : return false;
124 : }
125 :
126 : /* When restarting we need to go from here. */
127 8 : saved_s = s;
128 :
129 : /* Work out the length needed. */
130 188 : for (quoted = false; *s &&
131 352 : (quoted || !strchr(sep,*s)); s++) {
132 176 : if (*s == '\"') {
133 0 : quoted = !quoted;
134 : } else {
135 176 : len++;
136 : }
137 : }
138 :
139 : /* We started with len = 1 so we have space for the nul. */
140 8 : *pp_buff = (char *)malloc(len);
141 8 : if (!*pp_buff) {
142 0 : return false;
143 : }
144 :
145 : /* copy over the token */
146 8 : pbuf = *pp_buff;
147 8 : s = saved_s;
148 188 : for (quoted = false; *s &&
149 352 : (quoted || !strchr(sep,*s)); s++) {
150 176 : if ( *s == '\"' ) {
151 0 : quoted = !quoted;
152 : } else {
153 176 : *pbuf++ = *s;
154 : }
155 : }
156 :
157 8 : *ptr = (*s) ? s+1 : s;
158 8 : *pbuf = 0;
159 :
160 8 : return true;
161 : }
162 :
163 : /* Fill a pwent structure from a winbindd_response structure. We use
164 : the static data passed to us by libc to put strings and stuff in.
165 : Return NSS_STATUS_TRYAGAIN if we run out of memory. */
166 :
167 6274 : static NSS_STATUS fill_pwent(struct passwd *result,
168 : struct winbindd_pw *pw,
169 : char **buffer, size_t *buflen)
170 : {
171 : size_t len;
172 :
173 : /* User name */
174 6274 : len = strlen(pw->pw_name) + 1;
175 :
176 6274 : if ((result->pw_name =
177 6274 : get_static(buffer, buflen, len)) == NULL) {
178 :
179 : /* Out of memory */
180 :
181 0 : return NSS_STATUS_TRYAGAIN;
182 : }
183 :
184 6274 : memcpy(result->pw_name, pw->pw_name, len);
185 :
186 : /* Password */
187 6274 : len = strlen(pw->pw_passwd) + 1;
188 :
189 6274 : if ((result->pw_passwd =
190 6274 : get_static(buffer, buflen, len)) == NULL) {
191 :
192 : /* Out of memory */
193 :
194 0 : return NSS_STATUS_TRYAGAIN;
195 : }
196 :
197 6274 : memcpy(result->pw_passwd, pw->pw_passwd, len);
198 :
199 : /* [ug]id */
200 :
201 6274 : result->pw_uid = pw->pw_uid;
202 6274 : result->pw_gid = pw->pw_gid;
203 :
204 : /* GECOS */
205 6274 : len = strlen(pw->pw_gecos) + 1;
206 :
207 6274 : if ((result->pw_gecos =
208 6274 : get_static(buffer, buflen, len)) == NULL) {
209 :
210 : /* Out of memory */
211 :
212 0 : return NSS_STATUS_TRYAGAIN;
213 : }
214 :
215 6274 : memcpy(result->pw_gecos, pw->pw_gecos, len);
216 :
217 : /* Home directory */
218 6274 : len = strlen(pw->pw_dir) + 1;
219 :
220 6274 : if ((result->pw_dir =
221 6274 : get_static(buffer, buflen, len)) == NULL) {
222 :
223 : /* Out of memory */
224 :
225 0 : return NSS_STATUS_TRYAGAIN;
226 : }
227 :
228 6274 : memcpy(result->pw_dir, pw->pw_dir, len);
229 :
230 : /* Logon shell */
231 6274 : len = strlen(pw->pw_shell) + 1;
232 :
233 6274 : if ((result->pw_shell =
234 6274 : get_static(buffer, buflen, len)) == NULL) {
235 :
236 : /* Out of memory */
237 :
238 0 : return NSS_STATUS_TRYAGAIN;
239 : }
240 :
241 6274 : memcpy(result->pw_shell, pw->pw_shell, len);
242 :
243 : /* The struct passwd for Solaris has some extra fields which must
244 : be initialised or nscd crashes. */
245 :
246 : #ifdef HAVE_PASSWD_PW_COMMENT
247 : result->pw_comment = "";
248 : #endif
249 :
250 : #ifdef HAVE_PASSWD_PW_AGE
251 : result->pw_age = "";
252 : #endif
253 :
254 6274 : return NSS_STATUS_SUCCESS;
255 : }
256 :
257 : /* Fill a grent structure from a winbindd_response structure. We use
258 : the static data passed to us by libc to put strings and stuff in.
259 : Return NSS_STATUS_TRYAGAIN if we run out of memory. */
260 :
261 3156 : static NSS_STATUS fill_grent(struct group *result, struct winbindd_gr *gr,
262 : const char *gr_mem, char **buffer, size_t *buflen)
263 : {
264 : char *name;
265 : int i;
266 : char *tst;
267 : size_t len;
268 :
269 : /* Group name */
270 3156 : len = strlen(gr->gr_name) + 1;
271 :
272 3156 : if ((result->gr_name =
273 3156 : get_static(buffer, buflen, len)) == NULL) {
274 :
275 : /* Out of memory */
276 :
277 0 : return NSS_STATUS_TRYAGAIN;
278 : }
279 :
280 3156 : memcpy(result->gr_name, gr->gr_name, len);
281 :
282 : /* Password */
283 3156 : len = strlen(gr->gr_passwd) + 1;
284 :
285 3156 : if ((result->gr_passwd =
286 3156 : get_static(buffer, buflen, len)) == NULL) {
287 :
288 : /* Out of memory */
289 0 : return NSS_STATUS_TRYAGAIN;
290 : }
291 :
292 3156 : memcpy(result->gr_passwd, gr->gr_passwd, len);
293 :
294 : /* gid */
295 :
296 3156 : result->gr_gid = gr->gr_gid;
297 :
298 : /* Group membership */
299 :
300 3156 : if (!gr_mem) {
301 520 : gr->num_gr_mem = 0;
302 : }
303 :
304 : /* this next value is a pointer to a pointer so let's align it */
305 :
306 : /* Calculate number of extra bytes needed to align on pointer size boundry */
307 3156 : if ((i = (unsigned long)(*buffer) % sizeof(char*)) != 0)
308 2740 : i = sizeof(char*) - i;
309 :
310 3156 : if ((tst = get_static(buffer, buflen, ((gr->num_gr_mem + 1) *
311 : sizeof(char *)+i))) == NULL) {
312 :
313 : /* Out of memory */
314 :
315 0 : return NSS_STATUS_TRYAGAIN;
316 : }
317 3156 : result->gr_mem = (char **)(tst + i);
318 :
319 3156 : if (gr->num_gr_mem == 0) {
320 :
321 : /* Group is empty */
322 :
323 3148 : *(result->gr_mem) = NULL;
324 3148 : return NSS_STATUS_SUCCESS;
325 : }
326 :
327 : /* Start looking at extra data */
328 :
329 8 : i = 0;
330 :
331 20 : while(next_token_alloc((const char **)&gr_mem, &name, ",")) {
332 : /* Allocate space for member */
333 8 : len = strlen(name) + 1;
334 :
335 12 : if (((result->gr_mem)[i] =
336 8 : get_static(buffer, buflen, len)) == NULL) {
337 0 : free(name);
338 : /* Out of memory */
339 0 : return NSS_STATUS_TRYAGAIN;
340 : }
341 8 : memcpy((result->gr_mem)[i], name, len);
342 8 : free(name);
343 8 : i++;
344 : }
345 :
346 : /* Terminate list */
347 :
348 8 : (result->gr_mem)[i] = NULL;
349 :
350 8 : return NSS_STATUS_SUCCESS;
351 : }
352 :
353 : /*
354 : * NSS user functions
355 : */
356 :
357 : static struct winbindd_response getpwent_response;
358 :
359 : static int ndx_pw_cache; /* Current index into pwd cache */
360 : static int num_pw_cache; /* Current size of pwd cache */
361 :
362 : /* Rewind "file pointer" to start of ntdom password database */
363 :
364 : _PUBLIC_ON_LINUX_
365 : NSS_STATUS
366 14 : _nss_winbind_setpwent(void)
367 : {
368 : NSS_STATUS ret;
369 : #ifdef DEBUG_NSS
370 : fprintf(stderr, "[%5d]: setpwent\n", getpid());
371 : #endif
372 :
373 : #ifdef HAVE_PTHREAD
374 14 : pthread_mutex_lock(&winbind_nss_mutex);
375 : #endif
376 :
377 14 : if (num_pw_cache > 0) {
378 0 : ndx_pw_cache = num_pw_cache = 0;
379 0 : winbindd_free_response(&getpwent_response);
380 : }
381 :
382 14 : winbind_set_client_name("nss_winbind");
383 14 : ret = winbindd_request_response(NULL, WINBINDD_SETPWENT, NULL, NULL);
384 : #ifdef DEBUG_NSS
385 : fprintf(stderr, "[%5d]: setpwent returns %s (%d)\n", getpid(),
386 : nss_err_str(ret), ret);
387 : #endif
388 :
389 : #ifdef HAVE_PTHREAD
390 14 : pthread_mutex_unlock(&winbind_nss_mutex);
391 : #endif
392 14 : return ret;
393 : }
394 :
395 : /* Close ntdom password database "file pointer" */
396 :
397 : _PUBLIC_ON_LINUX_
398 : NSS_STATUS
399 3676 : _nss_winbind_endpwent(void)
400 : {
401 : NSS_STATUS ret;
402 : #ifdef DEBUG_NSS
403 : fprintf(stderr, "[%5d]: endpwent\n", getpid());
404 : #endif
405 :
406 : #ifdef HAVE_PTHREAD
407 3676 : pthread_mutex_lock(&winbind_nss_mutex);
408 : #endif
409 :
410 3676 : if (num_pw_cache > 0) {
411 0 : ndx_pw_cache = num_pw_cache = 0;
412 0 : winbindd_free_response(&getpwent_response);
413 : }
414 :
415 3676 : winbind_set_client_name("nss_winbind");
416 3676 : ret = winbindd_request_response(NULL, WINBINDD_ENDPWENT, NULL, NULL);
417 : #ifdef DEBUG_NSS
418 : fprintf(stderr, "[%5d]: endpwent returns %s (%d)\n", getpid(),
419 : nss_err_str(ret), ret);
420 : #endif
421 :
422 : #ifdef HAVE_PTHREAD
423 3676 : pthread_mutex_unlock(&winbind_nss_mutex);
424 : #endif
425 :
426 3676 : return ret;
427 : }
428 :
429 : /* Fetch the next password entry from ntdom password database */
430 :
431 : _PUBLIC_ON_LINUX_
432 : NSS_STATUS
433 194 : _nss_winbind_getpwent_r(struct passwd *result, char *buffer,
434 : size_t buflen, int *errnop)
435 : {
436 : NSS_STATUS ret;
437 : struct winbindd_request request;
438 : static int called_again;
439 :
440 : #ifdef DEBUG_NSS
441 : fprintf(stderr, "[%5d]: getpwent\n", getpid());
442 : #endif
443 :
444 : #ifdef HAVE_PTHREAD
445 194 : pthread_mutex_lock(&winbind_nss_mutex);
446 : #endif
447 :
448 : /* Return an entry from the cache if we have one, or if we are
449 : called again because we exceeded our static buffer. */
450 :
451 208 : if ((ndx_pw_cache < num_pw_cache) || called_again) {
452 83 : goto return_result;
453 : }
454 :
455 : /* Else call winbindd to get a bunch of entries */
456 :
457 28 : if (num_pw_cache > 0) {
458 0 : winbindd_free_response(&getpwent_response);
459 : }
460 :
461 28 : ZERO_STRUCT(request);
462 28 : ZERO_STRUCT(getpwent_response);
463 :
464 28 : request.data.num_entries = MAX_GETPWENT_USERS;
465 :
466 28 : winbind_set_client_name("nss_winbind");
467 28 : ret = winbindd_request_response(NULL, WINBINDD_GETPWENT, &request,
468 : &getpwent_response);
469 :
470 28 : if (ret == NSS_STATUS_SUCCESS) {
471 : struct winbindd_pw *pw_cache;
472 :
473 : /* Fill cache */
474 :
475 14 : ndx_pw_cache = 0;
476 14 : num_pw_cache = getpwent_response.data.num_entries;
477 :
478 : /* Return a result */
479 :
480 263 : return_result:
481 :
482 180 : pw_cache = (struct winbindd_pw *)
483 : getpwent_response.extra_data.data;
484 :
485 : /* Check data is valid */
486 :
487 180 : if (pw_cache == NULL) {
488 0 : ret = NSS_STATUS_NOTFOUND;
489 0 : goto done;
490 : }
491 :
492 180 : ret = fill_pwent(result, &pw_cache[ndx_pw_cache],
493 : &buffer, &buflen);
494 :
495 : /* Out of memory - try again */
496 :
497 180 : if (ret == NSS_STATUS_TRYAGAIN) {
498 0 : called_again = true;
499 0 : *errnop = errno = ERANGE;
500 0 : goto done;
501 : }
502 :
503 180 : *errnop = errno = 0;
504 180 : called_again = false;
505 180 : ndx_pw_cache++;
506 :
507 : /* If we've finished with this lot of results free cache */
508 :
509 180 : if (ndx_pw_cache == num_pw_cache) {
510 14 : ndx_pw_cache = num_pw_cache = 0;
511 14 : winbindd_free_response(&getpwent_response);
512 : }
513 : }
514 277 : done:
515 : #ifdef DEBUG_NSS
516 : fprintf(stderr, "[%5d]: getpwent returns %s (%d)\n", getpid(),
517 : nss_err_str(ret), ret);
518 : #endif
519 :
520 : #ifdef HAVE_PTHREAD
521 194 : pthread_mutex_unlock(&winbind_nss_mutex);
522 : #endif
523 194 : return ret;
524 : }
525 :
526 : /* Return passwd struct from uid */
527 :
528 : _PUBLIC_ON_LINUX_
529 : NSS_STATUS
530 2613 : _nss_winbind_getpwuid_r(uid_t uid, struct passwd *result, char *buffer,
531 : size_t buflen, int *errnop)
532 : {
533 : NSS_STATUS ret;
534 : static struct winbindd_response response;
535 : struct winbindd_request request;
536 : static int keep_response;
537 :
538 : #ifdef DEBUG_NSS
539 : fprintf(stderr, "[%5d]: getpwuid_r %d\n", getpid(), (unsigned int)uid);
540 : #endif
541 :
542 : #ifdef HAVE_PTHREAD
543 2613 : pthread_mutex_lock(&winbind_nss_mutex);
544 : #endif
545 :
546 : /* If our static buffer needs to be expanded we are called again */
547 3137 : if (!keep_response || uid != response.data.pw.pw_uid) {
548 :
549 : /* Call for the first time */
550 :
551 2613 : response = (struct winbindd_response) {
552 : .length = 0,
553 : };
554 2613 : request = (struct winbindd_request) {
555 : .wb_flags = WBFLAG_FROM_NSS,
556 : .data = {
557 : .uid = uid,
558 : },
559 : };
560 :
561 2613 : winbind_set_client_name("nss_winbind");
562 2613 : ret = winbindd_request_response(NULL, WINBINDD_GETPWUID, &request, &response);
563 :
564 4702 : if (ret == NSS_STATUS_SUCCESS) {
565 937 : ret = fill_pwent(result, &response.data.pw,
566 : &buffer, &buflen);
567 :
568 937 : if (ret == NSS_STATUS_TRYAGAIN) {
569 0 : keep_response = true;
570 0 : *errnop = errno = ERANGE;
571 0 : goto done;
572 : }
573 : }
574 :
575 : } else {
576 :
577 : /* We've been called again */
578 :
579 0 : ret = fill_pwent(result, &response.data.pw, &buffer, &buflen);
580 :
581 0 : if (ret == NSS_STATUS_TRYAGAIN) {
582 0 : *errnop = errno = ERANGE;
583 0 : goto done;
584 : }
585 :
586 0 : keep_response = false;
587 0 : *errnop = errno = 0;
588 : }
589 :
590 2613 : winbindd_free_response(&response);
591 :
592 2613 : done:
593 :
594 : #ifdef DEBUG_NSS
595 : fprintf(stderr, "[%5d]: getpwuid %d returns %s (%d)\n", getpid(),
596 : (unsigned int)uid, nss_err_str(ret), ret);
597 : #endif
598 :
599 : #ifdef HAVE_PTHREAD
600 2613 : pthread_mutex_unlock(&winbind_nss_mutex);
601 : #endif
602 :
603 2613 : return ret;
604 : }
605 :
606 : /* Return passwd struct from username */
607 : _PUBLIC_ON_LINUX_
608 : NSS_STATUS
609 6068 : _nss_winbind_getpwnam_r(const char *name, struct passwd *result, char *buffer,
610 : size_t buflen, int *errnop)
611 : {
612 : NSS_STATUS ret;
613 : static struct winbindd_response response;
614 : struct winbindd_request request;
615 : static int keep_response;
616 :
617 : #ifdef DEBUG_NSS
618 : fprintf(stderr, "[%5d]: getpwnam_r %s\n", getpid(), name);
619 : #endif
620 :
621 : #ifdef HAVE_PTHREAD
622 6068 : pthread_mutex_lock(&winbind_nss_mutex);
623 : #endif
624 :
625 : /* If our static buffer needs to be expanded we are called again */
626 :
627 7508 : if (!keep_response || strcmp(name,response.data.pw.pw_name) != 0) {
628 :
629 : /* Call for the first time */
630 :
631 6068 : response = (struct winbindd_response) {
632 : .length = 0,
633 : };
634 6068 : request = (struct winbindd_request) {
635 : .wb_flags = WBFLAG_FROM_NSS,
636 : };
637 :
638 6068 : strncpy(request.data.username, name,
639 : sizeof(request.data.username) - 1);
640 : request.data.username
641 6068 : [sizeof(request.data.username) - 1] = '\0';
642 :
643 6068 : winbind_set_client_name("nss_winbind");
644 6068 : ret = winbindd_request_response(NULL, WINBINDD_GETPWNAM, &request, &response);
645 :
646 10696 : if (ret == NSS_STATUS_SUCCESS) {
647 5157 : ret = fill_pwent(result, &response.data.pw, &buffer,
648 : &buflen);
649 :
650 5157 : if (ret == NSS_STATUS_TRYAGAIN) {
651 0 : keep_response = true;
652 0 : *errnop = errno = ERANGE;
653 0 : goto done;
654 : }
655 : }
656 :
657 : } else {
658 :
659 : /* We've been called again */
660 :
661 0 : ret = fill_pwent(result, &response.data.pw, &buffer, &buflen);
662 :
663 0 : if (ret == NSS_STATUS_TRYAGAIN) {
664 0 : keep_response = true;
665 0 : *errnop = errno = ERANGE;
666 0 : goto done;
667 : }
668 :
669 0 : keep_response = false;
670 0 : *errnop = errno = 0;
671 : }
672 :
673 6068 : winbindd_free_response(&response);
674 6068 : done:
675 : #ifdef DEBUG_NSS
676 : fprintf(stderr, "[%5d]: getpwnam %s returns %s (%d)\n", getpid(),
677 : name, nss_err_str(ret), ret);
678 : #endif
679 :
680 : #ifdef HAVE_PTHREAD
681 6068 : pthread_mutex_unlock(&winbind_nss_mutex);
682 : #endif
683 :
684 6068 : return ret;
685 : }
686 :
687 : /*
688 : * NSS group functions
689 : */
690 :
691 : static struct winbindd_response getgrent_response;
692 :
693 : static int ndx_gr_cache; /* Current index into grp cache */
694 : static int num_gr_cache; /* Current size of grp cache */
695 :
696 : /* Rewind "file pointer" to start of ntdom group database */
697 :
698 : _PUBLIC_ON_LINUX_
699 : NSS_STATUS
700 2924 : _nss_winbind_setgrent(void)
701 : {
702 : NSS_STATUS ret;
703 : #ifdef DEBUG_NSS
704 : fprintf(stderr, "[%5d]: setgrent\n", getpid());
705 : #endif
706 :
707 : #ifdef HAVE_PTHREAD
708 2924 : pthread_mutex_lock(&winbind_nss_mutex);
709 : #endif
710 :
711 2924 : if (num_gr_cache > 0) {
712 0 : ndx_gr_cache = num_gr_cache = 0;
713 0 : winbindd_free_response(&getgrent_response);
714 : }
715 :
716 2924 : winbind_set_client_name("nss_winbind");
717 2924 : ret = winbindd_request_response(NULL, WINBINDD_SETGRENT, NULL, NULL);
718 : #ifdef DEBUG_NSS
719 : fprintf(stderr, "[%5d]: setgrent returns %s (%d)\n", getpid(),
720 : nss_err_str(ret), ret);
721 : #endif
722 :
723 : #ifdef HAVE_PTHREAD
724 2924 : pthread_mutex_unlock(&winbind_nss_mutex);
725 : #endif
726 :
727 2924 : return ret;
728 : }
729 :
730 : /* Close "file pointer" for ntdom group database */
731 :
732 : _PUBLIC_ON_LINUX_
733 : NSS_STATUS
734 2924 : _nss_winbind_endgrent(void)
735 : {
736 : NSS_STATUS ret;
737 : #ifdef DEBUG_NSS
738 : fprintf(stderr, "[%5d]: endgrent\n", getpid());
739 : #endif
740 :
741 : #ifdef HAVE_PTHREAD
742 2924 : pthread_mutex_lock(&winbind_nss_mutex);
743 : #endif
744 :
745 2924 : if (num_gr_cache > 0) {
746 0 : ndx_gr_cache = num_gr_cache = 0;
747 0 : winbindd_free_response(&getgrent_response);
748 : }
749 :
750 2924 : winbind_set_client_name("nss_winbind");
751 2924 : ret = winbindd_request_response(NULL, WINBINDD_ENDGRENT, NULL, NULL);
752 : #ifdef DEBUG_NSS
753 : fprintf(stderr, "[%5d]: endgrent returns %s (%d)\n", getpid(),
754 : nss_err_str(ret), ret);
755 : #endif
756 :
757 : #ifdef HAVE_PTHREAD
758 2924 : pthread_mutex_unlock(&winbind_nss_mutex);
759 : #endif
760 :
761 2924 : return ret;
762 : }
763 :
764 : /* Get next entry from ntdom group database */
765 :
766 : static NSS_STATUS
767 5552 : winbind_getgrent(enum winbindd_cmd cmd,
768 : struct group *result,
769 : char *buffer, size_t buflen, int *errnop)
770 : {
771 : NSS_STATUS ret;
772 : static struct winbindd_request request;
773 : static int called_again;
774 :
775 :
776 : #ifdef DEBUG_NSS
777 : fprintf(stderr, "[%5d]: getgrent\n", getpid());
778 : #endif
779 :
780 : #ifdef HAVE_PTHREAD
781 5552 : pthread_mutex_lock(&winbind_nss_mutex);
782 : #endif
783 :
784 : /* Return an entry from the cache if we have one, or if we are
785 : called again because we exceeded our static buffer. */
786 :
787 7539 : if ((ndx_gr_cache < num_gr_cache) || called_again) {
788 1241 : goto return_result;
789 : }
790 :
791 : /* Else call winbindd to get a bunch of entries */
792 :
793 3070 : if (num_gr_cache > 0) {
794 0 : winbindd_free_response(&getgrent_response);
795 : }
796 :
797 3070 : ZERO_STRUCT(request);
798 3070 : ZERO_STRUCT(getgrent_response);
799 :
800 3070 : request.data.num_entries = MAX_GETGRENT_USERS;
801 :
802 3070 : winbind_set_client_name("nss_winbind");
803 3070 : ret = winbindd_request_response(NULL, cmd, &request,
804 : &getgrent_response);
805 :
806 3070 : if (ret == NSS_STATUS_SUCCESS) {
807 : struct winbindd_gr *gr_cache;
808 : int mem_ofs;
809 :
810 : /* Fill cache */
811 :
812 146 : ndx_gr_cache = 0;
813 146 : num_gr_cache = getgrent_response.data.num_entries;
814 :
815 : /* Return a result */
816 :
817 3869 : return_result:
818 :
819 2628 : gr_cache = (struct winbindd_gr *)
820 : getgrent_response.extra_data.data;
821 :
822 : /* Check data is valid */
823 :
824 2628 : if (gr_cache == NULL) {
825 0 : ret = NSS_STATUS_NOTFOUND;
826 0 : goto done;
827 : }
828 :
829 : /* Fill group membership. The offset into the extra data
830 : for the group membership is the reported offset plus the
831 : size of all the winbindd_gr records returned. */
832 :
833 2628 : mem_ofs = gr_cache[ndx_gr_cache].gr_mem_ofs +
834 : num_gr_cache * sizeof(struct winbindd_gr);
835 :
836 2628 : ret = fill_grent(result, &gr_cache[ndx_gr_cache],
837 2628 : ((char *)getgrent_response.extra_data.data)+mem_ofs,
838 : &buffer, &buflen);
839 :
840 : /* Out of memory - try again */
841 :
842 2628 : if (ret == NSS_STATUS_TRYAGAIN) {
843 0 : called_again = true;
844 0 : *errnop = errno = ERANGE;
845 0 : goto done;
846 : }
847 :
848 2628 : *errnop = 0;
849 2628 : called_again = false;
850 2628 : ndx_gr_cache++;
851 :
852 : /* If we've finished with this lot of results free cache */
853 :
854 2628 : if (ndx_gr_cache == num_gr_cache) {
855 146 : ndx_gr_cache = num_gr_cache = 0;
856 146 : winbindd_free_response(&getgrent_response);
857 : }
858 : }
859 8634 : done:
860 : #ifdef DEBUG_NSS
861 : fprintf(stderr, "[%5d]: getgrent returns %s (%d)\n", getpid(),
862 : nss_err_str(ret), ret);
863 : #endif
864 :
865 : #ifdef HAVE_PTHREAD
866 5552 : pthread_mutex_unlock(&winbind_nss_mutex);
867 : #endif
868 :
869 5552 : return ret;
870 : }
871 :
872 :
873 : _PUBLIC_ON_LINUX_
874 : NSS_STATUS
875 5552 : _nss_winbind_getgrent_r(struct group *result,
876 : char *buffer, size_t buflen, int *errnop)
877 : {
878 5552 : return winbind_getgrent(WINBINDD_GETGRENT, result, buffer, buflen, errnop);
879 : }
880 :
881 : _PUBLIC_ON_LINUX_
882 : NSS_STATUS
883 0 : _nss_winbind_getgrlst_r(struct group *result,
884 : char *buffer, size_t buflen, int *errnop)
885 : {
886 0 : return winbind_getgrent(WINBINDD_GETGRLST, result, buffer, buflen, errnop);
887 : }
888 :
889 : /* Return group struct from group name */
890 :
891 : _PUBLIC_ON_LINUX_
892 : NSS_STATUS
893 372 : _nss_winbind_getgrnam_r(const char *name,
894 : struct group *result, char *buffer,
895 : size_t buflen, int *errnop)
896 : {
897 : NSS_STATUS ret;
898 : static struct winbindd_response response;
899 : struct winbindd_request request;
900 : static int keep_response;
901 :
902 : #ifdef DEBUG_NSS
903 : fprintf(stderr, "[%5d]: getgrnam %s\n", getpid(), name);
904 : #endif
905 :
906 : #ifdef HAVE_PTHREAD
907 372 : pthread_mutex_lock(&winbind_nss_mutex);
908 : #endif
909 :
910 : /* If our static buffer needs to be expanded we are called again */
911 : /* Or if the stored response group name differs from the request. */
912 :
913 490 : if (!keep_response || strcmp(name,response.data.gr.gr_name) != 0) {
914 :
915 : /* Call for the first time */
916 :
917 372 : response = (struct winbindd_response) {
918 : .length = 0,
919 : };
920 372 : request = (struct winbindd_request) {
921 : .wb_flags = WBFLAG_FROM_NSS,
922 : };
923 :
924 372 : strncpy(request.data.groupname, name,
925 : sizeof(request.data.groupname));
926 : request.data.groupname
927 372 : [sizeof(request.data.groupname) - 1] = '\0';
928 :
929 372 : winbind_set_client_name("nss_winbind");
930 372 : ret = winbindd_request_response(NULL, WINBINDD_GETGRNAM,
931 : &request, &response);
932 :
933 626 : if (ret == NSS_STATUS_SUCCESS) {
934 224 : ret = fill_grent(result, &response.data.gr,
935 224 : (char *)response.extra_data.data,
936 : &buffer, &buflen);
937 :
938 224 : if (ret == NSS_STATUS_TRYAGAIN) {
939 0 : keep_response = true;
940 0 : *errnop = errno = ERANGE;
941 0 : goto done;
942 : }
943 : }
944 :
945 : } else {
946 :
947 : /* We've been called again */
948 :
949 0 : ret = fill_grent(result, &response.data.gr,
950 0 : (char *)response.extra_data.data, &buffer,
951 : &buflen);
952 :
953 0 : if (ret == NSS_STATUS_TRYAGAIN) {
954 0 : keep_response = true;
955 0 : *errnop = errno = ERANGE;
956 0 : goto done;
957 : }
958 :
959 0 : keep_response = false;
960 0 : *errnop = 0;
961 : }
962 :
963 372 : winbindd_free_response(&response);
964 372 : done:
965 : #ifdef DEBUG_NSS
966 : fprintf(stderr, "[%5d]: getgrnam %s returns %s (%d)\n", getpid(),
967 : name, nss_err_str(ret), ret);
968 : #endif
969 :
970 : #ifdef HAVE_PTHREAD
971 372 : pthread_mutex_unlock(&winbind_nss_mutex);
972 : #endif
973 :
974 372 : return ret;
975 : }
976 :
977 : /* Return group struct from gid */
978 :
979 : _PUBLIC_ON_LINUX_
980 : NSS_STATUS
981 308 : _nss_winbind_getgrgid_r(gid_t gid,
982 : struct group *result, char *buffer,
983 : size_t buflen, int *errnop)
984 : {
985 : NSS_STATUS ret;
986 : static struct winbindd_response response;
987 : struct winbindd_request request;
988 : static int keep_response;
989 :
990 : #ifdef DEBUG_NSS
991 : fprintf(stderr, "[%5d]: getgrgid %d\n", getpid(), gid);
992 : #endif
993 :
994 : #ifdef HAVE_PTHREAD
995 308 : pthread_mutex_lock(&winbind_nss_mutex);
996 : #endif
997 :
998 : /* If our static buffer needs to be expanded we are called again */
999 : /* Or if the stored response group name differs from the request. */
1000 :
1001 462 : if (!keep_response || gid != response.data.gr.gr_gid) {
1002 :
1003 : /* Call for the first time */
1004 :
1005 308 : response = (struct winbindd_response) {
1006 : .length = 0,
1007 : };
1008 308 : request = (struct winbindd_request) {
1009 : .wb_flags = WBFLAG_FROM_NSS,
1010 : };
1011 :
1012 :
1013 308 : request.data.gid = gid;
1014 :
1015 308 : winbind_set_client_name("nss_winbind");
1016 308 : ret = winbindd_request_response(NULL, WINBINDD_GETGRGID,
1017 : &request, &response);
1018 :
1019 462 : if (ret == NSS_STATUS_SUCCESS) {
1020 :
1021 304 : ret = fill_grent(result, &response.data.gr,
1022 304 : (char *)response.extra_data.data,
1023 : &buffer, &buflen);
1024 :
1025 304 : if (ret == NSS_STATUS_TRYAGAIN) {
1026 0 : keep_response = true;
1027 0 : *errnop = errno = ERANGE;
1028 0 : goto done;
1029 : }
1030 : }
1031 :
1032 : } else {
1033 :
1034 : /* We've been called again */
1035 :
1036 0 : ret = fill_grent(result, &response.data.gr,
1037 0 : (char *)response.extra_data.data, &buffer,
1038 : &buflen);
1039 :
1040 0 : if (ret == NSS_STATUS_TRYAGAIN) {
1041 0 : keep_response = true;
1042 0 : *errnop = errno = ERANGE;
1043 0 : goto done;
1044 : }
1045 :
1046 0 : keep_response = false;
1047 0 : *errnop = 0;
1048 : }
1049 :
1050 308 : winbindd_free_response(&response);
1051 308 : done:
1052 : #ifdef DEBUG_NSS
1053 : fprintf(stderr, "[%5d]: getgrgid %d returns %s (%d)\n", getpid(),
1054 : (unsigned int)gid, nss_err_str(ret), ret);
1055 : #endif
1056 :
1057 : #ifdef HAVE_PTHREAD
1058 308 : pthread_mutex_unlock(&winbind_nss_mutex);
1059 : #endif
1060 308 : return ret;
1061 : }
1062 :
1063 : /* Initialise supplementary groups */
1064 :
1065 : _PUBLIC_ON_LINUX_
1066 : NSS_STATUS
1067 50 : _nss_winbind_initgroups_dyn(const char *user, gid_t group, long int *start,
1068 : long int *size, gid_t **groups, long int limit,
1069 : int *errnop)
1070 : {
1071 : NSS_STATUS ret;
1072 : struct winbindd_request request;
1073 : struct winbindd_response response;
1074 : int i;
1075 :
1076 : #ifdef DEBUG_NSS
1077 : fprintf(stderr, "[%5d]: initgroups %s (%d)\n", getpid(),
1078 : user, group);
1079 : #endif
1080 :
1081 : #ifdef HAVE_PTHREAD
1082 50 : pthread_mutex_lock(&winbind_nss_mutex);
1083 : #endif
1084 :
1085 50 : ZERO_STRUCT(request);
1086 50 : ZERO_STRUCT(response);
1087 :
1088 50 : strncpy(request.data.username, user,
1089 : sizeof(request.data.username) - 1);
1090 :
1091 50 : winbind_set_client_name("nss_winbind");
1092 50 : ret = winbindd_request_response(NULL, WINBINDD_GETGROUPS,
1093 : &request, &response);
1094 :
1095 50 : if (ret == NSS_STATUS_SUCCESS) {
1096 50 : int num_gids = response.data.num_entries;
1097 50 : gid_t *gid_list = (gid_t *)response.extra_data.data;
1098 :
1099 : #ifdef DEBUG_NSS
1100 : fprintf(stderr, "[%5d]: initgroups %s: got NSS_STATUS_SUCCESS "
1101 : "and %d gids\n", getpid(),
1102 : user, num_gids);
1103 : #endif
1104 50 : if (gid_list == NULL) {
1105 0 : ret = NSS_STATUS_NOTFOUND;
1106 0 : goto done;
1107 : }
1108 :
1109 : /* Copy group list to client */
1110 :
1111 176 : for (i = 0; i < num_gids; i++) {
1112 :
1113 : #ifdef DEBUG_NSS
1114 : fprintf(stderr, "[%5d]: initgroups %s (%d): "
1115 : "processing gid %d \n", getpid(),
1116 : user, group, gid_list[i]);
1117 : #endif
1118 :
1119 : /* Skip primary group */
1120 :
1121 126 : if (gid_list[i] == group) {
1122 50 : continue;
1123 : }
1124 :
1125 : /* Skip groups without a mapping */
1126 76 : if (gid_list[i] == (uid_t)-1) {
1127 0 : continue;
1128 : }
1129 :
1130 : /* Filled buffer ? If so, resize. */
1131 :
1132 76 : if (*start == *size) {
1133 : long int newsize;
1134 : gid_t *newgroups;
1135 :
1136 0 : newsize = 2 * (*size);
1137 0 : if (limit > 0) {
1138 0 : if (*size == limit) {
1139 0 : goto done;
1140 : }
1141 0 : if (newsize > limit) {
1142 0 : newsize = limit;
1143 : }
1144 : }
1145 :
1146 0 : newgroups = (gid_t *)
1147 0 : realloc((*groups),
1148 : newsize * sizeof(**groups));
1149 0 : if (!newgroups) {
1150 0 : *errnop = ENOMEM;
1151 0 : ret = NSS_STATUS_NOTFOUND;
1152 0 : goto done;
1153 : }
1154 0 : *groups = newgroups;
1155 0 : *size = newsize;
1156 : }
1157 :
1158 : /* Add to buffer */
1159 :
1160 76 : (*groups)[*start] = gid_list[i];
1161 76 : *start += 1;
1162 : }
1163 : }
1164 :
1165 : /* Back to your regularly scheduled programming */
1166 :
1167 50 : done:
1168 : #ifdef DEBUG_NSS
1169 : fprintf(stderr, "[%5d]: initgroups %s returns %s (%d)\n", getpid(),
1170 : user, nss_err_str(ret), ret);
1171 : #endif
1172 :
1173 : #ifdef HAVE_PTHREAD
1174 50 : pthread_mutex_unlock(&winbind_nss_mutex);
1175 : #endif
1176 :
1177 50 : return ret;
1178 : }
|