]> git.ipfire.org Git - thirdparty/glibc.git/blob - nis/nss_compat/compat-pwd.c
Update.
[thirdparty/glibc.git] / nis / nss_compat / compat-pwd.c
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.
4
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.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
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. */
19
20 #include <nss.h>
21 #include <pwd.h>
22 #include <errno.h>
23 #include <ctype.h>
24 #include <fcntl.h>
25 #include <netdb.h>
26 #include <string.h>
27 #include <bits/libc-lock.h>
28 #include <rpcsvc/yp.h>
29 #include <rpcsvc/ypclnt.h>
30 #include <rpcsvc/nis.h>
31 #include <nsswitch.h>
32
33 #include "netgroup.h"
34 #include "nss-nisplus.h"
35 #include "nisplus-parser.h"
36
37 static service_user *ni = NULL;
38 static bool_t use_nisplus = FALSE; /* default: passwd_compat: nis */
39 static nis_name pwdtable = NULL; /* Name of the pwd table */
40 static size_t pwdtablelen = 0;
41
42 /* Get the declaration of the parser function. */
43 #define ENTNAME pwent
44 #define STRUCTURE passwd
45 #define EXTERN_PARSER
46 #include <nss/nss_files/files-parse.c>
47
48 /* Structure for remembering -@netgroup and -user members ... */
49 #define BLACKLIST_INITIAL_SIZE 512
50 #define BLACKLIST_INCREMENT 256
51 struct blacklist_t
52 {
53 char *data;
54 int current;
55 int size;
56 };
57
58 struct ent_t
59 {
60 bool_t netgroup;
61 bool_t nis;
62 bool_t first;
63 char *oldkey;
64 int oldkeylen;
65 nis_result *result;
66 FILE *stream;
67 struct blacklist_t blacklist;
68 struct passwd pwd;
69 struct __netgrent netgrdata;
70 };
71 typedef struct ent_t ent_t;
72
73 static ent_t ext_ent = {0, 0, 0, NULL, 0, NULL, NULL, {NULL, 0, 0},
74 {NULL, NULL, 0, 0, NULL, NULL, NULL}};
75
76 /* Protect global state against multiple changers. */
77 __libc_lock_define_initialized (static, lock)
78
79 /* Prototypes for local functions. */
80 static void blacklist_store_name (const char *, ent_t *);
81 static int in_blacklist (const char *, int, ent_t *);
82
83 static void
84 give_pwd_free (struct passwd *pwd)
85 {
86 if (pwd->pw_name != NULL)
87 free (pwd->pw_name);
88 if (pwd->pw_passwd != NULL)
89 free (pwd->pw_passwd);
90 if (pwd->pw_gecos != NULL)
91 free (pwd->pw_gecos);
92 if (pwd->pw_dir != NULL)
93 free (pwd->pw_dir);
94 if (pwd->pw_shell != NULL)
95 free (pwd->pw_shell);
96
97 memset (pwd, '\0', sizeof (struct passwd));
98 }
99
100 static size_t
101 pwd_need_buflen (struct passwd *pwd)
102 {
103 size_t len = 0;
104
105 if (pwd->pw_passwd != NULL)
106 len += strlen (pwd->pw_passwd) + 1;
107
108 if (pwd->pw_gecos != NULL)
109 len += strlen (pwd->pw_gecos) + 1;
110
111 if (pwd->pw_dir != NULL)
112 len += strlen (pwd->pw_dir) + 1;
113
114 if (pwd->pw_shell != NULL)
115 len += strlen (pwd->pw_shell) + 1;
116
117 return len;
118 }
119
120 static void
121 copy_pwd_changes (struct passwd *dest, struct passwd *src,
122 char *buffer, size_t buflen)
123 {
124 if (src->pw_passwd != NULL && strlen (src->pw_passwd))
125 {
126 if (buffer == NULL)
127 dest->pw_passwd = strdup (src->pw_passwd);
128 else if (dest->pw_passwd &&
129 strlen (dest->pw_passwd) >= strlen (src->pw_passwd))
130 strcpy (dest->pw_passwd, src->pw_passwd);
131 else
132 {
133 dest->pw_passwd = buffer;
134 strcpy (dest->pw_passwd, src->pw_passwd);
135 buffer += strlen (dest->pw_passwd) + 1;
136 buflen = buflen - (strlen (dest->pw_passwd) + 1);
137 }
138 }
139
140 if (src->pw_gecos != NULL && strlen (src->pw_gecos))
141 {
142 if (buffer == NULL)
143 dest->pw_gecos = strdup (src->pw_gecos);
144 else if (dest->pw_gecos &&
145 strlen (dest->pw_gecos) >= strlen (src->pw_gecos))
146 strcpy (dest->pw_gecos, src->pw_gecos);
147 else
148 {
149 dest->pw_gecos = buffer;
150 strcpy (dest->pw_gecos, src->pw_gecos);
151 buffer += strlen (dest->pw_gecos) + 1;
152 buflen = buflen - (strlen (dest->pw_gecos) + 1);
153 }
154 }
155 if (src->pw_dir != NULL && strlen (src->pw_dir))
156 {
157 if (buffer == NULL)
158 dest->pw_dir = strdup (src->pw_dir);
159 else if (dest->pw_dir &&
160 strlen (dest->pw_dir) >= strlen (src->pw_dir))
161 strcpy (dest->pw_dir, src->pw_dir);
162 else
163 {
164 dest->pw_dir = buffer;
165 strcpy (dest->pw_dir, src->pw_dir);
166 buffer += strlen (dest->pw_dir) + 1;
167 buflen = buflen - (strlen (dest->pw_dir) + 1);
168 }
169 }
170
171 if (src->pw_shell != NULL && strlen (src->pw_shell))
172 {
173 if (buffer == NULL)
174 dest->pw_shell = strdup (src->pw_shell);
175 else if (dest->pw_shell &&
176 strlen (dest->pw_shell) >= strlen (src->pw_shell))
177 strcpy (dest->pw_shell, src->pw_shell);
178 else
179 {
180 dest->pw_shell = buffer;
181 strcpy (dest->pw_shell, src->pw_shell);
182 buffer += strlen (dest->pw_shell) + 1;
183 buflen = buflen - (strlen (dest->pw_shell) + 1);
184 }
185 }
186 }
187
188 static enum nss_status
189 internal_setpwent (ent_t *ent)
190 {
191 enum nss_status status = NSS_STATUS_SUCCESS;
192
193 ent->nis = ent->first = ent->netgroup = 0;
194
195 /* If something was left over free it. */
196 if (ent->netgroup)
197 __internal_endnetgrent (&ent->netgrdata);
198
199 if (ent->oldkey != NULL)
200 {
201 free (ent->oldkey);
202 ent->oldkey = NULL;
203 ent->oldkeylen = 0;
204 }
205
206 if (ent->result != NULL)
207 {
208 nis_freeresult (ent->result);
209 ent->result = NULL;
210 }
211
212 if (pwdtable == NULL)
213 {
214 static const char key[] = "passwd.org_dir.";
215 const char *local_dir = nis_local_directory ();
216 size_t len_local_dir = strlen (local_dir);
217
218 pwdtable = malloc (sizeof (key) + len_local_dir);
219 if (pwdtable == NULL)
220 return NSS_STATUS_TRYAGAIN;
221
222 pwdtablelen = ((char *) mempcpy (mempcpy (pwdtable,
223 key, sizeof (key) - 1),
224 local_dir, len_local_dir + 1)
225 - pwdtable) - 1;
226 }
227
228 if (ent->blacklist.data != NULL)
229 {
230 ent->blacklist.current = 1;
231 ent->blacklist.data[0] = '|';
232 ent->blacklist.data[1] = '\0';
233 }
234 else
235 ent->blacklist.current = 0;
236
237 if (ent->stream == NULL)
238 {
239 ent->stream = fopen ("/etc/passwd", "r");
240
241 if (ent->stream == NULL)
242 status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL;
243 else
244 {
245 /* We have to make sure the file is `closed on exec'. */
246 int result, flags;
247
248 result = flags = fcntl (fileno (ent->stream), F_GETFD, 0);
249 if (result >= 0)
250 {
251 flags |= FD_CLOEXEC;
252 result = fcntl (fileno (ent->stream), F_SETFD, flags);
253 }
254 if (result < 0)
255 {
256 /* Something went wrong. Close the stream and return a
257 failure. */
258 fclose (ent->stream);
259 ent->stream = NULL;
260 status = NSS_STATUS_UNAVAIL;
261 }
262 }
263 }
264 else
265 rewind (ent->stream);
266
267 give_pwd_free (&ent->pwd);
268
269 return status;
270 }
271
272
273 enum nss_status
274 _nss_compat_setpwent (void)
275 {
276 enum nss_status result;
277
278 __libc_lock_lock (lock);
279
280 if (ni == NULL)
281 {
282 __nss_database_lookup ("passwd_compat", NULL, "nis", &ni);
283 use_nisplus = (strcmp (ni->name, "nisplus") == 0);
284 }
285
286 result = internal_setpwent (&ext_ent);
287
288 __libc_lock_unlock (lock);
289
290 return result;
291 }
292
293
294 static enum nss_status
295 internal_endpwent (ent_t *ent)
296 {
297 if (ent->stream != NULL)
298 {
299 fclose (ent->stream);
300 ent->stream = NULL;
301 }
302
303 if (ent->netgroup)
304 __internal_endnetgrent (&ent->netgrdata);
305
306 ent->nis = ent->first = ent->netgroup = 0;
307
308 if (ent->oldkey != NULL)
309 {
310 free (ent->oldkey);
311 ent->oldkey = NULL;
312 ent->oldkeylen = 0;
313 }
314
315 if (ent->result != NULL)
316 {
317 nis_freeresult (ent->result);
318 ent->result = NULL;
319 }
320
321 if (ent->blacklist.data != NULL)
322 {
323 ent->blacklist.current = 1;
324 ent->blacklist.data[0] = '|';
325 ent->blacklist.data[1] = '\0';
326 }
327 else
328 ent->blacklist.current = 0;
329
330 give_pwd_free (&ent->pwd);
331
332 return NSS_STATUS_SUCCESS;
333 }
334
335 enum nss_status
336 _nss_compat_endpwent (void)
337 {
338 enum nss_status result;
339
340 __libc_lock_lock (lock);
341
342 result = internal_endpwent (&ext_ent);
343
344 __libc_lock_unlock (lock);
345
346 return result;
347 }
348
349 static enum nss_status
350 getpwent_next_nis_netgr (const char *name, struct passwd *result, ent_t *ent,
351 char *group, char *buffer, size_t buflen, int *errnop)
352 {
353 struct parser_data *data = (void *) buffer;
354 char *ypdomain, *host, *user, *domain, *outval, *p, *p2;
355 int status, outvallen;
356 size_t p2len;
357
358 if (yp_get_default_domain (&ypdomain) != YPERR_SUCCESS)
359 {
360 ent->netgroup = 0;
361 ent->first = 0;
362 give_pwd_free (&ent->pwd);
363 return NSS_STATUS_UNAVAIL;
364 }
365
366 if (ent->first == TRUE)
367 {
368 memset (&ent->netgrdata, 0, sizeof (struct __netgrent));
369 __internal_setnetgrent (group, &ent->netgrdata);
370 ent->first = FALSE;
371 }
372
373 while (1)
374 {
375 char *saved_cursor;
376 int parse_res;
377
378 saved_cursor = ent->netgrdata.cursor;
379 status = __internal_getnetgrent_r (&host, &user, &domain,
380 &ent->netgrdata, buffer, buflen,
381 errnop);
382 if (status != 1)
383 {
384 __internal_endnetgrent (&ent->netgrdata);
385 ent->netgroup = 0;
386 give_pwd_free (&ent->pwd);
387 return NSS_STATUS_RETURN;
388 }
389
390 if (user == NULL || user[0] == '-')
391 continue;
392
393 if (domain != NULL && strcmp (ypdomain, domain) != 0)
394 continue;
395
396 /* If name != NULL, we are called from getpwnam */
397 if (name != NULL)
398 if (strcmp (user, name) != 0)
399 continue;
400
401 if (yp_match (ypdomain, "passwd.byname", user,
402 strlen (user), &outval, &outvallen)
403 != YPERR_SUCCESS)
404 continue;
405
406 p2len = pwd_need_buflen (&ent->pwd);
407 if (p2len > buflen)
408 {
409 *errnop = ERANGE;
410 return NSS_STATUS_TRYAGAIN;
411 }
412 p2 = buffer + (buflen - p2len);
413 buflen -= p2len;
414 p = strncpy (buffer, outval, buflen);
415 while (isspace (*p))
416 p++;
417 free (outval);
418 parse_res = _nss_files_parse_pwent (p, result, data, buflen, errnop);
419 if (parse_res == -1)
420 {
421 ent->netgrdata.cursor = saved_cursor;
422 return NSS_STATUS_TRYAGAIN;
423 }
424
425 if (parse_res)
426 {
427 /* Store the User in the blacklist for the "+" at the end of
428 /etc/passwd */
429 blacklist_store_name (result->pw_name, ent);
430 copy_pwd_changes (result, &ent->pwd, p2, p2len);
431 break;
432 }
433 }
434
435 return NSS_STATUS_SUCCESS;
436 }
437
438 static enum nss_status
439 getpwent_next_nisplus_netgr (const char *name, struct passwd *result,
440 ent_t *ent, char *group, char *buffer,
441 size_t buflen, int *errnop)
442 {
443 char *ypdomain, *host, *user, *domain, *p2;
444 int status, parse_res;
445 size_t p2len;
446 nis_result *nisres;
447
448 /* Maybe we should use domainname here ? We need the current
449 domainname for the domain field in netgroups */
450 if (yp_get_default_domain (&ypdomain) != YPERR_SUCCESS)
451 {
452 ent->netgroup = 0;
453 ent->first = 0;
454 give_pwd_free (&ent->pwd);
455 return NSS_STATUS_UNAVAIL;
456 }
457
458 if (ent->first == TRUE)
459 {
460 bzero (&ent->netgrdata, sizeof (struct __netgrent));
461 __internal_setnetgrent (group, &ent->netgrdata);
462 ent->first = FALSE;
463 }
464
465 while (1)
466 {
467 char *saved_cursor;
468
469 saved_cursor = ent->netgrdata.cursor;
470 status = __internal_getnetgrent_r (&host, &user, &domain,
471 &ent->netgrdata, buffer, buflen,
472 errnop);
473 if (status != 1)
474 {
475 __internal_endnetgrent (&ent->netgrdata);
476 ent->netgroup = 0;
477 give_pwd_free (&ent->pwd);
478 return NSS_STATUS_RETURN;
479 }
480
481 if (user == NULL || user[0] == '-')
482 continue;
483
484 if (domain != NULL && strcmp (ypdomain, domain) != 0)
485 continue;
486
487 /* If name != NULL, we are called from getpwnam */
488 if (name != NULL)
489 if (strcmp (user, name) != 0)
490 continue;
491
492 p2len = pwd_need_buflen (&ent->pwd);
493 if (p2len > buflen)
494 {
495 *errnop = ERANGE;
496 return NSS_STATUS_TRYAGAIN;
497 }
498 p2 = buffer + (buflen - p2len);
499 buflen -= p2len;
500 {
501 char buf[strlen (user) + 30 + pwdtablelen];
502 sprintf(buf, "[name=%s],%s", user, pwdtable);
503 nisres = nis_list(buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
504 }
505 if (niserr2nss (nisres->status) != NSS_STATUS_SUCCESS)
506 {
507 nis_freeresult (nisres);
508 continue;
509 }
510 parse_res = _nss_nisplus_parse_pwent (nisres, result, buffer,
511 buflen, errnop);
512 if (parse_res == -1)
513 {
514 nis_freeresult (nisres);
515 ent->netgrdata.cursor = saved_cursor;
516 *errnop = ERANGE;
517 return NSS_STATUS_TRYAGAIN;
518 }
519 nis_freeresult (nisres);
520
521 if (parse_res)
522 {
523 /* Store the User in the blacklist for the "+" at the end of
524 /etc/passwd */
525 blacklist_store_name (result->pw_name, ent);
526 copy_pwd_changes (result, &ent->pwd, p2, p2len);
527 break;
528 }
529 }
530
531 return NSS_STATUS_SUCCESS;
532 }
533
534 /* get the next user from NIS+ (+ entry) */
535 static enum nss_status
536 getpwent_next_nisplus (struct passwd *result, ent_t *ent, char *buffer,
537 size_t buflen, int *errnop)
538 {
539 int parse_res;
540 size_t p2len;
541 char *p2;
542
543 p2len = pwd_need_buflen (&ent->pwd);
544 if (p2len > buflen)
545 {
546 *errnop = ERANGE;
547 return NSS_STATUS_TRYAGAIN;
548 }
549 p2 = buffer + (buflen - p2len);
550 buflen -= p2len;
551 do
552 {
553 bool_t saved_first;
554 nis_result *saved_res;
555
556 if (ent->first)
557 {
558 saved_first = TRUE;
559 saved_res = ent->result;
560
561 ent->result = nis_first_entry (pwdtable);
562 if (niserr2nss (ent->result->status) != NSS_STATUS_SUCCESS)
563 {
564 ent->nis = 0;
565 give_pwd_free (&ent->pwd);
566 return niserr2nss (ent->result->status);
567 }
568 ent->first = FALSE;
569 }
570 else
571 {
572 nis_result *res;
573
574 res = nis_next_entry (pwdtable, &ent->result->cookie);
575 saved_res = ent->result;
576 saved_first = FALSE;
577 ent->result = res;
578 if (niserr2nss (ent->result->status) != NSS_STATUS_SUCCESS)
579 {
580 ent->nis = 0;
581 nis_freeresult (saved_res);
582 give_pwd_free (&ent->pwd);
583 return niserr2nss (ent->result->status);
584 }
585 }
586 parse_res = _nss_nisplus_parse_pwent (ent->result, result, buffer,
587 buflen, errnop);
588 if (parse_res == -1)
589 {
590 nis_freeresult (ent->result);
591 ent->result = saved_res;
592 ent->first = saved_first;
593 *errnop = ERANGE;
594 return NSS_STATUS_TRYAGAIN;
595 }
596 else
597 {
598 if (!saved_first)
599 nis_freeresult (saved_res);
600 }
601
602 if (parse_res &&
603 in_blacklist (result->pw_name, strlen (result->pw_name), ent))
604 parse_res = 0; /* if result->pw_name in blacklist,search next entry */
605 }
606 while (!parse_res);
607
608 copy_pwd_changes (result, &ent->pwd, p2, p2len);
609
610 return NSS_STATUS_SUCCESS;
611 }
612
613 static enum nss_status
614 getpwent_next_nis (struct passwd *result, ent_t *ent, char *buffer,
615 size_t buflen, int *errnop)
616 {
617 struct parser_data *data = (void *) buffer;
618 char *domain, *outkey, *outval, *p, *p2;
619 int outkeylen, outvallen, parse_res;
620 size_t p2len;
621
622 if (yp_get_default_domain (&domain) != YPERR_SUCCESS)
623 {
624 ent->nis = 0;
625 give_pwd_free (&ent->pwd);
626 return NSS_STATUS_UNAVAIL;
627 }
628
629 p2len = pwd_need_buflen (&ent->pwd);
630 if (p2len > buflen)
631 {
632 *errnop = ERANGE;
633 return NSS_STATUS_TRYAGAIN;
634 }
635 p2 = buffer + (buflen - p2len);
636 buflen -= p2len;
637 do
638 {
639 bool_t saved_first;
640 char *saved_oldkey;
641 int saved_oldlen;
642
643 if (ent->first)
644 {
645 if (yp_first (domain, "passwd.byname", &outkey, &outkeylen,
646 &outval, &outvallen) != YPERR_SUCCESS)
647 {
648 ent->nis = 0;
649 give_pwd_free (&ent->pwd);
650 return NSS_STATUS_UNAVAIL;
651 }
652
653 saved_first = TRUE;
654 saved_oldkey = ent->oldkey;
655 saved_oldlen = ent->oldkeylen;
656 ent->oldkey = outkey;
657 ent->oldkeylen = outkeylen;
658 ent->first = FALSE;
659 }
660 else
661 {
662 if (yp_next (domain, "passwd.byname", ent->oldkey, ent->oldkeylen,
663 &outkey, &outkeylen, &outval, &outvallen)
664 != YPERR_SUCCESS)
665 {
666 ent->nis = 0;
667 give_pwd_free (&ent->pwd);
668 return NSS_STATUS_NOTFOUND;
669 }
670
671 saved_first = FALSE;
672 saved_oldkey = ent->oldkey;
673 saved_oldlen = ent->oldkeylen;
674 ent->oldkey = outkey;
675 ent->oldkeylen = outkeylen;
676 }
677
678 /* Copy the found data to our buffer */
679 p = strncpy (buffer, outval, buflen);
680
681 /* ...and free the data. */
682 free (outval);
683
684 while (isspace (*p))
685 ++p;
686 parse_res = _nss_files_parse_pwent (p, result, data, buflen, errnop);
687 if (parse_res == -1)
688 {
689 free (ent->oldkey);
690 ent->oldkey = saved_oldkey;
691 ent->oldkeylen = saved_oldlen;
692 ent->first = saved_first;
693 *errnop = ERANGE;
694 return NSS_STATUS_TRYAGAIN;
695 }
696 else
697 {
698 if (!saved_first)
699 free (saved_oldkey);
700 }
701 if (parse_res
702 && in_blacklist (result->pw_name, strlen (result->pw_name), ent))
703 parse_res = 0;
704 }
705 while (!parse_res);
706
707 copy_pwd_changes (result, &ent->pwd, p2, p2len);
708
709 return NSS_STATUS_SUCCESS;
710 }
711
712 /* This function handle the +user entrys in /etc/passwd */
713 static enum nss_status
714 getpwnam_plususer (const char *name, struct passwd *result, char *buffer,
715 size_t buflen, int *errnop)
716 {
717 struct parser_data *data = (void *) buffer;
718 struct passwd pwd;
719 int parse_res;
720 char *p;
721 size_t plen;
722
723 memset (&pwd, '\0', sizeof (struct passwd));
724
725 copy_pwd_changes (&pwd, result, NULL, 0);
726
727 plen = pwd_need_buflen (&pwd);
728 if (plen > buflen)
729 {
730 *errnop = ERANGE;
731 return NSS_STATUS_TRYAGAIN;
732 }
733 p = buffer + (buflen - plen);
734 buflen -= plen;
735
736 if (use_nisplus) /* Do the NIS+ query here */
737 {
738 nis_result *res;
739 char buf[strlen (name) + 24 + pwdtablelen];
740
741 sprintf(buf, "[name=%s],%s", name, pwdtable);
742 res = nis_list(buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
743 if (niserr2nss (res->status) != NSS_STATUS_SUCCESS)
744 {
745 enum nss_status status = niserr2nss (res->status);
746
747 nis_freeresult (res);
748 return status;
749 }
750 parse_res = _nss_nisplus_parse_pwent (res, result, buffer,
751 buflen, errnop);
752 if (parse_res == -1)
753 {
754 nis_freeresult (res);
755 *errnop = ERANGE;
756 return NSS_STATUS_TRYAGAIN;
757 }
758 nis_freeresult (res);
759 }
760 else /* Use NIS */
761 {
762 char *domain, *outval, *ptr;
763 int outvallen;
764
765 if (yp_get_default_domain (&domain) != YPERR_SUCCESS)
766 return NSS_STATUS_NOTFOUND;
767
768 if (yp_match (domain, "passwd.byname", name, strlen (name),
769 &outval, &outvallen) != YPERR_SUCCESS)
770 return NSS_STATUS_NOTFOUND;
771
772 ptr = strncpy (buffer, outval, buflen < (size_t) outvallen ?
773 buflen : (size_t) outvallen);
774 buffer[buflen < (size_t) outvallen ? buflen : (size_t) outvallen] = '\0';
775 free (outval);
776 while (isspace (*ptr))
777 ptr++;
778 parse_res = _nss_files_parse_pwent (ptr, result, data, buflen, errnop);
779 if (parse_res == -1)
780 return NSS_STATUS_TRYAGAIN;
781 }
782
783 if (parse_res > 0)
784 {
785 copy_pwd_changes (result, &pwd, p, plen);
786 give_pwd_free (&pwd);
787 /* We found the entry. */
788 return NSS_STATUS_SUCCESS;
789 }
790 else
791 {
792 /* Give buffer the old len back */
793 buflen += plen;
794 give_pwd_free (&pwd);
795 }
796 return NSS_STATUS_RETURN;
797 }
798
799 static enum nss_status
800 getpwent_next_file (struct passwd *result, ent_t *ent,
801 char *buffer, size_t buflen, int *errnop)
802 {
803 struct parser_data *data = (void *) buffer;
804 while (1)
805 {
806 fpos_t pos;
807 char *p;
808 int parse_res;
809
810 do
811 {
812 fgetpos (ent->stream, &pos);
813 p = fgets (buffer, buflen, ent->stream);
814 if (p == NULL)
815 {
816 if (feof (ent->stream))
817 return NSS_STATUS_NOTFOUND;
818 else
819 {
820 fsetpos (ent->stream, &pos);
821 *errnop = ERANGE;
822 return NSS_STATUS_TRYAGAIN;
823 }
824 }
825
826 /* Terminate the line for any case. */
827 buffer[buflen - 1] = '\0';
828
829 /* Skip leading blanks. */
830 while (isspace (*p))
831 ++p;
832 }
833 while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */
834 /* Parse the line. If it is invalid, loop to
835 get the next line of the file to parse. */
836 !(parse_res = _nss_files_parse_pwent (p, result, data, buflen,
837 errnop)));
838
839 if (parse_res == -1)
840 {
841 /* The parser ran out of space. */
842 fsetpos (ent->stream, &pos);
843 *errnop = ERANGE;
844 return NSS_STATUS_TRYAGAIN;
845 }
846
847 if (result->pw_name[0] != '+' && result->pw_name[0] != '-')
848 /* This is a real entry. */
849 break;
850
851 /* -@netgroup */
852 if (result->pw_name[0] == '-' && result->pw_name[1] == '@'
853 && result->pw_name[2] != '\0')
854 {
855 /* XXX Do not use fixed length buffer. */
856 char buf2[1024];
857 char *user, *host, *domain;
858 struct __netgrent netgrdata;
859
860 bzero (&netgrdata, sizeof (struct __netgrent));
861 __internal_setnetgrent (&result->pw_name[2], &netgrdata);
862 while (__internal_getnetgrent_r (&host, &user, &domain, &netgrdata,
863 buf2, sizeof (buf2), errnop))
864 {
865 if (user != NULL && user[0] != '-')
866 blacklist_store_name (user, ent);
867 }
868 __internal_endnetgrent (&netgrdata);
869 continue;
870 }
871
872 /* +@netgroup */
873 if (result->pw_name[0] == '+' && result->pw_name[1] == '@'
874 && result->pw_name[2] != '\0')
875 {
876 int status;
877
878 ent->netgroup = TRUE;
879 ent->first = TRUE;
880 copy_pwd_changes (&ent->pwd, result, NULL, 0);
881
882 if (use_nisplus)
883 status = getpwent_next_nisplus_netgr (NULL, result, ent,
884 &result->pw_name[2],
885 buffer, buflen, errnop);
886 else
887 status = getpwent_next_nis_netgr (NULL, result, ent,
888 &result->pw_name[2],
889 buffer, buflen, errnop);
890 if (status == NSS_STATUS_RETURN)
891 continue;
892 else
893 return status;
894 }
895
896 /* -user */
897 if (result->pw_name[0] == '-' && result->pw_name[1] != '\0'
898 && result->pw_name[1] != '@')
899 {
900 blacklist_store_name (&result->pw_name[1], ent);
901 continue;
902 }
903
904 /* +user */
905 if (result->pw_name[0] == '+' && result->pw_name[1] != '\0'
906 && result->pw_name[1] != '@')
907 {
908 enum nss_status status;
909
910 /* Store the User in the blacklist for the "+" at the end of
911 /etc/passwd */
912 blacklist_store_name (&result->pw_name[1], ent);
913 status = getpwnam_plususer (&result->pw_name[1], result, buffer,
914 buflen, errnop);
915 if (status == NSS_STATUS_SUCCESS) /* We found the entry. */
916 break;
917 else
918 if (status == NSS_STATUS_RETURN /* We couldn't parse the entry */
919 || status == NSS_STATUS_NOTFOUND) /* entry doesn't exist */
920 continue;
921 else
922 {
923 if (status == NSS_STATUS_TRYAGAIN)
924 {
925 /* The parser ran out of space */
926 fsetpos (ent->stream, &pos);
927 *errnop = ERANGE;
928 }
929 return status;
930 }
931 }
932
933 /* +:... */
934 if (result->pw_name[0] == '+' && result->pw_name[1] == '\0')
935 {
936 ent->nis = TRUE;
937 ent->first = TRUE;
938 copy_pwd_changes (&ent->pwd, result, NULL, 0);
939
940 if (use_nisplus)
941 return getpwent_next_nisplus (result, ent, buffer, buflen, errnop);
942 else
943 return getpwent_next_nis (result, ent, buffer, buflen, errnop);
944 }
945 }
946
947 return NSS_STATUS_SUCCESS;
948 }
949
950
951 static enum nss_status
952 internal_getpwent_r (struct passwd *pw, ent_t *ent, char *buffer,
953 size_t buflen, int *errnop)
954 {
955 if (ent->netgroup)
956 {
957 int status;
958
959 /* We are searching members in a netgroup */
960 /* Since this is not the first call, we don't need the group name */
961 if (use_nisplus)
962 status = getpwent_next_nisplus_netgr (NULL, pw, ent, NULL, buffer,
963 buflen, errnop);
964 else
965 status = getpwent_next_nis_netgr (NULL, pw, ent, NULL, buffer, buflen,
966 errnop);
967 if (status == NSS_STATUS_RETURN)
968 return getpwent_next_file (pw, ent, buffer, buflen, errnop);
969 else
970 return status;
971 }
972 else
973 if (ent->nis)
974 {
975 if (use_nisplus)
976 return getpwent_next_nisplus (pw, ent, buffer, buflen, errnop);
977 else
978 return getpwent_next_nis (pw, ent, buffer, buflen, errnop);
979 }
980 else
981 return getpwent_next_file (pw, ent, buffer, buflen, errnop);
982 }
983
984 enum nss_status
985 _nss_compat_getpwent_r (struct passwd *pwd, char *buffer, size_t buflen,
986 int *errnop)
987 {
988 enum nss_status status = NSS_STATUS_SUCCESS;
989
990 __libc_lock_lock (lock);
991
992 if (ni == NULL)
993 {
994 __nss_database_lookup ("passwd_compat", NULL, "nis", &ni);
995 use_nisplus = (strcmp (ni->name, "nisplus") == 0);
996 }
997
998 /* Be prepared that the setpwent function was not called before. */
999 if (ext_ent.stream == NULL)
1000 status = internal_setpwent (&ext_ent);
1001
1002 if (status == NSS_STATUS_SUCCESS)
1003 status = internal_getpwent_r (pwd, &ext_ent, buffer, buflen, errnop);
1004
1005 __libc_lock_unlock (lock);
1006
1007 return status;
1008 }
1009
1010 /* Searches in /etc/passwd and the NIS/NIS+ map for a special user */
1011 static enum nss_status
1012 internal_getpwnam_r (const char *name, struct passwd *result, ent_t *ent,
1013 char *buffer, size_t buflen, int *errnop)
1014 {
1015 struct parser_data *data = (void *) buffer;
1016
1017 while (1)
1018 {
1019 fpos_t pos;
1020 char *p;
1021 int parse_res;
1022
1023 do
1024 {
1025 fgetpos (ent->stream, &pos);
1026 p = fgets (buffer, buflen, ent->stream);
1027 if (p == NULL)
1028 {
1029 if (feof (ent->stream))
1030 return NSS_STATUS_NOTFOUND;
1031 else
1032 {
1033 fsetpos (ent->stream, &pos);
1034 *errnop = ERANGE;
1035 return NSS_STATUS_TRYAGAIN;
1036 }
1037 }
1038
1039 /* Terminate the line for any case. */
1040 buffer[buflen - 1] = '\0';
1041
1042 /* Skip leading blanks. */
1043 while (isspace (*p))
1044 ++p;
1045 }
1046 while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */
1047 /* Parse the line. If it is invalid, loop to
1048 get the next line of the file to parse. */
1049 !(parse_res = _nss_files_parse_pwent (p, result, data, buflen,
1050 errnop)));
1051
1052 if (parse_res == -1)
1053 {
1054 /* The parser ran out of space. */
1055 fsetpos (ent->stream, &pos);
1056 *errnop = ERANGE;
1057 return NSS_STATUS_TRYAGAIN;
1058 }
1059
1060 /* This is a real entry. */
1061 if (result->pw_name[0] != '+' && result->pw_name[0] != '-')
1062 {
1063 if (strcmp (result->pw_name, name) == 0)
1064 return NSS_STATUS_SUCCESS;
1065 else
1066 continue;
1067 }
1068
1069 /* -@netgroup */
1070 if (result->pw_name[0] == '-' && result->pw_name[1] == '@'
1071 && result->pw_name[2] != '\0')
1072 {
1073 /* XXX Do not use fixed length buffers. */
1074 char buf2[1024];
1075 char *user, *host, *domain;
1076 struct __netgrent netgrdata;
1077
1078 bzero (&netgrdata, sizeof (struct __netgrent));
1079 __internal_setnetgrent (&result->pw_name[2], &netgrdata);
1080 while (__internal_getnetgrent_r (&host, &user, &domain, &netgrdata,
1081 buf2, sizeof (buf2), errnop))
1082 {
1083 if (user != NULL && user[0] != '-')
1084 if (strcmp (user, name) == 0)
1085 return NSS_STATUS_NOTFOUND;
1086 }
1087 __internal_endnetgrent (&netgrdata);
1088 continue;
1089 }
1090
1091 /* +@netgroup */
1092 if (result->pw_name[0] == '+' && result->pw_name[1] == '@'
1093 && result->pw_name[2] != '\0')
1094 {
1095 char buf[strlen (result->pw_name)];
1096 int status;
1097
1098 strcpy (buf, &result->pw_name[2]);
1099 ent->netgroup = TRUE;
1100 ent->first = TRUE;
1101 copy_pwd_changes (&ent->pwd, result, NULL, 0);
1102
1103 do
1104 {
1105 if (use_nisplus)
1106 status = getpwent_next_nisplus_netgr (name, result, ent, buf,
1107 buffer, buflen, errnop);
1108 else
1109 status = getpwent_next_nis_netgr (name, result, ent, buf,
1110 buffer, buflen, errnop);
1111 if (status == NSS_STATUS_RETURN)
1112 continue;
1113
1114 if (status == NSS_STATUS_SUCCESS &&
1115 strcmp (result->pw_name, name) == 0)
1116 return NSS_STATUS_SUCCESS;
1117 } while (status == NSS_STATUS_SUCCESS);
1118 continue;
1119 }
1120
1121 /* -user */
1122 if (result->pw_name[0] == '-' && result->pw_name[1] != '\0'
1123 && result->pw_name[1] != '@')
1124 {
1125 if (strcmp (&result->pw_name[1], name) == 0)
1126 return NSS_STATUS_NOTFOUND;
1127 else
1128 continue;
1129 }
1130
1131 /* +user */
1132 if (result->pw_name[0] == '+' && result->pw_name[1] != '\0'
1133 && result->pw_name[1] != '@')
1134 {
1135 if (strcmp (name, &result->pw_name[1]) == 0)
1136 {
1137 enum nss_status status;
1138
1139 status = getpwnam_plususer (name, result, buffer, buflen,
1140 errnop);
1141 if (status == NSS_STATUS_RETURN)
1142 /* We couldn't parse the entry */
1143 return NSS_STATUS_NOTFOUND;
1144 else
1145 return status;
1146 }
1147 }
1148
1149 /* +:... */
1150 if (result->pw_name[0] == '+' && result->pw_name[1] == '\0')
1151 {
1152 enum nss_status status;
1153
1154 status = getpwnam_plususer (name, result, buffer, buflen, errnop);
1155 if (status == NSS_STATUS_SUCCESS) /* We found the entry. */
1156 break;
1157 else
1158 if (status == NSS_STATUS_RETURN) /* We couldn't parse the entry */
1159 return NSS_STATUS_NOTFOUND;
1160 else
1161 return status;
1162 }
1163 }
1164 return NSS_STATUS_SUCCESS;
1165 }
1166
1167 enum nss_status
1168 _nss_compat_getpwnam_r (const char *name, struct passwd *pwd,
1169 char *buffer, size_t buflen, int *errnop)
1170 {
1171 ent_t ent = {0, 0, 0, NULL, 0, NULL, NULL, {NULL, 0, 0},
1172 {NULL, NULL, 0, 0, NULL, NULL, NULL}};
1173 enum nss_status status;
1174
1175 if (name[0] == '-' || name[0] == '+')
1176 return NSS_STATUS_NOTFOUND;
1177
1178 __libc_lock_lock (lock);
1179
1180 if (ni == NULL)
1181 {
1182 __nss_database_lookup ("passwd_compat", NULL, "nis", &ni);
1183 use_nisplus = (strcmp (ni->name, "nisplus") == 0);
1184 }
1185
1186 __libc_lock_unlock (lock);
1187
1188 status = internal_setpwent (&ent);
1189 if (status != NSS_STATUS_SUCCESS)
1190 return status;
1191
1192 status = internal_getpwnam_r (name, pwd, &ent, buffer, buflen, errnop);
1193
1194 internal_endpwent (&ent);
1195
1196 return status;
1197 }
1198
1199 /* This function handle the + entry in /etc/passwd for getpwuid */
1200 static enum nss_status
1201 getpwuid_plususer (uid_t uid, struct passwd *result, char *buffer,
1202 size_t buflen, int *errnop)
1203 {
1204 struct parser_data *data = (void *) buffer;
1205 struct passwd pwd;
1206 int parse_res;
1207 char *p;
1208 size_t plen;
1209
1210 memset (&pwd, '\0', sizeof (struct passwd));
1211
1212 copy_pwd_changes (&pwd, result, NULL, 0);
1213
1214 plen = pwd_need_buflen (&pwd);
1215 if (plen > buflen)
1216 {
1217 *errnop = ERANGE;
1218 return NSS_STATUS_TRYAGAIN;
1219 }
1220 p = buffer + (buflen - plen);
1221 buflen -= plen;
1222
1223 if (use_nisplus) /* Do the NIS+ query here */
1224 {
1225 nis_result *res;
1226 char buf[1024 + pwdtablelen];
1227
1228 snprintf(buf, sizeof (buf), "[uid=%d],%s", uid, pwdtable);
1229 res = nis_list(buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
1230 if (niserr2nss (res->status) != NSS_STATUS_SUCCESS)
1231 {
1232 enum nss_status status = niserr2nss (res->status);
1233
1234 nis_freeresult (res);
1235 return status;
1236 }
1237 if ((parse_res = _nss_nisplus_parse_pwent (res, result, buffer,
1238 buflen, errnop)) == -1)
1239 {
1240 nis_freeresult (res);
1241 *errnop = ERANGE;
1242 return NSS_STATUS_TRYAGAIN;
1243 }
1244 nis_freeresult (res);
1245 }
1246 else /* Use NIS */
1247 {
1248 char buf[1024];
1249 char *domain, *outval, *ptr;
1250 int outvallen;
1251
1252 if (yp_get_default_domain (&domain) != YPERR_SUCCESS)
1253 {
1254 *errnop = errno;
1255 return NSS_STATUS_TRYAGAIN;
1256 }
1257
1258 sprintf (buf, "%d", uid);
1259 if (yp_match (domain, "passwd.byuid", buf, strlen (buf),
1260 &outval, &outvallen)
1261 != YPERR_SUCCESS)
1262 {
1263 *errnop = errno;
1264 return NSS_STATUS_TRYAGAIN;
1265 }
1266 ptr = strncpy (buffer, outval, buflen < (size_t) outvallen ?
1267 buflen : (size_t) outvallen);
1268 buffer[buflen < (size_t) outvallen ? buflen : (size_t) outvallen] = '\0';
1269 free (outval);
1270 while (isspace (*ptr))
1271 ptr++;
1272 parse_res = _nss_files_parse_pwent (ptr, result, data, buflen, errnop);
1273 if (parse_res == -1)
1274 return NSS_STATUS_TRYAGAIN;
1275 }
1276
1277 if (parse_res > 0)
1278 {
1279 copy_pwd_changes (result, &pwd, p, plen);
1280 give_pwd_free (&pwd);
1281 /* We found the entry. */
1282 return NSS_STATUS_SUCCESS;
1283 }
1284 else
1285 {
1286 /* Give buffer the old len back */
1287 buflen += plen;
1288 give_pwd_free (&pwd);
1289 }
1290 return NSS_STATUS_RETURN;
1291 }
1292
1293 /* Searches in /etc/passwd and the NIS/NIS+ map for a special user id */
1294 static enum nss_status
1295 internal_getpwuid_r (uid_t uid, struct passwd *result, ent_t *ent,
1296 char *buffer, size_t buflen, int *errnop)
1297 {
1298 struct parser_data *data = (void *) buffer;
1299
1300 while (1)
1301 {
1302 fpos_t pos;
1303 char *p;
1304 int parse_res;
1305
1306 do
1307 {
1308 fgetpos (ent->stream, &pos);
1309 p = fgets (buffer, buflen, ent->stream);
1310 if (p == NULL)
1311 {
1312 if (feof (ent->stream))
1313 return NSS_STATUS_NOTFOUND;
1314 else
1315 {
1316 fsetpos (ent->stream, &pos);
1317 *errnop = ERANGE;
1318 return NSS_STATUS_TRYAGAIN;
1319 }
1320 }
1321
1322 /* Terminate the line for any case. */
1323 buffer[buflen - 1] = '\0';
1324
1325 /* Skip leading blanks. */
1326 while (isspace (*p))
1327 ++p;
1328 }
1329 while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */
1330 /* Parse the line. If it is invalid, loop to
1331 get the next line of the file to parse. */
1332 !(parse_res = _nss_files_parse_pwent (p, result, data, buflen,
1333 errnop)));
1334
1335 if (parse_res == -1)
1336 {
1337 /* The parser ran out of space. */
1338 fsetpos (ent->stream, &pos);
1339 *errnop = ERANGE;
1340 return NSS_STATUS_TRYAGAIN;
1341 }
1342
1343 /* This is a real entry. */
1344 if (result->pw_name[0] != '+' && result->pw_name[0] != '-')
1345 {
1346 if (result->pw_uid == uid)
1347 return NSS_STATUS_SUCCESS;
1348 else
1349 continue;
1350 }
1351
1352 /* -@netgroup */
1353 if (result->pw_name[0] == '-' && result->pw_name[1] == '@'
1354 && result->pw_name[2] != '\0')
1355 {
1356 /* XXX Do not use fixed length buffers. */
1357 char buf2[1024];
1358 char *user, *host, *domain;
1359 struct __netgrent netgrdata;
1360
1361 bzero (&netgrdata, sizeof (struct __netgrent));
1362 __internal_setnetgrent (&result->pw_name[2], &netgrdata);
1363 while (__internal_getnetgrent_r (&host, &user, &domain, &netgrdata,
1364 buf2, sizeof (buf2), errnop))
1365 {
1366 if (user != NULL && user[0] != '-')
1367 blacklist_store_name (user, ent);
1368 }
1369 __internal_endnetgrent (&netgrdata);
1370 continue;
1371 }
1372
1373 /* +@netgroup */
1374 if (result->pw_name[0] == '+' && result->pw_name[1] == '@'
1375 && result->pw_name[2] != '\0')
1376 {
1377 char buf[strlen (result->pw_name)];
1378 int status;
1379
1380 strcpy (buf, &result->pw_name[2]);
1381 ent->netgroup = TRUE;
1382 ent->first = TRUE;
1383 copy_pwd_changes (&ent->pwd, result, NULL, 0);
1384
1385 do
1386 {
1387 if (use_nisplus)
1388 status = getpwent_next_nisplus_netgr (NULL, result, ent, buf,
1389 buffer, buflen, errnop);
1390 else
1391 status = getpwent_next_nis_netgr (NULL, result, ent, buf,
1392 buffer, buflen, errnop);
1393 if (status == NSS_STATUS_RETURN)
1394 continue;
1395
1396 if (status == NSS_STATUS_SUCCESS && uid == result->pw_uid)
1397 return NSS_STATUS_SUCCESS;
1398 } while (status == NSS_STATUS_SUCCESS);
1399 continue;
1400 }
1401
1402 /* -user */
1403 if (result->pw_name[0] == '-' && result->pw_name[1] != '\0'
1404 && result->pw_name[1] != '@')
1405 {
1406 blacklist_store_name (&result->pw_name[1], ent);
1407 continue;
1408 }
1409
1410 /* +user */
1411 if (result->pw_name[0] == '+' && result->pw_name[1] != '\0'
1412 && result->pw_name[1] != '@')
1413 {
1414 enum nss_status status;
1415
1416 /* Store the User in the blacklist for the "+" at the end of
1417 /etc/passwd */
1418 blacklist_store_name (&result->pw_name[1], ent);
1419 status = getpwnam_plususer (&result->pw_name[1], result, buffer,
1420 buflen, errnop);
1421 if (status == NSS_STATUS_SUCCESS && result->pw_uid == uid)
1422 break;
1423 else
1424 continue;
1425 }
1426
1427 /* +:... */
1428 if (result->pw_name[0] == '+' && result->pw_name[1] == '\0')
1429 {
1430 enum nss_status status;
1431
1432 status = getpwuid_plususer (uid, result, buffer, buflen, errnop);
1433 if (status == NSS_STATUS_SUCCESS) /* We found the entry. */
1434 break;
1435 else
1436 if (status == NSS_STATUS_RETURN) /* We couldn't parse the entry */
1437 return NSS_STATUS_NOTFOUND;
1438 else
1439 return status;
1440 }
1441 }
1442 return NSS_STATUS_SUCCESS;
1443 }
1444
1445 enum nss_status
1446 _nss_compat_getpwuid_r (uid_t uid, struct passwd *pwd,
1447 char *buffer, size_t buflen, int *errnop)
1448 {
1449 ent_t ent = {0, 0, 0, NULL, 0, NULL, NULL, {NULL, 0, 0},
1450 {NULL, NULL, 0, 0, NULL, NULL, NULL}};
1451 enum nss_status status;
1452
1453 __libc_lock_lock (lock);
1454
1455 if (ni == NULL)
1456 {
1457 __nss_database_lookup ("passwd_compat", NULL, "nis", &ni);
1458 use_nisplus = (strcmp (ni->name, "nisplus") == 0);
1459 }
1460
1461 __libc_lock_unlock (lock);
1462
1463 status = internal_setpwent (&ent);
1464 if (status != NSS_STATUS_SUCCESS)
1465 return status;
1466
1467 status = internal_getpwuid_r (uid, pwd, &ent, buffer, buflen, errnop);
1468
1469 internal_endpwent (&ent);
1470
1471 return status;
1472 }
1473
1474
1475 /* Support routines for remembering -@netgroup and -user entries.
1476 The names are stored in a single string with `|' as separator. */
1477 static void
1478 blacklist_store_name (const char *name, ent_t *ent)
1479 {
1480 int namelen = strlen (name);
1481 char *tmp;
1482
1483 /* first call, setup cache */
1484 if (ent->blacklist.size == 0)
1485 {
1486 ent->blacklist.size = MAX (BLACKLIST_INITIAL_SIZE, 2 * namelen);
1487 ent->blacklist.data = malloc (ent->blacklist.size);
1488 if (ent->blacklist.data == NULL)
1489 return;
1490 ent->blacklist.data[0] = '|';
1491 ent->blacklist.data[1] = '\0';
1492 ent->blacklist.current = 1;
1493 }
1494 else
1495 {
1496 if (in_blacklist (name, namelen, ent))
1497 return; /* no duplicates */
1498
1499 if (ent->blacklist.current + namelen + 1 >= ent->blacklist.size)
1500 {
1501 ent->blacklist.size += MAX (BLACKLIST_INCREMENT, 2 * namelen);
1502 tmp = realloc (ent->blacklist.data, ent->blacklist.size);
1503 if (tmp == NULL)
1504 {
1505 free (ent->blacklist.data);
1506 ent->blacklist.size = 0;
1507 return;
1508 }
1509 ent->blacklist.data = tmp;
1510 }
1511 }
1512
1513 tmp = stpcpy (ent->blacklist.data + ent->blacklist.current, name);
1514 *tmp++ = '|';
1515 *tmp = '\0';
1516 ent->blacklist.current += namelen + 1;
1517
1518 return;
1519 }
1520
1521 /* returns TRUE if ent->blacklist contains name, else FALSE */
1522 static bool_t
1523 in_blacklist (const char *name, int namelen, ent_t *ent)
1524 {
1525 char buf[namelen + 3];
1526 char *cp;
1527
1528 if (ent->blacklist.data == NULL)
1529 return FALSE;
1530
1531 buf[0] = '|';
1532 cp = stpcpy (&buf[1], name);
1533 *cp++= '|';
1534 *cp = '\0';
1535 return strstr (ent->blacklist.data, buf) != NULL;
1536 }