]> sourceware.org Git - glibc.git/blob - nis/nss_compat/compat-pwd.c
Update.
[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 char buf [20 + strlen (nis_local_directory ())];
215 char *p;
216
217 p = stpcpy (buf, "passwd.org_dir.");
218 p = stpcpy (p, nis_local_directory ());
219 pwdtable = strdup (buf);
220 if (pwdtable == NULL)
221 return NSS_STATUS_TRYAGAIN;
222 pwdtablelen = strlen (pwdtable);
223 }
224
225 ent->blacklist.current = 0;
226 if (ent->blacklist.data != NULL)
227 ent->blacklist.data[0] = '\0';
228
229 if (ent->stream == NULL)
230 {
231 ent->stream = fopen ("/etc/passwd", "r");
232
233 if (ent->stream == NULL)
234 status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL;
235 else
236 {
237 /* We have to make sure the file is `closed on exec'. */
238 int result, flags;
239
240 result = flags = fcntl (fileno (ent->stream), F_GETFD, 0);
241 if (result >= 0)
242 {
243 flags |= FD_CLOEXEC;
244 result = fcntl (fileno (ent->stream), F_SETFD, flags);
245 }
246 if (result < 0)
247 {
248 /* Something went wrong. Close the stream and return a
249 failure. */
250 fclose (ent->stream);
251 ent->stream = NULL;
252 status = NSS_STATUS_UNAVAIL;
253 }
254 }
255 }
256 else
257 rewind (ent->stream);
258
259 give_pwd_free (&ent->pwd);
260
261 return status;
262 }
263
264
265 enum nss_status
266 _nss_compat_setpwent (void)
267 {
268 enum nss_status result;
269
270 __libc_lock_lock (lock);
271
272 if (ni == NULL)
273 {
274 __nss_database_lookup ("passwd_compat", NULL, "nis", &ni);
275 use_nisplus = (strcmp (ni->name, "nisplus") == 0);
276 }
277
278 result = internal_setpwent (&ext_ent);
279
280 __libc_lock_unlock (lock);
281
282 return result;
283 }
284
285
286 static enum nss_status
287 internal_endpwent (ent_t *ent)
288 {
289 if (ent->stream != NULL)
290 {
291 fclose (ent->stream);
292 ent->stream = NULL;
293 }
294
295 if (ent->netgroup)
296 __internal_endnetgrent (&ent->netgrdata);
297
298 ent->nis = ent->first = ent->netgroup = 0;
299
300 if (ent->oldkey != NULL)
301 {
302 free (ent->oldkey);
303 ent->oldkey = NULL;
304 ent->oldkeylen = 0;
305 }
306
307 if (ent->result != NULL)
308 {
309 nis_freeresult (ent->result);
310 ent->result = NULL;
311 }
312
313 ent->blacklist.current = 0;
314 if (ent->blacklist.data != NULL)
315 ent->blacklist.data[0] = '\0';
316
317 give_pwd_free (&ent->pwd);
318
319 return NSS_STATUS_SUCCESS;
320 }
321
322 enum nss_status
323 _nss_compat_endpwent (void)
324 {
325 enum nss_status result;
326
327 __libc_lock_lock (lock);
328
329 result = internal_endpwent (&ext_ent);
330
331 __libc_lock_unlock (lock);
332
333 return result;
334 }
335
336 static enum nss_status
337 getpwent_next_nis_netgr (struct passwd *result, ent_t *ent, char *group,
338 char *buffer, size_t buflen)
339 {
340 struct parser_data *data = (void *) buffer;
341 char *ypdomain, *host, *user, *domain, *outval, *p, *p2;
342 int status, outvallen;
343 size_t p2len;
344
345 if (yp_get_default_domain (&ypdomain) != YPERR_SUCCESS)
346 {
347 ent->netgroup = 0;
348 ent->first = 0;
349 give_pwd_free (&ent->pwd);
350 return NSS_STATUS_UNAVAIL;
351 }
352
353 if (ent->first == TRUE)
354 {
355 memset (&ent->netgrdata, 0, sizeof (struct __netgrent));
356 __internal_setnetgrent (group, &ent->netgrdata);
357 ent->first = FALSE;
358 }
359
360 while (1)
361 {
362 char *saved_cursor;
363 int parse_res;
364
365 saved_cursor = ent->netgrdata.cursor;
366 status = __internal_getnetgrent_r (&host, &user, &domain,
367 &ent->netgrdata, buffer, buflen);
368 if (status != 1)
369 {
370 __internal_endnetgrent (&ent->netgrdata);
371 ent->netgroup = 0;
372 give_pwd_free (&ent->pwd);
373 return NSS_STATUS_RETURN;
374 }
375
376 if (user == NULL || user[0] == '-')
377 continue;
378
379 if (domain != NULL && strcmp (ypdomain, domain) != 0)
380 continue;
381
382 if (yp_match (ypdomain, "passwd.byname", user,
383 strlen (user), &outval, &outvallen)
384 != YPERR_SUCCESS)
385 continue;
386
387 p2len = pwd_need_buflen (&ent->pwd);
388 if (p2len > buflen)
389 {
390 __set_errno (ERANGE);
391 return NSS_STATUS_TRYAGAIN;
392 }
393 p2 = buffer + (buflen - p2len);
394 buflen -= p2len;
395 p = strncpy (buffer, outval, buflen);
396 while (isspace (*p))
397 p++;
398 free (outval);
399 if ((parse_res = _nss_files_parse_pwent (p, result, data, buflen)) == -1)
400 {
401 ent->netgrdata.cursor = saved_cursor;
402 return NSS_STATUS_TRYAGAIN;
403 }
404
405 if (parse_res)
406 {
407 copy_pwd_changes (result, &ent->pwd, p2, p2len);
408 break;
409 }
410 }
411
412 return NSS_STATUS_SUCCESS;
413 }
414
415 static enum nss_status
416 getpwent_next_nisplus_netgr (struct passwd *result, ent_t *ent, char *group,
417 char *buffer, size_t buflen)
418 {
419 char *ypdomain, *host, *user, *domain, *p2;
420 int status, parse_res;
421 size_t p2len;
422 nis_result *nisres;
423
424 /* Maybe we should use domainname here ? We need the current
425 domainname for the domain field in netgroups */
426 if (yp_get_default_domain (&ypdomain) != YPERR_SUCCESS)
427 {
428 ent->netgroup = 0;
429 ent->first = 0;
430 give_pwd_free (&ent->pwd);
431 return NSS_STATUS_UNAVAIL;
432 }
433
434 if (ent->first == TRUE)
435 {
436 bzero (&ent->netgrdata, sizeof (struct __netgrent));
437 __internal_setnetgrent (group, &ent->netgrdata);
438 ent->first = FALSE;
439 }
440
441 while (1)
442 {
443 char *saved_cursor;
444
445 saved_cursor = ent->netgrdata.cursor;
446 status = __internal_getnetgrent_r (&host, &user, &domain,
447 &ent->netgrdata, buffer, buflen);
448 if (status != 1)
449 {
450 __internal_endnetgrent (&ent->netgrdata);
451 ent->netgroup = 0;
452 give_pwd_free (&ent->pwd);
453 return NSS_STATUS_RETURN;
454 }
455
456 if (user == NULL || user[0] == '-')
457 continue;
458
459 if (domain != NULL && strcmp (ypdomain, domain) != 0)
460 continue;
461
462 p2len = pwd_need_buflen (&ent->pwd);
463 if (p2len > buflen)
464 {
465 __set_errno (ERANGE);
466 return NSS_STATUS_TRYAGAIN;
467 }
468 p2 = buffer + (buflen - p2len);
469 buflen -= p2len;
470 {
471 char buf[strlen (user) + 30 + pwdtablelen];
472 sprintf(buf, "[name=%s],%s", user, pwdtable);
473 nisres = nis_list(buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
474 }
475 if (niserr2nss (nisres->status) != NSS_STATUS_SUCCESS)
476 {
477 nis_freeresult (nisres);
478 continue;
479 }
480 if ((parse_res = _nss_nisplus_parse_pwent (nisres, result, buffer,
481 buflen)) == -1)
482 {
483 nis_freeresult (nisres);
484 ent->netgrdata.cursor = saved_cursor;
485 return NSS_STATUS_TRYAGAIN;
486 }
487 nis_freeresult (nisres);
488
489 if (parse_res)
490 {
491 copy_pwd_changes (result, &ent->pwd, p2, p2len);
492 break;
493 }
494 }
495
496 return NSS_STATUS_SUCCESS;
497 }
498
499 static enum nss_status
500 getpwent_next_netgr (struct passwd *result, ent_t *ent, char *group,
501 char *buffer, size_t buflen)
502 {
503 if (use_nisplus)
504 return getpwent_next_nisplus_netgr (result, ent, group, buffer, buflen);
505 else
506 return getpwent_next_nis_netgr (result, ent, group, buffer, buflen);
507 }
508
509 static enum nss_status
510 getpwent_next_nisplus (struct passwd *result, ent_t *ent, char *buffer,
511 size_t buflen)
512 {
513 int parse_res;
514 size_t p2len;
515 char *p2;
516
517 p2len = pwd_need_buflen (&ent->pwd);
518 if (p2len > buflen)
519 {
520 __set_errno (ERANGE);
521 return NSS_STATUS_TRYAGAIN;
522 }
523 p2 = buffer + (buflen - p2len);
524 buflen -= p2len;
525 do
526 {
527 bool_t saved_first;
528 nis_result *saved_res;
529
530 if (ent->first)
531 {
532 saved_first = TRUE;
533 saved_res = ent->result;
534
535 ent->result = nis_first_entry(pwdtable);
536 if (niserr2nss (ent->result->status) != NSS_STATUS_SUCCESS)
537 {
538 ent->nis = 0;
539 give_pwd_free (&ent->pwd);
540 return niserr2nss (ent->result->status);
541 }
542 ent->first = FALSE;
543 }
544 else
545 {
546 nis_result *res;
547
548 res = nis_next_entry(pwdtable, &ent->result->cookie);
549 saved_res = ent->result;
550 saved_first = FALSE;
551 ent->result = res;
552 if (niserr2nss (ent->result->status) != NSS_STATUS_SUCCESS)
553 {
554 ent->nis = 0;
555 nis_freeresult (saved_res);
556 give_pwd_free (&ent->pwd);
557 return niserr2nss (ent->result->status);
558 }
559 }
560 if ((parse_res = _nss_nisplus_parse_pwent (ent->result, result, buffer,
561 buflen)) == -1)
562 {
563 nis_freeresult (ent->result);
564 ent->result = saved_res;
565 ent->first = saved_first;
566 __set_errno (ERANGE);
567 return NSS_STATUS_TRYAGAIN;
568 }
569 else
570 {
571 if (!saved_first)
572 nis_freeresult (saved_res);
573 }
574
575 if (parse_res &&
576 in_blacklist (result->pw_name, strlen (result->pw_name), ent))
577 parse_res = 0; /* if result->pw_name in blacklist,search next entry */
578 }
579 while (!parse_res);
580
581 copy_pwd_changes (result, &ent->pwd, p2, p2len);
582
583 return NSS_STATUS_SUCCESS;
584 }
585
586 static enum nss_status
587 getpwent_next_nis (struct passwd *result, ent_t *ent, char *buffer,
588 size_t buflen)
589 {
590 struct parser_data *data = (void *) buffer;
591 char *domain, *outkey, *outval, *p, *p2;
592 int outkeylen, outvallen, parse_res;
593 size_t p2len;
594
595 if (yp_get_default_domain (&domain) != YPERR_SUCCESS)
596 {
597 ent->nis = 0;
598 give_pwd_free (&ent->pwd);
599 return NSS_STATUS_UNAVAIL;
600 }
601
602 p2len = pwd_need_buflen (&ent->pwd);
603 if (p2len > buflen)
604 {
605 __set_errno (ERANGE);
606 return NSS_STATUS_TRYAGAIN;
607 }
608 p2 = buffer + (buflen - p2len);
609 buflen -= p2len;
610 do
611 {
612 bool_t saved_first;
613 char *saved_oldkey;
614 int saved_oldlen;
615
616 if (ent->first)
617 {
618 if (yp_first (domain, "passwd.byname", &outkey, &outkeylen,
619 &outval, &outvallen) != YPERR_SUCCESS)
620 {
621 ent->nis = 0;
622 give_pwd_free (&ent->pwd);
623 return NSS_STATUS_UNAVAIL;
624 }
625
626 saved_first = TRUE;
627 saved_oldkey = ent->oldkey;
628 saved_oldlen = ent->oldkeylen;
629 ent->oldkey = outkey;
630 ent->oldkeylen = outkeylen;
631 ent->first = FALSE;
632 }
633 else
634 {
635 if (yp_next (domain, "passwd.byname", ent->oldkey, ent->oldkeylen,
636 &outkey, &outkeylen, &outval, &outvallen)
637 != YPERR_SUCCESS)
638 {
639 ent->nis = 0;
640 give_pwd_free (&ent->pwd);
641 return NSS_STATUS_NOTFOUND;
642 }
643
644 saved_first = FALSE;
645 saved_oldkey = ent->oldkey;
646 saved_oldlen = ent->oldkeylen;
647 ent->oldkey = outkey;
648 ent->oldkeylen = outkeylen;
649 }
650
651 /* Copy the found data to our buffer */
652 p = strncpy (buffer, outval, buflen);
653
654 /* ...and free the data. */
655 free (outval);
656
657 while (isspace (*p))
658 ++p;
659 if ((parse_res = _nss_files_parse_pwent (p, result, data, buflen)) == -1)
660 {
661 free (ent->oldkey);
662 ent->oldkey = saved_oldkey;
663 ent->oldkeylen = saved_oldlen;
664 ent->first = saved_first;
665 __set_errno (ERANGE);
666 return NSS_STATUS_TRYAGAIN;
667 }
668 else
669 {
670 if (!saved_first)
671 free (saved_oldkey);
672 }
673 if (parse_res &&
674 in_blacklist (result->pw_name, strlen (result->pw_name), ent))
675 parse_res = 0;
676 }
677 while (!parse_res);
678
679 copy_pwd_changes (result, &ent->pwd, p2, p2len);
680
681 return NSS_STATUS_SUCCESS;
682 }
683
684 /* This function handle the +user entrys in /etc/passwd */
685 static enum nss_status
686 getpwent_next_file_plususer (struct passwd *result, char *buffer,
687 size_t buflen)
688 {
689 struct parser_data *data = (void *) buffer;
690 struct passwd pwd;
691 int parse_res;
692 char *p;
693 size_t plen;
694
695 memset (&pwd, '\0', sizeof (struct passwd));
696
697 copy_pwd_changes (&pwd, result, NULL, 0);
698
699 plen = pwd_need_buflen (&pwd);
700 if (plen > buflen)
701 {
702 __set_errno (ERANGE);
703 return NSS_STATUS_TRYAGAIN;
704 }
705 p = buffer + (buflen - plen);
706 buflen -= plen;
707
708 if (use_nisplus) /* Do the NIS+ query here */
709 {
710 nis_result *res;
711 char buf[strlen (result->pw_name) + 24 + pwdtablelen];
712
713 sprintf(buf, "[name=%s],%s", &result->pw_name[1], pwdtable);
714 res = nis_list(buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
715 if (niserr2nss (res->status) != NSS_STATUS_SUCCESS)
716 {
717 enum nss_status status = niserr2nss (res->status);
718
719 nis_freeresult (res);
720 return status;
721 }
722 if ((parse_res = _nss_nisplus_parse_pwent (res, result, buffer,
723 buflen)) == -1)
724 {
725 nis_freeresult (res);
726 __set_errno (ERANGE);
727 return NSS_STATUS_TRYAGAIN;
728 }
729 nis_freeresult (res);
730 }
731 else /* Use NIS */
732 {
733 char *domain;
734 char *outval;
735 int outvallen;
736
737 if (yp_get_default_domain (&domain) != YPERR_SUCCESS)
738 return NSS_STATUS_TRYAGAIN;
739
740 if (yp_match (domain, "passwd.byname", &result->pw_name[1],
741 strlen (result->pw_name) - 1, &outval, &outvallen)
742 != YPERR_SUCCESS)
743 return NSS_STATUS_TRYAGAIN;
744 p = strncpy (buffer, outval,
745 buflen < (size_t) outvallen ? buflen : (size_t) outvallen);
746 free (outval);
747 while (isspace (*p))
748 p++;
749 if ((parse_res = _nss_files_parse_pwent (p, result, data, buflen)) == -1)
750 {
751 __set_errno (ERANGE);
752 return NSS_STATUS_TRYAGAIN;
753 }
754 }
755
756 if (parse_res > 0)
757 {
758 copy_pwd_changes (result, &pwd, p, plen);
759 give_pwd_free (&pwd);
760 /* We found the entry. */
761 return NSS_STATUS_SUCCESS;
762 }
763 else
764 {
765 /* Give buffer the old len back */
766 buflen += plen;
767 give_pwd_free (&pwd);
768 }
769 return NSS_STATUS_RETURN;
770 }
771
772 static enum nss_status
773 getpwent_next_file (struct passwd *result, ent_t *ent,
774 char *buffer, size_t buflen)
775 {
776 struct parser_data *data = (void *) buffer;
777 while (1)
778 {
779 fpos_t pos;
780 char *p;
781 int parse_res;
782
783 do
784 {
785 fgetpos (ent->stream, &pos);
786 p = fgets (buffer, buflen, ent->stream);
787 if (p == NULL)
788 return NSS_STATUS_NOTFOUND;
789
790 /* Terminate the line for any case. */
791 buffer[buflen - 1] = '\0';
792
793 /* Skip leading blanks. */
794 while (isspace (*p))
795 ++p;
796 }
797 while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */
798 /* Parse the line. If it is invalid, loop to
799 get the next line of the file to parse. */
800 !(parse_res = _nss_files_parse_pwent (p, result, data, buflen)));
801
802 if (parse_res == -1)
803 {
804 /* The parser ran out of space. */
805 fsetpos (ent->stream, &pos);
806 __set_errno (ERANGE);
807 return NSS_STATUS_TRYAGAIN;
808 }
809
810 if (result->pw_name[0] != '+' && result->pw_name[0] != '-')
811 /* This is a real entry. */
812 break;
813
814 /* -@netgroup */
815 if (result->pw_name[0] == '-' && result->pw_name[1] == '@'
816 && result->pw_name[2] != '\0')
817 {
818 char buf2[1024];
819 char *user, *host, *domain;
820 struct __netgrent netgrdata;
821
822 bzero (&netgrdata, sizeof (struct __netgrent));
823 __internal_setnetgrent (&result->pw_name[2], &netgrdata);
824 while (__internal_getnetgrent_r (&host, &user, &domain,
825 &netgrdata, buf2, sizeof (buf2)))
826 {
827 if (user != NULL && user[0] != '-')
828 blacklist_store_name (user, ent);
829 }
830 __internal_endnetgrent (&netgrdata);
831 continue;
832 }
833
834 /* +@netgroup */
835 if (result->pw_name[0] == '+' && result->pw_name[1] == '@'
836 && result->pw_name[2] != '\0')
837 {
838 int status;
839
840 ent->netgroup = TRUE;
841 ent->first = TRUE;
842 copy_pwd_changes (&ent->pwd, result, NULL, 0);
843
844 status = getpwent_next_netgr (result, ent, &result->pw_name[2],
845 buffer, buflen);
846 if (status == NSS_STATUS_RETURN)
847 continue;
848 else
849 return status;
850 }
851
852 /* -user */
853 if (result->pw_name[0] == '-' && result->pw_name[1] != '\0'
854 && result->pw_name[1] != '@')
855 {
856 blacklist_store_name (&result->pw_name[1], ent);
857 continue;
858 }
859
860 /* +user */
861 if (result->pw_name[0] == '+' && result->pw_name[1] != '\0'
862 && result->pw_name[1] != '@')
863 {
864 enum nss_status status;
865
866 status = getpwent_next_file_plususer (result, buffer, buflen);
867 if (status == NSS_STATUS_SUCCESS) /* We found the entry. */
868 break;
869 else
870 if (status == NSS_STATUS_RETURN) /* We couldn't parse the entry */
871 continue;
872 else
873 return status;
874 }
875
876 /* +:... */
877 if (result->pw_name[0] == '+' && result->pw_name[1] == '\0')
878 {
879 ent->nis = TRUE;
880 ent->first = TRUE;
881 copy_pwd_changes (&ent->pwd, result, NULL, 0);
882
883 if (use_nisplus)
884 return getpwent_next_nisplus (result, ent, buffer, buflen);
885 else
886 return getpwent_next_nis (result, ent, buffer, buflen);
887 }
888 }
889
890 return NSS_STATUS_SUCCESS;
891 }
892
893
894 static enum nss_status
895 internal_getpwent_r (struct passwd *pw, ent_t *ent, char *buffer,
896 size_t buflen)
897 {
898 if (ent->netgroup)
899 {
900 int status;
901
902 /* We are searching members in a netgroup */
903 /* Since this is not the first call, we don't need the group name */
904 status = getpwent_next_netgr (pw, ent, NULL, buffer, buflen);
905 if (status == NSS_STATUS_RETURN)
906 return getpwent_next_file (pw, ent, buffer, buflen);
907 else
908 return status;
909 }
910 else if (ent->nis)
911 {
912 if (use_nisplus)
913 return getpwent_next_nisplus (pw, ent, buffer, buflen);
914 else
915 return getpwent_next_nis (pw, ent, buffer, buflen);
916 }
917 else
918 return getpwent_next_file (pw, ent, buffer, buflen);
919 }
920
921 enum nss_status
922 _nss_compat_getpwent_r (struct passwd *pwd, char *buffer,
923 size_t buflen)
924 {
925 enum nss_status status = NSS_STATUS_SUCCESS;
926
927 __libc_lock_lock (lock);
928
929 if (ni == NULL)
930 {
931 __nss_database_lookup ("passwd_compat", NULL, "nis", &ni);
932 use_nisplus = (strcmp (ni->name, "nisplus") == 0);
933 }
934
935 /* Be prepared that the setpwent function was not called before. */
936 if (ext_ent.stream == NULL)
937 status = internal_setpwent (&ext_ent);
938
939 if (status == NSS_STATUS_SUCCESS)
940 status = internal_getpwent_r (pwd, &ext_ent, buffer, buflen);
941
942 __libc_lock_unlock (lock);
943
944 return status;
945 }
946
947
948 enum nss_status
949 _nss_compat_getpwnam_r (const char *name, struct passwd *pwd,
950 char *buffer, size_t buflen)
951 {
952 ent_t ent = {0, 0, 0, NULL, 0, NULL, NULL, {NULL, 0, 0},
953 {NULL, NULL, 0, 0, NULL, NULL, NULL}};
954 enum nss_status status;
955
956 if (name[0] == '-' || name[0] == '+')
957 return NSS_STATUS_NOTFOUND;
958
959 __libc_lock_lock (lock);
960
961 if (ni == NULL)
962 {
963 __nss_database_lookup ("passwd_compat", NULL, "nis", &ni);
964 use_nisplus = (strcmp (ni->name, "nisplus") == 0);
965 }
966
967 __libc_lock_unlock (lock);
968
969 status = internal_setpwent (&ent);
970 if (status != NSS_STATUS_SUCCESS)
971 return status;
972
973 while ((status = internal_getpwent_r (pwd, &ent, buffer, buflen))
974 == NSS_STATUS_SUCCESS)
975 if (strcmp (pwd->pw_name, name) == 0)
976 break;
977
978 internal_endpwent (&ent);
979 return status;
980 }
981
982
983 enum nss_status
984 _nss_compat_getpwuid_r (uid_t uid, struct passwd *pwd,
985 char *buffer, size_t buflen)
986 {
987 ent_t ent = {0, 0, 0, NULL, 0, NULL, NULL, {NULL, 0, 0},
988 {NULL, NULL, 0, 0, NULL, NULL, NULL}};
989 enum nss_status status;
990
991 __libc_lock_lock (lock);
992
993 if (ni == NULL)
994 {
995 __nss_database_lookup ("passwd_compat", NULL, "nis", &ni);
996 use_nisplus = (strcmp (ni->name, "nisplus") == 0);
997 }
998
999 __libc_lock_unlock (lock);
1000
1001 status = internal_setpwent (&ent);
1002 if (status != NSS_STATUS_SUCCESS)
1003 return status;
1004
1005 while ((status = internal_getpwent_r (pwd, &ent, buffer, buflen))
1006 == NSS_STATUS_SUCCESS)
1007 if (pwd->pw_uid == uid && pwd->pw_name[0] != '+' && pwd->pw_name[0] != '-')
1008 break;
1009
1010 internal_endpwent (&ent);
1011 return status;
1012 }
1013
1014
1015 /* Support routines for remembering -@netgroup and -user entries.
1016 The names are stored in a single string with `|' as separator. */
1017 static void
1018 blacklist_store_name (const char *name, ent_t *ent)
1019 {
1020 int namelen = strlen (name);
1021 char *tmp;
1022
1023 /* first call, setup cache */
1024 if (ent->blacklist.size == 0)
1025 {
1026 ent->blacklist.size = MAX (BLACKLIST_INITIAL_SIZE, 2 * namelen);
1027 ent->blacklist.data = malloc (ent->blacklist.size);
1028 if (ent->blacklist.data == NULL)
1029 return;
1030 ent->blacklist.data[0] = '|';
1031 ent->blacklist.data[1] = '\0';
1032 ent->blacklist.current = 1;
1033 }
1034 else
1035 {
1036 if (in_blacklist (name, namelen, ent))
1037 return; /* no duplicates */
1038
1039 if (ent->blacklist.current + namelen + 1 >= ent->blacklist.size)
1040 {
1041 ent->blacklist.size += MAX (BLACKLIST_INCREMENT, 2 * namelen);
1042 tmp = realloc (ent->blacklist.data, ent->blacklist.size);
1043 if (tmp == NULL)
1044 {
1045 free (ent->blacklist.data);
1046 ent->blacklist.size = 0;
1047 return;
1048 }
1049 ent->blacklist.data = tmp;
1050 }
1051 }
1052
1053 tmp = stpcpy (ent->blacklist.data + ent->blacklist.current, name);
1054 *tmp++ = '|';
1055 *tmp = '\0';
1056 ent->blacklist.current += namelen + 1;
1057
1058 return;
1059 }
1060
1061 /* returns TRUE if ent->blacklist contains name, else FALSE */
1062 static bool_t
1063 in_blacklist (const char *name, int namelen, ent_t *ent)
1064 {
1065 char buf[namelen + 3];
1066 char *cp;
1067
1068 if (ent->blacklist.data == NULL)
1069 return FALSE;
1070
1071 buf[0] = '|';
1072 cp = stpcpy (&buf[1], name);
1073 *cp++= '|';
1074 *cp = '\0';
1075 return strstr (ent->blacklist.data, buf) != NULL;
1076 }
This page took 0.094402 seconds and 6 git commands to generate.