]>
git.ipfire.org Git - thirdparty/glibc.git/blob - nis/nss_compat/compat-pwd.c
1 /* Copyright (C) 1996,1997,1998,1999,2001,2002 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
)
226 return NSS_STATUS_TRYAGAIN
;
229 __mempcpy (__mempcpy (__mempcpy (__mempcpy
230 (res
, *result
, (p1
- *result
)),
232 encrypted
, endp
- encrypted
),
240 return NSS_STATUS_SUCCESS
;
243 static enum nss_status
244 internal_setpwent (ent_t
*ent
)
246 enum nss_status status
= NSS_STATUS_SUCCESS
;
248 ent
->nis
= ent
->first
= ent
->netgroup
= 0;
250 /* If something was left over free it. */
252 __internal_endnetgrent (&ent
->netgrdata
);
254 if (ent
->oldkey
!= NULL
)
261 if (ent
->result
!= NULL
)
263 nis_freeresult (ent
->result
);
267 if (pwdtable
== NULL
)
269 static const char key
[] = "passwd.org_dir.";
270 const char *local_dir
= nis_local_directory ();
271 size_t len_local_dir
= strlen (local_dir
);
273 pwdtable
= malloc (sizeof (key
) + len_local_dir
);
274 if (pwdtable
== NULL
)
275 return NSS_STATUS_TRYAGAIN
;
277 pwdtablelen
= ((char *) mempcpy (mempcpy (pwdtable
,
278 key
, sizeof (key
) - 1),
279 local_dir
, len_local_dir
+ 1)
283 if (ent
->blacklist
.data
!= NULL
)
285 ent
->blacklist
.current
= 1;
286 ent
->blacklist
.data
[0] = '|';
287 ent
->blacklist
.data
[1] = '\0';
290 ent
->blacklist
.current
= 0;
292 if (ent
->stream
== NULL
)
294 ent
->stream
= fopen ("/etc/passwd", "r");
296 if (ent
->stream
== NULL
)
297 status
= errno
== EAGAIN
? NSS_STATUS_TRYAGAIN
: NSS_STATUS_UNAVAIL
;
300 /* We have to make sure the file is `closed on exec'. */
303 result
= flags
= fcntl (fileno (ent
->stream
), F_GETFD
, 0);
307 result
= fcntl (fileno (ent
->stream
), F_SETFD
, flags
);
311 /* Something went wrong. Close the stream and return a
313 fclose (ent
->stream
);
315 status
= NSS_STATUS_UNAVAIL
;
320 rewind (ent
->stream
);
322 give_pwd_free (&ent
->pwd
);
329 _nss_compat_setpwent (int stayopen
)
331 enum nss_status result
;
333 __libc_lock_lock (lock
);
337 __nss_database_lookup ("passwd_compat", NULL
, "nis", &ni
);
338 use_nisplus
= (strcmp (ni
->name
, "nisplus") == 0);
341 result
= internal_setpwent (&ext_ent
);
343 __libc_lock_unlock (lock
);
349 static enum nss_status
350 internal_endpwent (ent_t
*ent
)
352 if (ent
->stream
!= NULL
)
354 fclose (ent
->stream
);
359 __internal_endnetgrent (&ent
->netgrdata
);
361 ent
->nis
= ent
->first
= ent
->netgroup
= 0;
363 if (ent
->oldkey
!= NULL
)
370 if (ent
->result
!= NULL
)
372 nis_freeresult (ent
->result
);
376 if (ent
->blacklist
.data
!= NULL
)
378 ent
->blacklist
.current
= 1;
379 ent
->blacklist
.data
[0] = '|';
380 ent
->blacklist
.data
[1] = '\0';
383 ent
->blacklist
.current
= 0;
385 give_pwd_free (&ent
->pwd
);
387 return NSS_STATUS_SUCCESS
;
391 _nss_compat_endpwent (void)
393 enum nss_status result
;
395 __libc_lock_lock (lock
);
397 result
= internal_endpwent (&ext_ent
);
399 __libc_lock_unlock (lock
);
404 static enum nss_status
405 getpwent_next_nis_netgr (const char *name
, struct passwd
*result
, ent_t
*ent
,
406 char *group
, char *buffer
, size_t buflen
, int *errnop
)
408 struct parser_data
*data
= (void *) buffer
;
409 char *ypdomain
, *host
, *user
, *domain
, *outval
, *p
, *p2
;
410 int status
, outvallen
;
413 if (yp_get_default_domain (&ypdomain
) != YPERR_SUCCESS
)
417 give_pwd_free (&ent
->pwd
);
418 return NSS_STATUS_UNAVAIL
;
421 if (ent
->first
== TRUE
)
423 memset (&ent
->netgrdata
, 0, sizeof (struct __netgrent
));
424 __internal_setnetgrent (group
, &ent
->netgrdata
);
433 saved_cursor
= ent
->netgrdata
.cursor
;
434 status
= __internal_getnetgrent_r (&host
, &user
, &domain
,
435 &ent
->netgrdata
, buffer
, buflen
,
439 __internal_endnetgrent (&ent
->netgrdata
);
441 give_pwd_free (&ent
->pwd
);
442 return NSS_STATUS_RETURN
;
445 if (user
== NULL
|| user
[0] == '-')
448 if (domain
!= NULL
&& strcmp (ypdomain
, domain
) != 0)
451 /* If name != NULL, we are called from getpwnam. */
453 if (strcmp (user
, name
) != 0)
456 if (yp_match (ypdomain
, "passwd.byname", user
,
457 strlen (user
), &outval
, &outvallen
)
461 if (insert_passwd_adjunct (&outval
, &outvallen
, ypdomain
, errnop
)
462 != NSS_STATUS_SUCCESS
)
465 return NSS_STATUS_TRYAGAIN
;
468 p2len
= pwd_need_buflen (&ent
->pwd
);
473 return NSS_STATUS_TRYAGAIN
;
475 p2
= buffer
+ (buflen
- p2len
);
478 if (buflen
< ((size_t) outvallen
+ 1))
482 return NSS_STATUS_TRYAGAIN
;
484 p
= strncpy (buffer
, outval
, buflen
);
489 parse_res
= _nss_files_parse_pwent (p
, result
, data
, buflen
, errnop
);
492 ent
->netgrdata
.cursor
= saved_cursor
;
493 return NSS_STATUS_TRYAGAIN
;
496 if (parse_res
&& !in_blacklist (result
->pw_name
,
497 strlen (result
->pw_name
), ent
))
499 /* Store the User in the blacklist for the "+" at the end of
501 blacklist_store_name (result
->pw_name
, ent
);
502 copy_pwd_changes (result
, &ent
->pwd
, p2
, p2len
);
507 return NSS_STATUS_SUCCESS
;
510 static enum nss_status
511 getpwent_next_nisplus_netgr (const char *name
, struct passwd
*result
,
512 ent_t
*ent
, char *group
, char *buffer
,
513 size_t buflen
, int *errnop
)
515 char *ypdomain
, *host
, *user
, *domain
, *p2
;
516 int status
, parse_res
;
520 /* Maybe we should use domainname here ? We need the current
521 domainname for the domain field in netgroups */
522 if (yp_get_default_domain (&ypdomain
) != YPERR_SUCCESS
)
526 give_pwd_free (&ent
->pwd
);
527 return NSS_STATUS_UNAVAIL
;
530 if (ent
->first
== TRUE
)
532 bzero (&ent
->netgrdata
, sizeof (struct __netgrent
));
533 __internal_setnetgrent (group
, &ent
->netgrdata
);
541 saved_cursor
= ent
->netgrdata
.cursor
;
542 status
= __internal_getnetgrent_r (&host
, &user
, &domain
,
543 &ent
->netgrdata
, buffer
, buflen
,
547 __internal_endnetgrent (&ent
->netgrdata
);
549 give_pwd_free (&ent
->pwd
);
550 return NSS_STATUS_RETURN
;
553 if (user
== NULL
|| user
[0] == '-')
556 if (domain
!= NULL
&& strcmp (ypdomain
, domain
) != 0)
559 /* If name != NULL, we are called from getpwnam */
561 if (strcmp (user
, name
) != 0)
564 p2len
= pwd_need_buflen (&ent
->pwd
);
568 return NSS_STATUS_TRYAGAIN
;
570 p2
= buffer
+ (buflen
- p2len
);
573 char buf
[strlen (user
) + 30 + pwdtablelen
];
574 sprintf(buf
, "[name=%s],%s", user
, pwdtable
);
575 nisres
= nis_list(buf
, FOLLOW_PATH
| FOLLOW_LINKS
, NULL
, NULL
);
577 if (niserr2nss (nisres
->status
) != NSS_STATUS_SUCCESS
)
579 nis_freeresult (nisres
);
582 parse_res
= _nss_nisplus_parse_pwent (nisres
, result
, buffer
,
586 nis_freeresult (nisres
);
587 ent
->netgrdata
.cursor
= saved_cursor
;
589 return NSS_STATUS_TRYAGAIN
;
591 nis_freeresult (nisres
);
593 if (parse_res
&& !in_blacklist (result
->pw_name
,
594 strlen (result
->pw_name
), ent
))
596 /* Store the User in the blacklist for the "+" at the end of
598 blacklist_store_name (result
->pw_name
, ent
);
599 copy_pwd_changes (result
, &ent
->pwd
, p2
, p2len
);
604 return NSS_STATUS_SUCCESS
;
607 /* get the next user from NIS+ (+ entry) */
608 static enum nss_status
609 getpwent_next_nisplus (struct passwd
*result
, ent_t
*ent
, char *buffer
,
610 size_t buflen
, int *errnop
)
616 p2len
= pwd_need_buflen (&ent
->pwd
);
620 return NSS_STATUS_TRYAGAIN
;
622 p2
= buffer
+ (buflen
- p2len
);
627 nis_result
*saved_res
;
632 saved_res
= ent
->result
;
634 ent
->result
= nis_first_entry (pwdtable
);
635 if (niserr2nss (ent
->result
->status
) != NSS_STATUS_SUCCESS
)
638 give_pwd_free (&ent
->pwd
);
639 return niserr2nss (ent
->result
->status
);
647 res
= nis_next_entry (pwdtable
, &ent
->result
->cookie
);
648 saved_res
= ent
->result
;
651 if (niserr2nss (ent
->result
->status
) != NSS_STATUS_SUCCESS
)
654 nis_freeresult (saved_res
);
655 give_pwd_free (&ent
->pwd
);
656 return niserr2nss (ent
->result
->status
);
659 parse_res
= _nss_nisplus_parse_pwent (ent
->result
, result
, buffer
,
663 nis_freeresult (ent
->result
);
664 ent
->result
= saved_res
;
665 ent
->first
= saved_first
;
667 return NSS_STATUS_TRYAGAIN
;
672 nis_freeresult (saved_res
);
676 in_blacklist (result
->pw_name
, strlen (result
->pw_name
), ent
))
677 parse_res
= 0; /* if result->pw_name in blacklist,search next entry */
681 copy_pwd_changes (result
, &ent
->pwd
, p2
, p2len
);
683 return NSS_STATUS_SUCCESS
;
686 static enum nss_status
687 getpwent_next_nis (struct passwd
*result
, ent_t
*ent
, char *buffer
,
688 size_t buflen
, int *errnop
)
690 struct parser_data
*data
= (void *) buffer
;
691 char *domain
, *outkey
, *outval
, *p
, *p2
;
692 int outkeylen
, outvallen
, parse_res
;
695 if (yp_get_default_domain (&domain
) != YPERR_SUCCESS
)
698 give_pwd_free (&ent
->pwd
);
699 return NSS_STATUS_UNAVAIL
;
702 p2len
= pwd_need_buflen (&ent
->pwd
);
706 return NSS_STATUS_TRYAGAIN
;
708 p2
= buffer
+ (buflen
- p2len
);
718 if (yp_first (domain
, "passwd.byname", &outkey
, &outkeylen
,
719 &outval
, &outvallen
) != YPERR_SUCCESS
)
722 give_pwd_free (&ent
->pwd
);
723 return NSS_STATUS_UNAVAIL
;
726 if (insert_passwd_adjunct (&outval
, &outvallen
, domain
, errnop
) !=
730 return NSS_STATUS_TRYAGAIN
;
733 if (buflen
< ((size_t) outvallen
+ 1))
737 return NSS_STATUS_TRYAGAIN
;
741 saved_oldkey
= ent
->oldkey
;
742 saved_oldlen
= ent
->oldkeylen
;
743 ent
->oldkey
= outkey
;
744 ent
->oldkeylen
= outkeylen
;
749 if (yp_next (domain
, "passwd.byname", ent
->oldkey
, ent
->oldkeylen
,
750 &outkey
, &outkeylen
, &outval
, &outvallen
)
754 give_pwd_free (&ent
->pwd
);
755 return NSS_STATUS_NOTFOUND
;
758 if (insert_passwd_adjunct (&outval
, &outvallen
, domain
, errnop
)
759 != NSS_STATUS_SUCCESS
)
762 return NSS_STATUS_TRYAGAIN
;
765 if (buflen
< ((size_t) outvallen
+ 1))
769 return NSS_STATUS_TRYAGAIN
;
773 saved_oldkey
= ent
->oldkey
;
774 saved_oldlen
= ent
->oldkeylen
;
775 ent
->oldkey
= outkey
;
776 ent
->oldkeylen
= outkeylen
;
779 /* Copy the found data to our buffer */
780 p
= strncpy (buffer
, outval
, buflen
);
782 /* ...and free the data. */
787 parse_res
= _nss_files_parse_pwent (p
, result
, data
, buflen
, errnop
);
791 ent
->oldkey
= saved_oldkey
;
792 ent
->oldkeylen
= saved_oldlen
;
793 ent
->first
= saved_first
;
795 return NSS_STATUS_TRYAGAIN
;
803 && in_blacklist (result
->pw_name
, strlen (result
->pw_name
), ent
))
808 copy_pwd_changes (result
, &ent
->pwd
, p2
, p2len
);
810 return NSS_STATUS_SUCCESS
;
813 /* This function handle the +user entrys in /etc/passwd */
814 static enum nss_status
815 getpwnam_plususer (const char *name
, struct passwd
*result
, ent_t
*ent
,
816 char *buffer
, size_t buflen
, int *errnop
)
818 struct parser_data
*data
= (void *) buffer
;
824 memset (&pwd
, '\0', sizeof (struct passwd
));
826 copy_pwd_changes (&pwd
, result
, NULL
, 0);
828 plen
= pwd_need_buflen (&pwd
);
832 return NSS_STATUS_TRYAGAIN
;
834 p
= buffer
+ (buflen
- plen
);
837 if (use_nisplus
) /* Do the NIS+ query here */
840 char buf
[strlen (name
) + 24 + pwdtablelen
];
842 sprintf(buf
, "[name=%s],%s", name
, pwdtable
);
843 res
= nis_list(buf
, FOLLOW_PATH
| FOLLOW_LINKS
, NULL
, NULL
);
844 if (niserr2nss (res
->status
) != NSS_STATUS_SUCCESS
)
846 enum nss_status status
= niserr2nss (res
->status
);
848 nis_freeresult (res
);
851 parse_res
= _nss_nisplus_parse_pwent (res
, result
, buffer
,
854 nis_freeresult (res
);
859 return NSS_STATUS_TRYAGAIN
;
862 if (in_blacklist (result
->pw_name
, strlen (result
->pw_name
), ent
))
863 return NSS_STATUS_NOTFOUND
;
867 char *domain
, *outval
, *ptr
;
870 if (yp_get_default_domain (&domain
) != YPERR_SUCCESS
)
871 return NSS_STATUS_NOTFOUND
;
873 if (yp_match (domain
, "passwd.byname", name
, strlen (name
),
874 &outval
, &outvallen
) != YPERR_SUCCESS
)
875 return NSS_STATUS_NOTFOUND
;
877 if (insert_passwd_adjunct (&outval
, &outvallen
, domain
, errnop
)
878 != NSS_STATUS_SUCCESS
)
881 return NSS_STATUS_TRYAGAIN
;
884 if (buflen
< ((size_t) outvallen
+ 1))
888 return NSS_STATUS_TRYAGAIN
;
891 ptr
= strncpy (buffer
, outval
, buflen
);
894 while (isspace (*ptr
))
897 parse_res
= _nss_files_parse_pwent (ptr
, result
, data
, buflen
, errnop
);
899 return NSS_STATUS_TRYAGAIN
;
901 if (in_blacklist (result
->pw_name
, strlen (result
->pw_name
), ent
))
902 return NSS_STATUS_NOTFOUND
;
907 copy_pwd_changes (result
, &pwd
, p
, plen
);
908 give_pwd_free (&pwd
);
909 /* We found the entry. */
910 return NSS_STATUS_SUCCESS
;
914 /* Give buffer the old len back */
916 give_pwd_free (&pwd
);
918 return NSS_STATUS_RETURN
;
921 static enum nss_status
922 getpwent_next_file (struct passwd
*result
, ent_t
*ent
,
923 char *buffer
, size_t buflen
, int *errnop
)
925 struct parser_data
*data
= (void *) buffer
;
934 fgetpos (ent
->stream
, &pos
);
935 buffer
[buflen
- 1] = '\xff';
936 p
= fgets (buffer
, buflen
, ent
->stream
);
937 if (p
== NULL
&& feof (ent
->stream
))
938 return NSS_STATUS_NOTFOUND
;
940 if (p
== NULL
|| buffer
[buflen
- 1] != '\xff')
942 fsetpos (ent
->stream
, &pos
);
944 return NSS_STATUS_TRYAGAIN
;
947 /* Terminate the line for any case. */
948 buffer
[buflen
- 1] = '\0';
950 /* Skip leading blanks. */
954 while (*p
== '\0' || *p
== '#' || /* Ignore empty and comment lines. */
955 /* Parse the line. If it is invalid, loop to
956 get the next line of the file to parse. */
957 !(parse_res
= _nss_files_parse_pwent (p
, result
, data
, buflen
,
962 /* The parser ran out of space. */
963 fsetpos (ent
->stream
, &pos
);
965 return NSS_STATUS_TRYAGAIN
;
968 if (result
->pw_name
[0] != '+' && result
->pw_name
[0] != '-')
969 /* This is a real entry. */
973 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] == '@'
974 && result
->pw_name
[2] != '\0')
976 /* XXX Do not use fixed length buffer. */
978 char *user
, *host
, *domain
;
979 struct __netgrent netgrdata
;
981 bzero (&netgrdata
, sizeof (struct __netgrent
));
982 __internal_setnetgrent (&result
->pw_name
[2], &netgrdata
);
983 while (__internal_getnetgrent_r (&host
, &user
, &domain
, &netgrdata
,
984 buf2
, sizeof (buf2
), errnop
))
986 if (user
!= NULL
&& user
[0] != '-')
987 blacklist_store_name (user
, ent
);
989 __internal_endnetgrent (&netgrdata
);
994 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '@'
995 && result
->pw_name
[2] != '\0')
997 enum nss_status status
;
999 ent
->netgroup
= TRUE
;
1001 copy_pwd_changes (&ent
->pwd
, result
, NULL
, 0);
1004 status
= getpwent_next_nisplus_netgr (NULL
, result
, ent
,
1005 &result
->pw_name
[2],
1006 buffer
, buflen
, errnop
);
1008 status
= getpwent_next_nis_netgr (NULL
, result
, ent
,
1009 &result
->pw_name
[2],
1010 buffer
, buflen
, errnop
);
1011 if (status
== NSS_STATUS_RETURN
)
1018 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] != '\0'
1019 && result
->pw_name
[1] != '@')
1021 blacklist_store_name (&result
->pw_name
[1], ent
);
1026 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] != '\0'
1027 && result
->pw_name
[1] != '@')
1029 char buf
[strlen (result
->pw_name
)];
1030 enum nss_status status
;
1032 /* Store the User in the blacklist for the "+" at the end of
1034 strcpy (buf
, &result
->pw_name
[1]);
1035 status
= getpwnam_plususer (&result
->pw_name
[1], result
, ent
,
1036 buffer
, buflen
, errnop
);
1037 blacklist_store_name (buf
, ent
);
1039 if (status
== NSS_STATUS_SUCCESS
) /* We found the entry. */
1042 if (status
== NSS_STATUS_RETURN
/* We couldn't parse the entry */
1043 || status
== NSS_STATUS_NOTFOUND
) /* entry doesn't exist */
1047 if (status
== NSS_STATUS_TRYAGAIN
)
1049 /* The parser ran out of space */
1050 fsetpos (ent
->stream
, &pos
);
1058 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '\0')
1062 copy_pwd_changes (&ent
->pwd
, result
, NULL
, 0);
1065 return getpwent_next_nisplus (result
, ent
, buffer
, buflen
, errnop
);
1067 return getpwent_next_nis (result
, ent
, buffer
, buflen
, errnop
);
1071 return NSS_STATUS_SUCCESS
;
1075 static enum nss_status
1076 internal_getpwent_r (struct passwd
*pw
, ent_t
*ent
, char *buffer
,
1077 size_t buflen
, int *errnop
)
1081 enum nss_status status
;
1083 /* We are searching members in a netgroup */
1084 /* Since this is not the first call, we don't need the group name */
1086 status
= getpwent_next_nisplus_netgr (NULL
, pw
, ent
, NULL
, buffer
,
1089 status
= getpwent_next_nis_netgr (NULL
, pw
, ent
, NULL
, buffer
, buflen
,
1091 if (status
== NSS_STATUS_RETURN
)
1092 return getpwent_next_file (pw
, ent
, buffer
, buflen
, errnop
);
1100 return getpwent_next_nisplus (pw
, ent
, buffer
, buflen
, errnop
);
1102 return getpwent_next_nis (pw
, ent
, buffer
, buflen
, errnop
);
1105 return getpwent_next_file (pw
, ent
, buffer
, buflen
, errnop
);
1109 _nss_compat_getpwent_r (struct passwd
*pwd
, char *buffer
, size_t buflen
,
1112 enum nss_status status
= NSS_STATUS_SUCCESS
;
1114 __libc_lock_lock (lock
);
1118 __nss_database_lookup ("passwd_compat", NULL
, "nis", &ni
);
1119 use_nisplus
= (strcmp (ni
->name
, "nisplus") == 0);
1122 /* Be prepared that the setpwent function was not called before. */
1123 if (ext_ent
.stream
== NULL
)
1124 status
= internal_setpwent (&ext_ent
);
1126 if (status
== NSS_STATUS_SUCCESS
)
1127 status
= internal_getpwent_r (pwd
, &ext_ent
, buffer
, buflen
, errnop
);
1129 __libc_lock_unlock (lock
);
1134 /* Searches in /etc/passwd and the NIS/NIS+ map for a special user */
1135 static enum nss_status
1136 internal_getpwnam_r (const char *name
, struct passwd
*result
, ent_t
*ent
,
1137 char *buffer
, size_t buflen
, int *errnop
)
1139 struct parser_data
*data
= (void *) buffer
;
1149 fgetpos (ent
->stream
, &pos
);
1150 buffer
[buflen
- 1] = '\xff';
1151 p
= fgets (buffer
, buflen
, ent
->stream
);
1152 if (p
== NULL
&& feof (ent
->stream
))
1154 return NSS_STATUS_NOTFOUND
;
1156 if (p
== NULL
|| buffer
[buflen
- 1] != '\xff')
1158 fsetpos (ent
->stream
, &pos
);
1160 return NSS_STATUS_TRYAGAIN
;
1163 /* Terminate the line for any case. */
1164 buffer
[buflen
- 1] = '\0';
1166 /* Skip leading blanks. */
1167 while (isspace (*p
))
1170 while (*p
== '\0' || *p
== '#' || /* Ignore empty and comment lines. */
1171 /* Parse the line. If it is invalid, loop to
1172 get the next line of the file to parse. */
1173 !(parse_res
= _nss_files_parse_pwent (p
, result
, data
, buflen
,
1176 if (parse_res
== -1)
1178 /* The parser ran out of space. */
1179 fsetpos (ent
->stream
, &pos
);
1181 return NSS_STATUS_TRYAGAIN
;
1184 /* This is a real entry. */
1185 if (result
->pw_name
[0] != '+' && result
->pw_name
[0] != '-')
1187 if (strcmp (result
->pw_name
, name
) == 0)
1188 return NSS_STATUS_SUCCESS
;
1194 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] == '@'
1195 && result
->pw_name
[2] != '\0')
1197 if (innetgr (&result
->pw_name
[2], NULL
, name
, NULL
))
1198 return NSS_STATUS_NOTFOUND
;
1203 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '@'
1204 && result
->pw_name
[2] != '\0')
1206 enum nss_status status
;
1208 if (innetgr (&result
->pw_name
[2], NULL
, name
, NULL
))
1210 status
= getpwnam_plususer (name
, result
, ent
, buffer
,
1213 if (status
== NSS_STATUS_RETURN
)
1222 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] != '\0'
1223 && result
->pw_name
[1] != '@')
1225 if (strcmp (&result
->pw_name
[1], name
) == 0)
1226 return NSS_STATUS_NOTFOUND
;
1232 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] != '\0'
1233 && result
->pw_name
[1] != '@')
1235 if (strcmp (name
, &result
->pw_name
[1]) == 0)
1237 enum nss_status status
;
1239 status
= getpwnam_plususer (name
, result
, ent
, buffer
, buflen
,
1241 if (status
== NSS_STATUS_RETURN
)
1242 /* We couldn't parse the entry */
1243 return NSS_STATUS_NOTFOUND
;
1250 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '\0')
1252 enum nss_status status
;
1254 status
= getpwnam_plususer (name
, result
, ent
,
1255 buffer
, buflen
, errnop
);
1256 if (status
== NSS_STATUS_SUCCESS
) /* We found the entry. */
1259 if (status
== NSS_STATUS_RETURN
) /* We couldn't parse the entry */
1260 return NSS_STATUS_NOTFOUND
;
1265 return NSS_STATUS_SUCCESS
;
1269 _nss_compat_getpwnam_r (const char *name
, struct passwd
*pwd
,
1270 char *buffer
, size_t buflen
, int *errnop
)
1272 ent_t ent
= {0, 0, 0, NULL
, 0, NULL
, NULL
, {NULL
, 0, 0},
1273 {NULL
, NULL
, 0, 0, NULL
, NULL
, NULL
}};
1274 enum nss_status status
;
1276 if (name
[0] == '-' || name
[0] == '+')
1277 return NSS_STATUS_NOTFOUND
;
1279 __libc_lock_lock (lock
);
1283 __nss_database_lookup ("passwd_compat", NULL
, "nis", &ni
);
1284 use_nisplus
= (strcmp (ni
->name
, "nisplus") == 0);
1287 __libc_lock_unlock (lock
);
1289 status
= internal_setpwent (&ent
);
1290 if (status
!= NSS_STATUS_SUCCESS
)
1293 status
= internal_getpwnam_r (name
, pwd
, &ent
, buffer
, buflen
, errnop
);
1295 internal_endpwent (&ent
);
1300 /* This function handle the + entry in /etc/passwd for getpwuid */
1301 static enum nss_status
1302 getpwuid_plususer (uid_t uid
, struct passwd
*result
, char *buffer
,
1303 size_t buflen
, int *errnop
)
1305 struct parser_data
*data
= (void *) buffer
;
1311 memset (&pwd
, '\0', sizeof (struct passwd
));
1313 copy_pwd_changes (&pwd
, result
, NULL
, 0);
1315 plen
= pwd_need_buflen (&pwd
);
1319 return NSS_STATUS_TRYAGAIN
;
1321 p
= buffer
+ (buflen
- plen
);
1324 if (use_nisplus
) /* Do the NIS+ query here */
1327 char buf
[1024 + pwdtablelen
];
1329 snprintf (buf
, sizeof (buf
), "[uid=%lu],%s", (unsigned long int) uid
,
1331 res
= nis_list (buf
, FOLLOW_PATH
| FOLLOW_LINKS
, NULL
, NULL
);
1332 if (niserr2nss (res
->status
) != NSS_STATUS_SUCCESS
)
1334 enum nss_status status
= niserr2nss (res
->status
);
1336 nis_freeresult (res
);
1339 if ((parse_res
= _nss_nisplus_parse_pwent (res
, result
, buffer
,
1340 buflen
, errnop
)) == -1)
1342 nis_freeresult (res
);
1344 return NSS_STATUS_TRYAGAIN
;
1346 nis_freeresult (res
);
1351 char *domain
, *outval
, *ptr
;
1354 if (yp_get_default_domain (&domain
) != YPERR_SUCCESS
)
1355 return NSS_STATUS_NOTFOUND
;
1357 sprintf (buf
, "%lu", (unsigned long int) uid
);
1358 if (yp_match (domain
, "passwd.byuid", buf
, strlen (buf
),
1359 &outval
, &outvallen
)
1361 return NSS_STATUS_NOTFOUND
;
1363 if (insert_passwd_adjunct (&outval
, &outvallen
, domain
, errnop
)
1364 != NSS_STATUS_SUCCESS
)
1367 return NSS_STATUS_TRYAGAIN
;
1370 if (buflen
< ((size_t) outvallen
+ 1))
1374 return NSS_STATUS_TRYAGAIN
;
1377 ptr
= strncpy (buffer
, outval
, buflen
);
1380 while (isspace (*ptr
))
1382 parse_res
= _nss_files_parse_pwent (ptr
, result
, data
, buflen
, errnop
);
1383 if (parse_res
== -1)
1384 return NSS_STATUS_TRYAGAIN
;
1389 copy_pwd_changes (result
, &pwd
, p
, plen
);
1390 give_pwd_free (&pwd
);
1391 /* We found the entry. */
1392 return NSS_STATUS_SUCCESS
;
1396 /* Give buffer the old len back */
1398 give_pwd_free (&pwd
);
1400 return NSS_STATUS_RETURN
;
1403 /* Searches in /etc/passwd and the NIS/NIS+ map for a special user id */
1404 static enum nss_status
1405 internal_getpwuid_r (uid_t uid
, struct passwd
*result
, ent_t
*ent
,
1406 char *buffer
, size_t buflen
, int *errnop
)
1408 struct parser_data
*data
= (void *) buffer
;
1418 fgetpos (ent
->stream
, &pos
);
1419 buffer
[buflen
- 1] = '\xff';
1420 p
= fgets (buffer
, buflen
, ent
->stream
);
1421 if (p
== NULL
&& feof (ent
->stream
))
1422 return NSS_STATUS_NOTFOUND
;
1424 if (p
== NULL
|| buffer
[buflen
- 1] != '\xff')
1426 fsetpos (ent
->stream
, &pos
);
1428 return NSS_STATUS_TRYAGAIN
;
1431 /* Terminate the line for any case. */
1432 buffer
[buflen
- 1] = '\0';
1434 /* Skip leading blanks. */
1435 while (isspace (*p
))
1438 while (*p
== '\0' || *p
== '#' || /* Ignore empty and comment lines. */
1439 /* Parse the line. If it is invalid, loop to
1440 get the next line of the file to parse. */
1441 !(parse_res
= _nss_files_parse_pwent (p
, result
, data
, buflen
,
1444 if (parse_res
== -1)
1446 /* The parser ran out of space. */
1447 fsetpos (ent
->stream
, &pos
);
1449 return NSS_STATUS_TRYAGAIN
;
1452 /* This is a real entry. */
1453 if (result
->pw_name
[0] != '+' && result
->pw_name
[0] != '-')
1455 if (result
->pw_uid
== uid
)
1456 return NSS_STATUS_SUCCESS
;
1462 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] == '@'
1463 && result
->pw_name
[2] != '\0')
1465 char buf
[strlen (result
->pw_name
)];
1466 enum nss_status status
;
1468 strcpy (buf
, &result
->pw_name
[2]);
1470 status
= getpwuid_plususer (uid
, result
, buffer
, buflen
, errnop
);
1471 if (status
== NSS_STATUS_SUCCESS
&&
1472 innetgr (buf
, NULL
, result
->pw_name
, NULL
))
1473 return NSS_STATUS_NOTFOUND
;
1479 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '@'
1480 && result
->pw_name
[2] != '\0')
1482 char buf
[strlen (result
->pw_name
)];
1483 enum nss_status status
;
1485 strcpy (buf
, &result
->pw_name
[2]);
1487 status
= getpwuid_plususer (uid
, result
, buffer
, buflen
, errnop
);
1489 if (status
== NSS_STATUS_RETURN
)
1492 if (status
== NSS_STATUS_SUCCESS
)
1494 if (innetgr (buf
, NULL
, result
->pw_name
, NULL
))
1495 return NSS_STATUS_SUCCESS
;
1498 if (status
== NSS_STATUS_RETURN
) /* We couldn't parse the entry */
1499 return NSS_STATUS_NOTFOUND
;
1507 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] != '\0'
1508 && result
->pw_name
[1] != '@')
1510 char buf
[strlen (result
->pw_name
)];
1511 enum nss_status status
;
1513 strcpy (buf
, &result
->pw_name
[1]);
1515 status
= getpwuid_plususer (uid
, result
, buffer
, buflen
, errnop
);
1516 if (status
== NSS_STATUS_SUCCESS
&&
1517 innetgr (buf
, NULL
, result
->pw_name
, NULL
))
1518 return NSS_STATUS_NOTFOUND
;
1523 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] != '\0'
1524 && result
->pw_name
[1] != '@')
1526 char buf
[strlen (result
->pw_name
)];
1527 enum nss_status status
;
1529 strcpy (buf
, &result
->pw_name
[1]);
1531 status
= getpwuid_plususer (uid
, result
, buffer
, buflen
, errnop
);
1533 if (status
== NSS_STATUS_RETURN
)
1536 if (status
== NSS_STATUS_SUCCESS
)
1538 if (strcmp (buf
, result
->pw_name
) == 0)
1539 return NSS_STATUS_SUCCESS
;
1542 if (status
== NSS_STATUS_RETURN
) /* We couldn't parse the entry */
1543 return NSS_STATUS_NOTFOUND
;
1551 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '\0')
1553 enum nss_status status
;
1555 status
= getpwuid_plususer (uid
, result
, buffer
, buflen
, errnop
);
1556 if (status
== NSS_STATUS_SUCCESS
) /* We found the entry. */
1559 if (status
== NSS_STATUS_RETURN
) /* We couldn't parse the entry */
1560 return NSS_STATUS_NOTFOUND
;
1565 return NSS_STATUS_SUCCESS
;
1569 _nss_compat_getpwuid_r (uid_t uid
, struct passwd
*pwd
,
1570 char *buffer
, size_t buflen
, int *errnop
)
1572 ent_t ent
= {0, 0, 0, NULL
, 0, NULL
, NULL
, {NULL
, 0, 0},
1573 {NULL
, NULL
, 0, 0, NULL
, NULL
, NULL
}};
1574 enum nss_status status
;
1576 __libc_lock_lock (lock
);
1580 __nss_database_lookup ("passwd_compat", NULL
, "nis", &ni
);
1581 use_nisplus
= (strcmp (ni
->name
, "nisplus") == 0);
1584 __libc_lock_unlock (lock
);
1586 status
= internal_setpwent (&ent
);
1587 if (status
!= NSS_STATUS_SUCCESS
)
1590 status
= internal_getpwuid_r (uid
, pwd
, &ent
, buffer
, buflen
, errnop
);
1592 internal_endpwent (&ent
);
1598 /* Support routines for remembering -@netgroup and -user entries.
1599 The names are stored in a single string with `|' as separator. */
1601 blacklist_store_name (const char *name
, ent_t
*ent
)
1603 int namelen
= strlen (name
);
1606 /* first call, setup cache */
1607 if (ent
->blacklist
.size
== 0)
1609 ent
->blacklist
.size
= MAX (BLACKLIST_INITIAL_SIZE
, 2 * namelen
);
1610 ent
->blacklist
.data
= malloc (ent
->blacklist
.size
);
1611 if (ent
->blacklist
.data
== NULL
)
1613 ent
->blacklist
.data
[0] = '|';
1614 ent
->blacklist
.data
[1] = '\0';
1615 ent
->blacklist
.current
= 1;
1619 if (in_blacklist (name
, namelen
, ent
))
1620 return; /* no duplicates */
1622 if (ent
->blacklist
.current
+ namelen
+ 1 >= ent
->blacklist
.size
)
1624 ent
->blacklist
.size
+= MAX (BLACKLIST_INCREMENT
, 2 * namelen
);
1625 tmp
= realloc (ent
->blacklist
.data
, ent
->blacklist
.size
);
1628 free (ent
->blacklist
.data
);
1629 ent
->blacklist
.size
= 0;
1632 ent
->blacklist
.data
= tmp
;
1636 tmp
= stpcpy (ent
->blacklist
.data
+ ent
->blacklist
.current
, name
);
1639 ent
->blacklist
.current
+= namelen
+ 1;
1644 /* returns TRUE if ent->blacklist contains name, else FALSE */
1646 in_blacklist (const char *name
, int namelen
, ent_t
*ent
)
1648 char buf
[namelen
+ 3];
1651 if (ent
->blacklist
.data
== NULL
)
1655 cp
= stpcpy (&buf
[1], name
);
1658 return strstr (ent
->blacklist
.data
, buf
) != NULL
;