Update.
[glibc.git] / nis / nss_compat / compat-pwd.c
blobb47a8b13c1e8452762bb2f0546b84ac881bddcde
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 <netdb.h>
25 #include <string.h>
26 #include <libc-lock.h>
27 #include <rpcsvc/yp.h>
28 #include <rpcsvc/ypclnt.h>
29 #include <rpcsvc/nis.h>
30 #include <rpcsvc/nislib.h>
31 #include <nsswitch.h>
33 #include "netgroup.h"
34 #include "nss-nisplus.h"
36 static service_user *ni = NULL;
37 static bool_t use_nisplus = FALSE; /* default: passwd_compat: nis */
39 /* Get the declaration of the parser function. */
40 #define ENTNAME pwent
41 #define STRUCTURE passwd
42 #define EXTERN_PARSER
43 #include "../../nss/nss_files/files-parse.c"
45 /* Structure for remembering -@netgroup and -user members ... */
46 #define BLACKLIST_INITIAL_SIZE 512
47 #define BLACKLIST_INCREMENT 256
48 struct blacklist_t
50 char *data;
51 int current;
52 int size;
55 struct ent_t
57 bool_t netgroup;
58 bool_t nis;
59 bool_t first;
60 char *oldkey;
61 int oldkeylen;
62 nis_result *result;
63 nis_name *names;
64 u_long names_nr;
65 FILE *stream;
66 struct blacklist_t blacklist;
67 struct passwd pwd;
68 struct __netgrent netgrdata;
70 typedef struct ent_t ent_t;
72 static ent_t ext_ent = {0, 0, 0, NULL, 0, NULL, NULL, 0, NULL, {NULL, 0, 0},
73 {NULL, NULL, 0, 0, NULL, NULL, NULL}};
75 /* Protect global state against multiple changers. */
76 __libc_lock_define_initialized (static, lock)
78 /* Prototypes for local functions. */
79 static void blacklist_store_name (const char *, ent_t *);
80 static int in_blacklist (const char *, int, ent_t *);
81 extern int _nss_nisplus_parse_pwent (nis_result *, struct passwd *,
82 char *, size_t);
83 static void
84 give_pwd_free (struct passwd *pwd)
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);
97 memset (pwd, '\0', sizeof (struct passwd));
100 static size_t
101 pwd_need_buflen (struct passwd *pwd)
103 size_t len = 0;
105 if (pwd->pw_passwd != NULL)
106 len += strlen (pwd->pw_passwd) + 1;
108 if (pwd->pw_gecos != NULL)
109 len += strlen (pwd->pw_gecos) + 1;
111 if (pwd->pw_dir != NULL)
112 len += strlen (pwd->pw_dir) + 1;
114 if (pwd->pw_shell != NULL)
115 len += strlen (pwd->pw_shell) + 1;
117 return len;
120 static void
121 copy_pwd_changes (struct passwd *dest, struct passwd *src,
122 char *buffer, size_t buflen)
124 if (src->pw_passwd != NULL && strlen (src->pw_passwd))
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
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);
140 if (src->pw_gecos != NULL && strlen (src->pw_gecos))
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
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);
155 if (src->pw_dir != NULL && strlen (src->pw_dir))
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
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);
171 if (src->pw_shell != NULL && strlen (src->pw_shell))
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
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);
188 static enum nss_status
189 internal_setpwent (ent_t *ent)
191 enum nss_status status = NSS_STATUS_SUCCESS;
193 ent->nis = ent->first = ent->netgroup = 0;
195 /* If something was left over free it. */
196 if (ent->netgroup)
197 __internal_endnetgrent (&ent->netgrdata);
199 if (ent->oldkey != NULL)
201 free (ent->oldkey);
202 ent->oldkey = NULL;
203 ent->oldkeylen = 0;
206 if (ent->result != NULL)
208 nis_freeresult (ent->result);
209 ent->result = NULL;
212 if (ent->names != NULL)
214 nis_freenames (ent->names);
215 ent->names = NULL;
217 ent->names_nr = 0;
218 ent->blacklist.current = 0;
219 if (ent->blacklist.data != NULL)
220 ent->blacklist.data[0] = '\0';
222 if (ent->stream == NULL)
224 ent->stream = fopen ("/etc/passwd", "r");
226 if (ent->stream == NULL)
227 status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL;
229 else
230 rewind (ent->stream);
232 give_pwd_free (&ent->pwd);
234 return status;
238 enum nss_status
239 _nss_compat_setpwent (void)
241 enum nss_status result;
243 __libc_lock_lock (lock);
245 if (ni == NULL)
247 __nss_database_lookup ("passwd_compat", NULL, "nis", &ni);
248 use_nisplus = (strcmp (ni->name, "nisplus") == 0);
251 result = internal_setpwent (&ext_ent);
253 __libc_lock_unlock (lock);
255 return result;
259 static enum nss_status
260 internal_endpwent (ent_t *ent)
262 if (ent->stream != NULL)
264 fclose (ent->stream);
265 ent->stream = NULL;
268 ent->nis = ent->first = ent->netgroup = 0;
270 if (ent->oldkey != NULL)
272 free (ent->oldkey);
273 ent->oldkey = NULL;
274 ent->oldkeylen = 0;
277 if (ent->result != NULL)
279 nis_freeresult (ent->result);
280 ent->result = NULL;
283 if (ent->names != NULL)
285 nis_freenames (ent->names);
286 ent->names = NULL;
288 ent->names_nr = 0;
290 ent->blacklist.current = 0;
291 if (ent->blacklist.data != NULL)
292 ent->blacklist.data[0] = '\0';
294 give_pwd_free (&ent->pwd);
296 return NSS_STATUS_SUCCESS;
299 enum nss_status
300 _nss_compat_endpwent (void)
302 enum nss_status result;
304 __libc_lock_lock (lock);
306 if (ext_ent.netgroup)
307 __internal_endnetgrent (&ext_ent.netgrdata);
309 result = internal_endpwent (&ext_ent);
311 __libc_lock_unlock (lock);
313 return result;
316 static enum nss_status
317 getpwent_next_nis_netgr (struct passwd *result, ent_t *ent, char *group,
318 char *buffer, size_t buflen)
320 struct parser_data *data = (void *) buffer;
321 char *ypdomain, *host, *user, *domain, *outval, *p, *p2;
322 int status, outvallen;
323 size_t p2len;
325 if (yp_get_default_domain (&ypdomain) != YPERR_SUCCESS)
327 ent->netgroup = 0;
328 ent->first = 0;
329 give_pwd_free (&ent->pwd);
330 return NSS_STATUS_UNAVAIL;
333 if (ent->first == TRUE)
335 memset (&ent->netgrdata, 0, sizeof (struct __netgrent));
336 __internal_setnetgrent (group, &ent->netgrdata);
337 ent->first = FALSE;
340 while (1)
342 status = __internal_getnetgrent_r (&host, &user, &domain,
343 &ent->netgrdata, buffer, buflen);
344 if (status != 1)
346 __internal_endnetgrent (&ent->netgrdata);
347 ent->netgroup = 0;
348 give_pwd_free (&ent->pwd);
349 return NSS_STATUS_RETURN;
352 if (user == NULL || user[0] == '-')
353 continue;
355 if (domain != NULL && strcmp (ypdomain, domain) != 0)
356 continue;
358 if (yp_match (ypdomain, "passwd.byname", user,
359 strlen (user), &outval, &outvallen)
360 != YPERR_SUCCESS)
361 continue;
363 p2len = pwd_need_buflen (&ent->pwd);
364 if (p2len > buflen)
366 __set_errno (ERANGE);
367 return NSS_STATUS_TRYAGAIN;
369 p2 = buffer + (buflen - p2len);
370 buflen -= p2len;
371 p = strncpy (buffer, outval, buflen);
372 while (isspace (*p))
373 p++;
374 free (outval);
375 if (_nss_files_parse_pwent (p, result, data, buflen))
377 copy_pwd_changes (result, &ent->pwd, p2, p2len);
378 break;
382 return NSS_STATUS_SUCCESS;
385 static enum nss_status
386 getpwent_next_nisplus_netgr (struct passwd *result, ent_t *ent, char *group,
387 char *buffer, size_t buflen)
389 char *ypdomain, *host, *user, *domain, *p2;
390 int status, parse_res;
391 size_t p2len;
392 nis_result *nisres;
394 /* Maybe we should use domainname here ? We need the current
395 domainname for the domain field in netgroups */
396 if (yp_get_default_domain (&ypdomain) != YPERR_SUCCESS)
398 ent->netgroup = 0;
399 ent->first = 0;
400 give_pwd_free (&ent->pwd);
401 return NSS_STATUS_UNAVAIL;
404 if (ent->first == TRUE)
406 bzero (&ent->netgrdata, sizeof (struct __netgrent));
407 __internal_setnetgrent (group, &ent->netgrdata);
408 ent->first = FALSE;
411 while (1)
413 status = __internal_getnetgrent_r (&host, &user, &domain,
414 &ent->netgrdata, buffer, buflen);
415 if (status != 1)
417 __internal_endnetgrent (&ent->netgrdata);
418 ent->netgroup = 0;
419 give_pwd_free (&ent->pwd);
420 return NSS_STATUS_RETURN;
423 if (user == NULL || user[0] == '-')
424 continue;
426 if (domain != NULL && strcmp (ypdomain, domain) != 0)
427 continue;
429 p2len = pwd_need_buflen (&ent->pwd);
430 if (p2len > buflen)
432 __set_errno (ERANGE);
433 return NSS_STATUS_TRYAGAIN;
435 p2 = buffer + (buflen - p2len);
436 buflen -= p2len;
438 char buf[strlen (user) + 30];
439 sprintf(buf, "[name=%s],passwd.org_dir", user);
440 nisres = nis_list(buf, EXPAND_NAME, NULL, NULL);
442 if (niserr2nss (nisres->status) != NSS_STATUS_SUCCESS)
444 nis_freeresult (nisres);
445 continue;
447 parse_res = _nss_nisplus_parse_pwent (nisres, result, buffer, buflen);
448 nis_freeresult (nisres);
450 if (parse_res)
452 copy_pwd_changes (result, &ent->pwd, p2, p2len);
453 break;
457 return NSS_STATUS_SUCCESS;
460 static enum nss_status
461 getpwent_next_netgr (struct passwd *result, ent_t *ent, char *group,
462 char *buffer, size_t buflen)
464 if (use_nisplus)
465 return getpwent_next_nisplus_netgr (result, ent, group, buffer, buflen);
466 else
467 return getpwent_next_nis_netgr (result, ent, group, buffer, buflen);
470 static enum nss_status
471 getpwent_next_nisplus (struct passwd *result, ent_t *ent, char *buffer,
472 size_t buflen)
474 int parse_res;
475 size_t p2len;
476 char *p2;
478 if (ent->names == NULL)
480 ent->names = nis_getnames ("passwd.org_dir");
481 if (ent->names == NULL || ent->names[0] == NULL)
483 ent->nis = 0;
484 return NSS_STATUS_UNAVAIL;
488 p2len = pwd_need_buflen (&ent->pwd);
489 if (p2len > buflen)
491 __set_errno (ERANGE);
492 return NSS_STATUS_TRYAGAIN;
494 p2 = buffer + (buflen - p2len);
495 buflen -= p2len;
498 if (ent->first)
500 next_name:
501 ent->result = nis_first_entry(ent->names[ent->names_nr]);
502 if (niserr2nss (ent->result->status) != NSS_STATUS_SUCCESS)
504 ent->nis = 0;
505 give_pwd_free (&ent->pwd);
506 return niserr2nss (ent->result->status);
508 ent->first = FALSE;
510 else
512 nis_result *res;
514 res = nis_next_entry(ent->names[ent->names_nr],
515 &ent->result->cookie);
516 nis_freeresult (ent->result);
517 ent->result = res;
518 if (niserr2nss (ent->result->status) != NSS_STATUS_SUCCESS)
520 if ((ent->result->status == NIS_NOTFOUND) &&
521 ent->names[ent->names_nr + 1] != NULL)
523 nis_freeresult (ent->result);
524 ent->names_nr += 1;
525 goto next_name;
527 else
529 ent->nis = 0;
530 give_pwd_free (&ent->pwd);
531 return niserr2nss (ent->result->status);
535 parse_res = _nss_nisplus_parse_pwent (ent->result, result, buffer,
536 buflen);
537 if (parse_res &&
538 in_blacklist (result->pw_name, strlen (result->pw_name), ent))
539 parse_res = 0; /* if result->pw_name in blacklist,search next entry */
541 while (!parse_res);
543 copy_pwd_changes (result, &ent->pwd, p2, p2len);
545 return NSS_STATUS_SUCCESS;
548 static enum nss_status
549 getpwent_next_nis (struct passwd *result, ent_t *ent, char *buffer,
550 size_t buflen)
552 struct parser_data *data = (void *) buffer;
553 char *domain, *outkey, *outval, *p, *p2;
554 int outkeylen, outvallen, parse_res;
555 size_t p2len;
557 if (yp_get_default_domain (&domain) != YPERR_SUCCESS)
559 ent->nis = 0;
560 give_pwd_free (&ent->pwd);
561 return NSS_STATUS_UNAVAIL;
564 p2len = pwd_need_buflen (&ent->pwd);
565 if (p2len > buflen)
567 __set_errno (ERANGE);
568 return NSS_STATUS_TRYAGAIN;
570 p2 = buffer + (buflen - p2len);
571 buflen -= p2len;
574 if (ent->first)
576 if (yp_first (domain, "passwd.byname", &outkey, &outkeylen,
577 &outval, &outvallen) != YPERR_SUCCESS)
579 ent->nis = 0;
580 give_pwd_free (&ent->pwd);
581 return NSS_STATUS_UNAVAIL;
584 ent->oldkey = outkey;
585 ent->oldkeylen = outkeylen;
586 ent->first = FALSE;
588 else
590 if (yp_next (domain, "passwd.byname", ent->oldkey, ent->oldkeylen,
591 &outkey, &outkeylen, &outval, &outvallen)
592 != YPERR_SUCCESS)
594 ent->nis = 0;
595 give_pwd_free (&ent->pwd);
596 return NSS_STATUS_NOTFOUND;
599 free (ent->oldkey);
600 ent->oldkey = outkey;
601 ent->oldkeylen = outkeylen;
604 /* Copy the found data to our buffer */
605 p = strncpy (buffer, outval, buflen);
607 /* ...and free the data. */
608 free (outval);
610 while (isspace (*p))
611 ++p;
612 parse_res = _nss_files_parse_pwent (p, result, data, buflen);
613 if (parse_res &&
614 in_blacklist (result->pw_name, strlen (result->pw_name), ent))
615 parse_res = 0;
617 while (!parse_res);
619 copy_pwd_changes (result, &ent->pwd, p2, p2len);
621 return NSS_STATUS_SUCCESS;
624 /* This function handle the +user entrys in /etc/passwd */
625 static enum nss_status
626 getpwent_next_file_plususer (struct passwd *result, char *buffer,
627 size_t buflen)
629 struct parser_data *data = (void *) buffer;
630 struct passwd pwd;
631 int parse_res;
632 char *p;
633 size_t plen;
635 memset (&pwd, '\0', sizeof (struct passwd));
637 copy_pwd_changes (&pwd, result, NULL, 0);
639 plen = pwd_need_buflen (&pwd);
640 if (plen > buflen)
642 __set_errno (ERANGE);
643 return NSS_STATUS_TRYAGAIN;
645 p = buffer + (buflen - plen);
646 buflen -= plen;
648 if (use_nisplus) /* Do the NIS+ query here */
650 nis_result *res;
651 char buf[strlen (result->pw_name) + 24];
653 sprintf(buf, "[name=%s],passwd.org_dir",
654 &result->pw_name[1]);
655 res = nis_list(buf, EXPAND_NAME, NULL, NULL);
656 if (niserr2nss (res->status) != NSS_STATUS_SUCCESS)
658 enum nss_status status = niserr2nss (res->status);
660 nis_freeresult (res);
661 return status;
663 parse_res = _nss_nisplus_parse_pwent (res, result, buffer, buflen);
664 nis_freeresult (res);
666 else /* Use NIS */
668 char *domain;
669 char *outval;
670 int outvallen;
672 if (yp_get_default_domain (&domain) != YPERR_SUCCESS)
673 return NSS_STATUS_TRYAGAIN;
675 if (yp_match (domain, "passwd.byname", &result->pw_name[1],
676 strlen (result->pw_name) - 1, &outval, &outvallen)
677 != YPERR_SUCCESS)
678 return NSS_STATUS_TRYAGAIN;
679 p = strncpy (buffer, outval,
680 buflen < (size_t) outvallen ? buflen : (size_t) outvallen);
681 free (outval);
682 while (isspace (*p))
683 p++;
684 parse_res = _nss_files_parse_pwent (p, result, data, buflen);
687 if (parse_res)
689 copy_pwd_changes (result, &pwd, p, plen);
690 give_pwd_free (&pwd);
691 /* We found the entry. */
692 return NSS_STATUS_SUCCESS;
694 else
696 /* Give buffer the old len back */
697 buflen += plen;
698 give_pwd_free (&pwd);
700 return NSS_STATUS_RETURN;
703 static enum nss_status
704 getpwent_next_file (struct passwd *result, ent_t *ent,
705 char *buffer, size_t buflen)
707 struct parser_data *data = (void *) buffer;
708 while (1)
710 char *p;
714 p = fgets (buffer, buflen, ent->stream);
715 if (p == NULL)
716 return NSS_STATUS_NOTFOUND;
718 /* Terminate the line for any case. */
719 buffer[buflen - 1] = '\0';
721 /* Skip leading blanks. */
722 while (isspace (*p))
723 ++p;
725 while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */
726 /* Parse the line. If it is invalid, loop to
727 get the next line of the file to parse. */
728 !_nss_files_parse_pwent (p, result, data, buflen));
730 if (result->pw_name[0] != '+' && result->pw_name[0] != '-')
731 /* This is a real entry. */
732 break;
734 /* -@netgroup */
735 if (result->pw_name[0] == '-' && result->pw_name[1] == '@'
736 && result->pw_name[2] != '\0')
738 char buf2[1024];
739 char *user, *host, *domain;
740 struct __netgrent netgrdata;
742 bzero (&netgrdata, sizeof (struct __netgrent));
743 __internal_setnetgrent (&result->pw_name[2], &netgrdata);
744 while (__internal_getnetgrent_r (&host, &user, &domain,
745 &netgrdata, buf2, sizeof (buf2)))
747 if (user != NULL && user[0] != '-')
748 blacklist_store_name (user, ent);
750 __internal_endnetgrent (&netgrdata);
751 continue;
754 /* +@netgroup */
755 if (result->pw_name[0] == '+' && result->pw_name[1] == '@'
756 && result->pw_name[2] != '\0')
758 int status;
760 ent->netgroup = TRUE;
761 ent->first = TRUE;
762 copy_pwd_changes (&ent->pwd, result, NULL, 0);
764 status = getpwent_next_netgr (result, ent, &result->pw_name[2],
765 buffer, buflen);
766 if (status == NSS_STATUS_RETURN)
767 continue;
768 else
769 return status;
772 /* -user */
773 if (result->pw_name[0] == '-' && result->pw_name[1] != '\0'
774 && result->pw_name[1] != '@')
776 blacklist_store_name (&result->pw_name[1], ent);
777 continue;
780 /* +user */
781 if (result->pw_name[0] == '+' && result->pw_name[1] != '\0'
782 && result->pw_name[1] != '@')
784 enum nss_status status;
786 status = getpwent_next_file_plususer (result, buffer, buflen);
787 if (status == NSS_STATUS_SUCCESS) /* We found the entry. */
788 break;
789 else
790 if (status == NSS_STATUS_RETURN) /* We couldn't parse the entry */
791 continue;
792 else
793 return status;
796 /* +:... */
797 if (result->pw_name[0] == '+' && result->pw_name[1] == '\0')
799 ent->nis = TRUE;
800 ent->first = TRUE;
801 copy_pwd_changes (&ent->pwd, result, NULL, 0);
803 if (use_nisplus)
804 return getpwent_next_nisplus (result, ent, buffer, buflen);
805 else
806 return getpwent_next_nis (result, ent, buffer, buflen);
810 return NSS_STATUS_SUCCESS;
814 static enum nss_status
815 internal_getpwent_r (struct passwd *pw, ent_t *ent, char *buffer,
816 size_t buflen)
818 if (ent->netgroup)
820 int status;
822 /* We are searching members in a netgroup */
823 /* Since this is not the first call, we don't need the group name */
824 status = getpwent_next_netgr (pw, ent, NULL, buffer, buflen);
825 if (status == NSS_STATUS_RETURN)
826 return getpwent_next_file (pw, ent, buffer, buflen);
827 else
828 return status;
830 else if (ent->nis)
832 if (use_nisplus)
833 return getpwent_next_nisplus (pw, ent, buffer, buflen);
834 else
835 return getpwent_next_nis (pw, ent, buffer, buflen);
837 else
838 return getpwent_next_file (pw, ent, buffer, buflen);
841 enum nss_status
842 _nss_compat_getpwent_r (struct passwd *pwd, char *buffer,
843 size_t buflen)
845 enum nss_status status = NSS_STATUS_SUCCESS;
847 __libc_lock_lock (lock);
849 if (ni == NULL)
851 __nss_database_lookup ("passwd_compat", NULL, "nis", &ni);
852 use_nisplus = (strcmp (ni->name, "nisplus") == 0);
855 /* Be prepared that the setpwent function was not called before. */
856 if (ext_ent.stream == NULL)
857 status = internal_setpwent (&ext_ent);
859 if (status == NSS_STATUS_SUCCESS)
860 status = internal_getpwent_r (pwd, &ext_ent, buffer, buflen);
862 __libc_lock_unlock (lock);
864 return status;
868 enum nss_status
869 _nss_compat_getpwnam_r (const char *name, struct passwd *pwd,
870 char *buffer, size_t buflen)
872 ent_t ent = {0, 0, 0, NULL, 0, NULL, NULL, 0, NULL, {NULL, 0, 0},
873 {NULL, NULL, 0, 0, NULL, NULL, NULL}};
874 enum nss_status status;
876 if (name[0] == '-' || name[0] == '+')
877 return NSS_STATUS_NOTFOUND;
879 __libc_lock_lock (lock);
881 if (ni == NULL)
883 __nss_database_lookup ("passwd_compat", NULL, "nis", &ni);
884 use_nisplus = (strcmp (ni->name, "nisplus") == 0);
887 __libc_lock_unlock (lock);
889 status = internal_setpwent (&ent);
890 if (status != NSS_STATUS_SUCCESS)
891 return status;
893 while ((status = internal_getpwent_r (pwd, &ent, buffer, buflen))
894 == NSS_STATUS_SUCCESS)
895 if (strcmp (pwd->pw_name, name) == 0)
896 break;
898 internal_endpwent (&ent);
899 return status;
903 enum nss_status
904 _nss_compat_getpwuid_r (uid_t uid, struct passwd *pwd,
905 char *buffer, size_t buflen)
907 ent_t ent = {0, 0, 0, NULL, 0, NULL, NULL, 0, NULL, {NULL, 0, 0},
908 {NULL, NULL, 0, 0, NULL, NULL, NULL}};
909 enum nss_status status;
911 __libc_lock_lock (lock);
913 if (ni == NULL)
915 __nss_database_lookup ("passwd_compat", NULL, "nis", &ni);
916 use_nisplus = (strcmp (ni->name, "nisplus") == 0);
919 __libc_lock_unlock (lock);
921 status = internal_setpwent (&ent);
922 if (status != NSS_STATUS_SUCCESS)
923 return status;
925 while ((status = internal_getpwent_r (pwd, &ent, buffer, buflen))
926 == NSS_STATUS_SUCCESS)
927 if (pwd->pw_uid == uid && pwd->pw_name[0] != '+' && pwd->pw_name[0] != '-')
928 break;
930 internal_endpwent (&ent);
931 return status;
935 /* Support routines for remembering -@netgroup and -user entries.
936 The names are stored in a single string with `|' as separator. */
937 static void
938 blacklist_store_name (const char *name, ent_t *ent)
940 int namelen = strlen (name);
941 char *tmp;
943 /* first call, setup cache */
944 if (ent->blacklist.size == 0)
946 ent->blacklist.size = MAX (BLACKLIST_INITIAL_SIZE, 2 * namelen);
947 ent->blacklist.data = malloc (ent->blacklist.size);
948 if (ent->blacklist.data == NULL)
949 return;
950 ent->blacklist.data[0] = '|';
951 ent->blacklist.data[1] = '\0';
952 ent->blacklist.current = 1;
954 else
956 if (in_blacklist (name, namelen, ent))
957 return; /* no duplicates */
959 if (ent->blacklist.current + namelen + 1 >= ent->blacklist.size)
961 ent->blacklist.size += MAX (BLACKLIST_INCREMENT, 2 * namelen);
962 tmp = realloc (ent->blacklist.data, ent->blacklist.size);
963 if (tmp == NULL)
965 free (ent->blacklist.data);
966 ent->blacklist.size = 0;
967 return;
969 ent->blacklist.data = tmp;
973 tmp = stpcpy (ent->blacklist.data + ent->blacklist.current, name);
974 *tmp++ = '|';
975 *tmp = '\0';
976 ent->blacklist.current += namelen + 1;
978 return;
981 /* returns TRUE if ent->blacklist contains name, else FALSE */
982 static bool_t
983 in_blacklist (const char *name, int namelen, ent_t *ent)
985 char buf[namelen + 3];
986 char *cp;
988 if (ent->blacklist.data == NULL)
989 return FALSE;
991 buf[0] = '|';
992 cp = stpcpy (&buf[1], name);
993 *cp++= '|';
994 *cp = '\0';
995 return strstr (ent->blacklist.data, buf) != NULL;