]> sourceware.org Git - glibc.git/blob - nis/nss_compat/compat-pwd.c
Update.
[glibc.git] / nis / nss_compat / compat-pwd.c
1 /* Copyright (C) 1996, 1997 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1996.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with the GNU C Library; see the file COPYING.LIB. If not,
17 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA. */
19
20 #include <nss.h>
21 #include <pwd.h>
22 #include <errno.h>
23 #include <ctype.h>
24 #include <fcntl.h>
25 #include <netdb.h>
26 #include <string.h>
27 #include <bits/libc-lock.h>
28 #include <rpcsvc/yp.h>
29 #include <rpcsvc/ypclnt.h>
30 #include <rpcsvc/nis.h>
31 #include <nsswitch.h>
32
33 #include "netgroup.h"
34 #include "nss-nisplus.h"
35 #include "nisplus-parser.h"
36
37 static service_user *ni = NULL;
38 static bool_t use_nisplus = FALSE; /* default: passwd_compat: nis */
39 static nis_name pwdtable = NULL; /* Name of the pwd table */
40 static size_t pwdtablelen = 0;
41
42 /* Get the declaration of the parser function. */
43 #define ENTNAME pwent
44 #define STRUCTURE passwd
45 #define EXTERN_PARSER
46 #include <nss/nss_files/files-parse.c>
47
48 /* Structure for remembering -@netgroup and -user members ... */
49 #define BLACKLIST_INITIAL_SIZE 512
50 #define BLACKLIST_INCREMENT 256
51 struct blacklist_t
52 {
53 char *data;
54 int current;
55 int size;
56 };
57
58 struct ent_t
59 {
60 bool_t netgroup;
61 bool_t nis;
62 bool_t first;
63 char *oldkey;
64 int oldkeylen;
65 nis_result *result;
66 FILE *stream;
67 struct blacklist_t blacklist;
68 struct passwd pwd;
69 struct __netgrent netgrdata;
70 };
71 typedef struct ent_t ent_t;
72
73 static ent_t ext_ent = {0, 0, 0, NULL, 0, NULL, NULL, {NULL, 0, 0},
74 {NULL, NULL, 0, 0, NULL, NULL, NULL}};
75
76 /* Protect global state against multiple changers. */
77 __libc_lock_define_initialized (static, lock)
78
79 /* Prototypes for local functions. */
80 static void blacklist_store_name (const char *, ent_t *);
81 static int in_blacklist (const char *, int, ent_t *);
82
83 static void
84 give_pwd_free (struct passwd *pwd)
85 {
86 if (pwd->pw_name != NULL)
87 free (pwd->pw_name);
88 if (pwd->pw_passwd != NULL)
89 free (pwd->pw_passwd);
90 if (pwd->pw_gecos != NULL)
91 free (pwd->pw_gecos);
92 if (pwd->pw_dir != NULL)
93 free (pwd->pw_dir);
94 if (pwd->pw_shell != NULL)
95 free (pwd->pw_shell);
96
97 memset (pwd, '\0', sizeof (struct passwd));
98 }
99
100 static size_t
101 pwd_need_buflen (struct passwd *pwd)
102 {
103 size_t len = 0;
104
105 if (pwd->pw_passwd != NULL)
106 len += strlen (pwd->pw_passwd) + 1;
107
108 if (pwd->pw_gecos != NULL)
109 len += strlen (pwd->pw_gecos) + 1;
110
111 if (pwd->pw_dir != NULL)
112 len += strlen (pwd->pw_dir) + 1;
113
114 if (pwd->pw_shell != NULL)
115 len += strlen (pwd->pw_shell) + 1;
116
117 return len;
118 }
119
120 static void
121 copy_pwd_changes (struct passwd *dest, struct passwd *src,
122 char *buffer, size_t buflen)
123 {
124 if (src->pw_passwd != NULL && strlen (src->pw_passwd))
125 {
126 if (buffer == NULL)
127 dest->pw_passwd = strdup (src->pw_passwd);
128 else if (dest->pw_passwd &&
129 strlen (dest->pw_passwd) >= strlen (src->pw_passwd))
130 strcpy (dest->pw_passwd, src->pw_passwd);
131 else
132 {
133 dest->pw_passwd = buffer;
134 strcpy (dest->pw_passwd, src->pw_passwd);
135 buffer += strlen (dest->pw_passwd) + 1;
136 buflen = buflen - (strlen (dest->pw_passwd) + 1);
137 }
138 }
139
140 if (src->pw_gecos != NULL && strlen (src->pw_gecos))
141 {
142 if (buffer == NULL)
143 dest->pw_gecos = strdup (src->pw_gecos);
144 else if (dest->pw_gecos &&
145 strlen (dest->pw_gecos) >= strlen (src->pw_gecos))
146 strcpy (dest->pw_gecos, src->pw_gecos);
147 else
148 {
149 dest->pw_gecos = buffer;
150 strcpy (dest->pw_gecos, src->pw_gecos);
151 buffer += strlen (dest->pw_gecos) + 1;
152 buflen = buflen - (strlen (dest->pw_gecos) + 1);
153 }
154 }
155 if (src->pw_dir != NULL && strlen (src->pw_dir))
156 {
157 if (buffer == NULL)
158 dest->pw_dir = strdup (src->pw_dir);
159 else if (dest->pw_dir &&
160 strlen (dest->pw_dir) >= strlen (src->pw_dir))
161 strcpy (dest->pw_dir, src->pw_dir);
162 else
163 {
164 dest->pw_dir = buffer;
165 strcpy (dest->pw_dir, src->pw_dir);
166 buffer += strlen (dest->pw_dir) + 1;
167 buflen = buflen - (strlen (dest->pw_dir) + 1);
168 }
169 }
170
171 if (src->pw_shell != NULL && strlen (src->pw_shell))
172 {
173 if (buffer == NULL)
174 dest->pw_shell = strdup (src->pw_shell);
175 else if (dest->pw_shell &&
176 strlen (dest->pw_shell) >= strlen (src->pw_shell))
177 strcpy (dest->pw_shell, src->pw_shell);
178 else
179 {
180 dest->pw_shell = buffer;
181 strcpy (dest->pw_shell, src->pw_shell);
182 buffer += strlen (dest->pw_shell) + 1;
183 buflen = buflen - (strlen (dest->pw_shell) + 1);
184 }
185 }
186 }
187
188 static enum nss_status
189 internal_setpwent (ent_t *ent)
190 {
191 enum nss_status status = NSS_STATUS_SUCCESS;
192
193 ent->nis = ent->first = ent->netgroup = 0;
194
195 /* If something was left over free it. */
196 if (ent->netgroup)
197 __internal_endnetgrent (&ent->netgrdata);
198
199 if (ent->oldkey != NULL)
200 {
201 free (ent->oldkey);
202 ent->oldkey = NULL;
203 ent->oldkeylen = 0;
204 }
205
206 if (ent->result != NULL)
207 {
208 nis_freeresult (ent->result);
209 ent->result = NULL;
210 }
211
212 if (pwdtable == NULL)
213 {
214 static const char key[] = "passwd.org_dir.";
215 const char *local_dir = nis_local_directory ();
216 size_t len_local_dir = strlen (local_dir);
217
218 pwdtable = malloc (sizeof (key) + len_local_dir);
219 if (pwdtable == NULL)
220 return NSS_STATUS_TRYAGAIN;
221
222 pwdtablelen = ((char *) mempcpy (mempcpy (pwdtable,
223 key, sizeof (key) - 1),
224 local_dir, len_local_dir + 1)
225 - pwdtable) - 1;
226 }
227
228 ent->blacklist.current = 0;
229 if (ent->blacklist.data != NULL)
230 ent->blacklist.data[0] = '\0';
231
232 if (ent->stream == NULL)
233 {
234 ent->stream = fopen ("/etc/passwd", "r");
235
236 if (ent->stream == NULL)
237 status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL;
238 else
239 {
240 /* We have to make sure the file is `closed on exec'. */
241 int result, flags;
242
243 result = flags = fcntl (fileno (ent->stream), F_GETFD, 0);
244 if (result >= 0)
245 {
246 flags |= FD_CLOEXEC;
247 result = fcntl (fileno (ent->stream), F_SETFD, flags);
248 }
249 if (result < 0)
250 {
251 /* Something went wrong. Close the stream and return a
252 failure. */
253 fclose (ent->stream);
254 ent->stream = NULL;
255 status = NSS_STATUS_UNAVAIL;
256 }
257 }
258 }
259 else
260 rewind (ent->stream);
261
262 give_pwd_free (&ent->pwd);
263
264 return status;
265 }
266
267
268 enum nss_status
269 _nss_compat_setpwent (void)
270 {
271 enum nss_status result;
272
273 __libc_lock_lock (lock);
274
275 if (ni == NULL)
276 {
277 __nss_database_lookup ("passwd_compat", NULL, "nis", &ni);
278 use_nisplus = (strcmp (ni->name, "nisplus") == 0);
279 }
280
281 result = internal_setpwent (&ext_ent);
282
283 __libc_lock_unlock (lock);
284
285 return result;
286 }
287
288
289 static enum nss_status
290 internal_endpwent (ent_t *ent)
291 {
292 if (ent->stream != NULL)
293 {
294 fclose (ent->stream);
295 ent->stream = NULL;
296 }
297
298 if (ent->netgroup)
299 __internal_endnetgrent (&ent->netgrdata);
300
301 ent->nis = ent->first = ent->netgroup = 0;
302
303 if (ent->oldkey != NULL)
304 {
305 free (ent->oldkey);
306 ent->oldkey = NULL;
307 ent->oldkeylen = 0;
308 }
309
310 if (ent->result != NULL)
311 {
312 nis_freeresult (ent->result);
313 ent->result = NULL;
314 }
315
316 ent->blacklist.current = 0;
317 if (ent->blacklist.data != NULL)
318 ent->blacklist.data[0] = '\0';
319
320 give_pwd_free (&ent->pwd);
321
322 return NSS_STATUS_SUCCESS;
323 }
324
325 enum nss_status
326 _nss_compat_endpwent (void)
327 {
328 enum nss_status result;
329
330 __libc_lock_lock (lock);
331
332 result = internal_endpwent (&ext_ent);
333
334 __libc_lock_unlock (lock);
335
336 return result;
337 }
338
339 static enum nss_status
340 getpwent_next_nis_netgr (const char *name, struct passwd *result, ent_t *ent,
341 char *group, char *buffer, size_t buflen)
342 {
343 struct parser_data *data = (void *) buffer;
344 char *ypdomain, *host, *user, *domain, *outval, *p, *p2;
345 int status, outvallen;
346 size_t p2len;
347
348 if (yp_get_default_domain (&ypdomain) != YPERR_SUCCESS)
349 {
350 ent->netgroup = 0;
351 ent->first = 0;
352 give_pwd_free (&ent->pwd);
353 return NSS_STATUS_UNAVAIL;
354 }
355
356 if (ent->first == TRUE)
357 {
358 memset (&ent->netgrdata, 0, sizeof (struct __netgrent));
359 __internal_setnetgrent (group, &ent->netgrdata);
360 ent->first = FALSE;
361 }
362
363 while (1)
364 {
365 char *saved_cursor;
366 int parse_res;
367
368 saved_cursor = ent->netgrdata.cursor;
369 status = __internal_getnetgrent_r (&host, &user, &domain,
370 &ent->netgrdata, buffer, buflen);
371 if (status != 1)
372 {
373 __internal_endnetgrent (&ent->netgrdata);
374 ent->netgroup = 0;
375 give_pwd_free (&ent->pwd);
376 return NSS_STATUS_RETURN;
377 }
378
379 if (user == NULL || user[0] == '-')
380 continue;
381
382 if (domain != NULL && strcmp (ypdomain, domain) != 0)
383 continue;
384
385 /* If name != NULL, we are called from getpwnam */
386 if (name != NULL)
387 if (strcmp (user, name) != 0)
388 continue;
389
390 if (yp_match (ypdomain, "passwd.byname", user,
391 strlen (user), &outval, &outvallen)
392 != YPERR_SUCCESS)
393 continue;
394
395 p2len = pwd_need_buflen (&ent->pwd);
396 if (p2len > buflen)
397 {
398 __set_errno (ERANGE);
399 return NSS_STATUS_TRYAGAIN;
400 }
401 p2 = buffer + (buflen - p2len);
402 buflen -= p2len;
403 p = strncpy (buffer, outval, buflen);
404 while (isspace (*p))
405 p++;
406 free (outval);
407 if ((parse_res = _nss_files_parse_pwent (p, result, data, buflen)) == -1)
408 {
409 ent->netgrdata.cursor = saved_cursor;
410 return NSS_STATUS_TRYAGAIN;
411 }
412
413 if (parse_res)
414 {
415 /* Store the User in the blacklist for the "+" at the end of
416 /etc/passwd */
417 blacklist_store_name (result->pw_name, ent);
418 copy_pwd_changes (result, &ent->pwd, p2, p2len);
419 break;
420 }
421 }
422
423 return NSS_STATUS_SUCCESS;
424 }
425
426 static enum nss_status
427 getpwent_next_nisplus_netgr (const char *name, struct passwd *result,
428 ent_t *ent, char *group, char *buffer,
429 size_t buflen)
430 {
431 char *ypdomain, *host, *user, *domain, *p2;
432 int status, parse_res;
433 size_t p2len;
434 nis_result *nisres;
435
436 /* Maybe we should use domainname here ? We need the current
437 domainname for the domain field in netgroups */
438 if (yp_get_default_domain (&ypdomain) != YPERR_SUCCESS)
439 {
440 ent->netgroup = 0;
441 ent->first = 0;
442 give_pwd_free (&ent->pwd);
443 return NSS_STATUS_UNAVAIL;
444 }
445
446 if (ent->first == TRUE)
447 {
448 bzero (&ent->netgrdata, sizeof (struct __netgrent));
449 __internal_setnetgrent (group, &ent->netgrdata);
450 ent->first = FALSE;
451 }
452
453 while (1)
454 {
455 char *saved_cursor;
456
457 saved_cursor = ent->netgrdata.cursor;
458 status = __internal_getnetgrent_r (&host, &user, &domain,
459 &ent->netgrdata, buffer, buflen);
460 if (status != 1)
461 {
462 __internal_endnetgrent (&ent->netgrdata);
463 ent->netgroup = 0;
464 give_pwd_free (&ent->pwd);
465 return NSS_STATUS_RETURN;
466 }
467
468 if (user == NULL || user[0] == '-')
469 continue;
470
471 if (domain != NULL && strcmp (ypdomain, domain) != 0)
472 continue;
473
474 /* If name != NULL, we are called from getpwnam */
475 if (name != NULL)
476 if (strcmp (user, name) != 0)
477 continue;
478
479 p2len = pwd_need_buflen (&ent->pwd);
480 if (p2len > buflen)
481 {
482 __set_errno (ERANGE);
483 return NSS_STATUS_TRYAGAIN;
484 }
485 p2 = buffer + (buflen - p2len);
486 buflen -= p2len;
487 {
488 char buf[strlen (user) + 30 + pwdtablelen];
489 sprintf(buf, "[name=%s],%s", user, pwdtable);
490 nisres = nis_list(buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
491 }
492 if (niserr2nss (nisres->status) != NSS_STATUS_SUCCESS)
493 {
494 nis_freeresult (nisres);
495 continue;
496 }
497 if ((parse_res = _nss_nisplus_parse_pwent (nisres, result, buffer,
498 buflen)) == -1)
499 {
500 nis_freeresult (nisres);
501 ent->netgrdata.cursor = saved_cursor;
502 return NSS_STATUS_TRYAGAIN;
503 }
504 nis_freeresult (nisres);
505
506 if (parse_res)
507 {
508 /* Store the User in the blacklist for the "+" at the end of
509 /etc/passwd */
510 blacklist_store_name (result->pw_name, ent);
511 copy_pwd_changes (result, &ent->pwd, p2, p2len);
512 break;
513 }
514 }
515
516 return NSS_STATUS_SUCCESS;
517 }
518
519 static enum nss_status
520 getpwent_next_nisplus (struct passwd *result, ent_t *ent, char *buffer,
521 size_t buflen)
522 {
523 int parse_res;
524 size_t p2len;
525 char *p2;
526
527 p2len = pwd_need_buflen (&ent->pwd);
528 if (p2len > buflen)
529 {
530 __set_errno (ERANGE);
531 return NSS_STATUS_TRYAGAIN;
532 }
533 p2 = buffer + (buflen - p2len);
534 buflen -= p2len;
535 do
536 {
537 bool_t saved_first;
538 nis_result *saved_res;
539
540 if (ent->first)
541 {
542 saved_first = TRUE;
543 saved_res = ent->result;
544
545 ent->result = nis_first_entry(pwdtable);
546 if (niserr2nss (ent->result->status) != NSS_STATUS_SUCCESS)
547 {
548 ent->nis = 0;
549 give_pwd_free (&ent->pwd);
550 return niserr2nss (ent->result->status);
551 }
552 ent->first = FALSE;
553 }
554 else
555 {
556 nis_result *res;
557
558 res = nis_next_entry(pwdtable, &ent->result->cookie);
559 saved_res = ent->result;
560 saved_first = FALSE;
561 ent->result = res;
562 if (niserr2nss (ent->result->status) != NSS_STATUS_SUCCESS)
563 {
564 ent->nis = 0;
565 nis_freeresult (saved_res);
566 give_pwd_free (&ent->pwd);
567 return niserr2nss (ent->result->status);
568 }
569 }
570 if ((parse_res = _nss_nisplus_parse_pwent (ent->result, result, buffer,
571 buflen)) == -1)
572 {
573 nis_freeresult (ent->result);
574 ent->result = saved_res;
575 ent->first = saved_first;
576 __set_errno (ERANGE);
577 return NSS_STATUS_TRYAGAIN;
578 }
579 else
580 {
581 if (!saved_first)
582 nis_freeresult (saved_res);
583 }
584
585 if (parse_res &&
586 in_blacklist (result->pw_name, strlen (result->pw_name), ent))
587 parse_res = 0; /* if result->pw_name in blacklist,search next entry */
588 }
589 while (!parse_res);
590
591 copy_pwd_changes (result, &ent->pwd, p2, p2len);
592
593 return NSS_STATUS_SUCCESS;
594 }
595
596 static enum nss_status
597 getpwent_next_nis (struct passwd *result, ent_t *ent, char *buffer,
598 size_t buflen)
599 {
600 struct parser_data *data = (void *) buffer;
601 char *domain, *outkey, *outval, *p, *p2;
602 int outkeylen, outvallen, parse_res;
603 size_t p2len;
604
605 if (yp_get_default_domain (&domain) != YPERR_SUCCESS)
606 {
607 ent->nis = 0;
608 give_pwd_free (&ent->pwd);
609 return NSS_STATUS_UNAVAIL;
610 }
611
612 p2len = pwd_need_buflen (&ent->pwd);
613 if (p2len > buflen)
614 {
615 __set_errno (ERANGE);
616 return NSS_STATUS_TRYAGAIN;
617 }
618 p2 = buffer + (buflen - p2len);
619 buflen -= p2len;
620 do
621 {
622 bool_t saved_first;
623 char *saved_oldkey;
624 int saved_oldlen;
625
626 if (ent->first)
627 {
628 if (yp_first (domain, "passwd.byname", &outkey, &outkeylen,
629 &outval, &outvallen) != YPERR_SUCCESS)
630 {
631 ent->nis = 0;
632 give_pwd_free (&ent->pwd);
633 return NSS_STATUS_UNAVAIL;
634 }
635
636 saved_first = TRUE;
637 saved_oldkey = ent->oldkey;
638 saved_oldlen = ent->oldkeylen;
639 ent->oldkey = outkey;
640 ent->oldkeylen = outkeylen;
641 ent->first = FALSE;
642 }
643 else
644 {
645 if (yp_next (domain, "passwd.byname", ent->oldkey, ent->oldkeylen,
646 &outkey, &outkeylen, &outval, &outvallen)
647 != YPERR_SUCCESS)
648 {
649 ent->nis = 0;
650 give_pwd_free (&ent->pwd);
651 return NSS_STATUS_NOTFOUND;
652 }
653
654 saved_first = FALSE;
655 saved_oldkey = ent->oldkey;
656 saved_oldlen = ent->oldkeylen;
657 ent->oldkey = outkey;
658 ent->oldkeylen = outkeylen;
659 }
660
661 /* Copy the found data to our buffer */
662 p = strncpy (buffer, outval, buflen);
663
664 /* ...and free the data. */
665 free (outval);
666
667 while (isspace (*p))
668 ++p;
669 if ((parse_res = _nss_files_parse_pwent (p, result, data, buflen)) == -1)
670 {
671 free (ent->oldkey);
672 ent->oldkey = saved_oldkey;
673 ent->oldkeylen = saved_oldlen;
674 ent->first = saved_first;
675 __set_errno (ERANGE);
676 return NSS_STATUS_TRYAGAIN;
677 }
678 else
679 {
680 if (!saved_first)
681 free (saved_oldkey);
682 }
683 if (parse_res &&
684 in_blacklist (result->pw_name, strlen (result->pw_name), ent))
685 parse_res = 0;
686 }
687 while (!parse_res);
688
689 copy_pwd_changes (result, &ent->pwd, p2, p2len);
690
691 return NSS_STATUS_SUCCESS;
692 }
693
694 /* This function handle the +user entrys in /etc/passwd */
695 static enum nss_status
696 getpwnam_plususer (const char *name, struct passwd *result, char *buffer,
697 size_t buflen)
698 {
699 struct parser_data *data = (void *) buffer;
700 struct passwd pwd;
701 int parse_res;
702 char *p;
703 size_t plen;
704
705 memset (&pwd, '\0', sizeof (struct passwd));
706
707 copy_pwd_changes (&pwd, result, NULL, 0);
708
709 plen = pwd_need_buflen (&pwd);
710 if (plen > buflen)
711 {
712 __set_errno (ERANGE);
713 return NSS_STATUS_TRYAGAIN;
714 }
715 p = buffer + (buflen - plen);
716 buflen -= plen;
717
718 if (use_nisplus) /* Do the NIS+ query here */
719 {
720 nis_result *res;
721 char buf[strlen (name) + 24 + pwdtablelen];
722
723 sprintf(buf, "[name=%s],%s", name, pwdtable);
724 res = nis_list(buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
725 if (niserr2nss (res->status) != NSS_STATUS_SUCCESS)
726 {
727 enum nss_status status = niserr2nss (res->status);
728
729 nis_freeresult (res);
730 return status;
731 }
732 if ((parse_res = _nss_nisplus_parse_pwent (res, result, buffer,
733 buflen)) == -1)
734 {
735 nis_freeresult (res);
736 __set_errno (ERANGE);
737 return NSS_STATUS_TRYAGAIN;
738 }
739 nis_freeresult (res);
740 }
741 else /* Use NIS */
742 {
743 char *domain, *outval, *ptr;
744 int outvallen;
745
746 if (yp_get_default_domain (&domain) != YPERR_SUCCESS)
747 return NSS_STATUS_TRYAGAIN;
748
749 if (yp_match (domain, "passwd.byname", name, strlen (name),
750 &outval, &outvallen)
751 != YPERR_SUCCESS)
752 return NSS_STATUS_TRYAGAIN;
753 ptr = strncpy (buffer, outval, buflen < (size_t) outvallen ?
754 buflen : (size_t) outvallen);
755 buffer[buflen < (size_t) outvallen ? buflen : (size_t) outvallen] = '\0';
756 free (outval);
757 while (isspace (*ptr))
758 ptr++;
759 if ((parse_res = _nss_files_parse_pwent (ptr, result, data, buflen))
760 == -1)
761 {
762 __set_errno (ERANGE);
763 return NSS_STATUS_TRYAGAIN;
764 }
765 }
766
767 if (parse_res > 0)
768 {
769 copy_pwd_changes (result, &pwd, p, plen);
770 give_pwd_free (&pwd);
771 /* We found the entry. */
772 return NSS_STATUS_SUCCESS;
773 }
774 else
775 {
776 /* Give buffer the old len back */
777 buflen += plen;
778 give_pwd_free (&pwd);
779 }
780 return NSS_STATUS_RETURN;
781 }
782
783 static enum nss_status
784 getpwent_next_file (struct passwd *result, ent_t *ent,
785 char *buffer, size_t buflen)
786 {
787 struct parser_data *data = (void *) buffer;
788 while (1)
789 {
790 fpos_t pos;
791 char *p;
792 int parse_res;
793
794 do
795 {
796 fgetpos (ent->stream, &pos);
797 p = fgets (buffer, buflen, ent->stream);
798 if (p == NULL)
799 return NSS_STATUS_NOTFOUND;
800
801 /* Terminate the line for any case. */
802 buffer[buflen - 1] = '\0';
803
804 /* Skip leading blanks. */
805 while (isspace (*p))
806 ++p;
807 }
808 while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */
809 /* Parse the line. If it is invalid, loop to
810 get the next line of the file to parse. */
811 !(parse_res = _nss_files_parse_pwent (p, result, data, buflen)));
812
813 if (parse_res == -1)
814 {
815 /* The parser ran out of space. */
816 fsetpos (ent->stream, &pos);
817 __set_errno (ERANGE);
818 return NSS_STATUS_TRYAGAIN;
819 }
820
821 if (result->pw_name[0] != '+' && result->pw_name[0] != '-')
822 /* This is a real entry. */
823 break;
824
825 /* -@netgroup */
826 if (result->pw_name[0] == '-' && result->pw_name[1] == '@'
827 && result->pw_name[2] != '\0')
828 {
829 char buf2[1024];
830 char *user, *host, *domain;
831 struct __netgrent netgrdata;
832
833 bzero (&netgrdata, sizeof (struct __netgrent));
834 __internal_setnetgrent (&result->pw_name[2], &netgrdata);
835 while (__internal_getnetgrent_r (&host, &user, &domain,
836 &netgrdata, buf2, sizeof (buf2)))
837 {
838 if (user != NULL && user[0] != '-')
839 blacklist_store_name (user, ent);
840 }
841 __internal_endnetgrent (&netgrdata);
842 continue;
843 }
844
845 /* +@netgroup */
846 if (result->pw_name[0] == '+' && result->pw_name[1] == '@'
847 && result->pw_name[2] != '\0')
848 {
849 int status;
850
851 ent->netgroup = TRUE;
852 ent->first = TRUE;
853 copy_pwd_changes (&ent->pwd, result, NULL, 0);
854
855 if (use_nisplus)
856 status = getpwent_next_nisplus_netgr (NULL, result, ent,
857 &result->pw_name[2],
858 buffer, buflen);
859 else
860 status = getpwent_next_nis_netgr (NULL, result, ent,
861 &result->pw_name[2],
862 buffer, buflen);
863 if (status == NSS_STATUS_RETURN)
864 continue;
865 else
866 return status;
867 }
868
869 /* -user */
870 if (result->pw_name[0] == '-' && result->pw_name[1] != '\0'
871 && result->pw_name[1] != '@')
872 {
873 blacklist_store_name (&result->pw_name[1], ent);
874 continue;
875 }
876
877 /* +user */
878 if (result->pw_name[0] == '+' && result->pw_name[1] != '\0'
879 && result->pw_name[1] != '@')
880 {
881 enum nss_status status;
882
883 /* Store the User in the blacklist for the "+" at the end of
884 /etc/passwd */
885 blacklist_store_name (&result->pw_name[1], ent);
886 status = getpwnam_plususer (&result->pw_name[1], result, buffer,
887 buflen);
888 if (status == NSS_STATUS_SUCCESS) /* We found the entry. */
889 break;
890 else
891 if (status == NSS_STATUS_RETURN) /* We couldn't parse the entry */
892 continue;
893 else
894 return status;
895 }
896
897 /* +:... */
898 if (result->pw_name[0] == '+' && result->pw_name[1] == '\0')
899 {
900 ent->nis = TRUE;
901 ent->first = TRUE;
902 copy_pwd_changes (&ent->pwd, result, NULL, 0);
903
904 if (use_nisplus)
905 return getpwent_next_nisplus (result, ent, buffer, buflen);
906 else
907 return getpwent_next_nis (result, ent, buffer, buflen);
908 }
909 }
910
911 return NSS_STATUS_SUCCESS;
912 }
913
914
915 static enum nss_status
916 internal_getpwent_r (struct passwd *pw, ent_t *ent, char *buffer,
917 size_t buflen)
918 {
919 if (ent->netgroup)
920 {
921 int status;
922
923 /* We are searching members in a netgroup */
924 /* Since this is not the first call, we don't need the group name */
925 if (use_nisplus)
926 status = getpwent_next_nisplus_netgr (NULL, pw, ent, NULL, buffer,
927 buflen);
928 else
929 status = getpwent_next_nis_netgr (NULL, pw, ent, NULL, buffer, buflen);
930 if (status == NSS_STATUS_RETURN)
931 return getpwent_next_file (pw, ent, buffer, buflen);
932 else
933 return status;
934 }
935 else
936 if (ent->nis)
937 {
938 if (use_nisplus)
939 return getpwent_next_nisplus (pw, ent, buffer, buflen);
940 else
941 return getpwent_next_nis (pw, ent, buffer, buflen);
942 }
943 else
944 return getpwent_next_file (pw, ent, buffer, buflen);
945 }
946
947 enum nss_status
948 _nss_compat_getpwent_r (struct passwd *pwd, char *buffer, size_t buflen)
949 {
950 enum nss_status status = NSS_STATUS_SUCCESS;
951
952 __libc_lock_lock (lock);
953
954 if (ni == NULL)
955 {
956 __nss_database_lookup ("passwd_compat", NULL, "nis", &ni);
957 use_nisplus = (strcmp (ni->name, "nisplus") == 0);
958 }
959
960 /* Be prepared that the setpwent function was not called before. */
961 if (ext_ent.stream == NULL)
962 status = internal_setpwent (&ext_ent);
963
964 if (status == NSS_STATUS_SUCCESS)
965 status = internal_getpwent_r (pwd, &ext_ent, buffer, buflen);
966
967 __libc_lock_unlock (lock);
968
969 return status;
970 }
971
972 /* Searches in /etc/passwd and the NIS/NIS+ map for a special user */
973 static enum nss_status
974 internal_getpwnam_r (const char *name, struct passwd *result, ent_t *ent,
975 char *buffer, size_t buflen)
976 {
977 struct parser_data *data = (void *) buffer;
978
979 while (1)
980 {
981 fpos_t pos;
982 char *p;
983 int parse_res;
984
985 do
986 {
987 fgetpos (ent->stream, &pos);
988 p = fgets (buffer, buflen, ent->stream);
989 if (p == NULL)
990 {
991 if (feof (ent->stream))
992 return NSS_STATUS_NOTFOUND;
993 else
994 {
995 __set_errno (ERANGE);
996 return NSS_STATUS_TRYAGAIN;
997 }
998 }
999
1000 /* Terminate the line for any case. */
1001 buffer[buflen - 1] = '\0';
1002
1003 /* Skip leading blanks. */
1004 while (isspace (*p))
1005 ++p;
1006 }
1007 while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */
1008 /* Parse the line. If it is invalid, loop to
1009 get the next line of the file to parse. */
1010 !(parse_res = _nss_files_parse_pwent (p, result, data, buflen)));
1011
1012 if (parse_res == -1)
1013 {
1014 /* The parser ran out of space. */
1015 fsetpos (ent->stream, &pos);
1016 __set_errno (ERANGE);
1017 return NSS_STATUS_TRYAGAIN;
1018 }
1019
1020 /* This is a real entry. */
1021 if (result->pw_name[0] != '+' && result->pw_name[0] != '-')
1022 {
1023 if (strcmp (result->pw_name, name) == 0)
1024 return NSS_STATUS_SUCCESS;
1025 else
1026 continue;
1027 }
1028
1029 /* -@netgroup */
1030 if (result->pw_name[0] == '-' && result->pw_name[1] == '@'
1031 && result->pw_name[2] != '\0')
1032 {
1033 char buf2[1024];
1034 char *user, *host, *domain;
1035 struct __netgrent netgrdata;
1036
1037 bzero (&netgrdata, sizeof (struct __netgrent));
1038 __internal_setnetgrent (&result->pw_name[2], &netgrdata);
1039 while (__internal_getnetgrent_r (&host, &user, &domain,
1040 &netgrdata, buf2, sizeof (buf2)))
1041 {
1042 if (user != NULL && user[0] != '-')
1043 if (strcmp (user, name) == 0)
1044 return NSS_STATUS_NOTFOUND;
1045 }
1046 __internal_endnetgrent (&netgrdata);
1047 continue;
1048 }
1049
1050 /* +@netgroup */
1051 if (result->pw_name[0] == '+' && result->pw_name[1] == '@'
1052 && result->pw_name[2] != '\0')
1053 {
1054 char buf[strlen (result->pw_name)];
1055 int status;
1056
1057 strcpy (buf, &result->pw_name[2]);
1058 ent->netgroup = TRUE;
1059 ent->first = TRUE;
1060 copy_pwd_changes (&ent->pwd, result, NULL, 0);
1061
1062 do
1063 {
1064 if (use_nisplus)
1065 status = getpwent_next_nisplus_netgr (name, result, ent, buf,
1066 buffer, buflen);
1067 else
1068 status = getpwent_next_nis_netgr (name, result, ent, buf,
1069 buffer, buflen);
1070 if (status == NSS_STATUS_RETURN)
1071 continue;
1072
1073 if (status == NSS_STATUS_SUCCESS &&
1074 strcmp (result->pw_name, name) == 0)
1075 return NSS_STATUS_SUCCESS;
1076 } while (status == NSS_STATUS_SUCCESS);
1077 continue;
1078 }
1079
1080 /* -user */
1081 if (result->pw_name[0] == '-' && result->pw_name[1] != '\0'
1082 && result->pw_name[1] != '@')
1083 {
1084 if (strcmp (&result->pw_name[1], name) == 0)
1085 return NSS_STATUS_NOTFOUND;
1086 else
1087 continue;
1088 }
1089
1090 /* +user */
1091 if (result->pw_name[0] == '+' && result->pw_name[1] != '\0'
1092 && result->pw_name[1] != '@')
1093 {
1094 if (strcmp (name, &result->pw_name[1]) == 0)
1095 {
1096 enum nss_status status;
1097
1098 status = getpwnam_plususer (name, result, buffer, buflen);
1099 if (status == NSS_STATUS_RETURN)
1100 /* We couldn't parse the entry */
1101 return NSS_STATUS_NOTFOUND;
1102 else
1103 return status;
1104 }
1105 }
1106
1107 /* +:... */
1108 if (result->pw_name[0] == '+' && result->pw_name[1] == '\0')
1109 {
1110 enum nss_status status;
1111
1112 status = getpwnam_plususer (name, result, buffer, buflen);
1113 if (status == NSS_STATUS_SUCCESS) /* We found the entry. */
1114 break;
1115 else
1116 if (status == NSS_STATUS_RETURN) /* We couldn't parse the entry */
1117 return NSS_STATUS_NOTFOUND;
1118 else
1119 return status;
1120 }
1121 }
1122 return NSS_STATUS_SUCCESS;
1123 }
1124
1125 enum nss_status
1126 _nss_compat_getpwnam_r (const char *name, struct passwd *pwd,
1127 char *buffer, size_t buflen)
1128 {
1129 ent_t ent = {0, 0, 0, NULL, 0, NULL, NULL, {NULL, 0, 0},
1130 {NULL, NULL, 0, 0, NULL, NULL, NULL}};
1131 enum nss_status status;
1132
1133 if (name[0] == '-' || name[0] == '+')
1134 return NSS_STATUS_NOTFOUND;
1135
1136 __libc_lock_lock (lock);
1137
1138 if (ni == NULL)
1139 {
1140 __nss_database_lookup ("passwd_compat", NULL, "nis", &ni);
1141 use_nisplus = (strcmp (ni->name, "nisplus") == 0);
1142 }
1143
1144 __libc_lock_unlock (lock);
1145
1146 status = internal_setpwent (&ent);
1147 if (status != NSS_STATUS_SUCCESS)
1148 return status;
1149
1150 status = internal_getpwnam_r (name, pwd, &ent, buffer, buflen);
1151
1152 internal_endpwent (&ent);
1153
1154 return status;
1155 }
1156
1157 /* This function handle the + entry in /etc/passwd for getpwuid */
1158 static enum nss_status
1159 getpwuid_plususer (uid_t uid, struct passwd *result, char *buffer,
1160 size_t buflen)
1161 {
1162 struct parser_data *data = (void *) buffer;
1163 struct passwd pwd;
1164 int parse_res;
1165 char *p;
1166 size_t plen;
1167
1168 memset (&pwd, '\0', sizeof (struct passwd));
1169
1170 copy_pwd_changes (&pwd, result, NULL, 0);
1171
1172 plen = pwd_need_buflen (&pwd);
1173 if (plen > buflen)
1174 {
1175 __set_errno (ERANGE);
1176 return NSS_STATUS_TRYAGAIN;
1177 }
1178 p = buffer + (buflen - plen);
1179 buflen -= plen;
1180
1181 if (use_nisplus) /* Do the NIS+ query here */
1182 {
1183 nis_result *res;
1184 char buf[1024 + pwdtablelen];
1185
1186 sprintf(buf, "[uid=%d],%s", uid, pwdtable);
1187 res = nis_list(buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
1188 if (niserr2nss (res->status) != NSS_STATUS_SUCCESS)
1189 {
1190 enum nss_status status = niserr2nss (res->status);
1191
1192 nis_freeresult (res);
1193 return status;
1194 }
1195 if ((parse_res = _nss_nisplus_parse_pwent (res, result, buffer,
1196 buflen)) == -1)
1197 {
1198 nis_freeresult (res);
1199 __set_errno (ERANGE);
1200 return NSS_STATUS_TRYAGAIN;
1201 }
1202 nis_freeresult (res);
1203 }
1204 else /* Use NIS */
1205 {
1206 char buf[1024];
1207 char *domain, *outval, *ptr;
1208 int outvallen;
1209
1210 if (yp_get_default_domain (&domain) != YPERR_SUCCESS)
1211 return NSS_STATUS_TRYAGAIN;
1212
1213 sprintf (buf, "%d", uid);
1214 if (yp_match (domain, "passwd.byuid", buf, strlen (buf),
1215 &outval, &outvallen)
1216 != YPERR_SUCCESS)
1217 return NSS_STATUS_TRYAGAIN;
1218 ptr = strncpy (buffer, outval, buflen < (size_t) outvallen ?
1219 buflen : (size_t) outvallen);
1220 buffer[buflen < (size_t) outvallen ? buflen : (size_t) outvallen] = '\0';
1221 free (outval);
1222 while (isspace (*ptr))
1223 ptr++;
1224 if ((parse_res = _nss_files_parse_pwent (ptr, result, data, buflen))
1225 == -1)
1226 {
1227 __set_errno (ERANGE);
1228 return NSS_STATUS_TRYAGAIN;
1229 }
1230 }
1231
1232 if (parse_res > 0)
1233 {
1234 copy_pwd_changes (result, &pwd, p, plen);
1235 give_pwd_free (&pwd);
1236 /* We found the entry. */
1237 return NSS_STATUS_SUCCESS;
1238 }
1239 else
1240 {
1241 /* Give buffer the old len back */
1242 buflen += plen;
1243 give_pwd_free (&pwd);
1244 }
1245 return NSS_STATUS_RETURN;
1246 }
1247
1248 /* Searches in /etc/passwd and the NIS/NIS+ map for a special user id */
1249 static enum nss_status
1250 internal_getpwuid_r (uid_t uid, struct passwd *result, ent_t *ent,
1251 char *buffer, size_t buflen)
1252 {
1253 struct parser_data *data = (void *) buffer;
1254
1255 while (1)
1256 {
1257 fpos_t pos;
1258 char *p;
1259 int parse_res;
1260
1261 do
1262 {
1263 fgetpos (ent->stream, &pos);
1264 p = fgets (buffer, buflen, ent->stream);
1265 if (p == NULL)
1266 return NSS_STATUS_NOTFOUND;
1267
1268 /* Terminate the line for any case. */
1269 buffer[buflen - 1] = '\0';
1270
1271 /* Skip leading blanks. */
1272 while (isspace (*p))
1273 ++p;
1274 }
1275 while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */
1276 /* Parse the line. If it is invalid, loop to
1277 get the next line of the file to parse. */
1278 !(parse_res = _nss_files_parse_pwent (p, result, data, buflen)));
1279
1280 if (parse_res == -1)
1281 {
1282 /* The parser ran out of space. */
1283 fsetpos (ent->stream, &pos);
1284 __set_errno (ERANGE);
1285 return NSS_STATUS_TRYAGAIN;
1286 }
1287
1288 /* This is a real entry. */
1289 if (result->pw_name[0] != '+' && result->pw_name[0] != '-')
1290 {
1291 if (result->pw_uid == uid)
1292 return NSS_STATUS_SUCCESS;
1293 else
1294 continue;
1295 }
1296
1297 /* -@netgroup */
1298 if (result->pw_name[0] == '-' && result->pw_name[1] == '@'
1299 && result->pw_name[2] != '\0')
1300 {
1301 char buf2[1024];
1302 char *user, *host, *domain;
1303 struct __netgrent netgrdata;
1304
1305 bzero (&netgrdata, sizeof (struct __netgrent));
1306 __internal_setnetgrent (&result->pw_name[2], &netgrdata);
1307 while (__internal_getnetgrent_r (&host, &user, &domain,
1308 &netgrdata, buf2, sizeof (buf2)))
1309 {
1310 if (user != NULL && user[0] != '-')
1311 blacklist_store_name (user, ent);
1312 }
1313 __internal_endnetgrent (&netgrdata);
1314 continue;
1315 }
1316
1317 /* +@netgroup */
1318 if (result->pw_name[0] == '+' && result->pw_name[1] == '@'
1319 && result->pw_name[2] != '\0')
1320 {
1321 char buf[strlen (result->pw_name)];
1322 int status;
1323
1324 strcpy (buf, &result->pw_name[2]);
1325 ent->netgroup = TRUE;
1326 ent->first = TRUE;
1327 copy_pwd_changes (&ent->pwd, result, NULL, 0);
1328
1329 do
1330 {
1331 if (use_nisplus)
1332 status = getpwent_next_nisplus_netgr (NULL, result, ent, buf,
1333 buffer, buflen);
1334 else
1335 status = getpwent_next_nis_netgr (NULL, result, ent, buf,
1336 buffer, buflen);
1337 if (status == NSS_STATUS_RETURN)
1338 continue;
1339
1340 if (status == NSS_STATUS_SUCCESS && uid == result->pw_uid)
1341 return NSS_STATUS_SUCCESS;
1342 } while (status == NSS_STATUS_SUCCESS);
1343 continue;
1344 }
1345
1346 /* -user */
1347 if (result->pw_name[0] == '-' && result->pw_name[1] != '\0'
1348 && result->pw_name[1] != '@')
1349 {
1350 blacklist_store_name (&result->pw_name[1], ent);
1351 continue;
1352 }
1353
1354 /* +user */
1355 if (result->pw_name[0] == '+' && result->pw_name[1] != '\0'
1356 && result->pw_name[1] != '@')
1357 {
1358 enum nss_status status;
1359
1360 /* Store the User in the blacklist for the "+" at the end of
1361 /etc/passwd */
1362 blacklist_store_name (&result->pw_name[1], ent);
1363 status = getpwnam_plususer (&result->pw_name[1], result, buffer,
1364 buflen);
1365 if (status == NSS_STATUS_SUCCESS && result->pw_uid == uid)
1366 break;
1367 else
1368 continue;
1369 }
1370
1371 /* +:... */
1372 if (result->pw_name[0] == '+' && result->pw_name[1] == '\0')
1373 {
1374 enum nss_status status;
1375
1376 status = getpwuid_plususer (uid, result, buffer, buflen);
1377 if (status == NSS_STATUS_SUCCESS) /* We found the entry. */
1378 break;
1379 else
1380 if (status == NSS_STATUS_RETURN) /* We couldn't parse the entry */
1381 return NSS_STATUS_NOTFOUND;
1382 else
1383 return status;
1384 }
1385 }
1386 return NSS_STATUS_SUCCESS;
1387 }
1388
1389 enum nss_status
1390 _nss_compat_getpwuid_r (uid_t uid, struct passwd *pwd,
1391 char *buffer, size_t buflen)
1392 {
1393 ent_t ent = {0, 0, 0, NULL, 0, NULL, NULL, {NULL, 0, 0},
1394 {NULL, NULL, 0, 0, NULL, NULL, NULL}};
1395 enum nss_status status;
1396
1397 __libc_lock_lock (lock);
1398
1399 if (ni == NULL)
1400 {
1401 __nss_database_lookup ("passwd_compat", NULL, "nis", &ni);
1402 use_nisplus = (strcmp (ni->name, "nisplus") == 0);
1403 }
1404
1405 __libc_lock_unlock (lock);
1406
1407 status = internal_setpwent (&ent);
1408 if (status != NSS_STATUS_SUCCESS)
1409 return status;
1410
1411 status = internal_getpwuid_r (uid, pwd, &ent, buffer, buflen);
1412
1413 internal_endpwent (&ent);
1414
1415 return status;
1416 }
1417
1418
1419 /* Support routines for remembering -@netgroup and -user entries.
1420 The names are stored in a single string with `|' as separator. */
1421 static void
1422 blacklist_store_name (const char *name, ent_t *ent)
1423 {
1424 int namelen = strlen (name);
1425 char *tmp;
1426
1427 /* first call, setup cache */
1428 if (ent->blacklist.size == 0)
1429 {
1430 ent->blacklist.size = MAX (BLACKLIST_INITIAL_SIZE, 2 * namelen);
1431 ent->blacklist.data = malloc (ent->blacklist.size);
1432 if (ent->blacklist.data == NULL)
1433 return;
1434 ent->blacklist.data[0] = '|';
1435 ent->blacklist.data[1] = '\0';
1436 ent->blacklist.current = 1;
1437 }
1438 else
1439 {
1440 if (in_blacklist (name, namelen, ent))
1441 return; /* no duplicates */
1442
1443 if (ent->blacklist.current + namelen + 1 >= ent->blacklist.size)
1444 {
1445 ent->blacklist.size += MAX (BLACKLIST_INCREMENT, 2 * namelen);
1446 tmp = realloc (ent->blacklist.data, ent->blacklist.size);
1447 if (tmp == NULL)
1448 {
1449 free (ent->blacklist.data);
1450 ent->blacklist.size = 0;
1451 return;
1452 }
1453 ent->blacklist.data = tmp;
1454 }
1455 }
1456
1457 tmp = stpcpy (ent->blacklist.data + ent->blacklist.current, name);
1458 *tmp++ = '|';
1459 *tmp = '\0';
1460 ent->blacklist.current += namelen + 1;
1461
1462 return;
1463 }
1464
1465 /* returns TRUE if ent->blacklist contains name, else FALSE */
1466 static bool_t
1467 in_blacklist (const char *name, int namelen, ent_t *ent)
1468 {
1469 char buf[namelen + 3];
1470 char *cp;
1471
1472 if (ent->blacklist.data == NULL)
1473 return FALSE;
1474
1475 buf[0] = '|';
1476 cp = stpcpy (&buf[1], name);
1477 *cp++= '|';
1478 *cp = '\0';
1479 return strstr (ent->blacklist.data, buf) != NULL;
1480 }
This page took 0.111194 seconds and 6 git commands to generate.