* nis/nss_nisplus/nisplus-netgrp.c: Cleanups.
[glibc.git] / nis / nss_compat / compat-spwd.c
blob120e3bd38d47e6607f7bafb181365fe7f61c9b38
1 /* Copyright (C) 1996-1999,2001-2004,2005 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 <ctype.h>
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <netdb.h>
24 #include <nss.h>
25 #include <nsswitch.h>
26 #include <shadow.h>
27 #include <stdio_ext.h>
28 #include <string.h>
29 #include <rpc/types.h>
30 #include <rpcsvc/ypclnt.h>
31 #include <bits/libc-lock.h>
33 #include "netgroup.h"
35 static service_user *ni;
36 static enum nss_status (*nss_setspent) (int stayopen);
37 static enum nss_status (*nss_getspnam_r) (const char *name, struct spwd * sp,
38 char *buffer, size_t buflen,
39 int *errnop);
40 static enum nss_status (*nss_getspent_r) (struct spwd * sp, char *buffer,
41 size_t buflen, int *errnop);
42 static enum nss_status (*nss_endspent) (void);
44 /* Get the declaration of the parser function. */
45 #define ENTNAME spent
46 #define STRUCTURE spwd
47 #define EXTERN_PARSER
48 #include <nss/nss_files/files-parse.c>
50 /* Structure for remembering -@netgroup and -user members ... */
51 #define BLACKLIST_INITIAL_SIZE 512
52 #define BLACKLIST_INCREMENT 256
53 struct blacklist_t
55 char *data;
56 int current;
57 int size;
60 struct ent_t
62 bool_t netgroup;
63 bool_t files;
64 bool_t first;
65 FILE *stream;
66 struct blacklist_t blacklist;
67 struct spwd pwd;
68 struct __netgrent netgrdata;
70 typedef struct ent_t ent_t;
72 static ent_t ext_ent = {0, TRUE, 0, NULL, {NULL, 0, 0},
73 {NULL, NULL, 0, 0, 0, 0, 0, 0, 0}};
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 *);
82 /* Initialize the NSS interface/functions. The calling function must
83 hold the lock. */
84 static void
85 init_nss_interface (void)
87 if (__nss_database_lookup ("shadow_compat", "passwd_compat",
88 "nis", &ni) >= 0)
90 nss_setspent = __nss_lookup_function (ni, "setspent");
91 nss_getspnam_r = __nss_lookup_function (ni, "getspnam_r");
92 nss_getspent_r = __nss_lookup_function (ni, "getspent_r");
93 nss_endspent = __nss_lookup_function (ni, "endspent");
97 static void
98 give_spwd_free (struct spwd *pwd)
100 if (pwd->sp_namp != NULL)
101 free (pwd->sp_namp);
102 if (pwd->sp_pwdp != NULL)
103 free (pwd->sp_pwdp);
105 memset (pwd, '\0', sizeof (struct spwd));
106 pwd->sp_warn = -1;
107 pwd->sp_inact = -1;
108 pwd->sp_expire = -1;
109 pwd->sp_flag = ~0ul;
112 static int
113 spwd_need_buflen (struct spwd *pwd)
115 int len = 0;
117 if (pwd->sp_pwdp != NULL)
118 len += strlen (pwd->sp_pwdp) + 1;
120 return len;
123 static void
124 copy_spwd_changes (struct spwd *dest, struct spwd *src,
125 char *buffer, size_t buflen)
127 if (src->sp_pwdp != NULL && strlen (src->sp_pwdp))
129 if (buffer == NULL)
130 dest->sp_pwdp = strdup (src->sp_pwdp);
131 else if (dest->sp_pwdp &&
132 strlen (dest->sp_pwdp) >= strlen (src->sp_pwdp))
133 strcpy (dest->sp_pwdp, src->sp_pwdp);
134 else
136 dest->sp_pwdp = buffer;
137 strcpy (dest->sp_pwdp, src->sp_pwdp);
138 buffer += strlen (dest->sp_pwdp) + 1;
139 buflen = buflen - (strlen (dest->sp_pwdp) + 1);
142 if (src->sp_lstchg != 0)
143 dest->sp_lstchg = src->sp_lstchg;
144 if (src->sp_min != 0)
145 dest->sp_min = src->sp_min;
146 if (src->sp_max != 0)
147 dest->sp_max = src->sp_max;
148 if (src->sp_warn != -1)
149 dest->sp_warn = src->sp_warn;
150 if (src->sp_inact != -1)
151 dest->sp_inact = src->sp_inact;
152 if (src->sp_expire != -1)
153 dest->sp_expire = src->sp_expire;
154 if (src->sp_flag != ~0ul)
155 dest->sp_flag = src->sp_flag;
158 static enum nss_status
159 internal_setspent (ent_t *ent, int stayopen)
161 enum nss_status status = NSS_STATUS_SUCCESS;
163 ent->first = ent->netgroup = 0;
164 ent->files = TRUE;
166 /* If something was left over free it. */
167 if (ent->netgroup)
168 __internal_endnetgrent (&ent->netgrdata);
170 if (ent->blacklist.data != NULL)
172 ent->blacklist.current = 1;
173 ent->blacklist.data[0] = '|';
174 ent->blacklist.data[1] = '\0';
176 else
177 ent->blacklist.current = 0;
179 if (ent->stream == NULL)
181 ent->stream = fopen ("/etc/shadow", "rm");
183 if (ent->stream == NULL)
184 status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL;
185 else
187 /* We have to make sure the file is `closed on exec'. */
188 int result, flags;
190 result = flags = fcntl (fileno_unlocked (ent->stream), F_GETFD, 0);
191 if (result >= 0)
193 flags |= FD_CLOEXEC;
194 result = fcntl (fileno_unlocked (ent->stream), F_SETFD, flags);
196 if (result < 0)
198 /* Something went wrong. Close the stream and return a
199 failure. */
200 fclose (ent->stream);
201 ent->stream = NULL;
202 status = NSS_STATUS_UNAVAIL;
204 else
205 /* We take care of locking ourself. */
206 __fsetlocking (ent->stream, FSETLOCKING_BYCALLER);
209 else
210 rewind (ent->stream);
212 give_spwd_free (&ent->pwd);
214 if (status == NSS_STATUS_SUCCESS && nss_setspent)
215 return nss_setspent (stayopen);
217 return status;
221 enum nss_status
222 _nss_compat_setspent (int stayopen)
224 enum nss_status result;
226 __libc_lock_lock (lock);
228 if (ni == NULL)
229 init_nss_interface ();
231 result = internal_setspent (&ext_ent, stayopen);
233 __libc_lock_unlock (lock);
235 return result;
239 static enum nss_status
240 internal_endspent (ent_t *ent)
242 if (nss_endspent)
243 nss_endspent ();
245 if (ent->stream != NULL)
247 fclose (ent->stream);
248 ent->stream = NULL;
251 if (ent->netgroup)
252 __internal_endnetgrent (&ent->netgrdata);
254 ent->first = ent->netgroup = FALSE;
255 ent->files = TRUE;
257 if (ent->blacklist.data != NULL)
259 ent->blacklist.current = 1;
260 ent->blacklist.data[0] = '|';
261 ent->blacklist.data[1] = '\0';
263 else
264 ent->blacklist.current = 0;
266 give_spwd_free (&ent->pwd);
268 return NSS_STATUS_SUCCESS;
271 enum nss_status
272 _nss_compat_endspent (void)
274 enum nss_status result;
276 __libc_lock_lock (lock);
278 result = internal_endspent (&ext_ent);
280 __libc_lock_unlock (lock);
282 return result;
286 static enum nss_status
287 getspent_next_nss_netgr (const char *name, struct spwd *result, ent_t *ent,
288 char *group, char *buffer, size_t buflen,
289 int *errnop)
291 char *curdomain, *host, *user, *domain, *p2;
292 size_t p2len;
294 if (!nss_getspnam_r)
295 return NSS_STATUS_UNAVAIL;
297 if (yp_get_default_domain (&curdomain) != YPERR_SUCCESS)
299 ent->netgroup = FALSE;
300 ent->first = FALSE;
301 give_spwd_free (&ent->pwd);
302 return NSS_STATUS_UNAVAIL;
305 if (ent->first == TRUE)
307 memset (&ent->netgrdata, 0, sizeof (struct __netgrent));
308 __internal_setnetgrent (group, &ent->netgrdata);
309 ent->first = FALSE;
312 while (1)
314 char *saved_cursor;
315 enum nss_status status;
317 saved_cursor = ent->netgrdata.cursor;
318 status = __internal_getnetgrent_r (&host, &user, &domain,
319 &ent->netgrdata, buffer, buflen,
320 errnop);
321 if (status != 1)
323 __internal_endnetgrent (&ent->netgrdata);
324 ent->netgroup = FALSE;
325 give_spwd_free (&ent->pwd);
326 return NSS_STATUS_RETURN;
329 if (user == NULL || user[0] == '-')
330 continue;
332 if (domain != NULL && strcmp (curdomain, domain) != 0)
333 continue;
335 /* If name != NULL, we are called from getpwnam */
336 if (name != NULL)
337 if (strcmp (user, name) != 0)
338 continue;
340 p2len = spwd_need_buflen (&ent->pwd);
341 if (p2len > buflen)
343 *errnop = ERANGE;
344 return NSS_STATUS_TRYAGAIN;
346 p2 = buffer + (buflen - p2len);
347 buflen -= p2len;
349 if (nss_getspnam_r (user, result, buffer, buflen, errnop) !=
350 NSS_STATUS_SUCCESS)
351 continue;
353 if (!in_blacklist (result->sp_namp, strlen (result->sp_namp), ent))
355 /* Store the User in the blacklist for possible the "+" at the
356 end of /etc/passwd */
357 blacklist_store_name (result->sp_namp, ent);
358 copy_spwd_changes (result, &ent->pwd, p2, p2len);
359 break;
363 return NSS_STATUS_SUCCESS;
367 static enum nss_status
368 getspent_next_nss (struct spwd *result, ent_t *ent,
369 char *buffer, size_t buflen, int *errnop)
371 enum nss_status status;
372 char *p2;
373 size_t p2len;
375 if (!nss_getspent_r)
376 return NSS_STATUS_UNAVAIL;
378 p2len = spwd_need_buflen (&ent->pwd);
379 if (p2len > buflen)
381 *errnop = ERANGE;
382 return NSS_STATUS_TRYAGAIN;
384 p2 = buffer + (buflen - p2len);
385 buflen -= p2len;
388 if ((status = nss_getspent_r (result, buffer, buflen, errnop)) !=
389 NSS_STATUS_SUCCESS)
390 return status;
392 while (in_blacklist (result->sp_namp, strlen (result->sp_namp), ent));
394 copy_spwd_changes (result, &ent->pwd, p2, p2len);
396 return NSS_STATUS_SUCCESS;
399 /* This function handle the +user entrys in /etc/shadow */
400 static enum nss_status
401 getspnam_plususer (const char *name, struct spwd *result, ent_t *ent,
402 char *buffer, size_t buflen, int *errnop)
404 if (!nss_getspnam_r)
405 return NSS_STATUS_UNAVAIL;
407 struct spwd pwd;
408 memset (&pwd, '\0', sizeof (struct spwd));
409 pwd.sp_warn = -1;
410 pwd.sp_inact = -1;
411 pwd.sp_expire = -1;
412 pwd.sp_flag = ~0ul;
414 copy_spwd_changes (&pwd, result, NULL, 0);
416 size_t plen = spwd_need_buflen (&pwd);
417 if (plen > buflen)
419 *errnop = ERANGE;
420 return NSS_STATUS_TRYAGAIN;
422 char *p = buffer + (buflen - plen);
423 buflen -= plen;
425 enum nss_status status = nss_getspnam_r (name, result, buffer, buflen,
426 errnop);
427 if (status != NSS_STATUS_SUCCESS)
428 return status;
430 if (in_blacklist (result->sp_namp, strlen (result->sp_namp), ent))
431 return NSS_STATUS_NOTFOUND;
433 copy_spwd_changes (result, &pwd, p, plen);
434 give_spwd_free (&pwd);
435 /* We found the entry. */
436 return NSS_STATUS_SUCCESS;
439 static enum nss_status
440 getspent_next_file (struct spwd *result, ent_t *ent,
441 char *buffer, size_t buflen, int *errnop)
443 struct parser_data *data = (void *) buffer;
444 while (1)
446 fpos_t pos;
447 int parse_res = 0;
448 char *p;
452 /* We need at least 3 characters for one line. */
453 if (__builtin_expect (buflen < 3, 0))
455 erange:
456 *errnop = ERANGE;
457 return NSS_STATUS_TRYAGAIN;
460 fgetpos (ent->stream, &pos);
461 buffer[buflen - 1] = '\xff';
462 p = fgets_unlocked (buffer, buflen, ent->stream);
463 if (p == NULL && feof_unlocked (ent->stream))
464 return NSS_STATUS_NOTFOUND;
466 if (p == NULL || __builtin_expect (buffer[buflen - 1] != '\xff', 0))
468 erange_reset:
469 fsetpos (ent->stream, &pos);
470 goto erange;
473 /* Skip leading blanks. */
474 while (isspace (*p))
475 ++p;
477 while (*p == '\0' || *p == '#' /* Ignore empty and comment lines. */
478 /* Parse the line. If it is invalid, loop to
479 get the next line of the file to parse. */
480 || !(parse_res = _nss_files_parse_spent (p, result, data,
481 buflen, errnop)));
483 if (__builtin_expect (parse_res == -1, 0))
484 /* The parser ran out of space. */
485 goto erange_reset;
487 if (result->sp_namp[0] != '+' && result->sp_namp[0] != '-')
488 /* This is a real entry. */
489 break;
491 /* -@netgroup */
492 if (result->sp_namp[0] == '-' && result->sp_namp[1] == '@'
493 && result->sp_namp[2] != '\0')
495 /* XXX Do not use fixed length buffers. */
496 char buf2[1024];
497 char *user, *host, *domain;
498 struct __netgrent netgrdata;
500 bzero (&netgrdata, sizeof (struct __netgrent));
501 __internal_setnetgrent (&result->sp_namp[2], &netgrdata);
502 while (__internal_getnetgrent_r (&host, &user, &domain,
503 &netgrdata, buf2, sizeof (buf2),
504 errnop))
506 if (user != NULL && user[0] != '-')
507 blacklist_store_name (user, ent);
509 __internal_endnetgrent (&netgrdata);
510 continue;
513 /* +@netgroup */
514 if (result->sp_namp[0] == '+' && result->sp_namp[1] == '@'
515 && result->sp_namp[2] != '\0')
517 int status;
519 ent->netgroup = TRUE;
520 ent->first = TRUE;
521 copy_spwd_changes (&ent->pwd, result, NULL, 0);
523 status = getspent_next_nss_netgr (NULL, result, ent,
524 &result->sp_namp[2],
525 buffer, buflen, errnop);
526 if (status == NSS_STATUS_RETURN)
527 continue;
528 else
529 return status;
532 /* -user */
533 if (result->sp_namp[0] == '-' && result->sp_namp[1] != '\0'
534 && result->sp_namp[1] != '@')
536 blacklist_store_name (&result->sp_namp[1], ent);
537 continue;
540 /* +user */
541 if (result->sp_namp[0] == '+' && result->sp_namp[1] != '\0'
542 && result->sp_namp[1] != '@')
544 size_t len = strlen (result->sp_namp);
545 char buf[len];
546 enum nss_status status;
548 /* Store the User in the blacklist for the "+" at the end of
549 /etc/passwd */
550 memcpy (buf, &result->sp_namp[1], len);
551 status = getspnam_plususer (&result->sp_namp[1], result, ent,
552 buffer, buflen, errnop);
553 blacklist_store_name (buf, ent);
555 if (status == NSS_STATUS_SUCCESS) /* We found the entry. */
556 break;
557 /* We couldn't parse the entry */
558 else if (status == NSS_STATUS_RETURN
559 /* entry doesn't exist */
560 || status == NSS_STATUS_NOTFOUND)
561 continue;
562 else
564 if (status == NSS_STATUS_TRYAGAIN)
566 fsetpos (ent->stream, &pos);
567 *errnop = ERANGE;
569 return status;
573 /* +:... */
574 if (result->sp_namp[0] == '+' && result->sp_namp[1] == '\0')
576 ent->files = FALSE;
577 ent->first = TRUE;
578 copy_spwd_changes (&ent->pwd, result, NULL, 0);
580 return getspent_next_nss (result, ent, buffer, buflen, errnop);
584 return NSS_STATUS_SUCCESS;
588 static enum nss_status
589 internal_getspent_r (struct spwd *pw, ent_t *ent,
590 char *buffer, size_t buflen, int *errnop)
592 if (ent->netgroup)
594 enum nss_status status;
596 /* We are searching members in a netgroup */
597 /* Since this is not the first call, we don't need the group name */
598 status = getspent_next_nss_netgr (NULL, pw, ent, NULL, buffer,
599 buflen, errnop);
601 if (status == NSS_STATUS_RETURN)
602 return getspent_next_file (pw, ent, buffer, buflen, errnop);
603 else
604 return status;
606 else if (ent->files)
607 return getspent_next_file (pw, ent, buffer, buflen, errnop);
608 else
609 return getspent_next_nss (pw, ent, buffer, buflen, errnop);
612 enum nss_status
613 _nss_compat_getspent_r (struct spwd *pwd, char *buffer, size_t buflen,
614 int *errnop)
616 enum nss_status result = NSS_STATUS_SUCCESS;
618 __libc_lock_lock (lock);
620 /* Be prepared that the setpwent function was not called before. */
621 if (ni == NULL)
622 init_nss_interface ();
624 if (ext_ent.stream == NULL)
625 result = internal_setspent (&ext_ent, 1);
627 if (result == NSS_STATUS_SUCCESS)
628 result = internal_getspent_r (pwd, &ext_ent, buffer, buflen, errnop);
630 __libc_lock_unlock (lock);
632 return result;
635 /* Searches in /etc/passwd and the NIS/NIS+ map for a special user */
636 static enum nss_status
637 internal_getspnam_r (const char *name, struct spwd *result, ent_t *ent,
638 char *buffer, size_t buflen, int *errnop)
640 struct parser_data *data = (void *) buffer;
642 while (1)
644 fpos_t pos;
645 char *p;
646 int parse_res;
650 /* We need at least 3 characters for one line. */
651 if (__builtin_expect (buflen < 3, 0))
653 erange:
654 *errnop = ERANGE;
655 return NSS_STATUS_TRYAGAIN;
658 fgetpos (ent->stream, &pos);
659 buffer[buflen - 1] = '\xff';
660 p = fgets_unlocked (buffer, buflen, ent->stream);
661 if (p == NULL && feof_unlocked (ent->stream))
662 return NSS_STATUS_NOTFOUND;
664 if (p == NULL || buffer[buflen - 1] != '\xff')
666 erange_reset:
667 fsetpos (ent->stream, &pos);
668 goto erange;
671 /* Terminate the line for any case. */
672 buffer[buflen - 1] = '\0';
674 /* Skip leading blanks. */
675 while (isspace (*p))
676 ++p;
678 while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */
679 /* Parse the line. If it is invalid, loop to
680 get the next line of the file to parse. */
681 !(parse_res = _nss_files_parse_spent (p, result, data, buflen,
682 errnop)));
684 if (__builtin_expect (parse_res == -1, 0))
685 /* The parser ran out of space. */
686 goto erange_reset;
688 /* This is a real entry. */
689 if (result->sp_namp[0] != '+' && result->sp_namp[0] != '-')
691 if (strcmp (result->sp_namp, name) == 0)
692 return NSS_STATUS_SUCCESS;
693 else
694 continue;
697 /* -@netgroup */
698 /* If the loaded NSS module does not support this service, add
699 all users from a +@netgroup entry to the blacklist, too. */
700 if (result->sp_namp[0] == '-' && result->sp_namp[1] == '@'
701 && result->sp_namp[2] != '\0')
703 if (innetgr (&result->sp_namp[2], NULL, name, NULL))
704 return NSS_STATUS_NOTFOUND;
705 continue;
708 /* +@netgroup */
709 if (result->sp_namp[0] == '+' && result->sp_namp[1] == '@'
710 && result->sp_namp[2] != '\0')
712 enum nss_status status;
714 if (innetgr (&result->sp_namp[2], NULL, name, NULL))
716 status = getspnam_plususer (name, result, ent, buffer,
717 buflen, errnop);
719 if (status == NSS_STATUS_RETURN)
720 continue;
722 return status;
724 continue;
727 /* -user */
728 if (result->sp_namp[0] == '-' && result->sp_namp[1] != '\0'
729 && result->sp_namp[1] != '@')
731 if (strcmp (&result->sp_namp[1], name) == 0)
732 return NSS_STATUS_NOTFOUND;
733 else
734 continue;
737 /* +user */
738 if (result->sp_namp[0] == '+' && result->sp_namp[1] != '\0'
739 && result->sp_namp[1] != '@')
741 if (strcmp (name, &result->sp_namp[1]) == 0)
743 enum nss_status status;
745 status = getspnam_plususer (name, result, ent,
746 buffer, buflen, errnop);
748 if (status == NSS_STATUS_RETURN)
749 /* We couldn't parse the entry */
750 return NSS_STATUS_NOTFOUND;
751 else
752 return status;
756 /* +:... */
757 if (result->sp_namp[0] == '+' && result->sp_namp[1] == '\0')
759 enum nss_status status;
761 status = getspnam_plususer (name, result, ent,
762 buffer, buflen, errnop);
764 if (status == NSS_STATUS_SUCCESS)
765 /* We found the entry. */
766 break;
767 else if (status == NSS_STATUS_RETURN)
768 /* We couldn't parse the entry */
769 return NSS_STATUS_NOTFOUND;
770 else
771 return status;
774 return NSS_STATUS_SUCCESS;
777 enum nss_status
778 _nss_compat_getspnam_r (const char *name, struct spwd *pwd,
779 char *buffer, size_t buflen, int *errnop)
781 enum nss_status result;
782 ent_t ent = {0, TRUE, 0, NULL, {NULL, 0, 0},
783 {NULL, NULL, 0, 0, 0, 0, 0, 0, 0}};
785 if (name[0] == '-' || name[0] == '+')
786 return NSS_STATUS_NOTFOUND;
788 __libc_lock_lock (lock);
790 if (ni == NULL)
791 init_nss_interface ();
793 __libc_lock_unlock (lock);
795 result = internal_setspent (&ent, 0);
797 if (result == NSS_STATUS_SUCCESS)
798 result = internal_getspnam_r (name, pwd, &ent, buffer, buflen, errnop);
800 internal_endspent (&ent);
802 return result;
805 /* Support routines for remembering -@netgroup and -user entries.
806 The names are stored in a single string with `|' as separator. */
807 static void
808 blacklist_store_name (const char *name, ent_t *ent)
810 int namelen = strlen (name);
811 char *tmp;
813 /* first call, setup cache */
814 if (ent->blacklist.size == 0)
816 ent->blacklist.size = MAX (BLACKLIST_INITIAL_SIZE, 2 * namelen);
817 ent->blacklist.data = malloc (ent->blacklist.size);
818 if (ent->blacklist.data == NULL)
819 return;
820 ent->blacklist.data[0] = '|';
821 ent->blacklist.data[1] = '\0';
822 ent->blacklist.current = 1;
824 else
826 if (in_blacklist (name, namelen, ent))
827 return; /* no duplicates */
829 if (ent->blacklist.current + namelen + 1 >= ent->blacklist.size)
831 ent->blacklist.size += MAX (BLACKLIST_INCREMENT, 2 * namelen);
832 tmp = realloc (ent->blacklist.data, ent->blacklist.size);
833 if (tmp == NULL)
835 free (ent->blacklist.data);
836 ent->blacklist.size = 0;
837 return;
839 ent->blacklist.data = tmp;
843 tmp = stpcpy (ent->blacklist.data + ent->blacklist.current, name);
844 *tmp++ = '|';
845 *tmp = '\0';
846 ent->blacklist.current += namelen + 1;
848 return;
851 /* Returns TRUE if ent->blacklist contains name, else FALSE. */
852 static bool_t
853 in_blacklist (const char *name, int namelen, ent_t *ent)
855 char buf[namelen + 3];
856 char *cp;
858 if (ent->blacklist.data == NULL)
859 return FALSE;
861 buf[0] = '|';
862 cp = stpcpy (&buf[1], name);
863 *cp++ = '|';
864 *cp = '\0';
865 return strstr (ent->blacklist.data, buf) != NULL;