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