1 /* Copyright (C) 1996, 1997, 1998 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. */
21 #include <glibc-compat/include/pwd.h>
25 #include <glibc-compat/include/netdb.h>
27 #include <bits/libc-lock.h>
28 #include <rpcsvc/yp.h>
29 #include <rpcsvc/ypclnt.h>
34 /* Get the declaration of the parser function. */
36 #define STRUCTURE passwd
38 #include "../nss_files/files-parse.c"
40 /* Structure for remembering -@netgroup and -user members ... */
41 #define BLACKLIST_INITIAL_SIZE 512
42 #define BLACKLIST_INCREMENT 256
58 struct blacklist_t blacklist
;
60 struct __netgrent netgrdata
;
62 typedef struct ent_t ent_t
;
64 static ent_t ext_ent
= {0, 0, 0, NULL
, 0, NULL
, {NULL
, 0, 0},
65 {NULL
, NULL
, 0, 0, NULL
, NULL
, NULL
}};
67 /* Protect global state against multiple changers. */
68 __libc_lock_define_initialized (static, lock
)
70 /* Prototypes for local functions. */
71 static void blacklist_store_name (const char *, ent_t
*);
72 static int in_blacklist (const char *, int, ent_t
*);
75 give_pwd_free (struct passwd
*pwd
)
77 if (pwd
->pw_name
!= NULL
)
79 if (pwd
->pw_passwd
!= NULL
)
80 free (pwd
->pw_passwd
);
81 if (pwd
->pw_gecos
!= NULL
)
83 if (pwd
->pw_dir
!= NULL
)
85 if (pwd
->pw_shell
!= NULL
)
88 memset (pwd
, '\0', sizeof (struct passwd
));
92 pwd_need_buflen (struct passwd
*pwd
)
96 if (pwd
->pw_passwd
!= NULL
)
97 len
+= strlen (pwd
->pw_passwd
) + 1;
99 if (pwd
->pw_gecos
!= NULL
)
100 len
+= strlen (pwd
->pw_gecos
) + 1;
102 if (pwd
->pw_dir
!= NULL
)
103 len
+= strlen (pwd
->pw_dir
) + 1;
105 if (pwd
->pw_shell
!= NULL
)
106 len
+= strlen (pwd
->pw_shell
) + 1;
112 copy_pwd_changes (struct passwd
*dest
, struct passwd
*src
,
113 char *buffer
, size_t buflen
)
115 if (src
->pw_passwd
!= NULL
&& strlen (src
->pw_passwd
))
118 dest
->pw_passwd
= strdup (src
->pw_passwd
);
119 else if (dest
->pw_passwd
&&
120 strlen (dest
->pw_passwd
) >= strlen (src
->pw_passwd
))
121 strcpy (dest
->pw_passwd
, src
->pw_passwd
);
124 dest
->pw_passwd
= buffer
;
125 strcpy (dest
->pw_passwd
, src
->pw_passwd
);
126 buffer
+= strlen (dest
->pw_passwd
) + 1;
127 buflen
= buflen
- (strlen (dest
->pw_passwd
) + 1);
131 if (src
->pw_gecos
!= NULL
&& strlen (src
->pw_gecos
))
134 dest
->pw_gecos
= strdup (src
->pw_gecos
);
135 else if (dest
->pw_gecos
&&
136 strlen (dest
->pw_gecos
) >= strlen (src
->pw_gecos
))
137 strcpy (dest
->pw_gecos
, src
->pw_gecos
);
140 dest
->pw_gecos
= buffer
;
141 strcpy (dest
->pw_gecos
, src
->pw_gecos
);
142 buffer
+= strlen (dest
->pw_gecos
) + 1;
143 buflen
= buflen
- (strlen (dest
->pw_gecos
) + 1);
146 if (src
->pw_dir
!= NULL
&& strlen (src
->pw_dir
))
149 dest
->pw_dir
= strdup (src
->pw_dir
);
150 else if (dest
->pw_dir
&&
151 strlen (dest
->pw_dir
) >= strlen (src
->pw_dir
))
152 strcpy (dest
->pw_dir
, src
->pw_dir
);
155 dest
->pw_dir
= buffer
;
156 strcpy (dest
->pw_dir
, src
->pw_dir
);
157 buffer
+= strlen (dest
->pw_dir
) + 1;
158 buflen
= buflen
- (strlen (dest
->pw_dir
) + 1);
162 if (src
->pw_shell
!= NULL
&& strlen (src
->pw_shell
))
165 dest
->pw_shell
= strdup (src
->pw_shell
);
166 else if (dest
->pw_shell
&&
167 strlen (dest
->pw_shell
) >= strlen (src
->pw_shell
))
168 strcpy (dest
->pw_shell
, src
->pw_shell
);
171 dest
->pw_shell
= buffer
;
172 strcpy (dest
->pw_shell
, src
->pw_shell
);
173 buffer
+= strlen (dest
->pw_shell
) + 1;
174 buflen
= buflen
- (strlen (dest
->pw_shell
) + 1);
179 static enum nss_status
180 internal_setpwent (ent_t
*ent
)
182 enum nss_status status
= NSS_STATUS_SUCCESS
;
184 ent
->nis
= ent
->first
= ent
->netgroup
= 0;
186 /* If something was left over free it. */
188 __internal_endnetgrent (&ent
->netgrdata
);
190 if (ent
->oldkey
!= NULL
)
197 if (ent
->blacklist
.data
!= NULL
)
199 ent
->blacklist
.current
= 1;
200 ent
->blacklist
.data
[0] = '|';
201 ent
->blacklist
.data
[1] = '\0';
204 ent
->blacklist
.current
= 0;
206 if (ent
->stream
== NULL
)
208 ent
->stream
= fopen ("/etc/passwd", "r");
210 if (ent
->stream
== NULL
)
211 status
= errno
== EAGAIN
? NSS_STATUS_TRYAGAIN
: NSS_STATUS_UNAVAIL
;
214 /* We have to make sure the file is `closed on exec'. */
217 result
= flags
= fcntl (fileno (ent
->stream
), F_GETFD
, 0);
221 result
= fcntl (fileno (ent
->stream
), F_SETFD
, flags
);
225 /* Something went wrong. Close the stream and return a
227 fclose (ent
->stream
);
229 status
= NSS_STATUS_UNAVAIL
;
234 rewind (ent
->stream
);
236 give_pwd_free (&ent
->pwd
);
243 _nss_compat_setpwent (void)
245 enum nss_status result
;
247 __libc_lock_lock (lock
);
249 result
= internal_setpwent (&ext_ent
);
251 __libc_lock_unlock (lock
);
257 static enum nss_status
258 internal_endpwent (ent_t
*ent
)
260 if (ent
->stream
!= NULL
)
262 fclose (ent
->stream
);
267 __internal_endnetgrent (&ent
->netgrdata
);
269 ent
->nis
= ent
->first
= ent
->netgroup
= 0;
271 if (ent
->oldkey
!= NULL
)
278 if (ent
->blacklist
.data
!= NULL
)
280 ent
->blacklist
.current
= 1;
281 ent
->blacklist
.data
[0] = '|';
282 ent
->blacklist
.data
[1] = '\0';
285 ent
->blacklist
.current
= 0;
287 give_pwd_free (&ent
->pwd
);
289 return NSS_STATUS_SUCCESS
;
293 _nss_compat_endpwent (void)
295 enum nss_status result
;
297 __libc_lock_lock (lock
);
299 result
= internal_endpwent (&ext_ent
);
301 __libc_lock_unlock (lock
);
306 static enum nss_status
307 getpwent_next_nis_netgr (const char *name
, struct passwd
*result
, ent_t
*ent
,
308 char *group
, char *buffer
, size_t buflen
)
310 struct parser_data
*data
= (void *) buffer
;
311 char *ypdomain
, *host
, *user
, *domain
, *outval
, *p
, *p2
;
312 int status
, outvallen
;
315 if (yp_get_default_domain (&ypdomain
) != YPERR_SUCCESS
)
319 give_pwd_free (&ent
->pwd
);
320 return NSS_STATUS_UNAVAIL
;
323 if (ent
->first
== TRUE
)
325 memset (&ent
->netgrdata
, 0, sizeof (struct __netgrent
));
326 __internal_setnetgrent (group
, &ent
->netgrdata
);
335 saved_cursor
= ent
->netgrdata
.cursor
;
336 status
= __internal_getnetgrent_r (&host
, &user
, &domain
,
337 &ent
->netgrdata
, buffer
, buflen
,
341 __internal_endnetgrent (&ent
->netgrdata
);
343 give_pwd_free (&ent
->pwd
);
344 return NSS_STATUS_RETURN
;
347 if (user
== NULL
|| user
[0] == '-')
350 if (domain
!= NULL
&& strcmp (ypdomain
, domain
) != 0)
353 /* If name != NULL, we are called from getpwnam */
355 if (strcmp (user
, name
) != 0)
358 if (yp_match (ypdomain
, "passwd.byname", user
,
359 strlen (user
), &outval
, &outvallen
)
363 p2len
= pwd_need_buflen (&ent
->pwd
);
366 __set_errno (ERANGE
);
367 return NSS_STATUS_TRYAGAIN
;
369 p2
= buffer
+ (buflen
- p2len
);
371 p
= strncpy (buffer
, outval
, buflen
);
375 if ((parse_res
= _nss_files_parse_pwent (p
, result
, data
, buflen
)) == -1)
377 ent
->netgrdata
.cursor
= saved_cursor
;
378 return NSS_STATUS_TRYAGAIN
;
383 /* Store the User in the blacklist for the "+" at the end of
385 blacklist_store_name (result
->pw_name
, ent
);
386 copy_pwd_changes (result
, &ent
->pwd
, p2
, p2len
);
391 return NSS_STATUS_SUCCESS
;
394 static enum nss_status
395 getpwent_next_nis (struct passwd
*result
, ent_t
*ent
, char *buffer
,
398 struct parser_data
*data
= (void *) buffer
;
399 char *domain
, *outkey
, *outval
, *p
, *p2
;
400 int outkeylen
, outvallen
, parse_res
;
403 if (yp_get_default_domain (&domain
) != YPERR_SUCCESS
)
406 give_pwd_free (&ent
->pwd
);
407 return NSS_STATUS_UNAVAIL
;
410 p2len
= pwd_need_buflen (&ent
->pwd
);
413 __set_errno (ERANGE
);
414 return NSS_STATUS_TRYAGAIN
;
416 p2
= buffer
+ (buflen
- p2len
);
426 if (yp_first (domain
, "passwd.byname", &outkey
, &outkeylen
,
427 &outval
, &outvallen
) != YPERR_SUCCESS
)
430 give_pwd_free (&ent
->pwd
);
431 return NSS_STATUS_UNAVAIL
;
435 saved_oldkey
= ent
->oldkey
;
436 saved_oldlen
= ent
->oldkeylen
;
437 ent
->oldkey
= outkey
;
438 ent
->oldkeylen
= outkeylen
;
443 if (yp_next (domain
, "passwd.byname", ent
->oldkey
, ent
->oldkeylen
,
444 &outkey
, &outkeylen
, &outval
, &outvallen
)
448 give_pwd_free (&ent
->pwd
);
449 return NSS_STATUS_NOTFOUND
;
453 saved_oldkey
= ent
->oldkey
;
454 saved_oldlen
= ent
->oldkeylen
;
455 ent
->oldkey
= outkey
;
456 ent
->oldkeylen
= outkeylen
;
459 /* Copy the found data to our buffer */
460 p
= strncpy (buffer
, outval
, buflen
);
462 /* ...and free the data. */
467 if ((parse_res
= _nss_files_parse_pwent (p
, result
, data
, buflen
)) == -1)
470 ent
->oldkey
= saved_oldkey
;
471 ent
->oldkeylen
= saved_oldlen
;
472 ent
->first
= saved_first
;
473 __set_errno (ERANGE
);
474 return NSS_STATUS_TRYAGAIN
;
482 in_blacklist (result
->pw_name
, strlen (result
->pw_name
), ent
))
487 copy_pwd_changes (result
, &ent
->pwd
, p2
, p2len
);
489 return NSS_STATUS_SUCCESS
;
492 /* This function handle the +user entrys in /etc/passwd */
493 static enum nss_status
494 getpwnam_plususer (const char *name
, struct passwd
*result
, char *buffer
,
497 struct parser_data
*data
= (void *) buffer
;
502 char *domain
, *outval
, *ptr
;
505 memset (&pwd
, '\0', sizeof (struct passwd
));
507 copy_pwd_changes (&pwd
, result
, NULL
, 0);
509 plen
= pwd_need_buflen (&pwd
);
512 __set_errno (ERANGE
);
513 return NSS_STATUS_TRYAGAIN
;
515 p
= buffer
+ (buflen
- plen
);
519 if (yp_get_default_domain (&domain
) != YPERR_SUCCESS
)
520 return NSS_STATUS_NOTFOUND
;
522 if (yp_match (domain
, "passwd.byname", name
, strlen (name
),
523 &outval
, &outvallen
) != YPERR_SUCCESS
)
524 return NSS_STATUS_NOTFOUND
;
525 ptr
= strncpy (buffer
, outval
, buflen
< (size_t) outvallen
?
526 buflen
: (size_t) outvallen
);
527 buffer
[buflen
< (size_t) outvallen
? buflen
: (size_t) outvallen
] = '\0';
529 while (isspace (*ptr
))
531 if ((parse_res
= _nss_files_parse_pwent (ptr
, result
, data
, buflen
))
534 __set_errno (ERANGE
);
535 return NSS_STATUS_TRYAGAIN
;
540 copy_pwd_changes (result
, &pwd
, p
, plen
);
541 give_pwd_free (&pwd
);
542 /* We found the entry. */
543 return NSS_STATUS_SUCCESS
;
547 /* Give buffer the old len back */
549 give_pwd_free (&pwd
);
551 return NSS_STATUS_RETURN
;
554 /* get the next user from NIS+ (+ entry) */
555 static enum nss_status
556 getpwent_next_file (struct passwd
*result
, ent_t
*ent
,
557 char *buffer
, size_t buflen
)
559 struct parser_data
*data
= (void *) buffer
;
568 fgetpos (ent
->stream
, &pos
);
569 buffer
[buflen
- 1] = '\xff';
570 p
= fgets (buffer
, buflen
, ent
->stream
);
571 if (p
== NULL
&& feof (ent
->stream
))
572 return NSS_STATUS_NOTFOUND
;
573 if (p
== NULL
|| buffer
[buflen
- 1] != '\xff')
575 fsetpos (ent
->stream
, &pos
);
576 __set_errno (ERANGE
);
577 return NSS_STATUS_TRYAGAIN
;
580 /* Terminate the line for any case. */
581 buffer
[buflen
- 1] = '\0';
583 /* Skip leading blanks. */
587 while (*p
== '\0' || *p
== '#' || /* Ignore empty and comment lines. */
588 /* Parse the line. If it is invalid, loop to
589 get the next line of the file to parse. */
590 !(parse_res
= _nss_files_parse_pwent (p
, result
, data
, buflen
)));
594 /* The parser ran out of space. */
595 fsetpos (ent
->stream
, &pos
);
596 __set_errno (ERANGE
);
597 return NSS_STATUS_TRYAGAIN
;
600 if (result
->pw_name
[0] != '+' && result
->pw_name
[0] != '-')
601 /* This is a real entry. */
605 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] == '@'
606 && result
->pw_name
[2] != '\0')
609 char *user
, *host
, *domain
;
610 struct __netgrent netgrdata
;
612 bzero (&netgrdata
, sizeof (struct __netgrent
));
613 __internal_setnetgrent (&result
->pw_name
[2], &netgrdata
);
614 while (__internal_getnetgrent_r (&host
, &user
, &domain
,
615 &netgrdata
, buf2
, sizeof (buf2
),
618 if (user
!= NULL
&& user
[0] != '-')
619 blacklist_store_name (user
, ent
);
621 __internal_endnetgrent (&netgrdata
);
626 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '@'
627 && result
->pw_name
[2] != '\0')
631 ent
->netgroup
= TRUE
;
633 copy_pwd_changes (&ent
->pwd
, result
, NULL
, 0);
635 status
= getpwent_next_nis_netgr (NULL
, result
, ent
,
638 if (status
== NSS_STATUS_RETURN
)
645 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] != '\0'
646 && result
->pw_name
[1] != '@')
648 blacklist_store_name (&result
->pw_name
[1], ent
);
653 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] != '\0'
654 && result
->pw_name
[1] != '@')
656 enum nss_status status
;
658 /* Store the User in the blacklist for the "+" at the end of
660 blacklist_store_name (&result
->pw_name
[1], ent
);
661 status
= getpwnam_plususer (&result
->pw_name
[1], result
, buffer
,
663 if (status
== NSS_STATUS_SUCCESS
) /* We found the entry. */
666 if (status
== NSS_STATUS_RETURN
) /* We couldn't parse the entry */
673 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '\0')
677 copy_pwd_changes (&ent
->pwd
, result
, NULL
, 0);
679 return getpwent_next_nis (result
, ent
, buffer
, buflen
);
683 return NSS_STATUS_SUCCESS
;
687 /* get the next user from NIS (+ entry) */
688 static enum nss_status
689 internal_getpwent_r (struct passwd
*pw
, ent_t
*ent
, char *buffer
,
696 /* We are searching members in a netgroup */
697 /* Since this is not the first call, we don't need the group name */
698 status
= getpwent_next_nis_netgr (NULL
, pw
, ent
, NULL
, buffer
, buflen
);
699 if (status
== NSS_STATUS_RETURN
)
700 return getpwent_next_file (pw
, ent
, buffer
, buflen
);
707 return getpwent_next_nis (pw
, ent
, buffer
, buflen
);
710 return getpwent_next_file (pw
, ent
, buffer
, buflen
);
714 _nss_compat_getpwent_r (struct passwd
*pwd
, char *buffer
, size_t buflen
)
716 enum nss_status status
= NSS_STATUS_SUCCESS
;
718 __libc_lock_lock (lock
);
720 /* Be prepared that the setpwent function was not called before. */
721 if (ext_ent
.stream
== NULL
)
722 status
= internal_setpwent (&ext_ent
);
724 if (status
== NSS_STATUS_SUCCESS
)
725 status
= internal_getpwent_r (pwd
, &ext_ent
, buffer
, buflen
);
727 __libc_lock_unlock (lock
);
732 /* Searches in /etc/passwd and the NIS/NIS+ map for a special user */
733 static enum nss_status
734 internal_getpwnam_r (const char *name
, struct passwd
*result
, ent_t
*ent
,
735 char *buffer
, size_t buflen
)
737 struct parser_data
*data
= (void *) buffer
;
747 fgetpos (ent
->stream
, &pos
);
748 buffer
[buflen
- 1] = '\xff';
749 p
= fgets (buffer
, buflen
, ent
->stream
);
750 if (p
== NULL
&& feof (ent
->stream
))
751 return NSS_STATUS_NOTFOUND
;
752 if (p
== NULL
|| buffer
[buflen
- 1] != '\xff')
754 fsetpos (ent
->stream
, &pos
);
755 __set_errno (ERANGE
);
756 return NSS_STATUS_TRYAGAIN
;
759 /* Terminate the line for any case. */
760 buffer
[buflen
- 1] = '\0';
762 /* Skip leading blanks. */
766 while (*p
== '\0' || *p
== '#' || /* Ignore empty and comment lines. */
767 /* Parse the line. If it is invalid, loop to
768 get the next line of the file to parse. */
769 !(parse_res
= _nss_files_parse_pwent (p
, result
, data
, buflen
)));
773 /* The parser ran out of space. */
774 fsetpos (ent
->stream
, &pos
);
775 __set_errno (ERANGE
);
776 return NSS_STATUS_TRYAGAIN
;
779 /* This is a real entry. */
780 if (result
->pw_name
[0] != '+' && result
->pw_name
[0] != '-')
782 if (strcmp (result
->pw_name
, name
) == 0)
783 return NSS_STATUS_SUCCESS
;
789 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] == '@'
790 && result
->pw_name
[2] != '\0')
793 char *user
, *host
, *domain
;
794 struct __netgrent netgrdata
;
796 bzero (&netgrdata
, sizeof (struct __netgrent
));
797 __internal_setnetgrent (&result
->pw_name
[2], &netgrdata
);
798 while (__internal_getnetgrent_r (&host
, &user
, &domain
,
799 &netgrdata
, buf2
, sizeof (buf2
),
802 if (user
!= NULL
&& user
[0] != '-')
803 if (strcmp (user
, name
) == 0)
804 return NSS_STATUS_NOTFOUND
;
806 __internal_endnetgrent (&netgrdata
);
811 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '@'
812 && result
->pw_name
[2] != '\0')
814 char buf
[strlen (result
->pw_name
)];
817 strcpy (buf
, &result
->pw_name
[2]);
818 ent
->netgroup
= TRUE
;
820 copy_pwd_changes (&ent
->pwd
, result
, NULL
, 0);
824 status
= getpwent_next_nis_netgr (name
, result
, ent
, buf
,
826 if (status
== NSS_STATUS_RETURN
)
829 if (status
== NSS_STATUS_SUCCESS
&&
830 strcmp (result
->pw_name
, name
) == 0)
831 return NSS_STATUS_SUCCESS
;
832 } while (status
== NSS_STATUS_SUCCESS
);
837 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] != '\0'
838 && result
->pw_name
[1] != '@')
840 if (strcmp (&result
->pw_name
[1], name
) == 0)
841 return NSS_STATUS_NOTFOUND
;
847 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] != '\0'
848 && result
->pw_name
[1] != '@')
850 if (strcmp (name
, &result
->pw_name
[1]) == 0)
852 enum nss_status status
;
854 status
= getpwnam_plususer (name
, result
, buffer
, buflen
);
855 if (status
== NSS_STATUS_RETURN
)
856 /* We couldn't parse the entry */
857 return NSS_STATUS_NOTFOUND
;
864 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '\0')
866 enum nss_status status
;
868 status
= getpwnam_plususer (name
, result
, buffer
, buflen
);
869 if (status
== NSS_STATUS_SUCCESS
) /* We found the entry. */
872 if (status
== NSS_STATUS_RETURN
) /* We couldn't parse the entry */
873 return NSS_STATUS_NOTFOUND
;
878 return NSS_STATUS_SUCCESS
;
882 _nss_compat_getpwnam_r (const char *name
, struct passwd
*pwd
,
883 char *buffer
, size_t buflen
)
885 ent_t ent
= {0, 0, 0, NULL
, 0, NULL
, {NULL
, 0, 0},
886 {NULL
, NULL
, 0, 0, NULL
, NULL
, NULL
}};
887 enum nss_status status
;
889 if (name
[0] == '-' || name
[0] == '+')
890 return NSS_STATUS_NOTFOUND
;
892 status
= internal_setpwent (&ent
);
893 if (status
!= NSS_STATUS_SUCCESS
)
896 status
= internal_getpwnam_r (name
, pwd
, &ent
, buffer
, buflen
);
898 internal_endpwent (&ent
);
903 /* This function handle the + entry in /etc/passwd for getpwuid */
904 static enum nss_status
905 getpwuid_plususer (uid_t uid
, struct passwd
*result
, char *buffer
,
908 struct parser_data
*data
= (void *) buffer
;
914 char *domain
, *outval
, *ptr
;
917 memset (&pwd
, '\0', sizeof (struct passwd
));
919 copy_pwd_changes (&pwd
, result
, NULL
, 0);
921 plen
= pwd_need_buflen (&pwd
);
924 __set_errno (ERANGE
);
925 return NSS_STATUS_TRYAGAIN
;
927 p
= buffer
+ (buflen
- plen
);
931 if (yp_get_default_domain (&domain
) != YPERR_SUCCESS
)
932 return NSS_STATUS_TRYAGAIN
;
934 sprintf (buf
, "%d", uid
);
935 if (yp_match (domain
, "passwd.byuid", buf
, strlen (buf
),
938 return NSS_STATUS_TRYAGAIN
;
939 ptr
= strncpy (buffer
, outval
, buflen
< (size_t) outvallen
?
940 buflen
: (size_t) outvallen
);
941 buffer
[buflen
< (size_t) outvallen
? buflen
: (size_t) outvallen
] = '\0';
943 while (isspace (*ptr
))
945 if ((parse_res
= _nss_files_parse_pwent (ptr
, result
, data
, buflen
))
948 __set_errno (ERANGE
);
949 return NSS_STATUS_TRYAGAIN
;
954 copy_pwd_changes (result
, &pwd
, p
, plen
);
955 give_pwd_free (&pwd
);
956 /* We found the entry. */
957 return NSS_STATUS_SUCCESS
;
961 /* Give buffer the old len back */
963 give_pwd_free (&pwd
);
965 return NSS_STATUS_RETURN
;
968 /* Searches in /etc/passwd and the NIS/NIS+ map for a special user id */
969 static enum nss_status
970 internal_getpwuid_r (uid_t uid
, struct passwd
*result
, ent_t
*ent
,
971 char *buffer
, size_t buflen
)
973 struct parser_data
*data
= (void *) buffer
;
983 fgetpos (ent
->stream
, &pos
);
984 buffer
[buflen
- 1] = '\xff';
985 p
= fgets (buffer
, buflen
, ent
->stream
);
986 if (p
== NULL
&& feof (ent
->stream
))
987 return NSS_STATUS_NOTFOUND
;
988 if (p
== NULL
|| buffer
[buflen
- 1] != '\xff')
990 fsetpos (ent
->stream
, &pos
);
991 __set_errno (ERANGE
);
992 return NSS_STATUS_TRYAGAIN
;
995 /* Terminate the line for any case. */
996 buffer
[buflen
- 1] = '\0';
998 /* Skip leading blanks. */
1002 while (*p
== '\0' || *p
== '#' || /* Ignore empty and comment lines. */
1003 /* Parse the line. If it is invalid, loop to
1004 get the next line of the file to parse. */
1005 !(parse_res
= _nss_files_parse_pwent (p
, result
, data
, buflen
)));
1007 if (parse_res
== -1)
1009 /* The parser ran out of space. */
1010 fsetpos (ent
->stream
, &pos
);
1011 __set_errno (ERANGE
);
1012 return NSS_STATUS_TRYAGAIN
;
1015 /* This is a real entry. */
1016 if (result
->pw_name
[0] != '+' && result
->pw_name
[0] != '-')
1018 if (result
->pw_uid
== uid
)
1019 return NSS_STATUS_SUCCESS
;
1025 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] == '@'
1026 && result
->pw_name
[2] != '\0')
1029 char *user
, *host
, *domain
;
1030 struct __netgrent netgrdata
;
1032 bzero (&netgrdata
, sizeof (struct __netgrent
));
1033 __internal_setnetgrent (&result
->pw_name
[2], &netgrdata
);
1034 while (__internal_getnetgrent_r (&host
, &user
, &domain
,
1035 &netgrdata
, buf2
, sizeof (buf2
),
1038 if (user
!= NULL
&& user
[0] != '-')
1039 blacklist_store_name (user
, ent
);
1041 __internal_endnetgrent (&netgrdata
);
1046 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '@'
1047 && result
->pw_name
[2] != '\0')
1049 char buf
[strlen (result
->pw_name
)];
1052 strcpy (buf
, &result
->pw_name
[2]);
1053 ent
->netgroup
= TRUE
;
1055 copy_pwd_changes (&ent
->pwd
, result
, NULL
, 0);
1059 status
= getpwent_next_nis_netgr (NULL
, result
, ent
, buf
,
1061 if (status
== NSS_STATUS_RETURN
)
1064 if (status
== NSS_STATUS_SUCCESS
&& uid
== result
->pw_uid
)
1065 return NSS_STATUS_SUCCESS
;
1066 } while (status
== NSS_STATUS_SUCCESS
);
1071 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] != '\0'
1072 && result
->pw_name
[1] != '@')
1074 blacklist_store_name (&result
->pw_name
[1], ent
);
1079 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] != '\0'
1080 && result
->pw_name
[1] != '@')
1082 enum nss_status status
;
1084 /* Store the User in the blacklist for the "+" at the end of
1086 blacklist_store_name (&result
->pw_name
[1], ent
);
1087 status
= getpwnam_plususer (&result
->pw_name
[1], result
, buffer
,
1089 if (status
== NSS_STATUS_SUCCESS
&& result
->pw_uid
== uid
)
1096 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '\0')
1098 enum nss_status status
;
1100 status
= getpwuid_plususer (uid
, result
, buffer
, buflen
);
1101 if (status
== NSS_STATUS_SUCCESS
) /* We found the entry. */
1104 if (status
== NSS_STATUS_RETURN
) /* We couldn't parse the entry */
1105 return NSS_STATUS_NOTFOUND
;
1108 if (status
== NSS_STATUS_TRYAGAIN
)
1109 /* The parser ran out of space */
1110 fsetpos (ent
->stream
, &pos
);
1115 return NSS_STATUS_SUCCESS
;
1119 _nss_compat_getpwuid_r (uid_t uid
, struct passwd
*pwd
,
1120 char *buffer
, size_t buflen
)
1122 ent_t ent
= {0, 0, 0, NULL
, 0, NULL
, {NULL
, 0, 0},
1123 {NULL
, NULL
, 0, 0, NULL
, NULL
, NULL
}};
1124 enum nss_status status
;
1126 status
= internal_setpwent (&ent
);
1127 if (status
!= NSS_STATUS_SUCCESS
)
1130 status
= internal_getpwuid_r (uid
, pwd
, &ent
, buffer
, buflen
);
1132 internal_endpwent (&ent
);
1138 /* Support routines for remembering -@netgroup and -user entries.
1139 The names are stored in a single string with `|' as separator. */
1141 blacklist_store_name (const char *name
, ent_t
*ent
)
1143 int namelen
= strlen (name
);
1146 /* first call, setup cache */
1147 if (ent
->blacklist
.size
== 0)
1149 ent
->blacklist
.size
= MAX (BLACKLIST_INITIAL_SIZE
, 2 * namelen
);
1150 ent
->blacklist
.data
= malloc (ent
->blacklist
.size
);
1151 if (ent
->blacklist
.data
== NULL
)
1153 ent
->blacklist
.data
[0] = '|';
1154 ent
->blacklist
.data
[1] = '\0';
1155 ent
->blacklist
.current
= 1;
1159 if (in_blacklist (name
, namelen
, ent
))
1160 return; /* no duplicates */
1162 if (ent
->blacklist
.current
+ namelen
+ 1 >= ent
->blacklist
.size
)
1164 ent
->blacklist
.size
+= MAX (BLACKLIST_INCREMENT
, 2 * namelen
);
1165 tmp
= realloc (ent
->blacklist
.data
, ent
->blacklist
.size
);
1168 free (ent
->blacklist
.data
);
1169 ent
->blacklist
.size
= 0;
1172 ent
->blacklist
.data
= tmp
;
1176 tmp
= stpcpy (ent
->blacklist
.data
+ ent
->blacklist
.current
, name
);
1179 ent
->blacklist
.current
+= namelen
+ 1;
1184 /* returns TRUE if ent->blacklist contains name, else FALSE */
1186 in_blacklist (const char *name
, int namelen
, ent_t
*ent
)
1188 char buf
[namelen
+ 3];
1191 if (ent
->blacklist
.data
== NULL
)
1195 cp
= stpcpy (&buf
[1], name
);
1198 return strstr (ent
->blacklist
.data
, buf
) != NULL
;