]>
git.ipfire.org Git - thirdparty/glibc.git/blob - 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.
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.
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.
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. */
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
= NULL
;
38 static bool_t use_nisplus
= FALSE
; /* default: passwd_compat: nis */
39 static nis_name pwdtable
= NULL
; /* Name of the pwd table */
40 static size_t pwdtablelen
= 0;
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 internal_setpwent (ent_t
*ent
)
191 enum nss_status status
= NSS_STATUS_SUCCESS
;
193 ent
->nis
= ent
->first
= ent
->netgroup
= 0;
195 /* If something was left over free it. */
197 __internal_endnetgrent (&ent
->netgrdata
);
199 if (ent
->oldkey
!= NULL
)
206 if (ent
->result
!= NULL
)
208 nis_freeresult (ent
->result
);
212 if (pwdtable
== NULL
)
214 static const char key
[] = "passwd.org_dir.";
215 const char *local_dir
= nis_local_directory ();
216 size_t len_local_dir
= strlen (local_dir
);
218 pwdtable
= malloc (sizeof (key
) + len_local_dir
);
219 if (pwdtable
== NULL
)
220 return NSS_STATUS_TRYAGAIN
;
222 pwdtablelen
= ((char *) mempcpy (mempcpy (pwdtable
,
223 key
, sizeof (key
) - 1),
224 local_dir
, len_local_dir
+ 1)
228 if (ent
->blacklist
.data
!= NULL
)
230 ent
->blacklist
.current
= 1;
231 ent
->blacklist
.data
[0] = '|';
232 ent
->blacklist
.data
[1] = '\0';
235 ent
->blacklist
.current
= 0;
237 if (ent
->stream
== NULL
)
239 ent
->stream
= fopen ("/etc/passwd", "r");
241 if (ent
->stream
== NULL
)
242 status
= errno
== EAGAIN
? NSS_STATUS_TRYAGAIN
: NSS_STATUS_UNAVAIL
;
245 /* We have to make sure the file is `closed on exec'. */
248 result
= flags
= fcntl (fileno (ent
->stream
), F_GETFD
, 0);
252 result
= fcntl (fileno (ent
->stream
), F_SETFD
, flags
);
256 /* Something went wrong. Close the stream and return a
258 fclose (ent
->stream
);
260 status
= NSS_STATUS_UNAVAIL
;
265 rewind (ent
->stream
);
267 give_pwd_free (&ent
->pwd
);
274 _nss_compat_setpwent (void)
276 enum nss_status result
;
278 __libc_lock_lock (lock
);
282 __nss_database_lookup ("passwd_compat", NULL
, "nis", &ni
);
283 use_nisplus
= (strcmp (ni
->name
, "nisplus") == 0);
286 result
= internal_setpwent (&ext_ent
);
288 __libc_lock_unlock (lock
);
294 static enum nss_status
295 internal_endpwent (ent_t
*ent
)
297 if (ent
->stream
!= NULL
)
299 fclose (ent
->stream
);
304 __internal_endnetgrent (&ent
->netgrdata
);
306 ent
->nis
= ent
->first
= ent
->netgroup
= 0;
308 if (ent
->oldkey
!= NULL
)
315 if (ent
->result
!= NULL
)
317 nis_freeresult (ent
->result
);
321 if (ent
->blacklist
.data
!= NULL
)
323 ent
->blacklist
.current
= 1;
324 ent
->blacklist
.data
[0] = '|';
325 ent
->blacklist
.data
[1] = '\0';
328 ent
->blacklist
.current
= 0;
330 give_pwd_free (&ent
->pwd
);
332 return NSS_STATUS_SUCCESS
;
336 _nss_compat_endpwent (void)
338 enum nss_status result
;
340 __libc_lock_lock (lock
);
342 result
= internal_endpwent (&ext_ent
);
344 __libc_lock_unlock (lock
);
349 static enum nss_status
350 getpwent_next_nis_netgr (const char *name
, struct passwd
*result
, ent_t
*ent
,
351 char *group
, char *buffer
, size_t buflen
, int *errnop
)
353 struct parser_data
*data
= (void *) buffer
;
354 char *ypdomain
, *host
, *user
, *domain
, *outval
, *p
, *p2
;
355 int status
, outvallen
;
358 if (yp_get_default_domain (&ypdomain
) != YPERR_SUCCESS
)
362 give_pwd_free (&ent
->pwd
);
363 return NSS_STATUS_UNAVAIL
;
366 if (ent
->first
== TRUE
)
368 memset (&ent
->netgrdata
, 0, sizeof (struct __netgrent
));
369 __internal_setnetgrent (group
, &ent
->netgrdata
);
378 saved_cursor
= ent
->netgrdata
.cursor
;
379 status
= __internal_getnetgrent_r (&host
, &user
, &domain
,
380 &ent
->netgrdata
, buffer
, buflen
,
384 __internal_endnetgrent (&ent
->netgrdata
);
386 give_pwd_free (&ent
->pwd
);
387 return NSS_STATUS_RETURN
;
390 if (user
== NULL
|| user
[0] == '-')
393 if (domain
!= NULL
&& strcmp (ypdomain
, domain
) != 0)
396 /* If name != NULL, we are called from getpwnam */
398 if (strcmp (user
, name
) != 0)
401 if (yp_match (ypdomain
, "passwd.byname", user
,
402 strlen (user
), &outval
, &outvallen
)
406 p2len
= pwd_need_buflen (&ent
->pwd
);
410 return NSS_STATUS_TRYAGAIN
;
412 p2
= buffer
+ (buflen
- p2len
);
414 p
= strncpy (buffer
, outval
, buflen
);
418 parse_res
= _nss_files_parse_pwent (p
, result
, data
, buflen
, errnop
);
421 ent
->netgrdata
.cursor
= saved_cursor
;
422 return NSS_STATUS_TRYAGAIN
;
427 /* Store the User in the blacklist for the "+" at the end of
429 blacklist_store_name (result
->pw_name
, ent
);
430 copy_pwd_changes (result
, &ent
->pwd
, p2
, p2len
);
435 return NSS_STATUS_SUCCESS
;
438 static enum nss_status
439 getpwent_next_nisplus_netgr (const char *name
, struct passwd
*result
,
440 ent_t
*ent
, char *group
, char *buffer
,
441 size_t buflen
, int *errnop
)
443 char *ypdomain
, *host
, *user
, *domain
, *p2
;
444 int status
, parse_res
;
448 /* Maybe we should use domainname here ? We need the current
449 domainname for the domain field in netgroups */
450 if (yp_get_default_domain (&ypdomain
) != YPERR_SUCCESS
)
454 give_pwd_free (&ent
->pwd
);
455 return NSS_STATUS_UNAVAIL
;
458 if (ent
->first
== TRUE
)
460 bzero (&ent
->netgrdata
, sizeof (struct __netgrent
));
461 __internal_setnetgrent (group
, &ent
->netgrdata
);
469 saved_cursor
= ent
->netgrdata
.cursor
;
470 status
= __internal_getnetgrent_r (&host
, &user
, &domain
,
471 &ent
->netgrdata
, buffer
, buflen
,
475 __internal_endnetgrent (&ent
->netgrdata
);
477 give_pwd_free (&ent
->pwd
);
478 return NSS_STATUS_RETURN
;
481 if (user
== NULL
|| user
[0] == '-')
484 if (domain
!= NULL
&& strcmp (ypdomain
, domain
) != 0)
487 /* If name != NULL, we are called from getpwnam */
489 if (strcmp (user
, name
) != 0)
492 p2len
= pwd_need_buflen (&ent
->pwd
);
496 return NSS_STATUS_TRYAGAIN
;
498 p2
= buffer
+ (buflen
- p2len
);
501 char buf
[strlen (user
) + 30 + pwdtablelen
];
502 sprintf(buf
, "[name=%s],%s", user
, pwdtable
);
503 nisres
= nis_list(buf
, FOLLOW_PATH
| FOLLOW_LINKS
, NULL
, NULL
);
505 if (niserr2nss (nisres
->status
) != NSS_STATUS_SUCCESS
)
507 nis_freeresult (nisres
);
510 parse_res
= _nss_nisplus_parse_pwent (nisres
, result
, buffer
,
514 nis_freeresult (nisres
);
515 ent
->netgrdata
.cursor
= saved_cursor
;
517 return NSS_STATUS_TRYAGAIN
;
519 nis_freeresult (nisres
);
523 /* Store the User in the blacklist for the "+" at the end of
525 blacklist_store_name (result
->pw_name
, ent
);
526 copy_pwd_changes (result
, &ent
->pwd
, p2
, p2len
);
531 return NSS_STATUS_SUCCESS
;
534 /* get the next user from NIS+ (+ entry) */
535 static enum nss_status
536 getpwent_next_nisplus (struct passwd
*result
, ent_t
*ent
, char *buffer
,
537 size_t buflen
, int *errnop
)
543 p2len
= pwd_need_buflen (&ent
->pwd
);
547 return NSS_STATUS_TRYAGAIN
;
549 p2
= buffer
+ (buflen
- p2len
);
554 nis_result
*saved_res
;
559 saved_res
= ent
->result
;
561 ent
->result
= nis_first_entry (pwdtable
);
562 if (niserr2nss (ent
->result
->status
) != NSS_STATUS_SUCCESS
)
565 give_pwd_free (&ent
->pwd
);
566 return niserr2nss (ent
->result
->status
);
574 res
= nis_next_entry (pwdtable
, &ent
->result
->cookie
);
575 saved_res
= ent
->result
;
578 if (niserr2nss (ent
->result
->status
) != NSS_STATUS_SUCCESS
)
581 nis_freeresult (saved_res
);
582 give_pwd_free (&ent
->pwd
);
583 return niserr2nss (ent
->result
->status
);
586 parse_res
= _nss_nisplus_parse_pwent (ent
->result
, result
, buffer
,
590 nis_freeresult (ent
->result
);
591 ent
->result
= saved_res
;
592 ent
->first
= saved_first
;
594 return NSS_STATUS_TRYAGAIN
;
599 nis_freeresult (saved_res
);
603 in_blacklist (result
->pw_name
, strlen (result
->pw_name
), ent
))
604 parse_res
= 0; /* if result->pw_name in blacklist,search next entry */
608 copy_pwd_changes (result
, &ent
->pwd
, p2
, p2len
);
610 return NSS_STATUS_SUCCESS
;
613 static enum nss_status
614 getpwent_next_nis (struct passwd
*result
, ent_t
*ent
, char *buffer
,
615 size_t buflen
, int *errnop
)
617 struct parser_data
*data
= (void *) buffer
;
618 char *domain
, *outkey
, *outval
, *p
, *p2
;
619 int outkeylen
, outvallen
, parse_res
;
622 if (yp_get_default_domain (&domain
) != YPERR_SUCCESS
)
625 give_pwd_free (&ent
->pwd
);
626 return NSS_STATUS_UNAVAIL
;
629 p2len
= pwd_need_buflen (&ent
->pwd
);
633 return NSS_STATUS_TRYAGAIN
;
635 p2
= buffer
+ (buflen
- p2len
);
645 if (yp_first (domain
, "passwd.byname", &outkey
, &outkeylen
,
646 &outval
, &outvallen
) != YPERR_SUCCESS
)
649 give_pwd_free (&ent
->pwd
);
650 return NSS_STATUS_UNAVAIL
;
654 saved_oldkey
= ent
->oldkey
;
655 saved_oldlen
= ent
->oldkeylen
;
656 ent
->oldkey
= outkey
;
657 ent
->oldkeylen
= outkeylen
;
662 if (yp_next (domain
, "passwd.byname", ent
->oldkey
, ent
->oldkeylen
,
663 &outkey
, &outkeylen
, &outval
, &outvallen
)
667 give_pwd_free (&ent
->pwd
);
668 return NSS_STATUS_NOTFOUND
;
672 saved_oldkey
= ent
->oldkey
;
673 saved_oldlen
= ent
->oldkeylen
;
674 ent
->oldkey
= outkey
;
675 ent
->oldkeylen
= outkeylen
;
678 /* Copy the found data to our buffer */
679 p
= strncpy (buffer
, outval
, buflen
);
681 /* ...and free the data. */
686 parse_res
= _nss_files_parse_pwent (p
, result
, data
, buflen
, errnop
);
690 ent
->oldkey
= saved_oldkey
;
691 ent
->oldkeylen
= saved_oldlen
;
692 ent
->first
= saved_first
;
694 return NSS_STATUS_TRYAGAIN
;
702 && in_blacklist (result
->pw_name
, strlen (result
->pw_name
), ent
))
707 copy_pwd_changes (result
, &ent
->pwd
, p2
, p2len
);
709 return NSS_STATUS_SUCCESS
;
712 /* This function handle the +user entrys in /etc/passwd */
713 static enum nss_status
714 getpwnam_plususer (const char *name
, struct passwd
*result
, char *buffer
,
715 size_t buflen
, int *errnop
)
717 struct parser_data
*data
= (void *) buffer
;
723 memset (&pwd
, '\0', sizeof (struct passwd
));
725 copy_pwd_changes (&pwd
, result
, NULL
, 0);
727 plen
= pwd_need_buflen (&pwd
);
731 return NSS_STATUS_TRYAGAIN
;
733 p
= buffer
+ (buflen
- plen
);
736 if (use_nisplus
) /* Do the NIS+ query here */
739 char buf
[strlen (name
) + 24 + pwdtablelen
];
741 sprintf(buf
, "[name=%s],%s", name
, pwdtable
);
742 res
= nis_list(buf
, FOLLOW_PATH
| FOLLOW_LINKS
, NULL
, NULL
);
743 if (niserr2nss (res
->status
) != NSS_STATUS_SUCCESS
)
745 enum nss_status status
= niserr2nss (res
->status
);
747 nis_freeresult (res
);
750 parse_res
= _nss_nisplus_parse_pwent (res
, result
, buffer
,
754 nis_freeresult (res
);
756 return NSS_STATUS_TRYAGAIN
;
758 nis_freeresult (res
);
762 char *domain
, *outval
, *ptr
;
765 if (yp_get_default_domain (&domain
) != YPERR_SUCCESS
)
766 return NSS_STATUS_NOTFOUND
;
768 if (yp_match (domain
, "passwd.byname", name
, strlen (name
),
769 &outval
, &outvallen
) != YPERR_SUCCESS
)
770 return NSS_STATUS_NOTFOUND
;
772 ptr
= strncpy (buffer
, outval
, buflen
< (size_t) outvallen
?
773 buflen
: (size_t) outvallen
);
774 buffer
[buflen
< (size_t) outvallen
? buflen
: (size_t) outvallen
] = '\0';
776 while (isspace (*ptr
))
778 parse_res
= _nss_files_parse_pwent (ptr
, result
, data
, buflen
, errnop
);
780 return NSS_STATUS_TRYAGAIN
;
785 copy_pwd_changes (result
, &pwd
, p
, plen
);
786 give_pwd_free (&pwd
);
787 /* We found the entry. */
788 return NSS_STATUS_SUCCESS
;
792 /* Give buffer the old len back */
794 give_pwd_free (&pwd
);
796 return NSS_STATUS_RETURN
;
799 static enum nss_status
800 getpwent_next_file (struct passwd
*result
, ent_t
*ent
,
801 char *buffer
, size_t buflen
, int *errnop
)
803 struct parser_data
*data
= (void *) buffer
;
812 fgetpos (ent
->stream
, &pos
);
813 p
= fgets (buffer
, buflen
, ent
->stream
);
816 if (feof (ent
->stream
))
817 return NSS_STATUS_NOTFOUND
;
820 fsetpos (ent
->stream
, &pos
);
822 return NSS_STATUS_TRYAGAIN
;
826 /* Terminate the line for any case. */
827 buffer
[buflen
- 1] = '\0';
829 /* Skip leading blanks. */
833 while (*p
== '\0' || *p
== '#' || /* Ignore empty and comment lines. */
834 /* Parse the line. If it is invalid, loop to
835 get the next line of the file to parse. */
836 !(parse_res
= _nss_files_parse_pwent (p
, result
, data
, buflen
,
841 /* The parser ran out of space. */
842 fsetpos (ent
->stream
, &pos
);
844 return NSS_STATUS_TRYAGAIN
;
847 if (result
->pw_name
[0] != '+' && result
->pw_name
[0] != '-')
848 /* This is a real entry. */
852 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] == '@'
853 && result
->pw_name
[2] != '\0')
855 /* XXX Do not use fixed length buffer. */
857 char *user
, *host
, *domain
;
858 struct __netgrent netgrdata
;
860 bzero (&netgrdata
, sizeof (struct __netgrent
));
861 __internal_setnetgrent (&result
->pw_name
[2], &netgrdata
);
862 while (__internal_getnetgrent_r (&host
, &user
, &domain
, &netgrdata
,
863 buf2
, sizeof (buf2
), errnop
))
865 if (user
!= NULL
&& user
[0] != '-')
866 blacklist_store_name (user
, ent
);
868 __internal_endnetgrent (&netgrdata
);
873 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '@'
874 && result
->pw_name
[2] != '\0')
878 ent
->netgroup
= TRUE
;
880 copy_pwd_changes (&ent
->pwd
, result
, NULL
, 0);
883 status
= getpwent_next_nisplus_netgr (NULL
, result
, ent
,
885 buffer
, buflen
, errnop
);
887 status
= getpwent_next_nis_netgr (NULL
, result
, ent
,
889 buffer
, buflen
, errnop
);
890 if (status
== NSS_STATUS_RETURN
)
897 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] != '\0'
898 && result
->pw_name
[1] != '@')
900 blacklist_store_name (&result
->pw_name
[1], ent
);
905 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] != '\0'
906 && result
->pw_name
[1] != '@')
908 enum nss_status status
;
910 /* Store the User in the blacklist for the "+" at the end of
912 blacklist_store_name (&result
->pw_name
[1], ent
);
913 status
= getpwnam_plususer (&result
->pw_name
[1], result
, buffer
,
915 if (status
== NSS_STATUS_SUCCESS
) /* We found the entry. */
918 if (status
== NSS_STATUS_RETURN
/* We couldn't parse the entry */
919 || status
== NSS_STATUS_NOTFOUND
) /* entry doesn't exist */
923 if (status
== NSS_STATUS_TRYAGAIN
)
925 /* The parser ran out of space */
926 fsetpos (ent
->stream
, &pos
);
934 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '\0')
938 copy_pwd_changes (&ent
->pwd
, result
, NULL
, 0);
941 return getpwent_next_nisplus (result
, ent
, buffer
, buflen
, errnop
);
943 return getpwent_next_nis (result
, ent
, buffer
, buflen
, errnop
);
947 return NSS_STATUS_SUCCESS
;
951 static enum nss_status
952 internal_getpwent_r (struct passwd
*pw
, ent_t
*ent
, char *buffer
,
953 size_t buflen
, int *errnop
)
959 /* We are searching members in a netgroup */
960 /* Since this is not the first call, we don't need the group name */
962 status
= getpwent_next_nisplus_netgr (NULL
, pw
, ent
, NULL
, buffer
,
965 status
= getpwent_next_nis_netgr (NULL
, pw
, ent
, NULL
, buffer
, buflen
,
967 if (status
== NSS_STATUS_RETURN
)
968 return getpwent_next_file (pw
, ent
, buffer
, buflen
, errnop
);
976 return getpwent_next_nisplus (pw
, ent
, buffer
, buflen
, errnop
);
978 return getpwent_next_nis (pw
, ent
, buffer
, buflen
, errnop
);
981 return getpwent_next_file (pw
, ent
, buffer
, buflen
, errnop
);
985 _nss_compat_getpwent_r (struct passwd
*pwd
, char *buffer
, size_t buflen
,
988 enum nss_status status
= NSS_STATUS_SUCCESS
;
990 __libc_lock_lock (lock
);
994 __nss_database_lookup ("passwd_compat", NULL
, "nis", &ni
);
995 use_nisplus
= (strcmp (ni
->name
, "nisplus") == 0);
998 /* Be prepared that the setpwent function was not called before. */
999 if (ext_ent
.stream
== NULL
)
1000 status
= internal_setpwent (&ext_ent
);
1002 if (status
== NSS_STATUS_SUCCESS
)
1003 status
= internal_getpwent_r (pwd
, &ext_ent
, buffer
, buflen
, errnop
);
1005 __libc_lock_unlock (lock
);
1010 /* Searches in /etc/passwd and the NIS/NIS+ map for a special user */
1011 static enum nss_status
1012 internal_getpwnam_r (const char *name
, struct passwd
*result
, ent_t
*ent
,
1013 char *buffer
, size_t buflen
, int *errnop
)
1015 struct parser_data
*data
= (void *) buffer
;
1025 fgetpos (ent
->stream
, &pos
);
1026 p
= fgets (buffer
, buflen
, ent
->stream
);
1029 if (feof (ent
->stream
))
1030 return NSS_STATUS_NOTFOUND
;
1033 fsetpos (ent
->stream
, &pos
);
1035 return NSS_STATUS_TRYAGAIN
;
1039 /* Terminate the line for any case. */
1040 buffer
[buflen
- 1] = '\0';
1042 /* Skip leading blanks. */
1043 while (isspace (*p
))
1046 while (*p
== '\0' || *p
== '#' || /* Ignore empty and comment lines. */
1047 /* Parse the line. If it is invalid, loop to
1048 get the next line of the file to parse. */
1049 !(parse_res
= _nss_files_parse_pwent (p
, result
, data
, buflen
,
1052 if (parse_res
== -1)
1054 /* The parser ran out of space. */
1055 fsetpos (ent
->stream
, &pos
);
1057 return NSS_STATUS_TRYAGAIN
;
1060 /* This is a real entry. */
1061 if (result
->pw_name
[0] != '+' && result
->pw_name
[0] != '-')
1063 if (strcmp (result
->pw_name
, name
) == 0)
1064 return NSS_STATUS_SUCCESS
;
1070 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] == '@'
1071 && result
->pw_name
[2] != '\0')
1073 /* XXX Do not use fixed length buffers. */
1075 char *user
, *host
, *domain
;
1076 struct __netgrent netgrdata
;
1078 bzero (&netgrdata
, sizeof (struct __netgrent
));
1079 __internal_setnetgrent (&result
->pw_name
[2], &netgrdata
);
1080 while (__internal_getnetgrent_r (&host
, &user
, &domain
, &netgrdata
,
1081 buf2
, sizeof (buf2
), errnop
))
1083 if (user
!= NULL
&& user
[0] != '-')
1084 if (strcmp (user
, name
) == 0)
1085 return NSS_STATUS_NOTFOUND
;
1087 __internal_endnetgrent (&netgrdata
);
1092 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '@'
1093 && result
->pw_name
[2] != '\0')
1095 char buf
[strlen (result
->pw_name
)];
1098 strcpy (buf
, &result
->pw_name
[2]);
1099 ent
->netgroup
= TRUE
;
1101 copy_pwd_changes (&ent
->pwd
, result
, NULL
, 0);
1106 status
= getpwent_next_nisplus_netgr (name
, result
, ent
, buf
,
1107 buffer
, buflen
, errnop
);
1109 status
= getpwent_next_nis_netgr (name
, result
, ent
, buf
,
1110 buffer
, buflen
, errnop
);
1111 if (status
== NSS_STATUS_RETURN
)
1114 if (status
== NSS_STATUS_SUCCESS
&&
1115 strcmp (result
->pw_name
, name
) == 0)
1116 return NSS_STATUS_SUCCESS
;
1117 } while (status
== NSS_STATUS_SUCCESS
);
1122 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] != '\0'
1123 && result
->pw_name
[1] != '@')
1125 if (strcmp (&result
->pw_name
[1], name
) == 0)
1126 return NSS_STATUS_NOTFOUND
;
1132 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] != '\0'
1133 && result
->pw_name
[1] != '@')
1135 if (strcmp (name
, &result
->pw_name
[1]) == 0)
1137 enum nss_status status
;
1139 status
= getpwnam_plususer (name
, result
, buffer
, buflen
,
1141 if (status
== NSS_STATUS_RETURN
)
1142 /* We couldn't parse the entry */
1143 return NSS_STATUS_NOTFOUND
;
1150 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '\0')
1152 enum nss_status status
;
1154 status
= getpwnam_plususer (name
, result
, buffer
, buflen
, errnop
);
1155 if (status
== NSS_STATUS_SUCCESS
) /* We found the entry. */
1158 if (status
== NSS_STATUS_RETURN
) /* We couldn't parse the entry */
1159 return NSS_STATUS_NOTFOUND
;
1164 return NSS_STATUS_SUCCESS
;
1168 _nss_compat_getpwnam_r (const char *name
, struct passwd
*pwd
,
1169 char *buffer
, size_t buflen
, int *errnop
)
1171 ent_t ent
= {0, 0, 0, NULL
, 0, NULL
, NULL
, {NULL
, 0, 0},
1172 {NULL
, NULL
, 0, 0, NULL
, NULL
, NULL
}};
1173 enum nss_status status
;
1175 if (name
[0] == '-' || name
[0] == '+')
1176 return NSS_STATUS_NOTFOUND
;
1178 __libc_lock_lock (lock
);
1182 __nss_database_lookup ("passwd_compat", NULL
, "nis", &ni
);
1183 use_nisplus
= (strcmp (ni
->name
, "nisplus") == 0);
1186 __libc_lock_unlock (lock
);
1188 status
= internal_setpwent (&ent
);
1189 if (status
!= NSS_STATUS_SUCCESS
)
1192 status
= internal_getpwnam_r (name
, pwd
, &ent
, buffer
, buflen
, errnop
);
1194 internal_endpwent (&ent
);
1199 /* This function handle the + entry in /etc/passwd for getpwuid */
1200 static enum nss_status
1201 getpwuid_plususer (uid_t uid
, struct passwd
*result
, char *buffer
,
1202 size_t buflen
, int *errnop
)
1204 struct parser_data
*data
= (void *) buffer
;
1210 memset (&pwd
, '\0', sizeof (struct passwd
));
1212 copy_pwd_changes (&pwd
, result
, NULL
, 0);
1214 plen
= pwd_need_buflen (&pwd
);
1218 return NSS_STATUS_TRYAGAIN
;
1220 p
= buffer
+ (buflen
- plen
);
1223 if (use_nisplus
) /* Do the NIS+ query here */
1226 char buf
[1024 + pwdtablelen
];
1228 snprintf(buf
, sizeof (buf
), "[uid=%d],%s", uid
, pwdtable
);
1229 res
= nis_list(buf
, FOLLOW_PATH
| FOLLOW_LINKS
, NULL
, NULL
);
1230 if (niserr2nss (res
->status
) != NSS_STATUS_SUCCESS
)
1232 enum nss_status status
= niserr2nss (res
->status
);
1234 nis_freeresult (res
);
1237 if ((parse_res
= _nss_nisplus_parse_pwent (res
, result
, buffer
,
1238 buflen
, errnop
)) == -1)
1240 nis_freeresult (res
);
1242 return NSS_STATUS_TRYAGAIN
;
1244 nis_freeresult (res
);
1249 char *domain
, *outval
, *ptr
;
1252 if (yp_get_default_domain (&domain
) != YPERR_SUCCESS
)
1255 return NSS_STATUS_TRYAGAIN
;
1258 sprintf (buf
, "%d", uid
);
1259 if (yp_match (domain
, "passwd.byuid", buf
, strlen (buf
),
1260 &outval
, &outvallen
)
1264 return NSS_STATUS_TRYAGAIN
;
1266 ptr
= strncpy (buffer
, outval
, buflen
< (size_t) outvallen
?
1267 buflen
: (size_t) outvallen
);
1268 buffer
[buflen
< (size_t) outvallen
? buflen
: (size_t) outvallen
] = '\0';
1270 while (isspace (*ptr
))
1272 parse_res
= _nss_files_parse_pwent (ptr
, result
, data
, buflen
, errnop
);
1273 if (parse_res
== -1)
1274 return NSS_STATUS_TRYAGAIN
;
1279 copy_pwd_changes (result
, &pwd
, p
, plen
);
1280 give_pwd_free (&pwd
);
1281 /* We found the entry. */
1282 return NSS_STATUS_SUCCESS
;
1286 /* Give buffer the old len back */
1288 give_pwd_free (&pwd
);
1290 return NSS_STATUS_RETURN
;
1293 /* Searches in /etc/passwd and the NIS/NIS+ map for a special user id */
1294 static enum nss_status
1295 internal_getpwuid_r (uid_t uid
, struct passwd
*result
, ent_t
*ent
,
1296 char *buffer
, size_t buflen
, int *errnop
)
1298 struct parser_data
*data
= (void *) buffer
;
1308 fgetpos (ent
->stream
, &pos
);
1309 p
= fgets (buffer
, buflen
, ent
->stream
);
1312 if (feof (ent
->stream
))
1313 return NSS_STATUS_NOTFOUND
;
1316 fsetpos (ent
->stream
, &pos
);
1318 return NSS_STATUS_TRYAGAIN
;
1322 /* Terminate the line for any case. */
1323 buffer
[buflen
- 1] = '\0';
1325 /* Skip leading blanks. */
1326 while (isspace (*p
))
1329 while (*p
== '\0' || *p
== '#' || /* Ignore empty and comment lines. */
1330 /* Parse the line. If it is invalid, loop to
1331 get the next line of the file to parse. */
1332 !(parse_res
= _nss_files_parse_pwent (p
, result
, data
, buflen
,
1335 if (parse_res
== -1)
1337 /* The parser ran out of space. */
1338 fsetpos (ent
->stream
, &pos
);
1340 return NSS_STATUS_TRYAGAIN
;
1343 /* This is a real entry. */
1344 if (result
->pw_name
[0] != '+' && result
->pw_name
[0] != '-')
1346 if (result
->pw_uid
== uid
)
1347 return NSS_STATUS_SUCCESS
;
1353 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] == '@'
1354 && result
->pw_name
[2] != '\0')
1356 /* XXX Do not use fixed length buffers. */
1358 char *user
, *host
, *domain
;
1359 struct __netgrent netgrdata
;
1361 bzero (&netgrdata
, sizeof (struct __netgrent
));
1362 __internal_setnetgrent (&result
->pw_name
[2], &netgrdata
);
1363 while (__internal_getnetgrent_r (&host
, &user
, &domain
, &netgrdata
,
1364 buf2
, sizeof (buf2
), errnop
))
1366 if (user
!= NULL
&& user
[0] != '-')
1367 blacklist_store_name (user
, ent
);
1369 __internal_endnetgrent (&netgrdata
);
1374 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '@'
1375 && result
->pw_name
[2] != '\0')
1377 char buf
[strlen (result
->pw_name
)];
1380 strcpy (buf
, &result
->pw_name
[2]);
1381 ent
->netgroup
= TRUE
;
1383 copy_pwd_changes (&ent
->pwd
, result
, NULL
, 0);
1388 status
= getpwent_next_nisplus_netgr (NULL
, result
, ent
, buf
,
1389 buffer
, buflen
, errnop
);
1391 status
= getpwent_next_nis_netgr (NULL
, result
, ent
, buf
,
1392 buffer
, buflen
, errnop
);
1393 if (status
== NSS_STATUS_RETURN
)
1396 if (status
== NSS_STATUS_SUCCESS
&& uid
== result
->pw_uid
)
1397 return NSS_STATUS_SUCCESS
;
1398 } while (status
== NSS_STATUS_SUCCESS
);
1403 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] != '\0'
1404 && result
->pw_name
[1] != '@')
1406 blacklist_store_name (&result
->pw_name
[1], ent
);
1411 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] != '\0'
1412 && result
->pw_name
[1] != '@')
1414 enum nss_status status
;
1416 /* Store the User in the blacklist for the "+" at the end of
1418 blacklist_store_name (&result
->pw_name
[1], ent
);
1419 status
= getpwnam_plususer (&result
->pw_name
[1], result
, buffer
,
1421 if (status
== NSS_STATUS_SUCCESS
&& result
->pw_uid
== uid
)
1428 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '\0')
1430 enum nss_status status
;
1432 status
= getpwuid_plususer (uid
, result
, buffer
, buflen
, errnop
);
1433 if (status
== NSS_STATUS_SUCCESS
) /* We found the entry. */
1436 if (status
== NSS_STATUS_RETURN
) /* We couldn't parse the entry */
1437 return NSS_STATUS_NOTFOUND
;
1442 return NSS_STATUS_SUCCESS
;
1446 _nss_compat_getpwuid_r (uid_t uid
, struct passwd
*pwd
,
1447 char *buffer
, size_t buflen
, int *errnop
)
1449 ent_t ent
= {0, 0, 0, NULL
, 0, NULL
, NULL
, {NULL
, 0, 0},
1450 {NULL
, NULL
, 0, 0, NULL
, NULL
, NULL
}};
1451 enum nss_status status
;
1453 __libc_lock_lock (lock
);
1457 __nss_database_lookup ("passwd_compat", NULL
, "nis", &ni
);
1458 use_nisplus
= (strcmp (ni
->name
, "nisplus") == 0);
1461 __libc_lock_unlock (lock
);
1463 status
= internal_setpwent (&ent
);
1464 if (status
!= NSS_STATUS_SUCCESS
)
1467 status
= internal_getpwuid_r (uid
, pwd
, &ent
, buffer
, buflen
, errnop
);
1469 internal_endpwent (&ent
);
1475 /* Support routines for remembering -@netgroup and -user entries.
1476 The names are stored in a single string with `|' as separator. */
1478 blacklist_store_name (const char *name
, ent_t
*ent
)
1480 int namelen
= strlen (name
);
1483 /* first call, setup cache */
1484 if (ent
->blacklist
.size
== 0)
1486 ent
->blacklist
.size
= MAX (BLACKLIST_INITIAL_SIZE
, 2 * namelen
);
1487 ent
->blacklist
.data
= malloc (ent
->blacklist
.size
);
1488 if (ent
->blacklist
.data
== NULL
)
1490 ent
->blacklist
.data
[0] = '|';
1491 ent
->blacklist
.data
[1] = '\0';
1492 ent
->blacklist
.current
= 1;
1496 if (in_blacklist (name
, namelen
, ent
))
1497 return; /* no duplicates */
1499 if (ent
->blacklist
.current
+ namelen
+ 1 >= ent
->blacklist
.size
)
1501 ent
->blacklist
.size
+= MAX (BLACKLIST_INCREMENT
, 2 * namelen
);
1502 tmp
= realloc (ent
->blacklist
.data
, ent
->blacklist
.size
);
1505 free (ent
->blacklist
.data
);
1506 ent
->blacklist
.size
= 0;
1509 ent
->blacklist
.data
= tmp
;
1513 tmp
= stpcpy (ent
->blacklist
.data
+ ent
->blacklist
.current
, name
);
1516 ent
->blacklist
.current
+= namelen
+ 1;
1521 /* returns TRUE if ent->blacklist contains name, else FALSE */
1523 in_blacklist (const char *name
, int namelen
, ent_t
*ent
)
1525 char buf
[namelen
+ 3];
1528 if (ent
->blacklist
.data
== NULL
)
1532 cp
= stpcpy (&buf
[1], name
);
1535 return strstr (ent
->blacklist
.data
, buf
) != NULL
;