1 /* Copyright (C) 1996-1999,2001,2002,2003,2004 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 <stdio_ext.h>
29 #include <rpc/types.h>
30 #include <rpcsvc/ypclnt.h>
31 #include <bits/libc-lock.h>
35 static service_user
*ni
;
36 static enum nss_status (*nss_setpwent
) (int stayopen
);
37 static enum nss_status (*nss_getpwnam_r
) (const char *name
,
38 struct passwd
* pwd
, char *buffer
,
39 size_t buflen
, int *errnop
);
40 static enum nss_status (*nss_getpwuid_r
) (uid_t uid
, struct passwd
* pwd
,
41 char *buffer
, size_t buflen
,
43 static enum nss_status (*nss_getpwent_r
) (struct passwd
* pwd
, char *buffer
,
44 size_t buflen
, int *errnop
);
45 static enum nss_status (*nss_endpwent
) (void);
47 /* Get the declaration of the parser function. */
49 #define STRUCTURE passwd
51 #include <nss/nss_files/files-parse.c>
53 /* Structure for remembering -@netgroup and -user members ... */
54 #define BLACKLIST_INITIAL_SIZE 512
55 #define BLACKLIST_INCREMENT 256
69 struct blacklist_t blacklist
;
71 struct __netgrent netgrdata
;
73 typedef struct ent_t ent_t
;
75 static ent_t ext_ent
= {0, 0, TRUE
, NULL
, {NULL
, 0, 0},
76 {NULL
, NULL
, 0, 0, NULL
, NULL
, NULL
}};
78 /* Protect global state against multiple changers. */
79 __libc_lock_define_initialized (static, lock
)
81 /* Prototypes for local functions. */
82 static void blacklist_store_name (const char *, ent_t
*);
83 static int in_blacklist (const char *, int, ent_t
*);
85 /* Initialize the NSS interface/functions. The calling function must
88 init_nss_interface (void)
90 if (__nss_database_lookup ("passwd_compat", NULL
, "nis", &ni
) >= 0)
92 nss_setpwent
= __nss_lookup_function (ni
, "setpwent");
93 nss_getpwnam_r
= __nss_lookup_function (ni
, "getpwnam_r");
94 nss_getpwuid_r
= __nss_lookup_function (ni
, "getpwuid_r");
95 nss_getpwent_r
= __nss_lookup_function (ni
, "getpwent_r");
96 nss_endpwent
= __nss_lookup_function (ni
, "endpwent");
101 give_pwd_free (struct passwd
*pwd
)
103 if (pwd
->pw_name
!= NULL
)
105 if (pwd
->pw_passwd
!= NULL
)
106 free (pwd
->pw_passwd
);
107 if (pwd
->pw_gecos
!= NULL
)
108 free (pwd
->pw_gecos
);
109 if (pwd
->pw_dir
!= NULL
)
111 if (pwd
->pw_shell
!= NULL
)
112 free (pwd
->pw_shell
);
114 memset (pwd
, '\0', sizeof (struct passwd
));
118 pwd_need_buflen (struct passwd
*pwd
)
122 if (pwd
->pw_passwd
!= NULL
)
123 len
+= strlen (pwd
->pw_passwd
) + 1;
125 if (pwd
->pw_gecos
!= NULL
)
126 len
+= strlen (pwd
->pw_gecos
) + 1;
128 if (pwd
->pw_dir
!= NULL
)
129 len
+= strlen (pwd
->pw_dir
) + 1;
131 if (pwd
->pw_shell
!= NULL
)
132 len
+= strlen (pwd
->pw_shell
) + 1;
138 copy_pwd_changes (struct passwd
*dest
, struct passwd
*src
,
139 char *buffer
, size_t buflen
)
141 if (src
->pw_passwd
!= NULL
&& strlen (src
->pw_passwd
))
144 dest
->pw_passwd
= strdup (src
->pw_passwd
);
145 else if (dest
->pw_passwd
&&
146 strlen (dest
->pw_passwd
) >= strlen (src
->pw_passwd
))
147 strcpy (dest
->pw_passwd
, src
->pw_passwd
);
150 dest
->pw_passwd
= buffer
;
151 strcpy (dest
->pw_passwd
, src
->pw_passwd
);
152 buffer
+= strlen (dest
->pw_passwd
) + 1;
153 buflen
= buflen
- (strlen (dest
->pw_passwd
) + 1);
157 if (src
->pw_gecos
!= NULL
&& strlen (src
->pw_gecos
))
160 dest
->pw_gecos
= strdup (src
->pw_gecos
);
161 else if (dest
->pw_gecos
&&
162 strlen (dest
->pw_gecos
) >= strlen (src
->pw_gecos
))
163 strcpy (dest
->pw_gecos
, src
->pw_gecos
);
166 dest
->pw_gecos
= buffer
;
167 strcpy (dest
->pw_gecos
, src
->pw_gecos
);
168 buffer
+= strlen (dest
->pw_gecos
) + 1;
169 buflen
= buflen
- (strlen (dest
->pw_gecos
) + 1);
172 if (src
->pw_dir
!= NULL
&& strlen (src
->pw_dir
))
175 dest
->pw_dir
= strdup (src
->pw_dir
);
176 else if (dest
->pw_dir
&& strlen (dest
->pw_dir
) >= strlen (src
->pw_dir
))
177 strcpy (dest
->pw_dir
, src
->pw_dir
);
180 dest
->pw_dir
= buffer
;
181 strcpy (dest
->pw_dir
, src
->pw_dir
);
182 buffer
+= strlen (dest
->pw_dir
) + 1;
183 buflen
= buflen
- (strlen (dest
->pw_dir
) + 1);
187 if (src
->pw_shell
!= NULL
&& strlen (src
->pw_shell
))
190 dest
->pw_shell
= strdup (src
->pw_shell
);
191 else if (dest
->pw_shell
&&
192 strlen (dest
->pw_shell
) >= strlen (src
->pw_shell
))
193 strcpy (dest
->pw_shell
, src
->pw_shell
);
196 dest
->pw_shell
= buffer
;
197 strcpy (dest
->pw_shell
, src
->pw_shell
);
198 buffer
+= strlen (dest
->pw_shell
) + 1;
199 buflen
= buflen
- (strlen (dest
->pw_shell
) + 1);
204 static enum nss_status
205 internal_setpwent (ent_t
*ent
, int stayopen
)
207 enum nss_status status
= NSS_STATUS_SUCCESS
;
209 ent
->first
= ent
->netgroup
= FALSE
;
212 /* If something was left over free it. */
214 __internal_endnetgrent (&ent
->netgrdata
);
216 if (ent
->blacklist
.data
!= NULL
)
218 ent
->blacklist
.current
= 1;
219 ent
->blacklist
.data
[0] = '|';
220 ent
->blacklist
.data
[1] = '\0';
223 ent
->blacklist
.current
= 0;
225 if (ent
->stream
== NULL
)
227 ent
->stream
= fopen ("/etc/passwd", "rm");
229 if (ent
->stream
== NULL
)
230 status
= errno
== EAGAIN
? NSS_STATUS_TRYAGAIN
: NSS_STATUS_UNAVAIL
;
233 /* We have to make sure the file is `closed on exec'. */
236 result
= flags
= fcntl (fileno_unlocked (ent
->stream
), F_GETFD
, 0);
240 result
= fcntl (fileno_unlocked (ent
->stream
), F_SETFD
, flags
);
244 /* Something went wrong. Close the stream and return a
246 fclose (ent
->stream
);
248 status
= NSS_STATUS_UNAVAIL
;
251 /* We take care of locking ourself. */
252 __fsetlocking (ent
->stream
, FSETLOCKING_BYCALLER
);
256 rewind (ent
->stream
);
258 give_pwd_free (&ent
->pwd
);
260 if (status
== NSS_STATUS_SUCCESS
&& nss_setpwent
)
261 return nss_setpwent (stayopen
);
268 _nss_compat_setpwent (int stayopen
)
270 enum nss_status result
;
272 __libc_lock_lock (lock
);
275 init_nss_interface ();
277 result
= internal_setpwent (&ext_ent
, stayopen
);
279 __libc_lock_unlock (lock
);
285 static enum nss_status
286 internal_endpwent (ent_t
*ent
)
291 if (ent
->stream
!= NULL
)
293 fclose (ent
->stream
);
298 __internal_endnetgrent (&ent
->netgrdata
);
300 ent
->first
= ent
->netgroup
= FALSE
;
302 if (ent
->blacklist
.data
!= NULL
)
304 ent
->blacklist
.current
= 1;
305 ent
->blacklist
.data
[0] = '|';
306 ent
->blacklist
.data
[1] = '\0';
309 ent
->blacklist
.current
= 0;
311 give_pwd_free (&ent
->pwd
);
313 return NSS_STATUS_SUCCESS
;
317 _nss_compat_endpwent (void)
319 enum nss_status result
;
321 __libc_lock_lock (lock
);
323 result
= internal_endpwent (&ext_ent
);
325 __libc_lock_unlock (lock
);
331 static enum nss_status
332 getpwent_next_nss_netgr (const char *name
, struct passwd
*result
, ent_t
*ent
,
333 char *group
, char *buffer
, size_t buflen
,
336 char *curdomain
, *host
, *user
, *domain
, *p2
;
340 /* Leave function if NSS module does not support getpwnam_r,
341 we need this function here. */
343 return NSS_STATUS_UNAVAIL
;
345 if (yp_get_default_domain (&curdomain
) != YPERR_SUCCESS
)
347 ent
->netgroup
= FALSE
;
349 give_pwd_free (&ent
->pwd
);
350 return NSS_STATUS_UNAVAIL
;
353 if (ent
->first
== TRUE
)
355 memset (&ent
->netgrdata
, 0, sizeof (struct __netgrent
));
356 __internal_setnetgrent (group
, &ent
->netgrdata
);
364 saved_cursor
= ent
->netgrdata
.cursor
;
365 status
= __internal_getnetgrent_r (&host
, &user
, &domain
,
366 &ent
->netgrdata
, buffer
, buflen
,
370 __internal_endnetgrent (&ent
->netgrdata
);
372 give_pwd_free (&ent
->pwd
);
373 return NSS_STATUS_RETURN
;
376 if (user
== NULL
|| user
[0] == '-')
379 if (domain
!= NULL
&& strcmp (curdomain
, domain
) != 0)
382 /* If name != NULL, we are called from getpwnam. */
384 if (strcmp (user
, name
) != 0)
387 p2len
= pwd_need_buflen (&ent
->pwd
);
391 return NSS_STATUS_TRYAGAIN
;
393 p2
= buffer
+ (buflen
- p2len
);
396 if (nss_getpwnam_r (user
, result
, buffer
, buflen
, errnop
) !=
400 if (!in_blacklist (result
->pw_name
, strlen (result
->pw_name
), ent
))
402 /* Store the User in the blacklist for possible the "+" at the
403 end of /etc/passwd */
404 blacklist_store_name (result
->pw_name
, ent
);
405 copy_pwd_changes (result
, &ent
->pwd
, p2
, p2len
);
410 return NSS_STATUS_SUCCESS
;
413 /* get the next user from NSS (+ entry) */
414 static enum nss_status
415 getpwent_next_nss (struct passwd
*result
, ent_t
*ent
, char *buffer
,
416 size_t buflen
, int *errnop
)
418 enum nss_status status
;
422 /* Return if NSS module does not support getpwent_r. */
424 return NSS_STATUS_UNAVAIL
;
426 p2len
= pwd_need_buflen (&ent
->pwd
);
430 return NSS_STATUS_TRYAGAIN
;
432 p2
= buffer
+ (buflen
- p2len
);
440 if ((status
= nss_getpwent_r (result
, buffer
, buflen
, errnop
)) !=
444 while (in_blacklist (result
->pw_name
, strlen (result
->pw_name
), ent
));
446 copy_pwd_changes (result
, &ent
->pwd
, p2
, p2len
);
448 return NSS_STATUS_SUCCESS
;
451 /* This function handle the +user entrys in /etc/passwd */
452 static enum nss_status
453 getpwnam_plususer (const char *name
, struct passwd
*result
, ent_t
*ent
,
454 char *buffer
, size_t buflen
, int *errnop
)
461 return NSS_STATUS_UNAVAIL
;
463 memset (&pwd
, '\0', sizeof (struct passwd
));
465 copy_pwd_changes (&pwd
, result
, NULL
, 0);
467 plen
= pwd_need_buflen (&pwd
);
471 return NSS_STATUS_TRYAGAIN
;
473 p
= buffer
+ (buflen
- plen
);
476 if (nss_getpwnam_r (name
, result
, buffer
, buflen
, errnop
) !=
478 return NSS_STATUS_NOTFOUND
;
480 if (in_blacklist (result
->pw_name
, strlen (result
->pw_name
), ent
))
481 return NSS_STATUS_NOTFOUND
;
483 copy_pwd_changes (result
, &pwd
, p
, plen
);
484 give_pwd_free (&pwd
);
485 /* We found the entry. */
486 return NSS_STATUS_SUCCESS
;
489 static enum nss_status
490 getpwent_next_file (struct passwd
*result
, ent_t
*ent
,
491 char *buffer
, size_t buflen
, int *errnop
)
493 struct parser_data
*data
= (void *) buffer
;
502 /* We need at least 3 characters for one line. */
503 if (__builtin_expect (buflen
< 3, 0))
507 return NSS_STATUS_TRYAGAIN
;
510 fgetpos (ent
->stream
, &pos
);
511 buffer
[buflen
- 1] = '\xff';
512 p
= fgets_unlocked (buffer
, buflen
, ent
->stream
);
513 if (p
== NULL
&& feof_unlocked (ent
->stream
))
514 return NSS_STATUS_NOTFOUND
;
516 if (p
== NULL
|| __builtin_expect (buffer
[buflen
- 1] != '\xff', 0))
519 fsetpos (ent
->stream
, &pos
);
523 /* Terminate the line for any case. */
524 buffer
[buflen
- 1] = '\0';
526 /* Skip leading blanks. */
530 while (*p
== '\0' || *p
== '#' || /* Ignore empty and comment lines. */
531 /* Parse the line. If it is invalid, loop to
532 get the next line of the file to parse. */
533 !(parse_res
= _nss_files_parse_pwent (p
, result
, data
, buflen
,
536 if (__builtin_expect (parse_res
== -1, 0))
537 /* The parser ran out of space. */
540 if (result
->pw_name
[0] != '+' && result
->pw_name
[0] != '-')
541 /* This is a real entry. */
545 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] == '@'
546 && result
->pw_name
[2] != '\0')
548 /* XXX Do not use fixed length buffer. */
550 char *user
, *host
, *domain
;
551 struct __netgrent netgrdata
;
553 bzero (&netgrdata
, sizeof (struct __netgrent
));
554 __internal_setnetgrent (&result
->pw_name
[2], &netgrdata
);
555 while (__internal_getnetgrent_r (&host
, &user
, &domain
, &netgrdata
,
556 buf2
, sizeof (buf2
), errnop
))
558 if (user
!= NULL
&& user
[0] != '-')
559 blacklist_store_name (user
, ent
);
561 __internal_endnetgrent (&netgrdata
);
566 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '@'
567 && result
->pw_name
[2] != '\0')
569 enum nss_status status
;
571 ent
->netgroup
= TRUE
;
573 copy_pwd_changes (&ent
->pwd
, result
, NULL
, 0);
575 status
= getpwent_next_nss_netgr (NULL
, result
, ent
,
577 buffer
, buflen
, errnop
);
578 if (status
== NSS_STATUS_RETURN
)
585 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] != '\0'
586 && result
->pw_name
[1] != '@')
588 blacklist_store_name (&result
->pw_name
[1], ent
);
593 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] != '\0'
594 && result
->pw_name
[1] != '@')
596 size_t len
= strlen (result
->pw_name
);
598 enum nss_status status
;
600 /* Store the User in the blacklist for the "+" at the end of
602 memcpy (buf
, &result
->pw_name
[1], len
);
603 status
= getpwnam_plususer (&result
->pw_name
[1], result
, ent
,
604 buffer
, buflen
, errnop
);
605 blacklist_store_name (buf
, ent
);
607 if (status
== NSS_STATUS_SUCCESS
) /* We found the entry. */
609 else if (status
== NSS_STATUS_RETURN
/* We couldn't parse the entry */
610 || status
== NSS_STATUS_NOTFOUND
) /* entry doesn't exist */
614 if (status
== NSS_STATUS_TRYAGAIN
)
616 /* The parser ran out of space */
617 fsetpos (ent
->stream
, &pos
);
625 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '\0')
629 copy_pwd_changes (&ent
->pwd
, result
, NULL
, 0);
631 return getpwent_next_nss (result
, ent
, buffer
, buflen
, errnop
);
635 return NSS_STATUS_SUCCESS
;
639 static enum nss_status
640 internal_getpwent_r (struct passwd
*pw
, ent_t
*ent
, char *buffer
,
641 size_t buflen
, int *errnop
)
645 enum nss_status status
;
647 /* We are searching members in a netgroup */
648 /* Since this is not the first call, we don't need the group name */
649 status
= getpwent_next_nss_netgr (NULL
, pw
, ent
, NULL
, buffer
, buflen
,
651 if (status
== NSS_STATUS_RETURN
)
652 return getpwent_next_file (pw
, ent
, buffer
, buflen
, errnop
);
657 return getpwent_next_file (pw
, ent
, buffer
, buflen
, errnop
);
659 return getpwent_next_nss (pw
, ent
, buffer
, buflen
, errnop
);
664 _nss_compat_getpwent_r (struct passwd
*pwd
, char *buffer
, size_t buflen
,
667 enum nss_status result
= NSS_STATUS_SUCCESS
;
669 __libc_lock_lock (lock
);
671 /* Be prepared that the setpwent function was not called before. */
673 init_nss_interface ();
675 if (ext_ent
.stream
== NULL
)
676 result
= internal_setpwent (&ext_ent
, 1);
678 if (result
== NSS_STATUS_SUCCESS
)
679 result
= internal_getpwent_r (pwd
, &ext_ent
, buffer
, buflen
, errnop
);
681 __libc_lock_unlock (lock
);
686 /* Searches in /etc/passwd and the NIS/NIS+ map for a special user */
687 static enum nss_status
688 internal_getpwnam_r (const char *name
, struct passwd
*result
, ent_t
*ent
,
689 char *buffer
, size_t buflen
, int *errnop
)
691 struct parser_data
*data
= (void *) buffer
;
701 /* We need at least 3 characters for one line. */
702 if (__builtin_expect (buflen
< 3, 0))
706 return NSS_STATUS_TRYAGAIN
;
709 fgetpos (ent
->stream
, &pos
);
710 buffer
[buflen
- 1] = '\xff';
711 p
= fgets_unlocked (buffer
, buflen
, ent
->stream
);
712 if (p
== NULL
&& feof_unlocked (ent
->stream
))
714 return NSS_STATUS_NOTFOUND
;
716 if (p
== NULL
|| __builtin_expect (buffer
[buflen
- 1] != '\xff', 0))
719 fsetpos (ent
->stream
, &pos
);
723 /* Terminate the line for any case. */
724 buffer
[buflen
- 1] = '\0';
726 /* Skip leading blanks. */
730 while (*p
== '\0' || *p
== '#' || /* Ignore empty and comment lines. */
731 /* Parse the line. If it is invalid, loop to
732 get the next line of the file to parse. */
733 !(parse_res
= _nss_files_parse_pwent (p
, result
, data
, buflen
,
736 if (__builtin_expect (parse_res
== -1, 0))
737 /* The parser ran out of space. */
740 /* This is a real entry. */
741 if (result
->pw_name
[0] != '+' && result
->pw_name
[0] != '-')
743 if (strcmp (result
->pw_name
, name
) == 0)
744 return NSS_STATUS_SUCCESS
;
750 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] == '@'
751 && result
->pw_name
[2] != '\0')
753 if (innetgr (&result
->pw_name
[2], NULL
, name
, NULL
))
754 return NSS_STATUS_NOTFOUND
;
759 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '@'
760 && result
->pw_name
[2] != '\0')
762 enum nss_status status
;
764 if (innetgr (&result
->pw_name
[2], NULL
, name
, NULL
))
766 status
= getpwnam_plususer (name
, result
, ent
, buffer
,
769 if (status
== NSS_STATUS_RETURN
)
778 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] != '\0'
779 && result
->pw_name
[1] != '@')
781 if (strcmp (&result
->pw_name
[1], name
) == 0)
782 return NSS_STATUS_NOTFOUND
;
788 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] != '\0'
789 && result
->pw_name
[1] != '@')
791 if (strcmp (name
, &result
->pw_name
[1]) == 0)
793 enum nss_status status
;
795 status
= getpwnam_plususer (name
, result
, ent
, buffer
, buflen
,
797 if (status
== NSS_STATUS_RETURN
)
798 /* We couldn't parse the entry */
799 return NSS_STATUS_NOTFOUND
;
806 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '\0')
808 enum nss_status status
;
810 status
= getpwnam_plususer (name
, result
, ent
,
811 buffer
, buflen
, errnop
);
812 if (status
== NSS_STATUS_SUCCESS
) /* We found the entry. */
814 else if (status
== NSS_STATUS_RETURN
) /* We couldn't parse the entry */
815 return NSS_STATUS_NOTFOUND
;
820 return NSS_STATUS_SUCCESS
;
824 _nss_compat_getpwnam_r (const char *name
, struct passwd
*pwd
,
825 char *buffer
, size_t buflen
, int *errnop
)
827 enum nss_status result
;
828 ent_t ent
= {0, 0, TRUE
, NULL
, {NULL
, 0, 0},
829 {NULL
, NULL
, 0, 0, NULL
, NULL
, NULL
}};
831 if (name
[0] == '-' || name
[0] == '+')
832 return NSS_STATUS_NOTFOUND
;
834 __libc_lock_lock (lock
);
837 init_nss_interface ();
839 __libc_lock_unlock (lock
);
841 result
= internal_setpwent (&ent
, 0);
843 if (result
== NSS_STATUS_SUCCESS
)
844 result
= internal_getpwnam_r (name
, pwd
, &ent
, buffer
, buflen
, errnop
);
846 internal_endpwent (&ent
);
851 /* This function handle the + entry in /etc/passwd for getpwuid */
852 static enum nss_status
853 getpwuid_plususer (uid_t uid
, struct passwd
*result
, char *buffer
,
854 size_t buflen
, int *errnop
)
861 return NSS_STATUS_UNAVAIL
;
863 memset (&pwd
, '\0', sizeof (struct passwd
));
865 copy_pwd_changes (&pwd
, result
, NULL
, 0);
867 plen
= pwd_need_buflen (&pwd
);
871 return NSS_STATUS_TRYAGAIN
;
873 p
= buffer
+ (buflen
- plen
);
876 if (nss_getpwuid_r (uid
, result
, buffer
, buflen
, errnop
) ==
879 copy_pwd_changes (result
, &pwd
, p
, plen
);
880 give_pwd_free (&pwd
);
881 /* We found the entry. */
882 return NSS_STATUS_SUCCESS
;
886 /* Give buffer the old len back */
888 give_pwd_free (&pwd
);
890 return NSS_STATUS_RETURN
;
893 /* Searches in /etc/passwd and the NSS subsystem for a special user id */
894 static enum nss_status
895 internal_getpwuid_r (uid_t uid
, struct passwd
*result
, ent_t
*ent
,
896 char *buffer
, size_t buflen
, int *errnop
)
898 struct parser_data
*data
= (void *) buffer
;
908 /* We need at least 3 characters for one line. */
909 if (__builtin_expect (buflen
< 3, 0))
913 return NSS_STATUS_TRYAGAIN
;
916 fgetpos (ent
->stream
, &pos
);
917 buffer
[buflen
- 1] = '\xff';
918 p
= fgets_unlocked (buffer
, buflen
, ent
->stream
);
919 if (p
== NULL
&& feof_unlocked (ent
->stream
))
920 return NSS_STATUS_NOTFOUND
;
922 if (p
== NULL
|| __builtin_expect (buffer
[buflen
- 1] != '\xff', 0))
925 fsetpos (ent
->stream
, &pos
);
929 /* Terminate the line for any case. */
930 buffer
[buflen
- 1] = '\0';
932 /* Skip leading blanks. */
936 while (*p
== '\0' || *p
== '#' || /* Ignore empty and comment lines. */
937 /* Parse the line. If it is invalid, loop to
938 get the next line of the file to parse. */
939 !(parse_res
= _nss_files_parse_pwent (p
, result
, data
, buflen
,
942 if (__builtin_expect (parse_res
== -1, 0))
943 /* The parser ran out of space. */
946 /* This is a real entry. */
947 if (result
->pw_name
[0] != '+' && result
->pw_name
[0] != '-')
949 if (result
->pw_uid
== uid
)
950 return NSS_STATUS_SUCCESS
;
956 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] == '@'
957 && result
->pw_name
[2] != '\0')
959 /* -1, because we remove first two character of pw_name. */
960 size_t len
= strlen (result
->pw_name
) - 1;
962 enum nss_status status
;
964 memcpy (buf
, &result
->pw_name
[2], len
);
966 status
= getpwuid_plususer (uid
, result
, buffer
, buflen
, errnop
);
967 if (status
== NSS_STATUS_SUCCESS
&&
968 innetgr (buf
, NULL
, result
->pw_name
, NULL
))
969 return NSS_STATUS_NOTFOUND
;
975 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '@'
976 && result
->pw_name
[2] != '\0')
978 /* -1, because we remove first two characters of pw_name. */
979 size_t len
= strlen (result
->pw_name
) - 1;
981 enum nss_status status
;
983 memcpy (buf
, &result
->pw_name
[2], len
);
985 status
= getpwuid_plususer (uid
, result
, buffer
, buflen
, errnop
);
987 if (status
== NSS_STATUS_RETURN
)
990 if (status
== NSS_STATUS_SUCCESS
)
992 if (innetgr (buf
, NULL
, result
->pw_name
, NULL
))
993 return NSS_STATUS_SUCCESS
;
995 else if (status
== NSS_STATUS_RETURN
) /* We couldn't parse the entry */
996 return NSS_STATUS_NOTFOUND
;
1004 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] != '\0'
1005 && result
->pw_name
[1] != '@')
1007 size_t len
= strlen (result
->pw_name
);
1009 enum nss_status status
;
1011 memcpy (buf
, &result
->pw_name
[1], len
);
1013 status
= getpwuid_plususer (uid
, result
, buffer
, buflen
, errnop
);
1014 if (status
== NSS_STATUS_SUCCESS
&&
1015 innetgr (buf
, NULL
, result
->pw_name
, NULL
))
1016 return NSS_STATUS_NOTFOUND
;
1021 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] != '\0'
1022 && result
->pw_name
[1] != '@')
1024 size_t len
= strlen (result
->pw_name
);
1026 enum nss_status status
;
1028 memcpy (buf
, &result
->pw_name
[1], len
);
1030 status
= getpwuid_plususer (uid
, result
, buffer
, buflen
, errnop
);
1032 if (status
== NSS_STATUS_RETURN
)
1035 if (status
== NSS_STATUS_SUCCESS
)
1037 if (strcmp (buf
, result
->pw_name
) == 0)
1038 return NSS_STATUS_SUCCESS
;
1040 else if (status
== NSS_STATUS_RETURN
) /* We couldn't parse the entry */
1041 return NSS_STATUS_NOTFOUND
;
1049 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '\0')
1051 enum nss_status status
;
1053 status
= getpwuid_plususer (uid
, result
, buffer
, buflen
, errnop
);
1054 if (status
== NSS_STATUS_SUCCESS
) /* We found the entry. */
1056 else if (status
== NSS_STATUS_RETURN
) /* We couldn't parse the entry */
1057 return NSS_STATUS_NOTFOUND
;
1062 return NSS_STATUS_SUCCESS
;
1066 _nss_compat_getpwuid_r (uid_t uid
, struct passwd
*pwd
,
1067 char *buffer
, size_t buflen
, int *errnop
)
1069 enum nss_status result
;
1070 ent_t ent
= {0, 0, TRUE
, NULL
, {NULL
, 0, 0},
1071 {NULL
, NULL
, 0, 0, NULL
, NULL
, NULL
}};
1073 __libc_lock_lock (lock
);
1076 init_nss_interface ();
1078 __libc_lock_unlock (lock
);
1080 result
= internal_setpwent (&ent
, 0);
1082 if (result
== NSS_STATUS_SUCCESS
)
1083 result
= internal_getpwuid_r (uid
, pwd
, &ent
, buffer
, buflen
, errnop
);
1085 internal_endpwent (&ent
);
1091 /* Support routines for remembering -@netgroup and -user entries.
1092 The names are stored in a single string with `|' as separator. */
1094 blacklist_store_name (const char *name
, ent_t
*ent
)
1096 int namelen
= strlen (name
);
1099 /* first call, setup cache */
1100 if (ent
->blacklist
.size
== 0)
1102 ent
->blacklist
.size
= MAX (BLACKLIST_INITIAL_SIZE
, 2 * namelen
);
1103 ent
->blacklist
.data
= malloc (ent
->blacklist
.size
);
1104 if (ent
->blacklist
.data
== NULL
)
1106 ent
->blacklist
.data
[0] = '|';
1107 ent
->blacklist
.data
[1] = '\0';
1108 ent
->blacklist
.current
= 1;
1112 if (in_blacklist (name
, namelen
, ent
))
1113 return; /* no duplicates */
1115 if (ent
->blacklist
.current
+ namelen
+ 1 >= ent
->blacklist
.size
)
1117 ent
->blacklist
.size
+= MAX (BLACKLIST_INCREMENT
, 2 * namelen
);
1118 tmp
= realloc (ent
->blacklist
.data
, ent
->blacklist
.size
);
1121 free (ent
->blacklist
.data
);
1122 ent
->blacklist
.size
= 0;
1125 ent
->blacklist
.data
= tmp
;
1129 tmp
= stpcpy (ent
->blacklist
.data
+ ent
->blacklist
.current
, name
);
1132 ent
->blacklist
.current
+= namelen
+ 1;
1137 /* returns TRUE if ent->blacklist contains name, else FALSE */
1139 in_blacklist (const char *name
, int namelen
, ent_t
*ent
)
1141 char buf
[namelen
+ 3];
1144 if (ent
->blacklist
.data
== NULL
)
1148 cp
= stpcpy (&buf
[1], name
);
1151 return strstr (ent
->blacklist
.data
, buf
) != NULL
;