1 /* Copyright (C) 1996, 1997, 1998, 1999, 2001 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1996.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27 #include <bits/libc-lock.h>
28 #include <rpcsvc/yp.h>
29 #include <rpcsvc/ypclnt.h>
30 #include <rpcsvc/nis.h>
34 #include "nss-nisplus.h"
35 #include "nisplus-parser.h"
37 static service_user
*ni
;
38 static bool_t use_nisplus
; /* default: passwd_compat: nis */
39 static nis_name pwdtable
; /* Name of the pwd table */
40 static size_t pwdtablelen
;
42 /* Get the declaration of the parser function. */
44 #define STRUCTURE passwd
46 #include <nss/nss_files/files-parse.c>
48 /* Structure for remembering -@netgroup and -user members ... */
49 #define BLACKLIST_INITIAL_SIZE 512
50 #define BLACKLIST_INCREMENT 256
67 struct blacklist_t blacklist
;
69 struct __netgrent netgrdata
;
71 typedef struct ent_t ent_t
;
73 static ent_t ext_ent
= {0, 0, 0, NULL
, 0, NULL
, NULL
, {NULL
, 0, 0},
74 {NULL
, NULL
, 0, 0, NULL
, NULL
, NULL
}};
76 /* Protect global state against multiple changers. */
77 __libc_lock_define_initialized (static, lock
)
79 /* Prototypes for local functions. */
80 static void blacklist_store_name (const char *, ent_t
*);
81 static int in_blacklist (const char *, int, ent_t
*);
84 give_pwd_free (struct passwd
*pwd
)
86 if (pwd
->pw_name
!= NULL
)
88 if (pwd
->pw_passwd
!= NULL
)
89 free (pwd
->pw_passwd
);
90 if (pwd
->pw_gecos
!= NULL
)
92 if (pwd
->pw_dir
!= NULL
)
94 if (pwd
->pw_shell
!= NULL
)
97 memset (pwd
, '\0', sizeof (struct passwd
));
101 pwd_need_buflen (struct passwd
*pwd
)
105 if (pwd
->pw_passwd
!= NULL
)
106 len
+= strlen (pwd
->pw_passwd
) + 1;
108 if (pwd
->pw_gecos
!= NULL
)
109 len
+= strlen (pwd
->pw_gecos
) + 1;
111 if (pwd
->pw_dir
!= NULL
)
112 len
+= strlen (pwd
->pw_dir
) + 1;
114 if (pwd
->pw_shell
!= NULL
)
115 len
+= strlen (pwd
->pw_shell
) + 1;
121 copy_pwd_changes (struct passwd
*dest
, struct passwd
*src
,
122 char *buffer
, size_t buflen
)
124 if (src
->pw_passwd
!= NULL
&& strlen (src
->pw_passwd
))
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
);
133 dest
->pw_passwd
= buffer
;
134 strcpy (dest
->pw_passwd
, src
->pw_passwd
);
135 buffer
+= strlen (dest
->pw_passwd
) + 1;
136 buflen
= buflen
- (strlen (dest
->pw_passwd
) + 1);
140 if (src
->pw_gecos
!= NULL
&& strlen (src
->pw_gecos
))
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
);
149 dest
->pw_gecos
= buffer
;
150 strcpy (dest
->pw_gecos
, src
->pw_gecos
);
151 buffer
+= strlen (dest
->pw_gecos
) + 1;
152 buflen
= buflen
- (strlen (dest
->pw_gecos
) + 1);
155 if (src
->pw_dir
!= NULL
&& strlen (src
->pw_dir
))
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
);
164 dest
->pw_dir
= buffer
;
165 strcpy (dest
->pw_dir
, src
->pw_dir
);
166 buffer
+= strlen (dest
->pw_dir
) + 1;
167 buflen
= buflen
- (strlen (dest
->pw_dir
) + 1);
171 if (src
->pw_shell
!= NULL
&& strlen (src
->pw_shell
))
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
);
180 dest
->pw_shell
= buffer
;
181 strcpy (dest
->pw_shell
, src
->pw_shell
);
182 buffer
+= strlen (dest
->pw_shell
) + 1;
183 buflen
= buflen
- (strlen (dest
->pw_shell
) + 1);
188 static enum nss_status
189 insert_passwd_adjunct (char **result
, int *len
, char *domain
, int *errnop
)
191 char *p1
, *p2
, *result2
, *res
;
195 /* Check for adjunct style secret passwords. They can be
196 recognized by a password starting with "##". */
197 p1
= strchr (*result
, ':');
198 if (p1
== NULL
|| p1
[1] != '#' || p1
[2] != '#')
199 return NSS_STATUS_SUCCESS
;
200 p2
= strchr (p1
+ 3, ':');
202 namelen
= p2
- p1
- 3;
204 if (yp_match (domain
, "passwd.adjunct.byname", &p1
[3], namelen
,
205 &result2
, &len2
) == YPERR_SUCCESS
)
207 /* We found a passwd.adjunct entry. Merge encrypted
208 password therein into original result. */
209 char *encrypted
= strchr (result2
, ':');
213 if (encrypted
== NULL
|| (endp
= strchr (++encrypted
, ':')) == NULL
)
215 /* Invalid format of the entry. This never should happen
216 unless the data from which the NIS table is generated is
217 wrong. We simply ignore it. */
219 return NSS_STATUS_SUCCESS
;
222 restlen
= *len
- (p2
- *result
);
223 if ((res
= malloc (namelen
+ restlen
+ (endp
- encrypted
) + 2)) == NULL
)
227 return NSS_STATUS_TRYAGAIN
;
230 __mempcpy (__mempcpy (__mempcpy (__mempcpy
231 (res
, *result
, (p1
- *result
)),
233 encrypted
, endp
- encrypted
),
241 return NSS_STATUS_SUCCESS
;
244 static enum nss_status
245 internal_setpwent (ent_t
*ent
)
247 enum nss_status status
= NSS_STATUS_SUCCESS
;
249 ent
->nis
= ent
->first
= ent
->netgroup
= 0;
251 /* If something was left over free it. */
253 __internal_endnetgrent (&ent
->netgrdata
);
255 if (ent
->oldkey
!= NULL
)
262 if (ent
->result
!= NULL
)
264 nis_freeresult (ent
->result
);
268 if (pwdtable
== NULL
)
270 static const char key
[] = "passwd.org_dir.";
271 const char *local_dir
= nis_local_directory ();
272 size_t len_local_dir
= strlen (local_dir
);
274 pwdtable
= malloc (sizeof (key
) + len_local_dir
);
275 if (pwdtable
== NULL
)
276 return NSS_STATUS_TRYAGAIN
;
278 pwdtablelen
= ((char *) mempcpy (mempcpy (pwdtable
,
279 key
, sizeof (key
) - 1),
280 local_dir
, len_local_dir
+ 1)
284 if (ent
->blacklist
.data
!= NULL
)
286 ent
->blacklist
.current
= 1;
287 ent
->blacklist
.data
[0] = '|';
288 ent
->blacklist
.data
[1] = '\0';
291 ent
->blacklist
.current
= 0;
293 if (ent
->stream
== NULL
)
295 ent
->stream
= fopen ("/etc/passwd", "r");
297 if (ent
->stream
== NULL
)
298 status
= errno
== EAGAIN
? NSS_STATUS_TRYAGAIN
: NSS_STATUS_UNAVAIL
;
301 /* We have to make sure the file is `closed on exec'. */
304 result
= flags
= fcntl (fileno (ent
->stream
), F_GETFD
, 0);
308 result
= fcntl (fileno (ent
->stream
), F_SETFD
, flags
);
312 /* Something went wrong. Close the stream and return a
314 fclose (ent
->stream
);
316 status
= NSS_STATUS_UNAVAIL
;
321 rewind (ent
->stream
);
323 give_pwd_free (&ent
->pwd
);
330 _nss_compat_setpwent (int stayopen
)
332 enum nss_status result
;
334 __libc_lock_lock (lock
);
338 __nss_database_lookup ("passwd_compat", NULL
, "nis", &ni
);
339 use_nisplus
= (strcmp (ni
->name
, "nisplus") == 0);
342 result
= internal_setpwent (&ext_ent
);
344 __libc_lock_unlock (lock
);
350 static enum nss_status
351 internal_endpwent (ent_t
*ent
)
353 if (ent
->stream
!= NULL
)
355 fclose (ent
->stream
);
360 __internal_endnetgrent (&ent
->netgrdata
);
362 ent
->nis
= ent
->first
= ent
->netgroup
= 0;
364 if (ent
->oldkey
!= NULL
)
371 if (ent
->result
!= NULL
)
373 nis_freeresult (ent
->result
);
377 if (ent
->blacklist
.data
!= NULL
)
379 ent
->blacklist
.current
= 1;
380 ent
->blacklist
.data
[0] = '|';
381 ent
->blacklist
.data
[1] = '\0';
384 ent
->blacklist
.current
= 0;
386 give_pwd_free (&ent
->pwd
);
388 return NSS_STATUS_SUCCESS
;
392 _nss_compat_endpwent (void)
394 enum nss_status result
;
396 __libc_lock_lock (lock
);
398 result
= internal_endpwent (&ext_ent
);
400 __libc_lock_unlock (lock
);
405 static enum nss_status
406 getpwent_next_nis_netgr (const char *name
, struct passwd
*result
, ent_t
*ent
,
407 char *group
, char *buffer
, size_t buflen
, int *errnop
)
409 struct parser_data
*data
= (void *) buffer
;
410 char *ypdomain
, *host
, *user
, *domain
, *outval
, *p
, *p2
;
411 int status
, outvallen
;
414 if (yp_get_default_domain (&ypdomain
) != YPERR_SUCCESS
)
418 give_pwd_free (&ent
->pwd
);
419 return NSS_STATUS_UNAVAIL
;
422 if (ent
->first
== TRUE
)
424 memset (&ent
->netgrdata
, 0, sizeof (struct __netgrent
));
425 __internal_setnetgrent (group
, &ent
->netgrdata
);
434 saved_cursor
= ent
->netgrdata
.cursor
;
435 status
= __internal_getnetgrent_r (&host
, &user
, &domain
,
436 &ent
->netgrdata
, buffer
, buflen
,
440 __internal_endnetgrent (&ent
->netgrdata
);
442 give_pwd_free (&ent
->pwd
);
443 return NSS_STATUS_RETURN
;
446 if (user
== NULL
|| user
[0] == '-')
449 if (domain
!= NULL
&& strcmp (ypdomain
, domain
) != 0)
452 /* If name != NULL, we are called from getpwnam. */
454 if (strcmp (user
, name
) != 0)
457 if (yp_match (ypdomain
, "passwd.byname", user
,
458 strlen (user
), &outval
, &outvallen
)
462 if (insert_passwd_adjunct (&outval
, &outvallen
, ypdomain
, errnop
)
463 != NSS_STATUS_SUCCESS
)
466 return NSS_STATUS_TRYAGAIN
;
469 p2len
= pwd_need_buflen (&ent
->pwd
);
474 return NSS_STATUS_TRYAGAIN
;
476 p2
= buffer
+ (buflen
- p2len
);
479 if (buflen
< ((size_t) outvallen
+ 1))
483 return NSS_STATUS_TRYAGAIN
;
485 p
= strncpy (buffer
, outval
, buflen
);
490 parse_res
= _nss_files_parse_pwent (p
, result
, data
, buflen
, errnop
);
493 ent
->netgrdata
.cursor
= saved_cursor
;
494 return NSS_STATUS_TRYAGAIN
;
497 if (parse_res
&& !in_blacklist (result
->pw_name
,
498 strlen (result
->pw_name
), ent
))
500 /* Store the User in the blacklist for the "+" at the end of
502 blacklist_store_name (result
->pw_name
, ent
);
503 copy_pwd_changes (result
, &ent
->pwd
, p2
, p2len
);
508 return NSS_STATUS_SUCCESS
;
511 static enum nss_status
512 getpwent_next_nisplus_netgr (const char *name
, struct passwd
*result
,
513 ent_t
*ent
, char *group
, char *buffer
,
514 size_t buflen
, int *errnop
)
516 char *ypdomain
, *host
, *user
, *domain
, *p2
;
517 int status
, parse_res
;
521 /* Maybe we should use domainname here ? We need the current
522 domainname for the domain field in netgroups */
523 if (yp_get_default_domain (&ypdomain
) != YPERR_SUCCESS
)
527 give_pwd_free (&ent
->pwd
);
528 return NSS_STATUS_UNAVAIL
;
531 if (ent
->first
== TRUE
)
533 bzero (&ent
->netgrdata
, sizeof (struct __netgrent
));
534 __internal_setnetgrent (group
, &ent
->netgrdata
);
542 saved_cursor
= ent
->netgrdata
.cursor
;
543 status
= __internal_getnetgrent_r (&host
, &user
, &domain
,
544 &ent
->netgrdata
, buffer
, buflen
,
548 __internal_endnetgrent (&ent
->netgrdata
);
550 give_pwd_free (&ent
->pwd
);
551 return NSS_STATUS_RETURN
;
554 if (user
== NULL
|| user
[0] == '-')
557 if (domain
!= NULL
&& strcmp (ypdomain
, domain
) != 0)
560 /* If name != NULL, we are called from getpwnam */
562 if (strcmp (user
, name
) != 0)
565 p2len
= pwd_need_buflen (&ent
->pwd
);
569 return NSS_STATUS_TRYAGAIN
;
571 p2
= buffer
+ (buflen
- p2len
);
574 char buf
[strlen (user
) + 30 + pwdtablelen
];
575 sprintf(buf
, "[name=%s],%s", user
, pwdtable
);
576 nisres
= nis_list(buf
, FOLLOW_PATH
| FOLLOW_LINKS
, NULL
, NULL
);
578 if (niserr2nss (nisres
->status
) != NSS_STATUS_SUCCESS
)
580 nis_freeresult (nisres
);
583 parse_res
= _nss_nisplus_parse_pwent (nisres
, result
, buffer
,
587 nis_freeresult (nisres
);
588 ent
->netgrdata
.cursor
= saved_cursor
;
590 return NSS_STATUS_TRYAGAIN
;
592 nis_freeresult (nisres
);
594 if (parse_res
&& !in_blacklist (result
->pw_name
,
595 strlen (result
->pw_name
), ent
))
597 /* Store the User in the blacklist for the "+" at the end of
599 blacklist_store_name (result
->pw_name
, ent
);
600 copy_pwd_changes (result
, &ent
->pwd
, p2
, p2len
);
605 return NSS_STATUS_SUCCESS
;
608 /* get the next user from NIS+ (+ entry) */
609 static enum nss_status
610 getpwent_next_nisplus (struct passwd
*result
, ent_t
*ent
, char *buffer
,
611 size_t buflen
, int *errnop
)
617 p2len
= pwd_need_buflen (&ent
->pwd
);
621 return NSS_STATUS_TRYAGAIN
;
623 p2
= buffer
+ (buflen
- p2len
);
628 nis_result
*saved_res
;
633 saved_res
= ent
->result
;
635 ent
->result
= nis_first_entry (pwdtable
);
636 if (niserr2nss (ent
->result
->status
) != NSS_STATUS_SUCCESS
)
639 give_pwd_free (&ent
->pwd
);
640 return niserr2nss (ent
->result
->status
);
648 res
= nis_next_entry (pwdtable
, &ent
->result
->cookie
);
649 saved_res
= ent
->result
;
652 if (niserr2nss (ent
->result
->status
) != NSS_STATUS_SUCCESS
)
655 nis_freeresult (saved_res
);
656 give_pwd_free (&ent
->pwd
);
657 return niserr2nss (ent
->result
->status
);
660 parse_res
= _nss_nisplus_parse_pwent (ent
->result
, result
, buffer
,
664 nis_freeresult (ent
->result
);
665 ent
->result
= saved_res
;
666 ent
->first
= saved_first
;
668 return NSS_STATUS_TRYAGAIN
;
673 nis_freeresult (saved_res
);
677 in_blacklist (result
->pw_name
, strlen (result
->pw_name
), ent
))
678 parse_res
= 0; /* if result->pw_name in blacklist,search next entry */
682 copy_pwd_changes (result
, &ent
->pwd
, p2
, p2len
);
684 return NSS_STATUS_SUCCESS
;
687 static enum nss_status
688 getpwent_next_nis (struct passwd
*result
, ent_t
*ent
, char *buffer
,
689 size_t buflen
, int *errnop
)
691 struct parser_data
*data
= (void *) buffer
;
692 char *domain
, *outkey
, *outval
, *p
, *p2
;
693 int outkeylen
, outvallen
, parse_res
;
696 if (yp_get_default_domain (&domain
) != YPERR_SUCCESS
)
699 give_pwd_free (&ent
->pwd
);
700 return NSS_STATUS_UNAVAIL
;
703 p2len
= pwd_need_buflen (&ent
->pwd
);
707 return NSS_STATUS_TRYAGAIN
;
709 p2
= buffer
+ (buflen
- p2len
);
719 if (yp_first (domain
, "passwd.byname", &outkey
, &outkeylen
,
720 &outval
, &outvallen
) != YPERR_SUCCESS
)
723 give_pwd_free (&ent
->pwd
);
724 return NSS_STATUS_UNAVAIL
;
727 if (insert_passwd_adjunct (&outval
, &outvallen
, domain
, errnop
) !=
731 return NSS_STATUS_TRYAGAIN
;
734 if (buflen
< ((size_t) outvallen
+ 1))
738 return NSS_STATUS_TRYAGAIN
;
742 saved_oldkey
= ent
->oldkey
;
743 saved_oldlen
= ent
->oldkeylen
;
744 ent
->oldkey
= outkey
;
745 ent
->oldkeylen
= outkeylen
;
750 if (yp_next (domain
, "passwd.byname", ent
->oldkey
, ent
->oldkeylen
,
751 &outkey
, &outkeylen
, &outval
, &outvallen
)
755 give_pwd_free (&ent
->pwd
);
757 return NSS_STATUS_NOTFOUND
;
760 if (insert_passwd_adjunct (&outval
, &outvallen
, domain
, errnop
)
761 != NSS_STATUS_SUCCESS
)
764 return NSS_STATUS_TRYAGAIN
;
767 if (buflen
< ((size_t) outvallen
+ 1))
771 return NSS_STATUS_TRYAGAIN
;
775 saved_oldkey
= ent
->oldkey
;
776 saved_oldlen
= ent
->oldkeylen
;
777 ent
->oldkey
= outkey
;
778 ent
->oldkeylen
= outkeylen
;
781 /* Copy the found data to our buffer */
782 p
= strncpy (buffer
, outval
, buflen
);
784 /* ...and free the data. */
789 parse_res
= _nss_files_parse_pwent (p
, result
, data
, buflen
, errnop
);
793 ent
->oldkey
= saved_oldkey
;
794 ent
->oldkeylen
= saved_oldlen
;
795 ent
->first
= saved_first
;
797 return NSS_STATUS_TRYAGAIN
;
805 && in_blacklist (result
->pw_name
, strlen (result
->pw_name
), ent
))
810 copy_pwd_changes (result
, &ent
->pwd
, p2
, p2len
);
812 return NSS_STATUS_SUCCESS
;
815 /* This function handle the +user entrys in /etc/passwd */
816 static enum nss_status
817 getpwnam_plususer (const char *name
, struct passwd
*result
, ent_t
*ent
,
818 char *buffer
, size_t buflen
, int *errnop
)
820 struct parser_data
*data
= (void *) buffer
;
826 memset (&pwd
, '\0', sizeof (struct passwd
));
828 copy_pwd_changes (&pwd
, result
, NULL
, 0);
830 plen
= pwd_need_buflen (&pwd
);
834 return NSS_STATUS_TRYAGAIN
;
836 p
= buffer
+ (buflen
- plen
);
839 if (use_nisplus
) /* Do the NIS+ query here */
842 char buf
[strlen (name
) + 24 + pwdtablelen
];
844 sprintf(buf
, "[name=%s],%s", name
, pwdtable
);
845 res
= nis_list(buf
, FOLLOW_PATH
| FOLLOW_LINKS
, NULL
, NULL
);
846 if (niserr2nss (res
->status
) != NSS_STATUS_SUCCESS
)
848 enum nss_status status
= niserr2nss (res
->status
);
850 nis_freeresult (res
);
853 parse_res
= _nss_nisplus_parse_pwent (res
, result
, buffer
,
856 nis_freeresult (res
);
861 return NSS_STATUS_TRYAGAIN
;
864 if (in_blacklist (result
->pw_name
, strlen (result
->pw_name
), ent
))
867 return NSS_STATUS_NOTFOUND
;
872 char *domain
, *outval
, *ptr
;
875 if (yp_get_default_domain (&domain
) != YPERR_SUCCESS
)
878 return NSS_STATUS_NOTFOUND
;
881 if (yp_match (domain
, "passwd.byname", name
, strlen (name
),
882 &outval
, &outvallen
) != YPERR_SUCCESS
)
885 return NSS_STATUS_NOTFOUND
;
888 if (insert_passwd_adjunct (&outval
, &outvallen
, domain
, errnop
)
889 != NSS_STATUS_SUCCESS
)
892 return NSS_STATUS_TRYAGAIN
;
895 if (buflen
< ((size_t) outvallen
+ 1))
899 return NSS_STATUS_TRYAGAIN
;
902 ptr
= strncpy (buffer
, outval
, buflen
);
905 while (isspace (*ptr
))
908 parse_res
= _nss_files_parse_pwent (ptr
, result
, data
, buflen
, errnop
);
910 return NSS_STATUS_TRYAGAIN
;
912 if (in_blacklist (result
->pw_name
, strlen (result
->pw_name
), ent
))
915 return NSS_STATUS_NOTFOUND
;
921 copy_pwd_changes (result
, &pwd
, p
, plen
);
922 give_pwd_free (&pwd
);
923 /* We found the entry. */
924 return NSS_STATUS_SUCCESS
;
928 /* Give buffer the old len back */
930 give_pwd_free (&pwd
);
932 return NSS_STATUS_RETURN
;
935 static enum nss_status
936 getpwent_next_file (struct passwd
*result
, ent_t
*ent
,
937 char *buffer
, size_t buflen
, int *errnop
)
939 struct parser_data
*data
= (void *) buffer
;
948 fgetpos (ent
->stream
, &pos
);
949 buffer
[buflen
- 1] = '\xff';
950 p
= fgets (buffer
, buflen
, ent
->stream
);
951 if (p
== NULL
&& feof (ent
->stream
))
954 return NSS_STATUS_NOTFOUND
;
956 if (p
== NULL
|| buffer
[buflen
- 1] != '\xff')
958 fsetpos (ent
->stream
, &pos
);
960 return NSS_STATUS_TRYAGAIN
;
963 /* Terminate the line for any case. */
964 buffer
[buflen
- 1] = '\0';
966 /* Skip leading blanks. */
970 while (*p
== '\0' || *p
== '#' || /* Ignore empty and comment lines. */
971 /* Parse the line. If it is invalid, loop to
972 get the next line of the file to parse. */
973 !(parse_res
= _nss_files_parse_pwent (p
, result
, data
, buflen
,
978 /* The parser ran out of space. */
979 fsetpos (ent
->stream
, &pos
);
981 return NSS_STATUS_TRYAGAIN
;
984 if (result
->pw_name
[0] != '+' && result
->pw_name
[0] != '-')
985 /* This is a real entry. */
989 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] == '@'
990 && result
->pw_name
[2] != '\0')
992 /* XXX Do not use fixed length buffer. */
994 char *user
, *host
, *domain
;
995 struct __netgrent netgrdata
;
997 bzero (&netgrdata
, sizeof (struct __netgrent
));
998 __internal_setnetgrent (&result
->pw_name
[2], &netgrdata
);
999 while (__internal_getnetgrent_r (&host
, &user
, &domain
, &netgrdata
,
1000 buf2
, sizeof (buf2
), errnop
))
1002 if (user
!= NULL
&& user
[0] != '-')
1003 blacklist_store_name (user
, ent
);
1005 __internal_endnetgrent (&netgrdata
);
1010 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '@'
1011 && result
->pw_name
[2] != '\0')
1013 enum nss_status status
;
1015 ent
->netgroup
= TRUE
;
1017 copy_pwd_changes (&ent
->pwd
, result
, NULL
, 0);
1020 status
= getpwent_next_nisplus_netgr (NULL
, result
, ent
,
1021 &result
->pw_name
[2],
1022 buffer
, buflen
, errnop
);
1024 status
= getpwent_next_nis_netgr (NULL
, result
, ent
,
1025 &result
->pw_name
[2],
1026 buffer
, buflen
, errnop
);
1027 if (status
== NSS_STATUS_RETURN
)
1031 if (status
== NSS_STATUS_NOTFOUND
)
1038 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] != '\0'
1039 && result
->pw_name
[1] != '@')
1041 blacklist_store_name (&result
->pw_name
[1], ent
);
1046 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] != '\0'
1047 && result
->pw_name
[1] != '@')
1049 char buf
[strlen (result
->pw_name
)];
1050 enum nss_status status
;
1052 /* Store the User in the blacklist for the "+" at the end of
1054 strcpy (buf
, &result
->pw_name
[1]);
1055 status
= getpwnam_plususer (&result
->pw_name
[1], result
, ent
,
1056 buffer
, buflen
, errnop
);
1057 blacklist_store_name (buf
, ent
);
1059 if (status
== NSS_STATUS_SUCCESS
) /* We found the entry. */
1062 if (status
== NSS_STATUS_RETURN
/* We couldn't parse the entry */
1063 || status
== NSS_STATUS_NOTFOUND
) /* entry doesn't exist */
1067 if (status
== NSS_STATUS_TRYAGAIN
)
1069 /* The parser ran out of space */
1070 fsetpos (ent
->stream
, &pos
);
1078 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '\0')
1082 copy_pwd_changes (&ent
->pwd
, result
, NULL
, 0);
1085 return getpwent_next_nisplus (result
, ent
, buffer
, buflen
, errnop
);
1087 return getpwent_next_nis (result
, ent
, buffer
, buflen
, errnop
);
1091 return NSS_STATUS_SUCCESS
;
1095 static enum nss_status
1096 internal_getpwent_r (struct passwd
*pw
, ent_t
*ent
, char *buffer
,
1097 size_t buflen
, int *errnop
)
1101 enum nss_status status
;
1103 /* We are searching members in a netgroup */
1104 /* Since this is not the first call, we don't need the group name */
1106 status
= getpwent_next_nisplus_netgr (NULL
, pw
, ent
, NULL
, buffer
,
1109 status
= getpwent_next_nis_netgr (NULL
, pw
, ent
, NULL
, buffer
, buflen
,
1111 if (status
== NSS_STATUS_RETURN
)
1112 return getpwent_next_file (pw
, ent
, buffer
, buflen
, errnop
);
1120 return getpwent_next_nisplus (pw
, ent
, buffer
, buflen
, errnop
);
1122 return getpwent_next_nis (pw
, ent
, buffer
, buflen
, errnop
);
1125 return getpwent_next_file (pw
, ent
, buffer
, buflen
, errnop
);
1129 _nss_compat_getpwent_r (struct passwd
*pwd
, char *buffer
, size_t buflen
,
1132 enum nss_status status
= NSS_STATUS_SUCCESS
;
1134 __libc_lock_lock (lock
);
1138 __nss_database_lookup ("passwd_compat", NULL
, "nis", &ni
);
1139 use_nisplus
= (strcmp (ni
->name
, "nisplus") == 0);
1142 /* Be prepared that the setpwent function was not called before. */
1143 if (ext_ent
.stream
== NULL
)
1144 status
= internal_setpwent (&ext_ent
);
1146 if (status
== NSS_STATUS_SUCCESS
)
1147 status
= internal_getpwent_r (pwd
, &ext_ent
, buffer
, buflen
, errnop
);
1149 __libc_lock_unlock (lock
);
1154 /* Searches in /etc/passwd and the NIS/NIS+ map for a special user */
1155 static enum nss_status
1156 internal_getpwnam_r (const char *name
, struct passwd
*result
, ent_t
*ent
,
1157 char *buffer
, size_t buflen
, int *errnop
)
1159 struct parser_data
*data
= (void *) buffer
;
1169 fgetpos (ent
->stream
, &pos
);
1170 buffer
[buflen
- 1] = '\xff';
1171 p
= fgets (buffer
, buflen
, ent
->stream
);
1172 if (p
== NULL
&& feof (ent
->stream
))
1175 return NSS_STATUS_NOTFOUND
;
1177 if (p
== NULL
|| buffer
[buflen
- 1] != '\xff')
1179 fsetpos (ent
->stream
, &pos
);
1181 return NSS_STATUS_TRYAGAIN
;
1184 /* Terminate the line for any case. */
1185 buffer
[buflen
- 1] = '\0';
1187 /* Skip leading blanks. */
1188 while (isspace (*p
))
1191 while (*p
== '\0' || *p
== '#' || /* Ignore empty and comment lines. */
1192 /* Parse the line. If it is invalid, loop to
1193 get the next line of the file to parse. */
1194 !(parse_res
= _nss_files_parse_pwent (p
, result
, data
, buflen
,
1197 if (parse_res
== -1)
1199 /* The parser ran out of space. */
1200 fsetpos (ent
->stream
, &pos
);
1202 return NSS_STATUS_TRYAGAIN
;
1205 /* This is a real entry. */
1206 if (result
->pw_name
[0] != '+' && result
->pw_name
[0] != '-')
1208 if (strcmp (result
->pw_name
, name
) == 0)
1209 return NSS_STATUS_SUCCESS
;
1215 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] == '@'
1216 && result
->pw_name
[2] != '\0')
1218 if (innetgr (&result
->pw_name
[2], NULL
, name
, NULL
))
1219 return NSS_STATUS_NOTFOUND
;
1224 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '@'
1225 && result
->pw_name
[2] != '\0')
1227 enum nss_status status
;
1229 if (innetgr (&result
->pw_name
[2], NULL
, name
, NULL
))
1231 status
= getpwnam_plususer (name
, result
, ent
, buffer
,
1234 if (status
== NSS_STATUS_RETURN
)
1243 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] != '\0'
1244 && result
->pw_name
[1] != '@')
1246 if (strcmp (&result
->pw_name
[1], name
) == 0)
1249 return NSS_STATUS_NOTFOUND
;
1256 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] != '\0'
1257 && result
->pw_name
[1] != '@')
1259 if (strcmp (name
, &result
->pw_name
[1]) == 0)
1261 enum nss_status status
;
1263 status
= getpwnam_plususer (name
, result
, ent
, buffer
, buflen
,
1265 if (status
== NSS_STATUS_RETURN
)
1266 /* We couldn't parse the entry */
1267 return NSS_STATUS_NOTFOUND
;
1274 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '\0')
1276 enum nss_status status
;
1278 status
= getpwnam_plususer (name
, result
, ent
,
1279 buffer
, buflen
, errnop
);
1280 if (status
== NSS_STATUS_SUCCESS
) /* We found the entry. */
1283 if (status
== NSS_STATUS_RETURN
) /* We couldn't parse the entry */
1284 return NSS_STATUS_NOTFOUND
;
1289 return NSS_STATUS_SUCCESS
;
1293 _nss_compat_getpwnam_r (const char *name
, struct passwd
*pwd
,
1294 char *buffer
, size_t buflen
, int *errnop
)
1296 ent_t ent
= {0, 0, 0, NULL
, 0, NULL
, NULL
, {NULL
, 0, 0},
1297 {NULL
, NULL
, 0, 0, NULL
, NULL
, NULL
}};
1298 enum nss_status status
;
1300 if (name
[0] == '-' || name
[0] == '+')
1303 return NSS_STATUS_NOTFOUND
;
1306 __libc_lock_lock (lock
);
1310 __nss_database_lookup ("passwd_compat", NULL
, "nis", &ni
);
1311 use_nisplus
= (strcmp (ni
->name
, "nisplus") == 0);
1314 __libc_lock_unlock (lock
);
1316 status
= internal_setpwent (&ent
);
1317 if (status
!= NSS_STATUS_SUCCESS
)
1320 status
= internal_getpwnam_r (name
, pwd
, &ent
, buffer
, buflen
, errnop
);
1322 internal_endpwent (&ent
);
1327 /* This function handle the + entry in /etc/passwd for getpwuid */
1328 static enum nss_status
1329 getpwuid_plususer (uid_t uid
, struct passwd
*result
, char *buffer
,
1330 size_t buflen
, int *errnop
)
1332 struct parser_data
*data
= (void *) buffer
;
1338 memset (&pwd
, '\0', sizeof (struct passwd
));
1340 copy_pwd_changes (&pwd
, result
, NULL
, 0);
1342 plen
= pwd_need_buflen (&pwd
);
1346 return NSS_STATUS_TRYAGAIN
;
1348 p
= buffer
+ (buflen
- plen
);
1351 if (use_nisplus
) /* Do the NIS+ query here */
1354 char buf
[1024 + pwdtablelen
];
1356 snprintf (buf
, sizeof (buf
), "[uid=%lu],%s", (unsigned long int) uid
,
1358 res
= nis_list (buf
, FOLLOW_PATH
| FOLLOW_LINKS
, NULL
, NULL
);
1359 if (niserr2nss (res
->status
) != NSS_STATUS_SUCCESS
)
1361 enum nss_status status
= niserr2nss (res
->status
);
1363 nis_freeresult (res
);
1366 if ((parse_res
= _nss_nisplus_parse_pwent (res
, result
, buffer
,
1367 buflen
, errnop
)) == -1)
1369 nis_freeresult (res
);
1371 return NSS_STATUS_TRYAGAIN
;
1373 nis_freeresult (res
);
1378 char *domain
, *outval
, *ptr
;
1381 if (yp_get_default_domain (&domain
) != YPERR_SUCCESS
)
1384 return NSS_STATUS_NOTFOUND
;
1387 sprintf (buf
, "%lu", (unsigned long int) uid
);
1388 if (yp_match (domain
, "passwd.byuid", buf
, strlen (buf
),
1389 &outval
, &outvallen
)
1393 return NSS_STATUS_NOTFOUND
;
1396 if (insert_passwd_adjunct (&outval
, &outvallen
, domain
, errnop
)
1397 != NSS_STATUS_SUCCESS
)
1400 return NSS_STATUS_TRYAGAIN
;
1403 if (buflen
< ((size_t) outvallen
+ 1))
1407 return NSS_STATUS_TRYAGAIN
;
1410 ptr
= strncpy (buffer
, outval
, buflen
);
1413 while (isspace (*ptr
))
1415 parse_res
= _nss_files_parse_pwent (ptr
, result
, data
, buflen
, errnop
);
1416 if (parse_res
== -1)
1417 return NSS_STATUS_TRYAGAIN
;
1422 copy_pwd_changes (result
, &pwd
, p
, plen
);
1423 give_pwd_free (&pwd
);
1424 /* We found the entry. */
1425 return NSS_STATUS_SUCCESS
;
1429 /* Give buffer the old len back */
1431 give_pwd_free (&pwd
);
1433 return NSS_STATUS_RETURN
;
1436 /* Searches in /etc/passwd and the NIS/NIS+ map for a special user id */
1437 static enum nss_status
1438 internal_getpwuid_r (uid_t uid
, struct passwd
*result
, ent_t
*ent
,
1439 char *buffer
, size_t buflen
, int *errnop
)
1441 struct parser_data
*data
= (void *) buffer
;
1451 fgetpos (ent
->stream
, &pos
);
1452 buffer
[buflen
- 1] = '\xff';
1453 p
= fgets (buffer
, buflen
, ent
->stream
);
1454 if (p
== NULL
&& feof (ent
->stream
))
1457 return NSS_STATUS_NOTFOUND
;
1459 if (p
== NULL
|| buffer
[buflen
- 1] != '\xff')
1461 fsetpos (ent
->stream
, &pos
);
1463 return NSS_STATUS_TRYAGAIN
;
1466 /* Terminate the line for any case. */
1467 buffer
[buflen
- 1] = '\0';
1469 /* Skip leading blanks. */
1470 while (isspace (*p
))
1473 while (*p
== '\0' || *p
== '#' || /* Ignore empty and comment lines. */
1474 /* Parse the line. If it is invalid, loop to
1475 get the next line of the file to parse. */
1476 !(parse_res
= _nss_files_parse_pwent (p
, result
, data
, buflen
,
1479 if (parse_res
== -1)
1481 /* The parser ran out of space. */
1482 fsetpos (ent
->stream
, &pos
);
1484 return NSS_STATUS_TRYAGAIN
;
1487 /* This is a real entry. */
1488 if (result
->pw_name
[0] != '+' && result
->pw_name
[0] != '-')
1490 if (result
->pw_uid
== uid
)
1491 return NSS_STATUS_SUCCESS
;
1497 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] == '@'
1498 && result
->pw_name
[2] != '\0')
1500 char buf
[strlen (result
->pw_name
)];
1501 enum nss_status status
;
1503 strcpy (buf
, &result
->pw_name
[2]);
1505 status
= getpwuid_plususer (uid
, result
, buffer
, buflen
, errnop
);
1506 if (status
== NSS_STATUS_SUCCESS
&&
1507 innetgr (buf
, NULL
, result
->pw_name
, NULL
))
1510 return NSS_STATUS_NOTFOUND
;
1516 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '@'
1517 && result
->pw_name
[2] != '\0')
1519 char buf
[strlen (result
->pw_name
)];
1520 enum nss_status status
;
1522 strcpy (buf
, &result
->pw_name
[2]);
1524 status
= getpwuid_plususer (uid
, result
, buffer
, buflen
, errnop
);
1526 if (status
== NSS_STATUS_RETURN
)
1529 if (status
== NSS_STATUS_SUCCESS
)
1531 if (innetgr (buf
, NULL
, result
->pw_name
, NULL
))
1532 return NSS_STATUS_SUCCESS
;
1535 if (status
== NSS_STATUS_RETURN
) /* We couldn't parse the entry */
1538 return NSS_STATUS_NOTFOUND
;
1547 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] != '\0'
1548 && result
->pw_name
[1] != '@')
1550 char buf
[strlen (result
->pw_name
)];
1551 enum nss_status status
;
1553 strcpy (buf
, &result
->pw_name
[1]);
1555 status
= getpwuid_plususer (uid
, result
, buffer
, buflen
, errnop
);
1556 if (status
== NSS_STATUS_SUCCESS
&&
1557 innetgr (buf
, NULL
, result
->pw_name
, NULL
))
1560 return NSS_STATUS_NOTFOUND
;
1566 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] != '\0'
1567 && result
->pw_name
[1] != '@')
1569 char buf
[strlen (result
->pw_name
)];
1570 enum nss_status status
;
1572 strcpy (buf
, &result
->pw_name
[1]);
1574 status
= getpwuid_plususer (uid
, result
, buffer
, buflen
, errnop
);
1576 if (status
== NSS_STATUS_RETURN
)
1579 if (status
== NSS_STATUS_SUCCESS
)
1581 if (strcmp (buf
, result
->pw_name
) == 0)
1582 return NSS_STATUS_SUCCESS
;
1585 if (status
== NSS_STATUS_RETURN
) /* We couldn't parse the entry */
1588 return NSS_STATUS_NOTFOUND
;
1597 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '\0')
1599 enum nss_status status
;
1601 status
= getpwuid_plususer (uid
, result
, buffer
, buflen
, errnop
);
1602 if (status
== NSS_STATUS_SUCCESS
) /* We found the entry. */
1605 if (status
== NSS_STATUS_RETURN
) /* We couldn't parse the entry */
1608 return NSS_STATUS_NOTFOUND
;
1614 return NSS_STATUS_SUCCESS
;
1618 _nss_compat_getpwuid_r (uid_t uid
, struct passwd
*pwd
,
1619 char *buffer
, size_t buflen
, int *errnop
)
1621 ent_t ent
= {0, 0, 0, NULL
, 0, NULL
, NULL
, {NULL
, 0, 0},
1622 {NULL
, NULL
, 0, 0, NULL
, NULL
, NULL
}};
1623 enum nss_status status
;
1625 __libc_lock_lock (lock
);
1629 __nss_database_lookup ("passwd_compat", NULL
, "nis", &ni
);
1630 use_nisplus
= (strcmp (ni
->name
, "nisplus") == 0);
1633 __libc_lock_unlock (lock
);
1635 status
= internal_setpwent (&ent
);
1636 if (status
!= NSS_STATUS_SUCCESS
)
1639 status
= internal_getpwuid_r (uid
, pwd
, &ent
, buffer
, buflen
, errnop
);
1641 internal_endpwent (&ent
);
1647 /* Support routines for remembering -@netgroup and -user entries.
1648 The names are stored in a single string with `|' as separator. */
1650 blacklist_store_name (const char *name
, ent_t
*ent
)
1652 int namelen
= strlen (name
);
1655 /* first call, setup cache */
1656 if (ent
->blacklist
.size
== 0)
1658 ent
->blacklist
.size
= MAX (BLACKLIST_INITIAL_SIZE
, 2 * namelen
);
1659 ent
->blacklist
.data
= malloc (ent
->blacklist
.size
);
1660 if (ent
->blacklist
.data
== NULL
)
1662 ent
->blacklist
.data
[0] = '|';
1663 ent
->blacklist
.data
[1] = '\0';
1664 ent
->blacklist
.current
= 1;
1668 if (in_blacklist (name
, namelen
, ent
))
1669 return; /* no duplicates */
1671 if (ent
->blacklist
.current
+ namelen
+ 1 >= ent
->blacklist
.size
)
1673 ent
->blacklist
.size
+= MAX (BLACKLIST_INCREMENT
, 2 * namelen
);
1674 tmp
= realloc (ent
->blacklist
.data
, ent
->blacklist
.size
);
1677 free (ent
->blacklist
.data
);
1678 ent
->blacklist
.size
= 0;
1681 ent
->blacklist
.data
= tmp
;
1685 tmp
= stpcpy (ent
->blacklist
.data
+ ent
->blacklist
.current
, name
);
1688 ent
->blacklist
.current
+= namelen
+ 1;
1693 /* returns TRUE if ent->blacklist contains name, else FALSE */
1695 in_blacklist (const char *name
, int namelen
, ent_t
*ent
)
1697 char buf
[namelen
+ 3];
1700 if (ent
->blacklist
.data
== NULL
)
1704 cp
= stpcpy (&buf
[1], name
);
1707 return strstr (ent
->blacklist
.data
, buf
) != NULL
;