* posix/execl.c: Fix last argument of memcpy. Reported by Brian
[glibc.git] / nis / nss_compat / compat-pwd.c
blob3579520944d493dd71800f88fc9fcef28d5bbe8d
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.
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.
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.
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. */
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>
33 #include "netgroup.h"
34 #include "nss-nisplus.h"
35 #include "nisplus-parser.h"
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;
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>
48 /* Structure for remembering -@netgroup and -user members ... */
49 #define BLACKLIST_INITIAL_SIZE 512
50 #define BLACKLIST_INCREMENT 256
51 struct blacklist_t
53 char *data;
54 int current;
55 int size;
58 struct ent_t
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;
71 typedef struct ent_t ent_t;
73 static ent_t ext_ent = {0, 0, 0, NULL, 0, NULL, NULL, {NULL, 0, 0},
74 {NULL, NULL, 0, 0, NULL, NULL, NULL}};
76 /* Protect global state against multiple changers. */
77 __libc_lock_define_initialized (static, lock)
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 *);
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 insert_passwd_adjunct (char **result, int *len, char *domain, int *errnop)
191 char *p1, *p2, *result2, *res;
192 int len2;
193 size_t namelen;
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, ':');
202 namelen = p2 - p1 - 3;
204 if (yp_match (domain, "passwd.adjunct.byname", &p1[3], namelen,
205 &result2, &len2) == YPERR_SUCCESS)
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;
213 if (encrypted == NULL || (endp = strchr (++encrypted, ':')) == NULL)
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;
222 restlen = *len - (p2 - *result);
223 if ((res = malloc (namelen + restlen + (endp - encrypted) + 2)) == NULL)
225 free (result2);
226 *errnop = ENOMEM;
227 return NSS_STATUS_TRYAGAIN;
230 __mempcpy (__mempcpy (__mempcpy (__mempcpy
231 (res, *result, (p1 - *result)),
232 ":", 1),
233 encrypted, endp - encrypted),
234 p2, restlen + 1);
236 free (result2);
237 free (*result);
238 *result = res;
239 *len = strlen (res);
241 return NSS_STATUS_SUCCESS;
244 static enum nss_status
245 internal_setpwent (ent_t *ent)
247 enum nss_status status = NSS_STATUS_SUCCESS;
249 ent->nis = ent->first = ent->netgroup = 0;
251 /* If something was left over free it. */
252 if (ent->netgroup)
253 __internal_endnetgrent (&ent->netgrdata);
255 if (ent->oldkey != NULL)
257 free (ent->oldkey);
258 ent->oldkey = NULL;
259 ent->oldkeylen = 0;
262 if (ent->result != NULL)
264 nis_freeresult (ent->result);
265 ent->result = NULL;
268 if (pwdtable == NULL)
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);
274 pwdtable = malloc (sizeof (key) + len_local_dir);
275 if (pwdtable == NULL)
276 return NSS_STATUS_TRYAGAIN;
278 pwdtablelen = ((char *) mempcpy (mempcpy (pwdtable,
279 key, sizeof (key) - 1),
280 local_dir, len_local_dir + 1)
281 - pwdtable) - 1;
284 if (ent->blacklist.data != NULL)
286 ent->blacklist.current = 1;
287 ent->blacklist.data[0] = '|';
288 ent->blacklist.data[1] = '\0';
290 else
291 ent->blacklist.current = 0;
293 if (ent->stream == NULL)
295 ent->stream = fopen ("/etc/passwd", "r");
297 if (ent->stream == NULL)
298 status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL;
299 else
301 /* We have to make sure the file is `closed on exec'. */
302 int result, flags;
304 result = flags = fcntl (fileno (ent->stream), F_GETFD, 0);
305 if (result >= 0)
307 flags |= FD_CLOEXEC;
308 result = fcntl (fileno (ent->stream), F_SETFD, flags);
310 if (result < 0)
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;
320 else
321 rewind (ent->stream);
323 give_pwd_free (&ent->pwd);
325 return status;
329 enum nss_status
330 _nss_compat_setpwent (int stayopen)
332 enum nss_status result;
334 __libc_lock_lock (lock);
336 if (ni == NULL)
338 __nss_database_lookup ("passwd_compat", NULL, "nis", &ni);
339 use_nisplus = (strcmp (ni->name, "nisplus") == 0);
342 result = internal_setpwent (&ext_ent);
344 __libc_lock_unlock (lock);
346 return result;
350 static enum nss_status
351 internal_endpwent (ent_t *ent)
353 if (ent->stream != NULL)
355 fclose (ent->stream);
356 ent->stream = NULL;
359 if (ent->netgroup)
360 __internal_endnetgrent (&ent->netgrdata);
362 ent->nis = ent->first = ent->netgroup = 0;
364 if (ent->oldkey != NULL)
366 free (ent->oldkey);
367 ent->oldkey = NULL;
368 ent->oldkeylen = 0;
371 if (ent->result != NULL)
373 nis_freeresult (ent->result);
374 ent->result = NULL;
377 if (ent->blacklist.data != NULL)
379 ent->blacklist.current = 1;
380 ent->blacklist.data[0] = '|';
381 ent->blacklist.data[1] = '\0';
383 else
384 ent->blacklist.current = 0;
386 give_pwd_free (&ent->pwd);
388 return NSS_STATUS_SUCCESS;
391 enum nss_status
392 _nss_compat_endpwent (void)
394 enum nss_status result;
396 __libc_lock_lock (lock);
398 result = internal_endpwent (&ext_ent);
400 __libc_lock_unlock (lock);
402 return result;
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)
409 struct parser_data *data = (void *) buffer;
410 char *ypdomain, *host, *user, *domain, *outval, *p, *p2;
411 int status, outvallen;
412 size_t p2len;
414 if (yp_get_default_domain (&ypdomain) != YPERR_SUCCESS)
416 ent->netgroup = 0;
417 ent->first = 0;
418 give_pwd_free (&ent->pwd);
419 return NSS_STATUS_UNAVAIL;
422 if (ent->first == TRUE)
424 memset (&ent->netgrdata, 0, sizeof (struct __netgrent));
425 __internal_setnetgrent (group, &ent->netgrdata);
426 ent->first = FALSE;
429 while (1)
431 char *saved_cursor;
432 int parse_res;
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)
440 __internal_endnetgrent (&ent->netgrdata);
441 ent->netgroup = 0;
442 give_pwd_free (&ent->pwd);
443 return NSS_STATUS_RETURN;
446 if (user == NULL || user[0] == '-')
447 continue;
449 if (domain != NULL && strcmp (ypdomain, domain) != 0)
450 continue;
452 /* If name != NULL, we are called from getpwnam. */
453 if (name != NULL)
454 if (strcmp (user, name) != 0)
455 continue;
457 if (yp_match (ypdomain, "passwd.byname", user,
458 strlen (user), &outval, &outvallen)
459 != YPERR_SUCCESS)
460 continue;
462 if (insert_passwd_adjunct (&outval, &outvallen, ypdomain, errnop)
463 != NSS_STATUS_SUCCESS)
465 free (outval);
466 return NSS_STATUS_TRYAGAIN;
469 p2len = pwd_need_buflen (&ent->pwd);
470 if (p2len > buflen)
472 free (outval);
473 *errnop = ERANGE;
474 return NSS_STATUS_TRYAGAIN;
476 p2 = buffer + (buflen - p2len);
477 buflen -= p2len;
479 if (buflen < ((size_t) outvallen + 1))
481 free (outval);
482 *errnop = ERANGE;
483 return NSS_STATUS_TRYAGAIN;
485 p = strncpy (buffer, outval, buflen);
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)
493 ent->netgrdata.cursor = saved_cursor;
494 return NSS_STATUS_TRYAGAIN;
497 if (parse_res && !in_blacklist (result->pw_name,
498 strlen (result->pw_name), ent))
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;
508 return NSS_STATUS_SUCCESS;
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)
516 char *ypdomain, *host, *user, *domain, *p2;
517 int status, parse_res;
518 size_t p2len;
519 nis_result *nisres;
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)
525 ent->netgroup = 0;
526 ent->first = 0;
527 give_pwd_free (&ent->pwd);
528 return NSS_STATUS_UNAVAIL;
531 if (ent->first == TRUE)
533 bzero (&ent->netgrdata, sizeof (struct __netgrent));
534 __internal_setnetgrent (group, &ent->netgrdata);
535 ent->first = FALSE;
538 while (1)
540 char *saved_cursor;
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)
548 __internal_endnetgrent (&ent->netgrdata);
549 ent->netgroup = 0;
550 give_pwd_free (&ent->pwd);
551 return NSS_STATUS_RETURN;
554 if (user == NULL || user[0] == '-')
555 continue;
557 if (domain != NULL && strcmp (ypdomain, domain) != 0)
558 continue;
560 /* If name != NULL, we are called from getpwnam */
561 if (name != NULL)
562 if (strcmp (user, name) != 0)
563 continue;
565 p2len = pwd_need_buflen (&ent->pwd);
566 if (p2len > buflen)
568 *errnop = ERANGE;
569 return NSS_STATUS_TRYAGAIN;
571 p2 = buffer + (buflen - p2len);
572 buflen -= p2len;
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);
578 if (niserr2nss (nisres->status) != NSS_STATUS_SUCCESS)
580 nis_freeresult (nisres);
581 continue;
583 parse_res = _nss_nisplus_parse_pwent (nisres, result, buffer,
584 buflen, errnop);
585 if (parse_res == -1)
587 nis_freeresult (nisres);
588 ent->netgrdata.cursor = saved_cursor;
589 *errnop = ERANGE;
590 return NSS_STATUS_TRYAGAIN;
592 nis_freeresult (nisres);
594 if (parse_res && !in_blacklist (result->pw_name,
595 strlen (result->pw_name), ent))
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;
605 return NSS_STATUS_SUCCESS;
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)
613 int parse_res;
614 size_t p2len;
615 char *p2;
617 p2len = pwd_need_buflen (&ent->pwd);
618 if (p2len > buflen)
620 *errnop = ERANGE;
621 return NSS_STATUS_TRYAGAIN;
623 p2 = buffer + (buflen - p2len);
624 buflen -= p2len;
627 bool_t saved_first;
628 nis_result *saved_res;
630 if (ent->first)
632 saved_first = TRUE;
633 saved_res = ent->result;
635 ent->result = nis_first_entry (pwdtable);
636 if (niserr2nss (ent->result->status) != NSS_STATUS_SUCCESS)
638 ent->nis = 0;
639 give_pwd_free (&ent->pwd);
640 return niserr2nss (ent->result->status);
642 ent->first = FALSE;
644 else
646 nis_result *res;
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)
654 ent->nis = 0;
655 nis_freeresult (saved_res);
656 give_pwd_free (&ent->pwd);
657 return niserr2nss (ent->result->status);
660 parse_res = _nss_nisplus_parse_pwent (ent->result, result, buffer,
661 buflen, errnop);
662 if (parse_res == -1)
664 nis_freeresult (ent->result);
665 ent->result = saved_res;
666 ent->first = saved_first;
667 *errnop = ERANGE;
668 return NSS_STATUS_TRYAGAIN;
670 else
672 if (!saved_first)
673 nis_freeresult (saved_res);
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 */
680 while (!parse_res);
682 copy_pwd_changes (result, &ent->pwd, p2, p2len);
684 return NSS_STATUS_SUCCESS;
687 static enum nss_status
688 getpwent_next_nis (struct passwd *result, ent_t *ent, char *buffer,
689 size_t buflen, int *errnop)
691 struct parser_data *data = (void *) buffer;
692 char *domain, *outkey, *outval, *p, *p2;
693 int outkeylen, outvallen, parse_res;
694 size_t p2len;
696 if (yp_get_default_domain (&domain) != YPERR_SUCCESS)
698 ent->nis = 0;
699 give_pwd_free (&ent->pwd);
700 return NSS_STATUS_UNAVAIL;
703 p2len = pwd_need_buflen (&ent->pwd);
704 if (p2len > buflen)
706 *errnop = ERANGE;
707 return NSS_STATUS_TRYAGAIN;
709 p2 = buffer + (buflen - p2len);
710 buflen -= p2len;
713 bool_t saved_first;
714 char *saved_oldkey;
715 int saved_oldlen;
717 if (ent->first)
719 if (yp_first (domain, "passwd.byname", &outkey, &outkeylen,
720 &outval, &outvallen) != YPERR_SUCCESS)
722 ent->nis = 0;
723 give_pwd_free (&ent->pwd);
724 return NSS_STATUS_UNAVAIL;
727 if (insert_passwd_adjunct (&outval, &outvallen, domain, errnop) !=
728 NSS_STATUS_SUCCESS)
730 free (outval);
731 return NSS_STATUS_TRYAGAIN;
734 if (buflen < ((size_t) outvallen + 1))
736 free (outval);
737 *errnop = ERANGE;
738 return NSS_STATUS_TRYAGAIN;
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;
748 else
750 if (yp_next (domain, "passwd.byname", ent->oldkey, ent->oldkeylen,
751 &outkey, &outkeylen, &outval, &outvallen)
752 != YPERR_SUCCESS)
754 ent->nis = 0;
755 give_pwd_free (&ent->pwd);
756 *errnop = ENOENT;
757 return NSS_STATUS_NOTFOUND;
760 if (insert_passwd_adjunct (&outval, &outvallen, domain, errnop)
761 != NSS_STATUS_SUCCESS)
763 free (outval);
764 return NSS_STATUS_TRYAGAIN;
767 if (buflen < ((size_t) outvallen + 1))
769 free (outval);
770 *errnop = ERANGE;
771 return NSS_STATUS_TRYAGAIN;
774 saved_first = FALSE;
775 saved_oldkey = ent->oldkey;
776 saved_oldlen = ent->oldkeylen;
777 ent->oldkey = outkey;
778 ent->oldkeylen = outkeylen;
781 /* Copy the found data to our buffer */
782 p = strncpy (buffer, outval, buflen);
784 /* ...and free the data. */
785 free (outval);
787 while (isspace (*p))
788 ++p;
789 parse_res = _nss_files_parse_pwent (p, result, data, buflen, errnop);
790 if (parse_res == -1)
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;
799 else
801 if (!saved_first)
802 free (saved_oldkey);
804 if (parse_res
805 && in_blacklist (result->pw_name, strlen (result->pw_name), ent))
806 parse_res = 0;
808 while (!parse_res);
810 copy_pwd_changes (result, &ent->pwd, p2, p2len);
812 return NSS_STATUS_SUCCESS;
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)
820 struct parser_data *data = (void *) buffer;
821 struct passwd pwd;
822 int parse_res;
823 char *p;
824 size_t plen;
826 memset (&pwd, '\0', sizeof (struct passwd));
828 copy_pwd_changes (&pwd, result, NULL, 0);
830 plen = pwd_need_buflen (&pwd);
831 if (plen > buflen)
833 *errnop = ERANGE;
834 return NSS_STATUS_TRYAGAIN;
836 p = buffer + (buflen - plen);
837 buflen -= plen;
839 if (use_nisplus) /* Do the NIS+ query here */
841 nis_result *res;
842 char buf[strlen (name) + 24 + pwdtablelen];
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)
848 enum nss_status status = niserr2nss (res->status);
850 nis_freeresult (res);
851 return status;
853 parse_res = _nss_nisplus_parse_pwent (res, result, buffer,
854 buflen, errnop);
856 nis_freeresult (res);
858 if (parse_res == -1)
860 *errnop = ERANGE;
861 return NSS_STATUS_TRYAGAIN;
864 if (in_blacklist (result->pw_name, strlen (result->pw_name), ent))
866 *errnop = ENOENT;
867 return NSS_STATUS_NOTFOUND;
870 else /* Use NIS */
872 char *domain, *outval, *ptr;
873 int outvallen;
875 if (yp_get_default_domain (&domain) != YPERR_SUCCESS)
877 *errnop = ENOENT;
878 return NSS_STATUS_NOTFOUND;
881 if (yp_match (domain, "passwd.byname", name, strlen (name),
882 &outval, &outvallen) != YPERR_SUCCESS)
884 *errnop = ENOENT;
885 return NSS_STATUS_NOTFOUND;
888 if (insert_passwd_adjunct (&outval, &outvallen, domain, errnop)
889 != NSS_STATUS_SUCCESS)
891 free (outval);
892 return NSS_STATUS_TRYAGAIN;
895 if (buflen < ((size_t) outvallen + 1))
897 free (outval);
898 *errnop = ERANGE;
899 return NSS_STATUS_TRYAGAIN;
902 ptr = strncpy (buffer, outval, buflen);
903 free (outval);
905 while (isspace (*ptr))
906 ptr++;
908 parse_res = _nss_files_parse_pwent (ptr, result, data, buflen, errnop);
909 if (parse_res == -1)
910 return NSS_STATUS_TRYAGAIN;
912 if (in_blacklist (result->pw_name, strlen (result->pw_name), ent))
914 *errnop = ENOENT;
915 return NSS_STATUS_NOTFOUND;
919 if (parse_res > 0)
921 copy_pwd_changes (result, &pwd, p, plen);
922 give_pwd_free (&pwd);
923 /* We found the entry. */
924 return NSS_STATUS_SUCCESS;
926 else
928 /* Give buffer the old len back */
929 buflen += plen;
930 give_pwd_free (&pwd);
932 return NSS_STATUS_RETURN;
935 static enum nss_status
936 getpwent_next_file (struct passwd *result, ent_t *ent,
937 char *buffer, size_t buflen, int *errnop)
939 struct parser_data *data = (void *) buffer;
940 while (1)
942 fpos_t pos;
943 char *p;
944 int parse_res;
948 fgetpos (ent->stream, &pos);
949 buffer[buflen - 1] = '\xff';
950 p = fgets (buffer, buflen, ent->stream);
951 if (p == NULL && feof (ent->stream))
953 *errnop = ENOENT;
954 return NSS_STATUS_NOTFOUND;
956 if (p == NULL || buffer[buflen - 1] != '\xff')
958 fsetpos (ent->stream, &pos);
959 *errnop = ERANGE;
960 return NSS_STATUS_TRYAGAIN;
963 /* Terminate the line for any case. */
964 buffer[buflen - 1] = '\0';
966 /* Skip leading blanks. */
967 while (isspace (*p))
968 ++p;
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)));
976 if (parse_res == -1)
978 /* The parser ran out of space. */
979 fsetpos (ent->stream, &pos);
980 *errnop = ERANGE;
981 return NSS_STATUS_TRYAGAIN;
984 if (result->pw_name[0] != '+' && result->pw_name[0] != '-')
985 /* This is a real entry. */
986 break;
988 /* -@netgroup */
989 if (result->pw_name[0] == '-' && result->pw_name[1] == '@'
990 && result->pw_name[2] != '\0')
992 /* XXX Do not use fixed length buffer. */
993 char buf2[1024];
994 char *user, *host, *domain;
995 struct __netgrent netgrdata;
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))
1002 if (user != NULL && user[0] != '-')
1003 blacklist_store_name (user, ent);
1005 __internal_endnetgrent (&netgrdata);
1006 continue;
1009 /* +@netgroup */
1010 if (result->pw_name[0] == '+' && result->pw_name[1] == '@'
1011 && result->pw_name[2] != '\0')
1013 enum nss_status status;
1015 ent->netgroup = TRUE;
1016 ent->first = TRUE;
1017 copy_pwd_changes (&ent->pwd, result, NULL, 0);
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
1031 if (status == NSS_STATUS_NOTFOUND)
1032 *errnop = ENOENT;
1033 return status;
1037 /* -user */
1038 if (result->pw_name[0] == '-' && result->pw_name[1] != '\0'
1039 && result->pw_name[1] != '@')
1041 blacklist_store_name (&result->pw_name[1], ent);
1042 continue;
1045 /* +user */
1046 if (result->pw_name[0] == '+' && result->pw_name[1] != '\0'
1047 && result->pw_name[1] != '@')
1049 char buf[strlen (result->pw_name)];
1050 enum nss_status status;
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);
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
1067 if (status == NSS_STATUS_TRYAGAIN)
1069 /* The parser ran out of space */
1070 fsetpos (ent->stream, &pos);
1071 *errnop = ERANGE;
1073 return status;
1077 /* +:... */
1078 if (result->pw_name[0] == '+' && result->pw_name[1] == '\0')
1080 ent->nis = TRUE;
1081 ent->first = TRUE;
1082 copy_pwd_changes (&ent->pwd, result, NULL, 0);
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);
1091 return NSS_STATUS_SUCCESS;
1095 static enum nss_status
1096 internal_getpwent_r (struct passwd *pw, ent_t *ent, char *buffer,
1097 size_t buflen, int *errnop)
1099 if (ent->netgroup)
1101 enum nss_status status;
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;
1116 else
1117 if (ent->nis)
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);
1124 else
1125 return getpwent_next_file (pw, ent, buffer, buflen, errnop);
1128 enum nss_status
1129 _nss_compat_getpwent_r (struct passwd *pwd, char *buffer, size_t buflen,
1130 int *errnop)
1132 enum nss_status status = NSS_STATUS_SUCCESS;
1134 __libc_lock_lock (lock);
1136 if (ni == NULL)
1138 __nss_database_lookup ("passwd_compat", NULL, "nis", &ni);
1139 use_nisplus = (strcmp (ni->name, "nisplus") == 0);
1142 /* Be prepared that the setpwent function was not called before. */
1143 if (ext_ent.stream == NULL)
1144 status = internal_setpwent (&ext_ent);
1146 if (status == NSS_STATUS_SUCCESS)
1147 status = internal_getpwent_r (pwd, &ext_ent, buffer, buflen, errnop);
1149 __libc_lock_unlock (lock);
1151 return status;
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)
1159 struct parser_data *data = (void *) buffer;
1161 while (1)
1163 fpos_t pos;
1164 char *p;
1165 int parse_res;
1169 fgetpos (ent->stream, &pos);
1170 buffer[buflen - 1] = '\xff';
1171 p = fgets (buffer, buflen, ent->stream);
1172 if (p == NULL && feof (ent->stream))
1174 *errnop = ENOENT;
1175 return NSS_STATUS_NOTFOUND;
1177 if (p == NULL || buffer[buflen - 1] != '\xff')
1179 fsetpos (ent->stream, &pos);
1180 *errnop = ERANGE;
1181 return NSS_STATUS_TRYAGAIN;
1184 /* Terminate the line for any case. */
1185 buffer[buflen - 1] = '\0';
1187 /* Skip leading blanks. */
1188 while (isspace (*p))
1189 ++p;
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)));
1197 if (parse_res == -1)
1199 /* The parser ran out of space. */
1200 fsetpos (ent->stream, &pos);
1201 *errnop = ERANGE;
1202 return NSS_STATUS_TRYAGAIN;
1205 /* This is a real entry. */
1206 if (result->pw_name[0] != '+' && result->pw_name[0] != '-')
1208 if (strcmp (result->pw_name, name) == 0)
1209 return NSS_STATUS_SUCCESS;
1210 else
1211 continue;
1214 /* -@netgroup */
1215 if (result->pw_name[0] == '-' && result->pw_name[1] == '@'
1216 && result->pw_name[2] != '\0')
1218 if (innetgr (&result->pw_name[2], NULL, name, NULL))
1219 return NSS_STATUS_NOTFOUND;
1220 continue;
1223 /* +@netgroup */
1224 if (result->pw_name[0] == '+' && result->pw_name[1] == '@'
1225 && result->pw_name[2] != '\0')
1227 enum nss_status status;
1229 if (innetgr (&result->pw_name[2], NULL, name, NULL))
1231 status = getpwnam_plususer (name, result, ent, buffer,
1232 buflen, errnop);
1234 if (status == NSS_STATUS_RETURN)
1235 continue;
1237 return status;
1239 continue;
1242 /* -user */
1243 if (result->pw_name[0] == '-' && result->pw_name[1] != '\0'
1244 && result->pw_name[1] != '@')
1246 if (strcmp (&result->pw_name[1], name) == 0)
1248 *errnop = ENOENT;
1249 return NSS_STATUS_NOTFOUND;
1251 else
1252 continue;
1255 /* +user */
1256 if (result->pw_name[0] == '+' && result->pw_name[1] != '\0'
1257 && result->pw_name[1] != '@')
1259 if (strcmp (name, &result->pw_name[1]) == 0)
1261 enum nss_status status;
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;
1273 /* +:... */
1274 if (result->pw_name[0] == '+' && result->pw_name[1] == '\0')
1276 enum nss_status status;
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;
1289 return NSS_STATUS_SUCCESS;
1292 enum nss_status
1293 _nss_compat_getpwnam_r (const char *name, struct passwd *pwd,
1294 char *buffer, size_t buflen, int *errnop)
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;
1300 if (name[0] == '-' || name[0] == '+')
1302 *errnop = ENOENT;
1303 return NSS_STATUS_NOTFOUND;
1306 __libc_lock_lock (lock);
1308 if (ni == NULL)
1310 __nss_database_lookup ("passwd_compat", NULL, "nis", &ni);
1311 use_nisplus = (strcmp (ni->name, "nisplus") == 0);
1314 __libc_lock_unlock (lock);
1316 status = internal_setpwent (&ent);
1317 if (status != NSS_STATUS_SUCCESS)
1318 return status;
1320 status = internal_getpwnam_r (name, pwd, &ent, buffer, buflen, errnop);
1322 internal_endpwent (&ent);
1324 return status;
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)
1332 struct parser_data *data = (void *) buffer;
1333 struct passwd pwd;
1334 int parse_res;
1335 char *p;
1336 size_t plen;
1338 memset (&pwd, '\0', sizeof (struct passwd));
1340 copy_pwd_changes (&pwd, result, NULL, 0);
1342 plen = pwd_need_buflen (&pwd);
1343 if (plen > buflen)
1345 *errnop = ERANGE;
1346 return NSS_STATUS_TRYAGAIN;
1348 p = buffer + (buflen - plen);
1349 buflen -= plen;
1351 if (use_nisplus) /* Do the NIS+ query here */
1353 nis_result *res;
1354 char buf[1024 + pwdtablelen];
1356 snprintf(buf, sizeof (buf), "[uid=%d],%s", uid, pwdtable);
1357 res = nis_list(buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
1358 if (niserr2nss (res->status) != NSS_STATUS_SUCCESS)
1360 enum nss_status status = niserr2nss (res->status);
1362 nis_freeresult (res);
1363 return status;
1365 if ((parse_res = _nss_nisplus_parse_pwent (res, result, buffer,
1366 buflen, errnop)) == -1)
1368 nis_freeresult (res);
1369 *errnop = ERANGE;
1370 return NSS_STATUS_TRYAGAIN;
1372 nis_freeresult (res);
1374 else /* Use NIS */
1376 char buf[1024];
1377 char *domain, *outval, *ptr;
1378 int outvallen;
1380 if (yp_get_default_domain (&domain) != YPERR_SUCCESS)
1382 *errnop = ENOENT;
1383 return NSS_STATUS_NOTFOUND;
1386 sprintf (buf, "%d", uid);
1387 if (yp_match (domain, "passwd.byuid", buf, strlen (buf),
1388 &outval, &outvallen)
1389 != YPERR_SUCCESS)
1391 *errnop = ENOENT;
1392 return NSS_STATUS_NOTFOUND;
1395 if (insert_passwd_adjunct (&outval, &outvallen, domain, errnop)
1396 != NSS_STATUS_SUCCESS)
1398 free (outval);
1399 return NSS_STATUS_TRYAGAIN;
1402 if (buflen < ((size_t) outvallen + 1))
1404 free (outval);
1405 *errnop = ERANGE;
1406 return NSS_STATUS_TRYAGAIN;
1409 ptr = strncpy (buffer, outval, buflen);
1410 free (outval);
1412 while (isspace (*ptr))
1413 ptr++;
1414 parse_res = _nss_files_parse_pwent (ptr, result, data, buflen, errnop);
1415 if (parse_res == -1)
1416 return NSS_STATUS_TRYAGAIN;
1419 if (parse_res > 0)
1421 copy_pwd_changes (result, &pwd, p, plen);
1422 give_pwd_free (&pwd);
1423 /* We found the entry. */
1424 return NSS_STATUS_SUCCESS;
1426 else
1428 /* Give buffer the old len back */
1429 buflen += plen;
1430 give_pwd_free (&pwd);
1432 return NSS_STATUS_RETURN;
1435 /* Searches in /etc/passwd and the NIS/NIS+ map for a special user id */
1436 static enum nss_status
1437 internal_getpwuid_r (uid_t uid, struct passwd *result, ent_t *ent,
1438 char *buffer, size_t buflen, int *errnop)
1440 struct parser_data *data = (void *) buffer;
1442 while (1)
1444 fpos_t pos;
1445 char *p;
1446 int parse_res;
1450 fgetpos (ent->stream, &pos);
1451 buffer[buflen - 1] = '\xff';
1452 p = fgets (buffer, buflen, ent->stream);
1453 if (p == NULL && feof (ent->stream))
1455 *errnop = ENOENT;
1456 return NSS_STATUS_NOTFOUND;
1458 if (p == NULL || buffer[buflen - 1] != '\xff')
1460 fsetpos (ent->stream, &pos);
1461 *errnop = ERANGE;
1462 return NSS_STATUS_TRYAGAIN;
1465 /* Terminate the line for any case. */
1466 buffer[buflen - 1] = '\0';
1468 /* Skip leading blanks. */
1469 while (isspace (*p))
1470 ++p;
1472 while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */
1473 /* Parse the line. If it is invalid, loop to
1474 get the next line of the file to parse. */
1475 !(parse_res = _nss_files_parse_pwent (p, result, data, buflen,
1476 errnop)));
1478 if (parse_res == -1)
1480 /* The parser ran out of space. */
1481 fsetpos (ent->stream, &pos);
1482 *errnop = ERANGE;
1483 return NSS_STATUS_TRYAGAIN;
1486 /* This is a real entry. */
1487 if (result->pw_name[0] != '+' && result->pw_name[0] != '-')
1489 if (result->pw_uid == uid)
1490 return NSS_STATUS_SUCCESS;
1491 else
1492 continue;
1495 /* -@netgroup */
1496 if (result->pw_name[0] == '-' && result->pw_name[1] == '@'
1497 && result->pw_name[2] != '\0')
1499 char buf[strlen (result->pw_name)];
1500 enum nss_status status;
1502 strcpy (buf, &result->pw_name[2]);
1504 status = getpwuid_plususer (uid, result, buffer, buflen, errnop);
1505 if (status == NSS_STATUS_SUCCESS &&
1506 innetgr (buf, NULL, result->pw_name, NULL))
1508 *errnop = ENOENT;
1509 return NSS_STATUS_NOTFOUND;
1511 continue;
1514 /* +@netgroup */
1515 if (result->pw_name[0] == '+' && result->pw_name[1] == '@'
1516 && result->pw_name[2] != '\0')
1518 char buf[strlen (result->pw_name)];
1519 enum nss_status status;
1521 strcpy (buf, &result->pw_name[2]);
1523 status = getpwuid_plususer (uid, result, buffer, buflen, errnop);
1525 if (status == NSS_STATUS_RETURN)
1526 continue;
1528 if (status == NSS_STATUS_SUCCESS)
1530 if (innetgr (buf, NULL, result->pw_name, NULL))
1531 return NSS_STATUS_SUCCESS;
1533 else
1534 if (status == NSS_STATUS_RETURN) /* We couldn't parse the entry */
1536 *errnop = ENOENT;
1537 return NSS_STATUS_NOTFOUND;
1539 else
1540 return status;
1542 continue;
1545 /* -user */
1546 if (result->pw_name[0] == '-' && result->pw_name[1] != '\0'
1547 && result->pw_name[1] != '@')
1549 char buf[strlen (result->pw_name)];
1550 enum nss_status status;
1552 strcpy (buf, &result->pw_name[1]);
1554 status = getpwuid_plususer (uid, result, buffer, buflen, errnop);
1555 if (status == NSS_STATUS_SUCCESS &&
1556 innetgr (buf, NULL, result->pw_name, NULL))
1558 *errnop = ENOENT;
1559 return NSS_STATUS_NOTFOUND;
1561 continue;
1564 /* +user */
1565 if (result->pw_name[0] == '+' && result->pw_name[1] != '\0'
1566 && result->pw_name[1] != '@')
1568 char buf[strlen (result->pw_name)];
1569 enum nss_status status;
1571 strcpy (buf, &result->pw_name[1]);
1573 status = getpwuid_plususer (uid, result, buffer, buflen, errnop);
1575 if (status == NSS_STATUS_RETURN)
1576 continue;
1578 if (status == NSS_STATUS_SUCCESS)
1580 if (strcmp (buf, result->pw_name) == 0)
1581 return NSS_STATUS_SUCCESS;
1583 else
1584 if (status == NSS_STATUS_RETURN) /* We couldn't parse the entry */
1586 *errnop = ENOENT;
1587 return NSS_STATUS_NOTFOUND;
1589 else
1590 return status;
1592 continue;
1595 /* +:... */
1596 if (result->pw_name[0] == '+' && result->pw_name[1] == '\0')
1598 enum nss_status status;
1600 status = getpwuid_plususer (uid, result, buffer, buflen, errnop);
1601 if (status == NSS_STATUS_SUCCESS) /* We found the entry. */
1602 break;
1603 else
1604 if (status == NSS_STATUS_RETURN) /* We couldn't parse the entry */
1606 *errnop = ENOENT;
1607 return NSS_STATUS_NOTFOUND;
1609 else
1610 return status;
1613 return NSS_STATUS_SUCCESS;
1616 enum nss_status
1617 _nss_compat_getpwuid_r (uid_t uid, struct passwd *pwd,
1618 char *buffer, size_t buflen, int *errnop)
1620 ent_t ent = {0, 0, 0, NULL, 0, NULL, NULL, {NULL, 0, 0},
1621 {NULL, NULL, 0, 0, NULL, NULL, NULL}};
1622 enum nss_status status;
1624 __libc_lock_lock (lock);
1626 if (ni == NULL)
1628 __nss_database_lookup ("passwd_compat", NULL, "nis", &ni);
1629 use_nisplus = (strcmp (ni->name, "nisplus") == 0);
1632 __libc_lock_unlock (lock);
1634 status = internal_setpwent (&ent);
1635 if (status != NSS_STATUS_SUCCESS)
1636 return status;
1638 status = internal_getpwuid_r (uid, pwd, &ent, buffer, buflen, errnop);
1640 internal_endpwent (&ent);
1642 return status;
1646 /* Support routines for remembering -@netgroup and -user entries.
1647 The names are stored in a single string with `|' as separator. */
1648 static void
1649 blacklist_store_name (const char *name, ent_t *ent)
1651 int namelen = strlen (name);
1652 char *tmp;
1654 /* first call, setup cache */
1655 if (ent->blacklist.size == 0)
1657 ent->blacklist.size = MAX (BLACKLIST_INITIAL_SIZE, 2 * namelen);
1658 ent->blacklist.data = malloc (ent->blacklist.size);
1659 if (ent->blacklist.data == NULL)
1660 return;
1661 ent->blacklist.data[0] = '|';
1662 ent->blacklist.data[1] = '\0';
1663 ent->blacklist.current = 1;
1665 else
1667 if (in_blacklist (name, namelen, ent))
1668 return; /* no duplicates */
1670 if (ent->blacklist.current + namelen + 1 >= ent->blacklist.size)
1672 ent->blacklist.size += MAX (BLACKLIST_INCREMENT, 2 * namelen);
1673 tmp = realloc (ent->blacklist.data, ent->blacklist.size);
1674 if (tmp == NULL)
1676 free (ent->blacklist.data);
1677 ent->blacklist.size = 0;
1678 return;
1680 ent->blacklist.data = tmp;
1684 tmp = stpcpy (ent->blacklist.data + ent->blacklist.current, name);
1685 *tmp++ = '|';
1686 *tmp = '\0';
1687 ent->blacklist.current += namelen + 1;
1689 return;
1692 /* returns TRUE if ent->blacklist contains name, else FALSE */
1693 static bool_t
1694 in_blacklist (const char *name, int namelen, ent_t *ent)
1696 char buf[namelen + 3];
1697 char *cp;
1699 if (ent->blacklist.data == NULL)
1700 return FALSE;
1702 buf[0] = '|';
1703 cp = stpcpy (&buf[1], name);
1704 *cp++= '|';
1705 *cp = '\0';
1706 return strstr (ent->blacklist.data, buf) != NULL;