(internal_setpwent): Set FD_CLOEXEC for stream on input file.
[glibc/history.git] / nis / nss_compat / compat-pwd.c
blob6fac0f46c62b965e7fc016227fff85fbaa74ca7f
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.
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.
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.
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. */
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 <rpcsvc/nislib.h>
32 #include <nsswitch.h>
34 #include "netgroup.h"
35 #include "nss-nisplus.h"
36 #include "nisplus-parser.h"
38 static service_user *ni = NULL;
39 static bool_t use_nisplus = FALSE; /* default: passwd_compat: nis */
40 static nis_name pwdtable = NULL; /* Name of the pwd table */
41 static size_t pwdtablelen = 0;
43 /* Get the declaration of the parser function. */
44 #define ENTNAME pwent
45 #define STRUCTURE passwd
46 #define EXTERN_PARSER
47 #include "../../nss/nss_files/files-parse.c"
49 /* Structure for remembering -@netgroup and -user members ... */
50 #define BLACKLIST_INITIAL_SIZE 512
51 #define BLACKLIST_INCREMENT 256
52 struct blacklist_t
54 char *data;
55 int current;
56 int size;
59 struct ent_t
61 bool_t netgroup;
62 bool_t nis;
63 bool_t first;
64 char *oldkey;
65 int oldkeylen;
66 nis_result *result;
67 FILE *stream;
68 struct blacklist_t blacklist;
69 struct passwd pwd;
70 struct __netgrent netgrdata;
72 typedef struct ent_t ent_t;
74 static ent_t ext_ent = {0, 0, 0, NULL, 0, NULL, NULL, {NULL, 0, 0},
75 {NULL, NULL, 0, 0, NULL, NULL, NULL}};
77 /* Protect global state against multiple changers. */
78 __libc_lock_define_initialized (static, lock)
80 /* Prototypes for local functions. */
81 static void blacklist_store_name (const char *, ent_t *);
82 static int in_blacklist (const char *, int, ent_t *);
84 static void
85 give_pwd_free (struct passwd *pwd)
87 if (pwd->pw_name != NULL)
88 free (pwd->pw_name);
89 if (pwd->pw_passwd != NULL)
90 free (pwd->pw_passwd);
91 if (pwd->pw_gecos != NULL)
92 free (pwd->pw_gecos);
93 if (pwd->pw_dir != NULL)
94 free (pwd->pw_dir);
95 if (pwd->pw_shell != NULL)
96 free (pwd->pw_shell);
98 memset (pwd, '\0', sizeof (struct passwd));
101 static size_t
102 pwd_need_buflen (struct passwd *pwd)
104 size_t len = 0;
106 if (pwd->pw_passwd != NULL)
107 len += strlen (pwd->pw_passwd) + 1;
109 if (pwd->pw_gecos != NULL)
110 len += strlen (pwd->pw_gecos) + 1;
112 if (pwd->pw_dir != NULL)
113 len += strlen (pwd->pw_dir) + 1;
115 if (pwd->pw_shell != NULL)
116 len += strlen (pwd->pw_shell) + 1;
118 return len;
121 static void
122 copy_pwd_changes (struct passwd *dest, struct passwd *src,
123 char *buffer, size_t buflen)
125 if (src->pw_passwd != NULL && strlen (src->pw_passwd))
127 if (buffer == NULL)
128 dest->pw_passwd = strdup (src->pw_passwd);
129 else if (dest->pw_passwd &&
130 strlen (dest->pw_passwd) >= strlen (src->pw_passwd))
131 strcpy (dest->pw_passwd, src->pw_passwd);
132 else
134 dest->pw_passwd = buffer;
135 strcpy (dest->pw_passwd, src->pw_passwd);
136 buffer += strlen (dest->pw_passwd) + 1;
137 buflen = buflen - (strlen (dest->pw_passwd) + 1);
141 if (src->pw_gecos != NULL && strlen (src->pw_gecos))
143 if (buffer == NULL)
144 dest->pw_gecos = strdup (src->pw_gecos);
145 else if (dest->pw_gecos &&
146 strlen (dest->pw_gecos) >= strlen (src->pw_gecos))
147 strcpy (dest->pw_gecos, src->pw_gecos);
148 else
150 dest->pw_gecos = buffer;
151 strcpy (dest->pw_gecos, src->pw_gecos);
152 buffer += strlen (dest->pw_gecos) + 1;
153 buflen = buflen - (strlen (dest->pw_gecos) + 1);
156 if (src->pw_dir != NULL && strlen (src->pw_dir))
158 if (buffer == NULL)
159 dest->pw_dir = strdup (src->pw_dir);
160 else if (dest->pw_dir &&
161 strlen (dest->pw_dir) >= strlen (src->pw_dir))
162 strcpy (dest->pw_dir, src->pw_dir);
163 else
165 dest->pw_dir = buffer;
166 strcpy (dest->pw_dir, src->pw_dir);
167 buffer += strlen (dest->pw_dir) + 1;
168 buflen = buflen - (strlen (dest->pw_dir) + 1);
172 if (src->pw_shell != NULL && strlen (src->pw_shell))
174 if (buffer == NULL)
175 dest->pw_shell = strdup (src->pw_shell);
176 else if (dest->pw_shell &&
177 strlen (dest->pw_shell) >= strlen (src->pw_shell))
178 strcpy (dest->pw_shell, src->pw_shell);
179 else
181 dest->pw_shell = buffer;
182 strcpy (dest->pw_shell, src->pw_shell);
183 buffer += strlen (dest->pw_shell) + 1;
184 buflen = buflen - (strlen (dest->pw_shell) + 1);
189 static enum nss_status
190 internal_setpwent (ent_t *ent)
192 enum nss_status status = NSS_STATUS_SUCCESS;
194 ent->nis = ent->first = ent->netgroup = 0;
196 /* If something was left over free it. */
197 if (ent->netgroup)
198 __internal_endnetgrent (&ent->netgrdata);
200 if (ent->oldkey != NULL)
202 free (ent->oldkey);
203 ent->oldkey = NULL;
204 ent->oldkeylen = 0;
207 if (ent->result != NULL)
209 nis_freeresult (ent->result);
210 ent->result = NULL;
213 if (pwdtable == NULL)
215 char buf [20 + strlen (nis_local_directory ())];
216 char *p;
218 p = stpcpy (buf, "passwd.org_dir.");
219 p = stpcpy (p, nis_local_directory ());
220 pwdtable = strdup (buf);
221 if (pwdtable == NULL)
222 return NSS_STATUS_TRYAGAIN;
223 pwdtablelen = strlen (pwdtable);
226 ent->blacklist.current = 0;
227 if (ent->blacklist.data != NULL)
228 ent->blacklist.data[0] = '\0';
230 if (ent->stream == NULL)
232 ent->stream = fopen ("/etc/passwd", "r");
234 if (ent->stream == NULL)
235 status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL;
236 else
238 /* We have to make sure the file is `closed on exec'. */
239 int result, flags;
241 result = flags = fcntl (fileno (ent->stream), F_GETFD, 0);
242 if (result >= 0)
244 flags |= FD_CLOEXEC;
245 result = fcntl (fileno (ent->stream), F_SETFD, flags);
247 if (result < 0)
249 /* Something went wrong. Close the stream and return a
250 failure. */
251 fclose (ent->stream);
252 ent->stream = NULL;
253 status = NSS_STATUS_UNAVAIL;
257 else
258 rewind (ent->stream);
260 give_pwd_free (&ent->pwd);
262 return status;
266 enum nss_status
267 _nss_compat_setpwent (void)
269 enum nss_status result;
271 __libc_lock_lock (lock);
273 if (ni == NULL)
275 __nss_database_lookup ("passwd_compat", NULL, "nis", &ni);
276 use_nisplus = (strcmp (ni->name, "nisplus") == 0);
279 result = internal_setpwent (&ext_ent);
281 __libc_lock_unlock (lock);
283 return result;
287 static enum nss_status
288 internal_endpwent (ent_t *ent)
290 if (ent->stream != NULL)
292 fclose (ent->stream);
293 ent->stream = NULL;
296 if (ent->netgroup)
297 __internal_endnetgrent (&ent->netgrdata);
299 ent->nis = ent->first = ent->netgroup = 0;
301 if (ent->oldkey != NULL)
303 free (ent->oldkey);
304 ent->oldkey = NULL;
305 ent->oldkeylen = 0;
308 if (ent->result != NULL)
310 nis_freeresult (ent->result);
311 ent->result = NULL;
314 ent->blacklist.current = 0;
315 if (ent->blacklist.data != NULL)
316 ent->blacklist.data[0] = '\0';
318 give_pwd_free (&ent->pwd);
320 return NSS_STATUS_SUCCESS;
323 enum nss_status
324 _nss_compat_endpwent (void)
326 enum nss_status result;
328 __libc_lock_lock (lock);
330 result = internal_endpwent (&ext_ent);
332 __libc_lock_unlock (lock);
334 return result;
337 static enum nss_status
338 getpwent_next_nis_netgr (struct passwd *result, ent_t *ent, char *group,
339 char *buffer, size_t buflen)
341 struct parser_data *data = (void *) buffer;
342 char *ypdomain, *host, *user, *domain, *outval, *p, *p2;
343 int status, outvallen;
344 size_t p2len;
346 if (yp_get_default_domain (&ypdomain) != YPERR_SUCCESS)
348 ent->netgroup = 0;
349 ent->first = 0;
350 give_pwd_free (&ent->pwd);
351 return NSS_STATUS_UNAVAIL;
354 if (ent->first == TRUE)
356 memset (&ent->netgrdata, 0, sizeof (struct __netgrent));
357 __internal_setnetgrent (group, &ent->netgrdata);
358 ent->first = FALSE;
361 while (1)
363 char *saved_cursor;
364 int parse_res;
366 saved_cursor = ent->netgrdata.cursor;
367 status = __internal_getnetgrent_r (&host, &user, &domain,
368 &ent->netgrdata, buffer, buflen);
369 if (status != 1)
371 __internal_endnetgrent (&ent->netgrdata);
372 ent->netgroup = 0;
373 give_pwd_free (&ent->pwd);
374 return NSS_STATUS_RETURN;
377 if (user == NULL || user[0] == '-')
378 continue;
380 if (domain != NULL && strcmp (ypdomain, domain) != 0)
381 continue;
383 if (yp_match (ypdomain, "passwd.byname", user,
384 strlen (user), &outval, &outvallen)
385 != YPERR_SUCCESS)
386 continue;
388 p2len = pwd_need_buflen (&ent->pwd);
389 if (p2len > buflen)
391 __set_errno (ERANGE);
392 return NSS_STATUS_TRYAGAIN;
394 p2 = buffer + (buflen - p2len);
395 buflen -= p2len;
396 p = strncpy (buffer, outval, buflen);
397 while (isspace (*p))
398 p++;
399 free (outval);
400 if ((parse_res = _nss_files_parse_pwent (p, result, data, buflen)) == -1)
402 ent->netgrdata.cursor = saved_cursor;
403 return NSS_STATUS_TRYAGAIN;
406 if (parse_res)
408 copy_pwd_changes (result, &ent->pwd, p2, p2len);
409 break;
413 return NSS_STATUS_SUCCESS;
416 static enum nss_status
417 getpwent_next_nisplus_netgr (struct passwd *result, ent_t *ent, char *group,
418 char *buffer, size_t buflen)
420 char *ypdomain, *host, *user, *domain, *p2;
421 int status, parse_res;
422 size_t p2len;
423 nis_result *nisres;
425 /* Maybe we should use domainname here ? We need the current
426 domainname for the domain field in netgroups */
427 if (yp_get_default_domain (&ypdomain) != YPERR_SUCCESS)
429 ent->netgroup = 0;
430 ent->first = 0;
431 give_pwd_free (&ent->pwd);
432 return NSS_STATUS_UNAVAIL;
435 if (ent->first == TRUE)
437 bzero (&ent->netgrdata, sizeof (struct __netgrent));
438 __internal_setnetgrent (group, &ent->netgrdata);
439 ent->first = FALSE;
442 while (1)
444 char *saved_cursor;
446 saved_cursor = ent->netgrdata.cursor;
447 status = __internal_getnetgrent_r (&host, &user, &domain,
448 &ent->netgrdata, buffer, buflen);
449 if (status != 1)
451 __internal_endnetgrent (&ent->netgrdata);
452 ent->netgroup = 0;
453 give_pwd_free (&ent->pwd);
454 return NSS_STATUS_RETURN;
457 if (user == NULL || user[0] == '-')
458 continue;
460 if (domain != NULL && strcmp (ypdomain, domain) != 0)
461 continue;
463 p2len = pwd_need_buflen (&ent->pwd);
464 if (p2len > buflen)
466 __set_errno (ERANGE);
467 return NSS_STATUS_TRYAGAIN;
469 p2 = buffer + (buflen - p2len);
470 buflen -= p2len;
472 char buf[strlen (user) + 30 + pwdtablelen];
473 sprintf(buf, "[name=%s],%s", user, pwdtable);
474 nisres = nis_list(buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
476 if (niserr2nss (nisres->status) != NSS_STATUS_SUCCESS)
478 nis_freeresult (nisres);
479 continue;
481 if ((parse_res = _nss_nisplus_parse_pwent (nisres, result, buffer,
482 buflen)) == -1)
484 nis_freeresult (nisres);
485 ent->netgrdata.cursor = saved_cursor;
486 return NSS_STATUS_TRYAGAIN;
488 nis_freeresult (nisres);
490 if (parse_res)
492 copy_pwd_changes (result, &ent->pwd, p2, p2len);
493 break;
497 return NSS_STATUS_SUCCESS;
500 static enum nss_status
501 getpwent_next_netgr (struct passwd *result, ent_t *ent, char *group,
502 char *buffer, size_t buflen)
504 if (use_nisplus)
505 return getpwent_next_nisplus_netgr (result, ent, group, buffer, buflen);
506 else
507 return getpwent_next_nis_netgr (result, ent, group, buffer, buflen);
510 static enum nss_status
511 getpwent_next_nisplus (struct passwd *result, ent_t *ent, char *buffer,
512 size_t buflen)
514 int parse_res;
515 size_t p2len;
516 char *p2;
518 p2len = pwd_need_buflen (&ent->pwd);
519 if (p2len > buflen)
521 __set_errno (ERANGE);
522 return NSS_STATUS_TRYAGAIN;
524 p2 = buffer + (buflen - p2len);
525 buflen -= p2len;
528 bool_t saved_first;
529 nis_result *saved_res;
531 if (ent->first)
533 saved_first = TRUE;
534 saved_res = ent->result;
536 ent->result = nis_first_entry(pwdtable);
537 if (niserr2nss (ent->result->status) != NSS_STATUS_SUCCESS)
539 ent->nis = 0;
540 give_pwd_free (&ent->pwd);
541 return niserr2nss (ent->result->status);
543 ent->first = FALSE;
545 else
547 nis_result *res;
549 res = nis_next_entry(pwdtable, &ent->result->cookie);
550 saved_res = ent->result;
551 saved_first = FALSE;
552 ent->result = res;
553 if (niserr2nss (ent->result->status) != NSS_STATUS_SUCCESS)
555 ent->nis = 0;
556 nis_freeresult (saved_res);
557 give_pwd_free (&ent->pwd);
558 return niserr2nss (ent->result->status);
561 if ((parse_res = _nss_nisplus_parse_pwent (ent->result, result, buffer,
562 buflen)) == -1)
564 nis_freeresult (ent->result);
565 ent->result = saved_res;
566 ent->first = saved_first;
567 __set_errno (ERANGE);
568 return NSS_STATUS_TRYAGAIN;
570 else
572 if (!saved_first)
573 nis_freeresult (saved_res);
576 if (parse_res &&
577 in_blacklist (result->pw_name, strlen (result->pw_name), ent))
578 parse_res = 0; /* if result->pw_name in blacklist,search next entry */
580 while (!parse_res);
582 copy_pwd_changes (result, &ent->pwd, p2, p2len);
584 return NSS_STATUS_SUCCESS;
587 static enum nss_status
588 getpwent_next_nis (struct passwd *result, ent_t *ent, char *buffer,
589 size_t buflen)
591 struct parser_data *data = (void *) buffer;
592 char *domain, *outkey, *outval, *p, *p2;
593 int outkeylen, outvallen, parse_res;
594 size_t p2len;
596 if (yp_get_default_domain (&domain) != YPERR_SUCCESS)
598 ent->nis = 0;
599 give_pwd_free (&ent->pwd);
600 return NSS_STATUS_UNAVAIL;
603 p2len = pwd_need_buflen (&ent->pwd);
604 if (p2len > buflen)
606 __set_errno (ERANGE);
607 return NSS_STATUS_TRYAGAIN;
609 p2 = buffer + (buflen - p2len);
610 buflen -= p2len;
613 bool_t saved_first;
614 char *saved_oldkey;
615 int saved_oldlen;
617 if (ent->first)
619 if (yp_first (domain, "passwd.byname", &outkey, &outkeylen,
620 &outval, &outvallen) != YPERR_SUCCESS)
622 ent->nis = 0;
623 give_pwd_free (&ent->pwd);
624 return NSS_STATUS_UNAVAIL;
627 saved_first = TRUE;
628 saved_oldkey = ent->oldkey;
629 saved_oldlen = ent->oldkeylen;
630 ent->oldkey = outkey;
631 ent->oldkeylen = outkeylen;
632 ent->first = FALSE;
634 else
636 if (yp_next (domain, "passwd.byname", ent->oldkey, ent->oldkeylen,
637 &outkey, &outkeylen, &outval, &outvallen)
638 != YPERR_SUCCESS)
640 ent->nis = 0;
641 give_pwd_free (&ent->pwd);
642 return NSS_STATUS_NOTFOUND;
645 saved_first = FALSE;
646 saved_oldkey = ent->oldkey;
647 saved_oldlen = ent->oldkeylen;
648 ent->oldkey = outkey;
649 ent->oldkeylen = outkeylen;
652 /* Copy the found data to our buffer */
653 p = strncpy (buffer, outval, buflen);
655 /* ...and free the data. */
656 free (outval);
658 while (isspace (*p))
659 ++p;
660 if ((parse_res = _nss_files_parse_pwent (p, result, data, buflen)) == -1)
662 free (ent->oldkey);
663 ent->oldkey = saved_oldkey;
664 ent->oldkeylen = saved_oldlen;
665 ent->first = saved_first;
666 __set_errno (ERANGE);
667 return NSS_STATUS_TRYAGAIN;
669 else
671 if (!saved_first)
672 free (saved_oldkey);
674 if (parse_res &&
675 in_blacklist (result->pw_name, strlen (result->pw_name), ent))
676 parse_res = 0;
678 while (!parse_res);
680 copy_pwd_changes (result, &ent->pwd, p2, p2len);
682 return NSS_STATUS_SUCCESS;
685 /* This function handle the +user entrys in /etc/passwd */
686 static enum nss_status
687 getpwent_next_file_plususer (struct passwd *result, char *buffer,
688 size_t buflen)
690 struct parser_data *data = (void *) buffer;
691 struct passwd pwd;
692 int parse_res;
693 char *p;
694 size_t plen;
696 memset (&pwd, '\0', sizeof (struct passwd));
698 copy_pwd_changes (&pwd, result, NULL, 0);
700 plen = pwd_need_buflen (&pwd);
701 if (plen > buflen)
703 __set_errno (ERANGE);
704 return NSS_STATUS_TRYAGAIN;
706 p = buffer + (buflen - plen);
707 buflen -= plen;
709 if (use_nisplus) /* Do the NIS+ query here */
711 nis_result *res;
712 char buf[strlen (result->pw_name) + 24 + pwdtablelen];
714 sprintf(buf, "[name=%s],%s", &result->pw_name[1], pwdtable);
715 res = nis_list(buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
716 if (niserr2nss (res->status) != NSS_STATUS_SUCCESS)
718 enum nss_status status = niserr2nss (res->status);
720 nis_freeresult (res);
721 return status;
723 if ((parse_res = _nss_nisplus_parse_pwent (res, result, buffer,
724 buflen)) == -1)
726 nis_freeresult (res);
727 __set_errno (ERANGE);
728 return NSS_STATUS_TRYAGAIN;
730 nis_freeresult (res);
732 else /* Use NIS */
734 char *domain;
735 char *outval;
736 int outvallen;
738 if (yp_get_default_domain (&domain) != YPERR_SUCCESS)
739 return NSS_STATUS_TRYAGAIN;
741 if (yp_match (domain, "passwd.byname", &result->pw_name[1],
742 strlen (result->pw_name) - 1, &outval, &outvallen)
743 != YPERR_SUCCESS)
744 return NSS_STATUS_TRYAGAIN;
745 p = strncpy (buffer, outval,
746 buflen < (size_t) outvallen ? buflen : (size_t) outvallen);
747 free (outval);
748 while (isspace (*p))
749 p++;
750 if ((parse_res = _nss_files_parse_pwent (p, result, data, buflen)) == -1)
752 __set_errno (ERANGE);
753 return NSS_STATUS_TRYAGAIN;
757 if (parse_res > 0)
759 copy_pwd_changes (result, &pwd, p, plen);
760 give_pwd_free (&pwd);
761 /* We found the entry. */
762 return NSS_STATUS_SUCCESS;
764 else
766 /* Give buffer the old len back */
767 buflen += plen;
768 give_pwd_free (&pwd);
770 return NSS_STATUS_RETURN;
773 static enum nss_status
774 getpwent_next_file (struct passwd *result, ent_t *ent,
775 char *buffer, size_t buflen)
777 struct parser_data *data = (void *) buffer;
778 while (1)
780 fpos_t pos;
781 char *p;
782 int parse_res;
786 fgetpos (ent->stream, &pos);
787 p = fgets (buffer, buflen, ent->stream);
788 if (p == NULL)
789 return NSS_STATUS_NOTFOUND;
791 /* Terminate the line for any case. */
792 buffer[buflen - 1] = '\0';
794 /* Skip leading blanks. */
795 while (isspace (*p))
796 ++p;
798 while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */
799 /* Parse the line. If it is invalid, loop to
800 get the next line of the file to parse. */
801 !(parse_res = _nss_files_parse_pwent (p, result, data, buflen)));
803 if (parse_res == -1)
805 /* The parser ran out of space. */
806 fsetpos (ent->stream, &pos);
807 __set_errno (ERANGE);
808 return NSS_STATUS_TRYAGAIN;
811 if (result->pw_name[0] != '+' && result->pw_name[0] != '-')
812 /* This is a real entry. */
813 break;
815 /* -@netgroup */
816 if (result->pw_name[0] == '-' && result->pw_name[1] == '@'
817 && result->pw_name[2] != '\0')
819 char buf2[1024];
820 char *user, *host, *domain;
821 struct __netgrent netgrdata;
823 bzero (&netgrdata, sizeof (struct __netgrent));
824 __internal_setnetgrent (&result->pw_name[2], &netgrdata);
825 while (__internal_getnetgrent_r (&host, &user, &domain,
826 &netgrdata, buf2, sizeof (buf2)))
828 if (user != NULL && user[0] != '-')
829 blacklist_store_name (user, ent);
831 __internal_endnetgrent (&netgrdata);
832 continue;
835 /* +@netgroup */
836 if (result->pw_name[0] == '+' && result->pw_name[1] == '@'
837 && result->pw_name[2] != '\0')
839 int status;
841 ent->netgroup = TRUE;
842 ent->first = TRUE;
843 copy_pwd_changes (&ent->pwd, result, NULL, 0);
845 status = getpwent_next_netgr (result, ent, &result->pw_name[2],
846 buffer, buflen);
847 if (status == NSS_STATUS_RETURN)
848 continue;
849 else
850 return status;
853 /* -user */
854 if (result->pw_name[0] == '-' && result->pw_name[1] != '\0'
855 && result->pw_name[1] != '@')
857 blacklist_store_name (&result->pw_name[1], ent);
858 continue;
861 /* +user */
862 if (result->pw_name[0] == '+' && result->pw_name[1] != '\0'
863 && result->pw_name[1] != '@')
865 enum nss_status status;
867 status = getpwent_next_file_plususer (result, buffer, buflen);
868 if (status == NSS_STATUS_SUCCESS) /* We found the entry. */
869 break;
870 else
871 if (status == NSS_STATUS_RETURN) /* We couldn't parse the entry */
872 continue;
873 else
874 return status;
877 /* +:... */
878 if (result->pw_name[0] == '+' && result->pw_name[1] == '\0')
880 ent->nis = TRUE;
881 ent->first = TRUE;
882 copy_pwd_changes (&ent->pwd, result, NULL, 0);
884 if (use_nisplus)
885 return getpwent_next_nisplus (result, ent, buffer, buflen);
886 else
887 return getpwent_next_nis (result, ent, buffer, buflen);
891 return NSS_STATUS_SUCCESS;
895 static enum nss_status
896 internal_getpwent_r (struct passwd *pw, ent_t *ent, char *buffer,
897 size_t buflen)
899 if (ent->netgroup)
901 int status;
903 /* We are searching members in a netgroup */
904 /* Since this is not the first call, we don't need the group name */
905 status = getpwent_next_netgr (pw, ent, NULL, buffer, buflen);
906 if (status == NSS_STATUS_RETURN)
907 return getpwent_next_file (pw, ent, buffer, buflen);
908 else
909 return status;
911 else if (ent->nis)
913 if (use_nisplus)
914 return getpwent_next_nisplus (pw, ent, buffer, buflen);
915 else
916 return getpwent_next_nis (pw, ent, buffer, buflen);
918 else
919 return getpwent_next_file (pw, ent, buffer, buflen);
922 enum nss_status
923 _nss_compat_getpwent_r (struct passwd *pwd, char *buffer,
924 size_t buflen)
926 enum nss_status status = NSS_STATUS_SUCCESS;
928 __libc_lock_lock (lock);
930 if (ni == NULL)
932 __nss_database_lookup ("passwd_compat", NULL, "nis", &ni);
933 use_nisplus = (strcmp (ni->name, "nisplus") == 0);
936 /* Be prepared that the setpwent function was not called before. */
937 if (ext_ent.stream == NULL)
938 status = internal_setpwent (&ext_ent);
940 if (status == NSS_STATUS_SUCCESS)
941 status = internal_getpwent_r (pwd, &ext_ent, buffer, buflen);
943 __libc_lock_unlock (lock);
945 return status;
949 enum nss_status
950 _nss_compat_getpwnam_r (const char *name, struct passwd *pwd,
951 char *buffer, size_t buflen)
953 ent_t ent = {0, 0, 0, NULL, 0, NULL, NULL, {NULL, 0, 0},
954 {NULL, NULL, 0, 0, NULL, NULL, NULL}};
955 enum nss_status status;
957 if (name[0] == '-' || name[0] == '+')
958 return NSS_STATUS_NOTFOUND;
960 __libc_lock_lock (lock);
962 if (ni == NULL)
964 __nss_database_lookup ("passwd_compat", NULL, "nis", &ni);
965 use_nisplus = (strcmp (ni->name, "nisplus") == 0);
968 __libc_lock_unlock (lock);
970 status = internal_setpwent (&ent);
971 if (status != NSS_STATUS_SUCCESS)
972 return status;
974 while ((status = internal_getpwent_r (pwd, &ent, buffer, buflen))
975 == NSS_STATUS_SUCCESS)
976 if (strcmp (pwd->pw_name, name) == 0)
977 break;
979 internal_endpwent (&ent);
980 return status;
984 enum nss_status
985 _nss_compat_getpwuid_r (uid_t uid, struct passwd *pwd,
986 char *buffer, size_t buflen)
988 ent_t ent = {0, 0, 0, NULL, 0, NULL, NULL, {NULL, 0, 0},
989 {NULL, NULL, 0, 0, NULL, NULL, NULL}};
990 enum nss_status status;
992 __libc_lock_lock (lock);
994 if (ni == NULL)
996 __nss_database_lookup ("passwd_compat", NULL, "nis", &ni);
997 use_nisplus = (strcmp (ni->name, "nisplus") == 0);
1000 __libc_lock_unlock (lock);
1002 status = internal_setpwent (&ent);
1003 if (status != NSS_STATUS_SUCCESS)
1004 return status;
1006 while ((status = internal_getpwent_r (pwd, &ent, buffer, buflen))
1007 == NSS_STATUS_SUCCESS)
1008 if (pwd->pw_uid == uid && pwd->pw_name[0] != '+' && pwd->pw_name[0] != '-')
1009 break;
1011 internal_endpwent (&ent);
1012 return status;
1016 /* Support routines for remembering -@netgroup and -user entries.
1017 The names are stored in a single string with `|' as separator. */
1018 static void
1019 blacklist_store_name (const char *name, ent_t *ent)
1021 int namelen = strlen (name);
1022 char *tmp;
1024 /* first call, setup cache */
1025 if (ent->blacklist.size == 0)
1027 ent->blacklist.size = MAX (BLACKLIST_INITIAL_SIZE, 2 * namelen);
1028 ent->blacklist.data = malloc (ent->blacklist.size);
1029 if (ent->blacklist.data == NULL)
1030 return;
1031 ent->blacklist.data[0] = '|';
1032 ent->blacklist.data[1] = '\0';
1033 ent->blacklist.current = 1;
1035 else
1037 if (in_blacklist (name, namelen, ent))
1038 return; /* no duplicates */
1040 if (ent->blacklist.current + namelen + 1 >= ent->blacklist.size)
1042 ent->blacklist.size += MAX (BLACKLIST_INCREMENT, 2 * namelen);
1043 tmp = realloc (ent->blacklist.data, ent->blacklist.size);
1044 if (tmp == NULL)
1046 free (ent->blacklist.data);
1047 ent->blacklist.size = 0;
1048 return;
1050 ent->blacklist.data = tmp;
1054 tmp = stpcpy (ent->blacklist.data + ent->blacklist.current, name);
1055 *tmp++ = '|';
1056 *tmp = '\0';
1057 ent->blacklist.current += namelen + 1;
1059 return;
1062 /* returns TRUE if ent->blacklist contains name, else FALSE */
1063 static bool_t
1064 in_blacklist (const char *name, int namelen, ent_t *ent)
1066 char buf[namelen + 3];
1067 char *cp;
1069 if (ent->blacklist.data == NULL)
1070 return FALSE;
1072 buf[0] = '|';
1073 cp = stpcpy (&buf[1], name);
1074 *cp++= '|';
1075 *cp = '\0';
1076 return strstr (ent->blacklist.data, buf) != NULL;