]> git.ipfire.org Git - thirdparty/glibc.git/blob - nis/nss_compat/compat-pwd.c
2a55df290887ab883985486d9f2ed59fce2a124a
[thirdparty/glibc.git] / nis / nss_compat / compat-pwd.c
1 /* Copyright (C) 1996, 1997, 1998, 1999, 2001 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 Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the 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 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18 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;
38 static bool_t use_nisplus; /* default: passwd_compat: nis */
39 static nis_name pwdtable; /* Name of the pwd table */
40 static size_t pwdtablelen;
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 insert_passwd_adjunct (char **result, int *len, char *domain, int *errnop)
190 {
191 char *p1, *p2, *result2, *res;
192 int len2;
193 size_t namelen;
194
195 /* Check for adjunct style secret passwords. They can be
196 recognized by a password starting with "##". */
197 p1 = strchr (*result, ':');
198 if (p1 == NULL || p1[1] != '#' || p1[2] != '#')
199 return NSS_STATUS_SUCCESS;
200 p2 = strchr (p1 + 3, ':');
201
202 namelen = p2 - p1 - 3;
203
204 if (yp_match (domain, "passwd.adjunct.byname", &p1[3], namelen,
205 &result2, &len2) == YPERR_SUCCESS)
206 {
207 /* We found a passwd.adjunct entry. Merge encrypted
208 password therein into original result. */
209 char *encrypted = strchr (result2, ':');
210 char *endp;
211 size_t restlen;
212
213 if (encrypted == NULL || (endp = strchr (++encrypted, ':')) == NULL)
214 {
215 /* Invalid format of the entry. This never should happen
216 unless the data from which the NIS table is generated is
217 wrong. We simply ignore it. */
218 free (result2);
219 return NSS_STATUS_SUCCESS;
220 }
221
222 restlen = *len - (p2 - *result);
223 if ((res = malloc (namelen + restlen + (endp - encrypted) + 2)) == NULL)
224 {
225 free (result2);
226 *errnop = ENOMEM;
227 return NSS_STATUS_TRYAGAIN;
228 }
229
230 __mempcpy (__mempcpy (__mempcpy (__mempcpy
231 (res, *result, (p1 - *result)),
232 ":", 1),
233 encrypted, endp - encrypted),
234 p2, restlen + 1);
235
236 free (result2);
237 free (*result);
238 *result = res;
239 *len = strlen (res);
240 }
241 return NSS_STATUS_SUCCESS;
242 }
243
244 static enum nss_status
245 internal_setpwent (ent_t *ent)
246 {
247 enum nss_status status = NSS_STATUS_SUCCESS;
248
249 ent->nis = ent->first = ent->netgroup = 0;
250
251 /* If something was left over free it. */
252 if (ent->netgroup)
253 __internal_endnetgrent (&ent->netgrdata);
254
255 if (ent->oldkey != NULL)
256 {
257 free (ent->oldkey);
258 ent->oldkey = NULL;
259 ent->oldkeylen = 0;
260 }
261
262 if (ent->result != NULL)
263 {
264 nis_freeresult (ent->result);
265 ent->result = NULL;
266 }
267
268 if (pwdtable == NULL)
269 {
270 static const char key[] = "passwd.org_dir.";
271 const char *local_dir = nis_local_directory ();
272 size_t len_local_dir = strlen (local_dir);
273
274 pwdtable = malloc (sizeof (key) + len_local_dir);
275 if (pwdtable == NULL)
276 return NSS_STATUS_TRYAGAIN;
277
278 pwdtablelen = ((char *) mempcpy (mempcpy (pwdtable,
279 key, sizeof (key) - 1),
280 local_dir, len_local_dir + 1)
281 - pwdtable) - 1;
282 }
283
284 if (ent->blacklist.data != NULL)
285 {
286 ent->blacklist.current = 1;
287 ent->blacklist.data[0] = '|';
288 ent->blacklist.data[1] = '\0';
289 }
290 else
291 ent->blacklist.current = 0;
292
293 if (ent->stream == NULL)
294 {
295 ent->stream = fopen ("/etc/passwd", "r");
296
297 if (ent->stream == NULL)
298 status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL;
299 else
300 {
301 /* We have to make sure the file is `closed on exec'. */
302 int result, flags;
303
304 result = flags = fcntl (fileno (ent->stream), F_GETFD, 0);
305 if (result >= 0)
306 {
307 flags |= FD_CLOEXEC;
308 result = fcntl (fileno (ent->stream), F_SETFD, flags);
309 }
310 if (result < 0)
311 {
312 /* Something went wrong. Close the stream and return a
313 failure. */
314 fclose (ent->stream);
315 ent->stream = NULL;
316 status = NSS_STATUS_UNAVAIL;
317 }
318 }
319 }
320 else
321 rewind (ent->stream);
322
323 give_pwd_free (&ent->pwd);
324
325 return status;
326 }
327
328
329 enum nss_status
330 _nss_compat_setpwent (int stayopen)
331 {
332 enum nss_status result;
333
334 __libc_lock_lock (lock);
335
336 if (ni == NULL)
337 {
338 __nss_database_lookup ("passwd_compat", NULL, "nis", &ni);
339 use_nisplus = (strcmp (ni->name, "nisplus") == 0);
340 }
341
342 result = internal_setpwent (&ext_ent);
343
344 __libc_lock_unlock (lock);
345
346 return result;
347 }
348
349
350 static enum nss_status
351 internal_endpwent (ent_t *ent)
352 {
353 if (ent->stream != NULL)
354 {
355 fclose (ent->stream);
356 ent->stream = NULL;
357 }
358
359 if (ent->netgroup)
360 __internal_endnetgrent (&ent->netgrdata);
361
362 ent->nis = ent->first = ent->netgroup = 0;
363
364 if (ent->oldkey != NULL)
365 {
366 free (ent->oldkey);
367 ent->oldkey = NULL;
368 ent->oldkeylen = 0;
369 }
370
371 if (ent->result != NULL)
372 {
373 nis_freeresult (ent->result);
374 ent->result = NULL;
375 }
376
377 if (ent->blacklist.data != NULL)
378 {
379 ent->blacklist.current = 1;
380 ent->blacklist.data[0] = '|';
381 ent->blacklist.data[1] = '\0';
382 }
383 else
384 ent->blacklist.current = 0;
385
386 give_pwd_free (&ent->pwd);
387
388 return NSS_STATUS_SUCCESS;
389 }
390
391 enum nss_status
392 _nss_compat_endpwent (void)
393 {
394 enum nss_status result;
395
396 __libc_lock_lock (lock);
397
398 result = internal_endpwent (&ext_ent);
399
400 __libc_lock_unlock (lock);
401
402 return result;
403 }
404
405 static enum nss_status
406 getpwent_next_nis_netgr (const char *name, struct passwd *result, ent_t *ent,
407 char *group, char *buffer, size_t buflen, int *errnop)
408 {
409 struct parser_data *data = (void *) buffer;
410 char *ypdomain, *host, *user, *domain, *outval, *p, *p2;
411 int status, outvallen;
412 size_t p2len;
413
414 if (yp_get_default_domain (&ypdomain) != YPERR_SUCCESS)
415 {
416 ent->netgroup = 0;
417 ent->first = 0;
418 give_pwd_free (&ent->pwd);
419 return NSS_STATUS_UNAVAIL;
420 }
421
422 if (ent->first == TRUE)
423 {
424 memset (&ent->netgrdata, 0, sizeof (struct __netgrent));
425 __internal_setnetgrent (group, &ent->netgrdata);
426 ent->first = FALSE;
427 }
428
429 while (1)
430 {
431 char *saved_cursor;
432 int parse_res;
433
434 saved_cursor = ent->netgrdata.cursor;
435 status = __internal_getnetgrent_r (&host, &user, &domain,
436 &ent->netgrdata, buffer, buflen,
437 errnop);
438 if (status != 1)
439 {
440 __internal_endnetgrent (&ent->netgrdata);
441 ent->netgroup = 0;
442 give_pwd_free (&ent->pwd);
443 return NSS_STATUS_RETURN;
444 }
445
446 if (user == NULL || user[0] == '-')
447 continue;
448
449 if (domain != NULL && strcmp (ypdomain, domain) != 0)
450 continue;
451
452 /* If name != NULL, we are called from getpwnam. */
453 if (name != NULL)
454 if (strcmp (user, name) != 0)
455 continue;
456
457 if (yp_match (ypdomain, "passwd.byname", user,
458 strlen (user), &outval, &outvallen)
459 != YPERR_SUCCESS)
460 continue;
461
462 if (insert_passwd_adjunct (&outval, &outvallen, ypdomain, errnop)
463 != NSS_STATUS_SUCCESS)
464 {
465 free (outval);
466 return NSS_STATUS_TRYAGAIN;
467 }
468
469 p2len = pwd_need_buflen (&ent->pwd);
470 if (p2len > buflen)
471 {
472 free (outval);
473 *errnop = ERANGE;
474 return NSS_STATUS_TRYAGAIN;
475 }
476 p2 = buffer + (buflen - p2len);
477 buflen -= p2len;
478
479 if (buflen < ((size_t) outvallen + 1))
480 {
481 free (outval);
482 *errnop = ERANGE;
483 return NSS_STATUS_TRYAGAIN;
484 }
485 p = strncpy (buffer, outval, buflen);
486
487 while (isspace (*p))
488 p++;
489 free (outval);
490 parse_res = _nss_files_parse_pwent (p, result, data, buflen, errnop);
491 if (parse_res == -1)
492 {
493 ent->netgrdata.cursor = saved_cursor;
494 return NSS_STATUS_TRYAGAIN;
495 }
496
497 if (parse_res && !in_blacklist (result->pw_name,
498 strlen (result->pw_name), ent))
499 {
500 /* Store the User in the blacklist for the "+" at the end of
501 /etc/passwd */
502 blacklist_store_name (result->pw_name, ent);
503 copy_pwd_changes (result, &ent->pwd, p2, p2len);
504 break;
505 }
506 }
507
508 return NSS_STATUS_SUCCESS;
509 }
510
511 static enum nss_status
512 getpwent_next_nisplus_netgr (const char *name, struct passwd *result,
513 ent_t *ent, char *group, char *buffer,
514 size_t buflen, int *errnop)
515 {
516 char *ypdomain, *host, *user, *domain, *p2;
517 int status, parse_res;
518 size_t p2len;
519 nis_result *nisres;
520
521 /* Maybe we should use domainname here ? We need the current
522 domainname for the domain field in netgroups */
523 if (yp_get_default_domain (&ypdomain) != YPERR_SUCCESS)
524 {
525 ent->netgroup = 0;
526 ent->first = 0;
527 give_pwd_free (&ent->pwd);
528 return NSS_STATUS_UNAVAIL;
529 }
530
531 if (ent->first == TRUE)
532 {
533 bzero (&ent->netgrdata, sizeof (struct __netgrent));
534 __internal_setnetgrent (group, &ent->netgrdata);
535 ent->first = FALSE;
536 }
537
538 while (1)
539 {
540 char *saved_cursor;
541
542 saved_cursor = ent->netgrdata.cursor;
543 status = __internal_getnetgrent_r (&host, &user, &domain,
544 &ent->netgrdata, buffer, buflen,
545 errnop);
546 if (status != 1)
547 {
548 __internal_endnetgrent (&ent->netgrdata);
549 ent->netgroup = 0;
550 give_pwd_free (&ent->pwd);
551 return NSS_STATUS_RETURN;
552 }
553
554 if (user == NULL || user[0] == '-')
555 continue;
556
557 if (domain != NULL && strcmp (ypdomain, domain) != 0)
558 continue;
559
560 /* If name != NULL, we are called from getpwnam */
561 if (name != NULL)
562 if (strcmp (user, name) != 0)
563 continue;
564
565 p2len = pwd_need_buflen (&ent->pwd);
566 if (p2len > buflen)
567 {
568 *errnop = ERANGE;
569 return NSS_STATUS_TRYAGAIN;
570 }
571 p2 = buffer + (buflen - p2len);
572 buflen -= p2len;
573 {
574 char buf[strlen (user) + 30 + pwdtablelen];
575 sprintf(buf, "[name=%s],%s", user, pwdtable);
576 nisres = nis_list(buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
577 }
578 if (niserr2nss (nisres->status) != NSS_STATUS_SUCCESS)
579 {
580 nis_freeresult (nisres);
581 continue;
582 }
583 parse_res = _nss_nisplus_parse_pwent (nisres, result, buffer,
584 buflen, errnop);
585 if (parse_res == -1)
586 {
587 nis_freeresult (nisres);
588 ent->netgrdata.cursor = saved_cursor;
589 *errnop = ERANGE;
590 return NSS_STATUS_TRYAGAIN;
591 }
592 nis_freeresult (nisres);
593
594 if (parse_res && !in_blacklist (result->pw_name,
595 strlen (result->pw_name), ent))
596 {
597 /* Store the User in the blacklist for the "+" at the end of
598 /etc/passwd */
599 blacklist_store_name (result->pw_name, ent);
600 copy_pwd_changes (result, &ent->pwd, p2, p2len);
601 break;
602 }
603 }
604
605 return NSS_STATUS_SUCCESS;
606 }
607
608 /* get the next user from NIS+ (+ entry) */
609 static enum nss_status
610 getpwent_next_nisplus (struct passwd *result, ent_t *ent, char *buffer,
611 size_t buflen, int *errnop)
612 {
613 int parse_res;
614 size_t p2len;
615 char *p2;
616
617 p2len = pwd_need_buflen (&ent->pwd);
618 if (p2len > buflen)
619 {
620 *errnop = ERANGE;
621 return NSS_STATUS_TRYAGAIN;
622 }
623 p2 = buffer + (buflen - p2len);
624 buflen -= p2len;
625 do
626 {
627 bool_t saved_first;
628 nis_result *saved_res;
629
630 if (ent->first)
631 {
632 saved_first = TRUE;
633 saved_res = ent->result;
634
635 ent->result = nis_first_entry (pwdtable);
636 if (niserr2nss (ent->result->status) != NSS_STATUS_SUCCESS)
637 {
638 ent->nis = 0;
639 give_pwd_free (&ent->pwd);
640 return niserr2nss (ent->result->status);
641 }
642 ent->first = FALSE;
643 }
644 else
645 {
646 nis_result *res;
647
648 res = nis_next_entry (pwdtable, &ent->result->cookie);
649 saved_res = ent->result;
650 saved_first = FALSE;
651 ent->result = res;
652 if (niserr2nss (ent->result->status) != NSS_STATUS_SUCCESS)
653 {
654 ent->nis = 0;
655 nis_freeresult (saved_res);
656 give_pwd_free (&ent->pwd);
657 return niserr2nss (ent->result->status);
658 }
659 }
660 parse_res = _nss_nisplus_parse_pwent (ent->result, result, buffer,
661 buflen, errnop);
662 if (parse_res == -1)
663 {
664 nis_freeresult (ent->result);
665 ent->result = saved_res;
666 ent->first = saved_first;
667 *errnop = ERANGE;
668 return NSS_STATUS_TRYAGAIN;
669 }
670 else
671 {
672 if (!saved_first)
673 nis_freeresult (saved_res);
674 }
675
676 if (parse_res &&
677 in_blacklist (result->pw_name, strlen (result->pw_name), ent))
678 parse_res = 0; /* if result->pw_name in blacklist,search next entry */
679 }
680 while (!parse_res);
681
682 copy_pwd_changes (result, &ent->pwd, p2, p2len);
683
684 return NSS_STATUS_SUCCESS;
685 }
686
687 static enum nss_status
688 getpwent_next_nis (struct passwd *result, ent_t *ent, char *buffer,
689 size_t buflen, int *errnop)
690 {
691 struct parser_data *data = (void *) buffer;
692 char *domain, *outkey, *outval, *p, *p2;
693 int outkeylen, outvallen, parse_res;
694 size_t p2len;
695
696 if (yp_get_default_domain (&domain) != YPERR_SUCCESS)
697 {
698 ent->nis = 0;
699 give_pwd_free (&ent->pwd);
700 return NSS_STATUS_UNAVAIL;
701 }
702
703 p2len = pwd_need_buflen (&ent->pwd);
704 if (p2len > buflen)
705 {
706 *errnop = ERANGE;
707 return NSS_STATUS_TRYAGAIN;
708 }
709 p2 = buffer + (buflen - p2len);
710 buflen -= p2len;
711 do
712 {
713 bool_t saved_first;
714 char *saved_oldkey;
715 int saved_oldlen;
716
717 if (ent->first)
718 {
719 if (yp_first (domain, "passwd.byname", &outkey, &outkeylen,
720 &outval, &outvallen) != YPERR_SUCCESS)
721 {
722 ent->nis = 0;
723 give_pwd_free (&ent->pwd);
724 return NSS_STATUS_UNAVAIL;
725 }
726
727 if (insert_passwd_adjunct (&outval, &outvallen, domain, errnop) !=
728 NSS_STATUS_SUCCESS)
729 {
730 free (outval);
731 return NSS_STATUS_TRYAGAIN;
732 }
733
734 if (buflen < ((size_t) outvallen + 1))
735 {
736 free (outval);
737 *errnop = ERANGE;
738 return NSS_STATUS_TRYAGAIN;
739 }
740
741 saved_first = TRUE;
742 saved_oldkey = ent->oldkey;
743 saved_oldlen = ent->oldkeylen;
744 ent->oldkey = outkey;
745 ent->oldkeylen = outkeylen;
746 ent->first = FALSE;
747 }
748 else
749 {
750 if (yp_next (domain, "passwd.byname", ent->oldkey, ent->oldkeylen,
751 &outkey, &outkeylen, &outval, &outvallen)
752 != YPERR_SUCCESS)
753 {
754 ent->nis = 0;
755 give_pwd_free (&ent->pwd);
756 *errnop = ENOENT;
757 return NSS_STATUS_NOTFOUND;
758 }
759
760 if (insert_passwd_adjunct (&outval, &outvallen, domain, errnop)
761 != NSS_STATUS_SUCCESS)
762 {
763 free (outval);
764 return NSS_STATUS_TRYAGAIN;
765 }
766
767 if (buflen < ((size_t) outvallen + 1))
768 {
769 free (outval);
770 *errnop = ERANGE;
771 return NSS_STATUS_TRYAGAIN;
772 }
773
774 saved_first = FALSE;
775 saved_oldkey = ent->oldkey;
776 saved_oldlen = ent->oldkeylen;
777 ent->oldkey = outkey;
778 ent->oldkeylen = outkeylen;
779 }
780
781 /* Copy the found data to our buffer */
782 p = strncpy (buffer, outval, buflen);
783
784 /* ...and free the data. */
785 free (outval);
786
787 while (isspace (*p))
788 ++p;
789 parse_res = _nss_files_parse_pwent (p, result, data, buflen, errnop);
790 if (parse_res == -1)
791 {
792 free (ent->oldkey);
793 ent->oldkey = saved_oldkey;
794 ent->oldkeylen = saved_oldlen;
795 ent->first = saved_first;
796 *errnop = ERANGE;
797 return NSS_STATUS_TRYAGAIN;
798 }
799 else
800 {
801 if (!saved_first)
802 free (saved_oldkey);
803 }
804 if (parse_res
805 && in_blacklist (result->pw_name, strlen (result->pw_name), ent))
806 parse_res = 0;
807 }
808 while (!parse_res);
809
810 copy_pwd_changes (result, &ent->pwd, p2, p2len);
811
812 return NSS_STATUS_SUCCESS;
813 }
814
815 /* This function handle the +user entrys in /etc/passwd */
816 static enum nss_status
817 getpwnam_plususer (const char *name, struct passwd *result, ent_t *ent,
818 char *buffer, size_t buflen, int *errnop)
819 {
820 struct parser_data *data = (void *) buffer;
821 struct passwd pwd;
822 int parse_res;
823 char *p;
824 size_t plen;
825
826 memset (&pwd, '\0', sizeof (struct passwd));
827
828 copy_pwd_changes (&pwd, result, NULL, 0);
829
830 plen = pwd_need_buflen (&pwd);
831 if (plen > buflen)
832 {
833 *errnop = ERANGE;
834 return NSS_STATUS_TRYAGAIN;
835 }
836 p = buffer + (buflen - plen);
837 buflen -= plen;
838
839 if (use_nisplus) /* Do the NIS+ query here */
840 {
841 nis_result *res;
842 char buf[strlen (name) + 24 + pwdtablelen];
843
844 sprintf(buf, "[name=%s],%s", name, pwdtable);
845 res = nis_list(buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
846 if (niserr2nss (res->status) != NSS_STATUS_SUCCESS)
847 {
848 enum nss_status status = niserr2nss (res->status);
849
850 nis_freeresult (res);
851 return status;
852 }
853 parse_res = _nss_nisplus_parse_pwent (res, result, buffer,
854 buflen, errnop);
855
856 nis_freeresult (res);
857
858 if (parse_res == -1)
859 {
860 *errnop = ERANGE;
861 return NSS_STATUS_TRYAGAIN;
862 }
863
864 if (in_blacklist (result->pw_name, strlen (result->pw_name), ent))
865 {
866 *errnop = ENOENT;
867 return NSS_STATUS_NOTFOUND;
868 }
869 }
870 else /* Use NIS */
871 {
872 char *domain, *outval, *ptr;
873 int outvallen;
874
875 if (yp_get_default_domain (&domain) != YPERR_SUCCESS)
876 {
877 *errnop = ENOENT;
878 return NSS_STATUS_NOTFOUND;
879 }
880
881 if (yp_match (domain, "passwd.byname", name, strlen (name),
882 &outval, &outvallen) != YPERR_SUCCESS)
883 {
884 *errnop = ENOENT;
885 return NSS_STATUS_NOTFOUND;
886 }
887
888 if (insert_passwd_adjunct (&outval, &outvallen, domain, errnop)
889 != NSS_STATUS_SUCCESS)
890 {
891 free (outval);
892 return NSS_STATUS_TRYAGAIN;
893 }
894
895 if (buflen < ((size_t) outvallen + 1))
896 {
897 free (outval);
898 *errnop = ERANGE;
899 return NSS_STATUS_TRYAGAIN;
900 }
901
902 ptr = strncpy (buffer, outval, buflen);
903 free (outval);
904
905 while (isspace (*ptr))
906 ptr++;
907
908 parse_res = _nss_files_parse_pwent (ptr, result, data, buflen, errnop);
909 if (parse_res == -1)
910 return NSS_STATUS_TRYAGAIN;
911
912 if (in_blacklist (result->pw_name, strlen (result->pw_name), ent))
913 {
914 *errnop = ENOENT;
915 return NSS_STATUS_NOTFOUND;
916 }
917 }
918
919 if (parse_res > 0)
920 {
921 copy_pwd_changes (result, &pwd, p, plen);
922 give_pwd_free (&pwd);
923 /* We found the entry. */
924 return NSS_STATUS_SUCCESS;
925 }
926 else
927 {
928 /* Give buffer the old len back */
929 buflen += plen;
930 give_pwd_free (&pwd);
931 }
932 return NSS_STATUS_RETURN;
933 }
934
935 static enum nss_status
936 getpwent_next_file (struct passwd *result, ent_t *ent,
937 char *buffer, size_t buflen, int *errnop)
938 {
939 struct parser_data *data = (void *) buffer;
940 while (1)
941 {
942 fpos_t pos;
943 char *p;
944 int parse_res;
945
946 do
947 {
948 fgetpos (ent->stream, &pos);
949 buffer[buflen - 1] = '\xff';
950 p = fgets (buffer, buflen, ent->stream);
951 if (p == NULL && feof (ent->stream))
952 {
953 *errnop = ENOENT;
954 return NSS_STATUS_NOTFOUND;
955 }
956 if (p == NULL || buffer[buflen - 1] != '\xff')
957 {
958 fsetpos (ent->stream, &pos);
959 *errnop = ERANGE;
960 return NSS_STATUS_TRYAGAIN;
961 }
962
963 /* Terminate the line for any case. */
964 buffer[buflen - 1] = '\0';
965
966 /* Skip leading blanks. */
967 while (isspace (*p))
968 ++p;
969 }
970 while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */
971 /* Parse the line. If it is invalid, loop to
972 get the next line of the file to parse. */
973 !(parse_res = _nss_files_parse_pwent (p, result, data, buflen,
974 errnop)));
975
976 if (parse_res == -1)
977 {
978 /* The parser ran out of space. */
979 fsetpos (ent->stream, &pos);
980 *errnop = ERANGE;
981 return NSS_STATUS_TRYAGAIN;
982 }
983
984 if (result->pw_name[0] != '+' && result->pw_name[0] != '-')
985 /* This is a real entry. */
986 break;
987
988 /* -@netgroup */
989 if (result->pw_name[0] == '-' && result->pw_name[1] == '@'
990 && result->pw_name[2] != '\0')
991 {
992 /* XXX Do not use fixed length buffer. */
993 char buf2[1024];
994 char *user, *host, *domain;
995 struct __netgrent netgrdata;
996
997 bzero (&netgrdata, sizeof (struct __netgrent));
998 __internal_setnetgrent (&result->pw_name[2], &netgrdata);
999 while (__internal_getnetgrent_r (&host, &user, &domain, &netgrdata,
1000 buf2, sizeof (buf2), errnop))
1001 {
1002 if (user != NULL && user[0] != '-')
1003 blacklist_store_name (user, ent);
1004 }
1005 __internal_endnetgrent (&netgrdata);
1006 continue;
1007 }
1008
1009 /* +@netgroup */
1010 if (result->pw_name[0] == '+' && result->pw_name[1] == '@'
1011 && result->pw_name[2] != '\0')
1012 {
1013 enum nss_status status;
1014
1015 ent->netgroup = TRUE;
1016 ent->first = TRUE;
1017 copy_pwd_changes (&ent->pwd, result, NULL, 0);
1018
1019 if (use_nisplus)
1020 status = getpwent_next_nisplus_netgr (NULL, result, ent,
1021 &result->pw_name[2],
1022 buffer, buflen, errnop);
1023 else
1024 status = getpwent_next_nis_netgr (NULL, result, ent,
1025 &result->pw_name[2],
1026 buffer, buflen, errnop);
1027 if (status == NSS_STATUS_RETURN)
1028 continue;
1029 else
1030 {
1031 if (status == NSS_STATUS_NOTFOUND)
1032 *errnop = ENOENT;
1033 return status;
1034 }
1035 }
1036
1037 /* -user */
1038 if (result->pw_name[0] == '-' && result->pw_name[1] != '\0'
1039 && result->pw_name[1] != '@')
1040 {
1041 blacklist_store_name (&result->pw_name[1], ent);
1042 continue;
1043 }
1044
1045 /* +user */
1046 if (result->pw_name[0] == '+' && result->pw_name[1] != '\0'
1047 && result->pw_name[1] != '@')
1048 {
1049 char buf[strlen (result->pw_name)];
1050 enum nss_status status;
1051
1052 /* Store the User in the blacklist for the "+" at the end of
1053 /etc/passwd */
1054 strcpy (buf, &result->pw_name[1]);
1055 status = getpwnam_plususer (&result->pw_name[1], result, ent,
1056 buffer, buflen, errnop);
1057 blacklist_store_name (buf, ent);
1058
1059 if (status == NSS_STATUS_SUCCESS) /* We found the entry. */
1060 break;
1061 else
1062 if (status == NSS_STATUS_RETURN /* We couldn't parse the entry */
1063 || status == NSS_STATUS_NOTFOUND) /* entry doesn't exist */
1064 continue;
1065 else
1066 {
1067 if (status == NSS_STATUS_TRYAGAIN)
1068 {
1069 /* The parser ran out of space */
1070 fsetpos (ent->stream, &pos);
1071 *errnop = ERANGE;
1072 }
1073 return status;
1074 }
1075 }
1076
1077 /* +:... */
1078 if (result->pw_name[0] == '+' && result->pw_name[1] == '\0')
1079 {
1080 ent->nis = TRUE;
1081 ent->first = TRUE;
1082 copy_pwd_changes (&ent->pwd, result, NULL, 0);
1083
1084 if (use_nisplus)
1085 return getpwent_next_nisplus (result, ent, buffer, buflen, errnop);
1086 else
1087 return getpwent_next_nis (result, ent, buffer, buflen, errnop);
1088 }
1089 }
1090
1091 return NSS_STATUS_SUCCESS;
1092 }
1093
1094
1095 static enum nss_status
1096 internal_getpwent_r (struct passwd *pw, ent_t *ent, char *buffer,
1097 size_t buflen, int *errnop)
1098 {
1099 if (ent->netgroup)
1100 {
1101 enum nss_status status;
1102
1103 /* We are searching members in a netgroup */
1104 /* Since this is not the first call, we don't need the group name */
1105 if (use_nisplus)
1106 status = getpwent_next_nisplus_netgr (NULL, pw, ent, NULL, buffer,
1107 buflen, errnop);
1108 else
1109 status = getpwent_next_nis_netgr (NULL, pw, ent, NULL, buffer, buflen,
1110 errnop);
1111 if (status == NSS_STATUS_RETURN)
1112 return getpwent_next_file (pw, ent, buffer, buflen, errnop);
1113 else
1114 return status;
1115 }
1116 else
1117 if (ent->nis)
1118 {
1119 if (use_nisplus)
1120 return getpwent_next_nisplus (pw, ent, buffer, buflen, errnop);
1121 else
1122 return getpwent_next_nis (pw, ent, buffer, buflen, errnop);
1123 }
1124 else
1125 return getpwent_next_file (pw, ent, buffer, buflen, errnop);
1126 }
1127
1128 enum nss_status
1129 _nss_compat_getpwent_r (struct passwd *pwd, char *buffer, size_t buflen,
1130 int *errnop)
1131 {
1132 enum nss_status status = NSS_STATUS_SUCCESS;
1133
1134 __libc_lock_lock (lock);
1135
1136 if (ni == NULL)
1137 {
1138 __nss_database_lookup ("passwd_compat", NULL, "nis", &ni);
1139 use_nisplus = (strcmp (ni->name, "nisplus") == 0);
1140 }
1141
1142 /* Be prepared that the setpwent function was not called before. */
1143 if (ext_ent.stream == NULL)
1144 status = internal_setpwent (&ext_ent);
1145
1146 if (status == NSS_STATUS_SUCCESS)
1147 status = internal_getpwent_r (pwd, &ext_ent, buffer, buflen, errnop);
1148
1149 __libc_lock_unlock (lock);
1150
1151 return status;
1152 }
1153
1154 /* Searches in /etc/passwd and the NIS/NIS+ map for a special user */
1155 static enum nss_status
1156 internal_getpwnam_r (const char *name, struct passwd *result, ent_t *ent,
1157 char *buffer, size_t buflen, int *errnop)
1158 {
1159 struct parser_data *data = (void *) buffer;
1160
1161 while (1)
1162 {
1163 fpos_t pos;
1164 char *p;
1165 int parse_res;
1166
1167 do
1168 {
1169 fgetpos (ent->stream, &pos);
1170 buffer[buflen - 1] = '\xff';
1171 p = fgets (buffer, buflen, ent->stream);
1172 if (p == NULL && feof (ent->stream))
1173 {
1174 *errnop = ENOENT;
1175 return NSS_STATUS_NOTFOUND;
1176 }
1177 if (p == NULL || buffer[buflen - 1] != '\xff')
1178 {
1179 fsetpos (ent->stream, &pos);
1180 *errnop = ERANGE;
1181 return NSS_STATUS_TRYAGAIN;
1182 }
1183
1184 /* Terminate the line for any case. */
1185 buffer[buflen - 1] = '\0';
1186
1187 /* Skip leading blanks. */
1188 while (isspace (*p))
1189 ++p;
1190 }
1191 while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */
1192 /* Parse the line. If it is invalid, loop to
1193 get the next line of the file to parse. */
1194 !(parse_res = _nss_files_parse_pwent (p, result, data, buflen,
1195 errnop)));
1196
1197 if (parse_res == -1)
1198 {
1199 /* The parser ran out of space. */
1200 fsetpos (ent->stream, &pos);
1201 *errnop = ERANGE;
1202 return NSS_STATUS_TRYAGAIN;
1203 }
1204
1205 /* This is a real entry. */
1206 if (result->pw_name[0] != '+' && result->pw_name[0] != '-')
1207 {
1208 if (strcmp (result->pw_name, name) == 0)
1209 return NSS_STATUS_SUCCESS;
1210 else
1211 continue;
1212 }
1213
1214 /* -@netgroup */
1215 if (result->pw_name[0] == '-' && result->pw_name[1] == '@'
1216 && result->pw_name[2] != '\0')
1217 {
1218 if (innetgr (&result->pw_name[2], NULL, name, NULL))
1219 return NSS_STATUS_NOTFOUND;
1220 continue;
1221 }
1222
1223 /* +@netgroup */
1224 if (result->pw_name[0] == '+' && result->pw_name[1] == '@'
1225 && result->pw_name[2] != '\0')
1226 {
1227 enum nss_status status;
1228
1229 if (innetgr (&result->pw_name[2], NULL, name, NULL))
1230 {
1231 status = getpwnam_plususer (name, result, ent, buffer,
1232 buflen, errnop);
1233
1234 if (status == NSS_STATUS_RETURN)
1235 continue;
1236
1237 return status;
1238 }
1239 continue;
1240 }
1241
1242 /* -user */
1243 if (result->pw_name[0] == '-' && result->pw_name[1] != '\0'
1244 && result->pw_name[1] != '@')
1245 {
1246 if (strcmp (&result->pw_name[1], name) == 0)
1247 {
1248 *errnop = ENOENT;
1249 return NSS_STATUS_NOTFOUND;
1250 }
1251 else
1252 continue;
1253 }
1254
1255 /* +user */
1256 if (result->pw_name[0] == '+' && result->pw_name[1] != '\0'
1257 && result->pw_name[1] != '@')
1258 {
1259 if (strcmp (name, &result->pw_name[1]) == 0)
1260 {
1261 enum nss_status status;
1262
1263 status = getpwnam_plususer (name, result, ent, buffer, buflen,
1264 errnop);
1265 if (status == NSS_STATUS_RETURN)
1266 /* We couldn't parse the entry */
1267 return NSS_STATUS_NOTFOUND;
1268 else
1269 return status;
1270 }
1271 }
1272
1273 /* +:... */
1274 if (result->pw_name[0] == '+' && result->pw_name[1] == '\0')
1275 {
1276 enum nss_status status;
1277
1278 status = getpwnam_plususer (name, result, ent,
1279 buffer, buflen, errnop);
1280 if (status == NSS_STATUS_SUCCESS) /* We found the entry. */
1281 break;
1282 else
1283 if (status == NSS_STATUS_RETURN) /* We couldn't parse the entry */
1284 return NSS_STATUS_NOTFOUND;
1285 else
1286 return status;
1287 }
1288 }
1289 return NSS_STATUS_SUCCESS;
1290 }
1291
1292 enum nss_status
1293 _nss_compat_getpwnam_r (const char *name, struct passwd *pwd,
1294 char *buffer, size_t buflen, int *errnop)
1295 {
1296 ent_t ent = {0, 0, 0, NULL, 0, NULL, NULL, {NULL, 0, 0},
1297 {NULL, NULL, 0, 0, NULL, NULL, NULL}};
1298 enum nss_status status;
1299
1300 if (name[0] == '-' || name[0] == '+')
1301 {
1302 *errnop = ENOENT;
1303 return NSS_STATUS_NOTFOUND;
1304 }
1305
1306 __libc_lock_lock (lock);
1307
1308 if (ni == NULL)
1309 {
1310 __nss_database_lookup ("passwd_compat", NULL, "nis", &ni);
1311 use_nisplus = (strcmp (ni->name, "nisplus") == 0);
1312 }
1313
1314 __libc_lock_unlock (lock);
1315
1316 status = internal_setpwent (&ent);
1317 if (status != NSS_STATUS_SUCCESS)
1318 return status;
1319
1320 status = internal_getpwnam_r (name, pwd, &ent, buffer, buflen, errnop);
1321
1322 internal_endpwent (&ent);
1323
1324 return status;
1325 }
1326
1327 /* This function handle the + entry in /etc/passwd for getpwuid */
1328 static enum nss_status
1329 getpwuid_plususer (uid_t uid, struct passwd *result, char *buffer,
1330 size_t buflen, int *errnop)
1331 {
1332 struct parser_data *data = (void *) buffer;
1333 struct passwd pwd;
1334 int parse_res;
1335 char *p;
1336 size_t plen;
1337
1338 memset (&pwd, '\0', sizeof (struct passwd));
1339
1340 copy_pwd_changes (&pwd, result, NULL, 0);
1341
1342 plen = pwd_need_buflen (&pwd);
1343 if (plen > buflen)
1344 {
1345 *errnop = ERANGE;
1346 return NSS_STATUS_TRYAGAIN;
1347 }
1348 p = buffer + (buflen - plen);
1349 buflen -= plen;
1350
1351 if (use_nisplus) /* Do the NIS+ query here */
1352 {
1353 nis_result *res;
1354 char buf[1024 + pwdtablelen];
1355
1356 snprintf (buf, sizeof (buf), "[uid=%lu],%s", (unsigned long int) uid,
1357 pwdtable);
1358 res = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
1359 if (niserr2nss (res->status) != NSS_STATUS_SUCCESS)
1360 {
1361 enum nss_status status = niserr2nss (res->status);
1362
1363 nis_freeresult (res);
1364 return status;
1365 }
1366 if ((parse_res = _nss_nisplus_parse_pwent (res, result, buffer,
1367 buflen, errnop)) == -1)
1368 {
1369 nis_freeresult (res);
1370 *errnop = ERANGE;
1371 return NSS_STATUS_TRYAGAIN;
1372 }
1373 nis_freeresult (res);
1374 }
1375 else /* Use NIS */
1376 {
1377 char buf[1024];
1378 char *domain, *outval, *ptr;
1379 int outvallen;
1380
1381 if (yp_get_default_domain (&domain) != YPERR_SUCCESS)
1382 {
1383 *errnop = ENOENT;
1384 return NSS_STATUS_NOTFOUND;
1385 }
1386
1387 sprintf (buf, "%lu", (unsigned long int) uid);
1388 if (yp_match (domain, "passwd.byuid", buf, strlen (buf),
1389 &outval, &outvallen)
1390 != YPERR_SUCCESS)
1391 {
1392 *errnop = ENOENT;
1393 return NSS_STATUS_NOTFOUND;
1394 }
1395
1396 if (insert_passwd_adjunct (&outval, &outvallen, domain, errnop)
1397 != NSS_STATUS_SUCCESS)
1398 {
1399 free (outval);
1400 return NSS_STATUS_TRYAGAIN;
1401 }
1402
1403 if (buflen < ((size_t) outvallen + 1))
1404 {
1405 free (outval);
1406 *errnop = ERANGE;
1407 return NSS_STATUS_TRYAGAIN;
1408 }
1409
1410 ptr = strncpy (buffer, outval, buflen);
1411 free (outval);
1412
1413 while (isspace (*ptr))
1414 ptr++;
1415 parse_res = _nss_files_parse_pwent (ptr, result, data, buflen, errnop);
1416 if (parse_res == -1)
1417 return NSS_STATUS_TRYAGAIN;
1418 }
1419
1420 if (parse_res > 0)
1421 {
1422 copy_pwd_changes (result, &pwd, p, plen);
1423 give_pwd_free (&pwd);
1424 /* We found the entry. */
1425 return NSS_STATUS_SUCCESS;
1426 }
1427 else
1428 {
1429 /* Give buffer the old len back */
1430 buflen += plen;
1431 give_pwd_free (&pwd);
1432 }
1433 return NSS_STATUS_RETURN;
1434 }
1435
1436 /* Searches in /etc/passwd and the NIS/NIS+ map for a special user id */
1437 static enum nss_status
1438 internal_getpwuid_r (uid_t uid, struct passwd *result, ent_t *ent,
1439 char *buffer, size_t buflen, int *errnop)
1440 {
1441 struct parser_data *data = (void *) buffer;
1442
1443 while (1)
1444 {
1445 fpos_t pos;
1446 char *p;
1447 int parse_res;
1448
1449 do
1450 {
1451 fgetpos (ent->stream, &pos);
1452 buffer[buflen - 1] = '\xff';
1453 p = fgets (buffer, buflen, ent->stream);
1454 if (p == NULL && feof (ent->stream))
1455 {
1456 *errnop = ENOENT;
1457 return NSS_STATUS_NOTFOUND;
1458 }
1459 if (p == NULL || buffer[buflen - 1] != '\xff')
1460 {
1461 fsetpos (ent->stream, &pos);
1462 *errnop = ERANGE;
1463 return NSS_STATUS_TRYAGAIN;
1464 }
1465
1466 /* Terminate the line for any case. */
1467 buffer[buflen - 1] = '\0';
1468
1469 /* Skip leading blanks. */
1470 while (isspace (*p))
1471 ++p;
1472 }
1473 while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */
1474 /* Parse the line. If it is invalid, loop to
1475 get the next line of the file to parse. */
1476 !(parse_res = _nss_files_parse_pwent (p, result, data, buflen,
1477 errnop)));
1478
1479 if (parse_res == -1)
1480 {
1481 /* The parser ran out of space. */
1482 fsetpos (ent->stream, &pos);
1483 *errnop = ERANGE;
1484 return NSS_STATUS_TRYAGAIN;
1485 }
1486
1487 /* This is a real entry. */
1488 if (result->pw_name[0] != '+' && result->pw_name[0] != '-')
1489 {
1490 if (result->pw_uid == uid)
1491 return NSS_STATUS_SUCCESS;
1492 else
1493 continue;
1494 }
1495
1496 /* -@netgroup */
1497 if (result->pw_name[0] == '-' && result->pw_name[1] == '@'
1498 && result->pw_name[2] != '\0')
1499 {
1500 char buf[strlen (result->pw_name)];
1501 enum nss_status status;
1502
1503 strcpy (buf, &result->pw_name[2]);
1504
1505 status = getpwuid_plususer (uid, result, buffer, buflen, errnop);
1506 if (status == NSS_STATUS_SUCCESS &&
1507 innetgr (buf, NULL, result->pw_name, NULL))
1508 {
1509 *errnop = ENOENT;
1510 return NSS_STATUS_NOTFOUND;
1511 }
1512 continue;
1513 }
1514
1515 /* +@netgroup */
1516 if (result->pw_name[0] == '+' && result->pw_name[1] == '@'
1517 && result->pw_name[2] != '\0')
1518 {
1519 char buf[strlen (result->pw_name)];
1520 enum nss_status status;
1521
1522 strcpy (buf, &result->pw_name[2]);
1523
1524 status = getpwuid_plususer (uid, result, buffer, buflen, errnop);
1525
1526 if (status == NSS_STATUS_RETURN)
1527 continue;
1528
1529 if (status == NSS_STATUS_SUCCESS)
1530 {
1531 if (innetgr (buf, NULL, result->pw_name, NULL))
1532 return NSS_STATUS_SUCCESS;
1533 }
1534 else
1535 if (status == NSS_STATUS_RETURN) /* We couldn't parse the entry */
1536 {
1537 *errnop = ENOENT;
1538 return NSS_STATUS_NOTFOUND;
1539 }
1540 else
1541 return status;
1542
1543 continue;
1544 }
1545
1546 /* -user */
1547 if (result->pw_name[0] == '-' && result->pw_name[1] != '\0'
1548 && result->pw_name[1] != '@')
1549 {
1550 char buf[strlen (result->pw_name)];
1551 enum nss_status status;
1552
1553 strcpy (buf, &result->pw_name[1]);
1554
1555 status = getpwuid_plususer (uid, result, buffer, buflen, errnop);
1556 if (status == NSS_STATUS_SUCCESS &&
1557 innetgr (buf, NULL, result->pw_name, NULL))
1558 {
1559 *errnop = ENOENT;
1560 return NSS_STATUS_NOTFOUND;
1561 }
1562 continue;
1563 }
1564
1565 /* +user */
1566 if (result->pw_name[0] == '+' && result->pw_name[1] != '\0'
1567 && result->pw_name[1] != '@')
1568 {
1569 char buf[strlen (result->pw_name)];
1570 enum nss_status status;
1571
1572 strcpy (buf, &result->pw_name[1]);
1573
1574 status = getpwuid_plususer (uid, result, buffer, buflen, errnop);
1575
1576 if (status == NSS_STATUS_RETURN)
1577 continue;
1578
1579 if (status == NSS_STATUS_SUCCESS)
1580 {
1581 if (strcmp (buf, result->pw_name) == 0)
1582 return NSS_STATUS_SUCCESS;
1583 }
1584 else
1585 if (status == NSS_STATUS_RETURN) /* We couldn't parse the entry */
1586 {
1587 *errnop = ENOENT;
1588 return NSS_STATUS_NOTFOUND;
1589 }
1590 else
1591 return status;
1592
1593 continue;
1594 }
1595
1596 /* +:... */
1597 if (result->pw_name[0] == '+' && result->pw_name[1] == '\0')
1598 {
1599 enum nss_status status;
1600
1601 status = getpwuid_plususer (uid, result, buffer, buflen, errnop);
1602 if (status == NSS_STATUS_SUCCESS) /* We found the entry. */
1603 break;
1604 else
1605 if (status == NSS_STATUS_RETURN) /* We couldn't parse the entry */
1606 {
1607 *errnop = ENOENT;
1608 return NSS_STATUS_NOTFOUND;
1609 }
1610 else
1611 return status;
1612 }
1613 }
1614 return NSS_STATUS_SUCCESS;
1615 }
1616
1617 enum nss_status
1618 _nss_compat_getpwuid_r (uid_t uid, struct passwd *pwd,
1619 char *buffer, size_t buflen, int *errnop)
1620 {
1621 ent_t ent = {0, 0, 0, NULL, 0, NULL, NULL, {NULL, 0, 0},
1622 {NULL, NULL, 0, 0, NULL, NULL, NULL}};
1623 enum nss_status status;
1624
1625 __libc_lock_lock (lock);
1626
1627 if (ni == NULL)
1628 {
1629 __nss_database_lookup ("passwd_compat", NULL, "nis", &ni);
1630 use_nisplus = (strcmp (ni->name, "nisplus") == 0);
1631 }
1632
1633 __libc_lock_unlock (lock);
1634
1635 status = internal_setpwent (&ent);
1636 if (status != NSS_STATUS_SUCCESS)
1637 return status;
1638
1639 status = internal_getpwuid_r (uid, pwd, &ent, buffer, buflen, errnop);
1640
1641 internal_endpwent (&ent);
1642
1643 return status;
1644 }
1645
1646
1647 /* Support routines for remembering -@netgroup and -user entries.
1648 The names are stored in a single string with `|' as separator. */
1649 static void
1650 blacklist_store_name (const char *name, ent_t *ent)
1651 {
1652 int namelen = strlen (name);
1653 char *tmp;
1654
1655 /* first call, setup cache */
1656 if (ent->blacklist.size == 0)
1657 {
1658 ent->blacklist.size = MAX (BLACKLIST_INITIAL_SIZE, 2 * namelen);
1659 ent->blacklist.data = malloc (ent->blacklist.size);
1660 if (ent->blacklist.data == NULL)
1661 return;
1662 ent->blacklist.data[0] = '|';
1663 ent->blacklist.data[1] = '\0';
1664 ent->blacklist.current = 1;
1665 }
1666 else
1667 {
1668 if (in_blacklist (name, namelen, ent))
1669 return; /* no duplicates */
1670
1671 if (ent->blacklist.current + namelen + 1 >= ent->blacklist.size)
1672 {
1673 ent->blacklist.size += MAX (BLACKLIST_INCREMENT, 2 * namelen);
1674 tmp = realloc (ent->blacklist.data, ent->blacklist.size);
1675 if (tmp == NULL)
1676 {
1677 free (ent->blacklist.data);
1678 ent->blacklist.size = 0;
1679 return;
1680 }
1681 ent->blacklist.data = tmp;
1682 }
1683 }
1684
1685 tmp = stpcpy (ent->blacklist.data + ent->blacklist.current, name);
1686 *tmp++ = '|';
1687 *tmp = '\0';
1688 ent->blacklist.current += namelen + 1;
1689
1690 return;
1691 }
1692
1693 /* returns TRUE if ent->blacklist contains name, else FALSE */
1694 static bool_t
1695 in_blacklist (const char *name, int namelen, ent_t *ent)
1696 {
1697 char buf[namelen + 3];
1698 char *cp;
1699
1700 if (ent->blacklist.data == NULL)
1701 return FALSE;
1702
1703 buf[0] = '|';
1704 cp = stpcpy (&buf[1], name);
1705 *cp++= '|';
1706 *cp = '\0';
1707 return strstr (ent->blacklist.data, buf) != NULL;
1708 }