1 /* Copyright (C) 1996-1999, 2001-2006, 2007 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>
32 #include <kernel-features.h>
36 static service_user
*ni
;
37 static enum nss_status (*nss_setpwent
) (int stayopen
);
38 static enum nss_status (*nss_getpwnam_r
) (const char *name
,
39 struct passwd
* pwd
, char *buffer
,
40 size_t buflen
, int *errnop
);
41 static enum nss_status (*nss_getpwuid_r
) (uid_t uid
, struct passwd
* pwd
,
42 char *buffer
, size_t buflen
,
44 static enum nss_status (*nss_getpwent_r
) (struct passwd
* pwd
, char *buffer
,
45 size_t buflen
, int *errnop
);
46 static enum nss_status (*nss_endpwent
) (void);
48 /* Get the declaration of the parser function. */
50 #define STRUCTURE passwd
52 #include <nss/nss_files/files-parse.c>
54 /* Structure for remembering -@netgroup and -user members ... */
55 #define BLACKLIST_INITIAL_SIZE 512
56 #define BLACKLIST_INCREMENT 256
69 enum nss_status setent_status
;
71 struct blacklist_t blacklist
;
73 struct __netgrent netgrdata
;
75 typedef struct ent_t ent_t
;
77 static ent_t ext_ent
= { false, false, true, NSS_STATUS_SUCCESS
, NULL
,
79 { NULL
, NULL
, 0, 0, NULL
, NULL
, NULL
}};
81 /* Protect global state against multiple changers. */
82 __libc_lock_define_initialized (static, lock
)
84 /* Positive if O_CLOEXEC is supported, negative if it is not supported,
85 zero if it is still undecided. This variable is shared with the
86 other compat functions. */
87 #ifdef __ASSUME_O_CLOEXEC
88 # define __compat_have_cloexec 1
91 extern int __compat_have_cloexec
;
93 # define __compat_have_cloexec -1
97 /* Prototypes for local functions. */
98 static void blacklist_store_name (const char *, ent_t
*);
99 static int in_blacklist (const char *, int, ent_t
*);
101 /* Initialize the NSS interface/functions. The calling function must
104 init_nss_interface (void)
106 if (__nss_database_lookup ("passwd_compat", NULL
, "nis", &ni
) >= 0)
108 nss_setpwent
= __nss_lookup_function (ni
, "setpwent");
109 nss_getpwnam_r
= __nss_lookup_function (ni
, "getpwnam_r");
110 nss_getpwuid_r
= __nss_lookup_function (ni
, "getpwuid_r");
111 nss_getpwent_r
= __nss_lookup_function (ni
, "getpwent_r");
112 nss_endpwent
= __nss_lookup_function (ni
, "endpwent");
117 give_pwd_free (struct passwd
*pwd
)
119 if (pwd
->pw_name
!= NULL
)
121 if (pwd
->pw_passwd
!= NULL
)
122 free (pwd
->pw_passwd
);
123 if (pwd
->pw_gecos
!= NULL
)
124 free (pwd
->pw_gecos
);
125 if (pwd
->pw_dir
!= NULL
)
127 if (pwd
->pw_shell
!= NULL
)
128 free (pwd
->pw_shell
);
130 memset (pwd
, '\0', sizeof (struct passwd
));
134 pwd_need_buflen (struct passwd
*pwd
)
138 if (pwd
->pw_passwd
!= NULL
)
139 len
+= strlen (pwd
->pw_passwd
) + 1;
141 if (pwd
->pw_gecos
!= NULL
)
142 len
+= strlen (pwd
->pw_gecos
) + 1;
144 if (pwd
->pw_dir
!= NULL
)
145 len
+= strlen (pwd
->pw_dir
) + 1;
147 if (pwd
->pw_shell
!= NULL
)
148 len
+= strlen (pwd
->pw_shell
) + 1;
154 copy_pwd_changes (struct passwd
*dest
, struct passwd
*src
,
155 char *buffer
, size_t buflen
)
157 if (src
->pw_passwd
!= NULL
&& strlen (src
->pw_passwd
))
160 dest
->pw_passwd
= strdup (src
->pw_passwd
);
161 else if (dest
->pw_passwd
&&
162 strlen (dest
->pw_passwd
) >= strlen (src
->pw_passwd
))
163 strcpy (dest
->pw_passwd
, src
->pw_passwd
);
166 dest
->pw_passwd
= buffer
;
167 strcpy (dest
->pw_passwd
, src
->pw_passwd
);
168 buffer
+= strlen (dest
->pw_passwd
) + 1;
169 buflen
= buflen
- (strlen (dest
->pw_passwd
) + 1);
173 if (src
->pw_gecos
!= NULL
&& strlen (src
->pw_gecos
))
176 dest
->pw_gecos
= strdup (src
->pw_gecos
);
177 else if (dest
->pw_gecos
&&
178 strlen (dest
->pw_gecos
) >= strlen (src
->pw_gecos
))
179 strcpy (dest
->pw_gecos
, src
->pw_gecos
);
182 dest
->pw_gecos
= buffer
;
183 strcpy (dest
->pw_gecos
, src
->pw_gecos
);
184 buffer
+= strlen (dest
->pw_gecos
) + 1;
185 buflen
= buflen
- (strlen (dest
->pw_gecos
) + 1);
188 if (src
->pw_dir
!= NULL
&& strlen (src
->pw_dir
))
191 dest
->pw_dir
= strdup (src
->pw_dir
);
192 else if (dest
->pw_dir
&& strlen (dest
->pw_dir
) >= strlen (src
->pw_dir
))
193 strcpy (dest
->pw_dir
, src
->pw_dir
);
196 dest
->pw_dir
= buffer
;
197 strcpy (dest
->pw_dir
, src
->pw_dir
);
198 buffer
+= strlen (dest
->pw_dir
) + 1;
199 buflen
= buflen
- (strlen (dest
->pw_dir
) + 1);
203 if (src
->pw_shell
!= NULL
&& strlen (src
->pw_shell
))
206 dest
->pw_shell
= strdup (src
->pw_shell
);
207 else if (dest
->pw_shell
&&
208 strlen (dest
->pw_shell
) >= strlen (src
->pw_shell
))
209 strcpy (dest
->pw_shell
, src
->pw_shell
);
212 dest
->pw_shell
= buffer
;
213 strcpy (dest
->pw_shell
, src
->pw_shell
);
214 buffer
+= strlen (dest
->pw_shell
) + 1;
215 buflen
= buflen
- (strlen (dest
->pw_shell
) + 1);
220 static enum nss_status
221 internal_setpwent (ent_t
*ent
, int stayopen
, int needent
)
223 enum nss_status status
= NSS_STATUS_SUCCESS
;
225 ent
->first
= ent
->netgroup
= false;
227 ent
->setent_status
= NSS_STATUS_SUCCESS
;
229 /* If something was left over free it. */
231 __internal_endnetgrent (&ent
->netgrdata
);
233 if (ent
->blacklist
.data
!= NULL
)
235 ent
->blacklist
.current
= 1;
236 ent
->blacklist
.data
[0] = '|';
237 ent
->blacklist
.data
[1] = '\0';
240 ent
->blacklist
.current
= 0;
242 if (ent
->stream
== NULL
)
244 ent
->stream
= fopen ("/etc/passwd", "rme");
246 if (ent
->stream
== NULL
)
247 status
= errno
== EAGAIN
? NSS_STATUS_TRYAGAIN
: NSS_STATUS_UNAVAIL
;
250 /* We have to make sure the file is `closed on exec'. */
253 if (__compat_have_cloexec
<= 0)
256 result
= flags
= fcntl (fileno_unlocked (ent
->stream
), F_GETFD
,
260 #if defined O_CLOEXEC && !defined __ASSUME_O_CLOEXEC
261 if (__compat_have_cloexec
== 0)
262 __compat_have_cloexec
= (flags
& FD_CLOEXEC
) ? 1 : -1;
264 if (__compat_have_cloexec
< 0)
268 result
= fcntl (fileno_unlocked (ent
->stream
), F_SETFD
,
276 /* Something went wrong. Close the stream and return a
278 fclose (ent
->stream
);
280 status
= NSS_STATUS_UNAVAIL
;
283 /* We take care of locking ourself. */
284 __fsetlocking (ent
->stream
, FSETLOCKING_BYCALLER
);
288 rewind (ent
->stream
);
290 give_pwd_free (&ent
->pwd
);
292 if (needent
&& status
== NSS_STATUS_SUCCESS
&& nss_setpwent
)
293 ent
->setent_status
= nss_setpwent (stayopen
);
300 _nss_compat_setpwent (int stayopen
)
302 enum nss_status result
;
304 __libc_lock_lock (lock
);
307 init_nss_interface ();
309 result
= internal_setpwent (&ext_ent
, stayopen
, 1);
311 __libc_lock_unlock (lock
);
317 static enum nss_status
318 internal_endpwent (ent_t
*ent
)
323 if (ent
->stream
!= NULL
)
325 fclose (ent
->stream
);
330 __internal_endnetgrent (&ent
->netgrdata
);
332 ent
->first
= ent
->netgroup
= false;
334 if (ent
->blacklist
.data
!= NULL
)
336 ent
->blacklist
.current
= 1;
337 ent
->blacklist
.data
[0] = '|';
338 ent
->blacklist
.data
[1] = '\0';
341 ent
->blacklist
.current
= 0;
343 give_pwd_free (&ent
->pwd
);
345 return NSS_STATUS_SUCCESS
;
349 _nss_compat_endpwent (void)
351 enum nss_status result
;
353 __libc_lock_lock (lock
);
355 result
= internal_endpwent (&ext_ent
);
357 __libc_lock_unlock (lock
);
363 static enum nss_status
364 getpwent_next_nss_netgr (const char *name
, struct passwd
*result
, ent_t
*ent
,
365 char *group
, char *buffer
, size_t buflen
,
368 char *curdomain
, *host
, *user
, *domain
, *p2
;
372 /* Leave function if NSS module does not support getpwnam_r,
373 we need this function here. */
375 return NSS_STATUS_UNAVAIL
;
377 if (yp_get_default_domain (&curdomain
) != YPERR_SUCCESS
)
379 ent
->netgroup
= false;
381 give_pwd_free (&ent
->pwd
);
382 return NSS_STATUS_UNAVAIL
;
385 if (ent
->first
== true)
387 memset (&ent
->netgrdata
, 0, sizeof (struct __netgrent
));
388 __internal_setnetgrent (group
, &ent
->netgrdata
);
396 saved_cursor
= ent
->netgrdata
.cursor
;
397 status
= __internal_getnetgrent_r (&host
, &user
, &domain
,
398 &ent
->netgrdata
, buffer
, buflen
,
402 __internal_endnetgrent (&ent
->netgrdata
);
404 give_pwd_free (&ent
->pwd
);
405 return NSS_STATUS_RETURN
;
408 if (user
== NULL
|| user
[0] == '-')
411 if (domain
!= NULL
&& strcmp (curdomain
, domain
) != 0)
414 /* If name != NULL, we are called from getpwnam. */
416 if (strcmp (user
, name
) != 0)
419 p2len
= pwd_need_buflen (&ent
->pwd
);
423 return NSS_STATUS_TRYAGAIN
;
425 p2
= buffer
+ (buflen
- p2len
);
428 if (nss_getpwnam_r (user
, result
, buffer
, buflen
, errnop
) !=
432 if (!in_blacklist (result
->pw_name
, strlen (result
->pw_name
), ent
))
434 /* Store the User in the blacklist for possible the "+" at the
435 end of /etc/passwd */
436 blacklist_store_name (result
->pw_name
, ent
);
437 copy_pwd_changes (result
, &ent
->pwd
, p2
, p2len
);
442 return NSS_STATUS_SUCCESS
;
445 /* get the next user from NSS (+ entry) */
446 static enum nss_status
447 getpwent_next_nss (struct passwd
*result
, ent_t
*ent
, char *buffer
,
448 size_t buflen
, int *errnop
)
450 enum nss_status status
;
454 /* Return if NSS module does not support getpwent_r. */
456 return NSS_STATUS_UNAVAIL
;
458 /* If the setpwent call failed, say so. */
459 if (ent
->setent_status
!= NSS_STATUS_SUCCESS
)
460 return ent
->setent_status
;
462 p2len
= pwd_need_buflen (&ent
->pwd
);
466 return NSS_STATUS_TRYAGAIN
;
468 p2
= buffer
+ (buflen
- p2len
);
476 if ((status
= nss_getpwent_r (result
, buffer
, buflen
, errnop
)) !=
480 while (in_blacklist (result
->pw_name
, strlen (result
->pw_name
), ent
));
482 copy_pwd_changes (result
, &ent
->pwd
, p2
, p2len
);
484 return NSS_STATUS_SUCCESS
;
487 /* This function handle the +user entrys in /etc/passwd */
488 static enum nss_status
489 getpwnam_plususer (const char *name
, struct passwd
*result
, ent_t
*ent
,
490 char *buffer
, size_t buflen
, int *errnop
)
493 return NSS_STATUS_UNAVAIL
;
496 memset (&pwd
, '\0', sizeof (struct passwd
));
498 copy_pwd_changes (&pwd
, result
, NULL
, 0);
500 size_t plen
= pwd_need_buflen (&pwd
);
504 return NSS_STATUS_TRYAGAIN
;
506 char *p
= buffer
+ (buflen
- plen
);
509 enum nss_status status
= nss_getpwnam_r (name
, result
, buffer
, buflen
,
511 if (status
!= NSS_STATUS_SUCCESS
)
514 if (in_blacklist (result
->pw_name
, strlen (result
->pw_name
), ent
))
515 return NSS_STATUS_NOTFOUND
;
517 copy_pwd_changes (result
, &pwd
, p
, plen
);
518 give_pwd_free (&pwd
);
519 /* We found the entry. */
520 return NSS_STATUS_SUCCESS
;
523 static enum nss_status
524 getpwent_next_file (struct passwd
*result
, ent_t
*ent
,
525 char *buffer
, size_t buflen
, int *errnop
)
527 struct parser_data
*data
= (void *) buffer
;
536 /* We need at least 3 characters for one line. */
537 if (__builtin_expect (buflen
< 3, 0))
541 return NSS_STATUS_TRYAGAIN
;
544 fgetpos (ent
->stream
, &pos
);
545 buffer
[buflen
- 1] = '\xff';
546 p
= fgets_unlocked (buffer
, buflen
, ent
->stream
);
547 if (p
== NULL
&& feof_unlocked (ent
->stream
))
548 return NSS_STATUS_NOTFOUND
;
550 if (p
== NULL
|| __builtin_expect (buffer
[buflen
- 1] != '\xff', 0))
553 fsetpos (ent
->stream
, &pos
);
557 /* Terminate the line for any case. */
558 buffer
[buflen
- 1] = '\0';
560 /* Skip leading blanks. */
564 while (*p
== '\0' || *p
== '#' || /* Ignore empty and comment lines. */
565 /* Parse the line. If it is invalid, loop to
566 get the next line of the file to parse. */
567 !(parse_res
= _nss_files_parse_pwent (p
, result
, data
, buflen
,
570 if (__builtin_expect (parse_res
== -1, 0))
571 /* The parser ran out of space. */
574 if (result
->pw_name
[0] != '+' && result
->pw_name
[0] != '-')
575 /* This is a real entry. */
579 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] == '@'
580 && result
->pw_name
[2] != '\0')
582 /* XXX Do not use fixed length buffer. */
584 char *user
, *host
, *domain
;
585 struct __netgrent netgrdata
;
587 bzero (&netgrdata
, sizeof (struct __netgrent
));
588 __internal_setnetgrent (&result
->pw_name
[2], &netgrdata
);
589 while (__internal_getnetgrent_r (&host
, &user
, &domain
, &netgrdata
,
590 buf2
, sizeof (buf2
), errnop
))
592 if (user
!= NULL
&& user
[0] != '-')
593 blacklist_store_name (user
, ent
);
595 __internal_endnetgrent (&netgrdata
);
600 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '@'
601 && result
->pw_name
[2] != '\0')
603 enum nss_status status
;
605 ent
->netgroup
= true;
607 copy_pwd_changes (&ent
->pwd
, result
, NULL
, 0);
609 status
= getpwent_next_nss_netgr (NULL
, result
, ent
,
611 buffer
, buflen
, errnop
);
612 if (status
== NSS_STATUS_RETURN
)
619 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] != '\0'
620 && result
->pw_name
[1] != '@')
622 blacklist_store_name (&result
->pw_name
[1], ent
);
627 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] != '\0'
628 && result
->pw_name
[1] != '@')
630 size_t len
= strlen (result
->pw_name
);
632 enum nss_status status
;
634 /* Store the User in the blacklist for the "+" at the end of
636 memcpy (buf
, &result
->pw_name
[1], len
);
637 status
= getpwnam_plususer (&result
->pw_name
[1], result
, ent
,
638 buffer
, buflen
, errnop
);
639 blacklist_store_name (buf
, ent
);
641 if (status
== NSS_STATUS_SUCCESS
) /* We found the entry. */
643 else if (status
== NSS_STATUS_RETURN
/* We couldn't parse the entry */
644 || status
== NSS_STATUS_NOTFOUND
) /* entry doesn't exist */
648 if (status
== NSS_STATUS_TRYAGAIN
)
650 /* The parser ran out of space */
651 fsetpos (ent
->stream
, &pos
);
659 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '\0')
663 copy_pwd_changes (&ent
->pwd
, result
, NULL
, 0);
665 return getpwent_next_nss (result
, ent
, buffer
, buflen
, errnop
);
669 return NSS_STATUS_SUCCESS
;
673 static enum nss_status
674 internal_getpwent_r (struct passwd
*pw
, ent_t
*ent
, char *buffer
,
675 size_t buflen
, int *errnop
)
679 enum nss_status status
;
681 /* We are searching members in a netgroup */
682 /* Since this is not the first call, we don't need the group name */
683 status
= getpwent_next_nss_netgr (NULL
, pw
, ent
, NULL
, buffer
, buflen
,
685 if (status
== NSS_STATUS_RETURN
)
686 return getpwent_next_file (pw
, ent
, buffer
, buflen
, errnop
);
691 return getpwent_next_file (pw
, ent
, buffer
, buflen
, errnop
);
693 return getpwent_next_nss (pw
, ent
, buffer
, buflen
, errnop
);
698 _nss_compat_getpwent_r (struct passwd
*pwd
, char *buffer
, size_t buflen
,
701 enum nss_status result
= NSS_STATUS_SUCCESS
;
703 __libc_lock_lock (lock
);
705 /* Be prepared that the setpwent function was not called before. */
707 init_nss_interface ();
709 if (ext_ent
.stream
== NULL
)
710 result
= internal_setpwent (&ext_ent
, 1, 1);
712 if (result
== NSS_STATUS_SUCCESS
)
713 result
= internal_getpwent_r (pwd
, &ext_ent
, buffer
, buflen
, errnop
);
715 __libc_lock_unlock (lock
);
720 /* Searches in /etc/passwd and the NIS/NIS+ map for a special user */
721 static enum nss_status
722 internal_getpwnam_r (const char *name
, struct passwd
*result
, ent_t
*ent
,
723 char *buffer
, size_t buflen
, int *errnop
)
725 struct parser_data
*data
= (void *) buffer
;
735 /* We need at least 3 characters for one line. */
736 if (__builtin_expect (buflen
< 3, 0))
740 return NSS_STATUS_TRYAGAIN
;
743 fgetpos (ent
->stream
, &pos
);
744 buffer
[buflen
- 1] = '\xff';
745 p
= fgets_unlocked (buffer
, buflen
, ent
->stream
);
746 if (p
== NULL
&& feof_unlocked (ent
->stream
))
748 return NSS_STATUS_NOTFOUND
;
750 if (p
== NULL
|| __builtin_expect (buffer
[buflen
- 1] != '\xff', 0))
753 fsetpos (ent
->stream
, &pos
);
757 /* Terminate the line for any case. */
758 buffer
[buflen
- 1] = '\0';
760 /* Skip leading blanks. */
764 while (*p
== '\0' || *p
== '#' || /* Ignore empty and comment lines. */
765 /* Parse the line. If it is invalid, loop to
766 get the next line of the file to parse. */
767 !(parse_res
= _nss_files_parse_pwent (p
, result
, data
, buflen
,
770 if (__builtin_expect (parse_res
== -1, 0))
771 /* The parser ran out of space. */
774 /* This is a real entry. */
775 if (result
->pw_name
[0] != '+' && result
->pw_name
[0] != '-')
777 if (strcmp (result
->pw_name
, name
) == 0)
778 return NSS_STATUS_SUCCESS
;
784 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] == '@'
785 && result
->pw_name
[2] != '\0')
787 if (innetgr (&result
->pw_name
[2], NULL
, name
, NULL
))
788 return NSS_STATUS_NOTFOUND
;
793 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '@'
794 && result
->pw_name
[2] != '\0')
796 enum nss_status status
;
798 if (innetgr (&result
->pw_name
[2], NULL
, name
, NULL
))
800 status
= getpwnam_plususer (name
, result
, ent
, buffer
,
803 if (status
== NSS_STATUS_RETURN
)
812 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] != '\0'
813 && result
->pw_name
[1] != '@')
815 if (strcmp (&result
->pw_name
[1], name
) == 0)
816 return NSS_STATUS_NOTFOUND
;
822 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] != '\0'
823 && result
->pw_name
[1] != '@')
825 if (strcmp (name
, &result
->pw_name
[1]) == 0)
827 enum nss_status status
;
829 status
= getpwnam_plususer (name
, result
, ent
, buffer
, buflen
,
831 if (status
== NSS_STATUS_RETURN
)
832 /* We couldn't parse the entry */
833 return NSS_STATUS_NOTFOUND
;
840 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '\0')
842 enum nss_status status
;
844 status
= getpwnam_plususer (name
, result
, ent
,
845 buffer
, buflen
, errnop
);
846 if (status
== NSS_STATUS_SUCCESS
) /* We found the entry. */
848 else if (status
== NSS_STATUS_RETURN
) /* We couldn't parse the entry */
849 return NSS_STATUS_NOTFOUND
;
854 return NSS_STATUS_SUCCESS
;
858 _nss_compat_getpwnam_r (const char *name
, struct passwd
*pwd
,
859 char *buffer
, size_t buflen
, int *errnop
)
861 enum nss_status result
;
862 ent_t ent
= { false, false, true, NSS_STATUS_SUCCESS
, NULL
, { NULL
, 0, 0 },
863 { NULL
, NULL
, 0, 0, NULL
, NULL
, NULL
}};
865 if (name
[0] == '-' || name
[0] == '+')
866 return NSS_STATUS_NOTFOUND
;
868 __libc_lock_lock (lock
);
871 init_nss_interface ();
873 __libc_lock_unlock (lock
);
875 result
= internal_setpwent (&ent
, 0, 0);
877 if (result
== NSS_STATUS_SUCCESS
)
878 result
= internal_getpwnam_r (name
, pwd
, &ent
, buffer
, buflen
, errnop
);
880 internal_endpwent (&ent
);
885 /* This function handle the + entry in /etc/passwd for getpwuid */
886 static enum nss_status
887 getpwuid_plususer (uid_t uid
, struct passwd
*result
, char *buffer
,
888 size_t buflen
, int *errnop
)
895 return NSS_STATUS_UNAVAIL
;
897 memset (&pwd
, '\0', sizeof (struct passwd
));
899 copy_pwd_changes (&pwd
, result
, NULL
, 0);
901 plen
= pwd_need_buflen (&pwd
);
905 return NSS_STATUS_TRYAGAIN
;
907 p
= buffer
+ (buflen
- plen
);
910 if (nss_getpwuid_r (uid
, result
, buffer
, buflen
, errnop
) ==
913 copy_pwd_changes (result
, &pwd
, p
, plen
);
914 give_pwd_free (&pwd
);
915 /* We found the entry. */
916 return NSS_STATUS_SUCCESS
;
920 /* Give buffer the old len back */
922 give_pwd_free (&pwd
);
924 return NSS_STATUS_RETURN
;
927 /* Searches in /etc/passwd and the NSS subsystem for a special user id */
928 static enum nss_status
929 internal_getpwuid_r (uid_t uid
, struct passwd
*result
, ent_t
*ent
,
930 char *buffer
, size_t buflen
, int *errnop
)
932 struct parser_data
*data
= (void *) buffer
;
942 /* We need at least 3 characters for one line. */
943 if (__builtin_expect (buflen
< 3, 0))
947 return NSS_STATUS_TRYAGAIN
;
950 fgetpos (ent
->stream
, &pos
);
951 buffer
[buflen
- 1] = '\xff';
952 p
= fgets_unlocked (buffer
, buflen
, ent
->stream
);
953 if (p
== NULL
&& feof_unlocked (ent
->stream
))
954 return NSS_STATUS_NOTFOUND
;
956 if (p
== NULL
|| __builtin_expect (buffer
[buflen
- 1] != '\xff', 0))
959 fsetpos (ent
->stream
, &pos
);
963 /* Terminate the line for any case. */
964 buffer
[buflen
- 1] = '\0';
966 /* Skip leading blanks. */
970 while (*p
== '\0' || *p
== '#' || /* Ignore empty and comment lines. */
971 /* Parse the line. If it is invalid, loop to
972 get the next line of the file to parse. */
973 !(parse_res
= _nss_files_parse_pwent (p
, result
, data
, buflen
,
976 if (__builtin_expect (parse_res
== -1, 0))
977 /* The parser ran out of space. */
980 /* This is a real entry. */
981 if (result
->pw_name
[0] != '+' && result
->pw_name
[0] != '-')
983 if (result
->pw_uid
== uid
)
984 return NSS_STATUS_SUCCESS
;
990 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] == '@'
991 && result
->pw_name
[2] != '\0')
993 /* -1, because we remove first two character of pw_name. */
994 size_t len
= strlen (result
->pw_name
) - 1;
996 enum nss_status status
;
998 memcpy (buf
, &result
->pw_name
[2], len
);
1000 status
= getpwuid_plususer (uid
, result
, buffer
, buflen
, errnop
);
1001 if (status
== NSS_STATUS_SUCCESS
&&
1002 innetgr (buf
, NULL
, result
->pw_name
, NULL
))
1003 return NSS_STATUS_NOTFOUND
;
1009 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '@'
1010 && result
->pw_name
[2] != '\0')
1012 /* -1, because we remove first two characters of pw_name. */
1013 size_t len
= strlen (result
->pw_name
) - 1;
1015 enum nss_status status
;
1017 memcpy (buf
, &result
->pw_name
[2], len
);
1019 status
= getpwuid_plususer (uid
, result
, buffer
, buflen
, errnop
);
1021 if (status
== NSS_STATUS_RETURN
)
1024 if (status
== NSS_STATUS_SUCCESS
)
1026 if (innetgr (buf
, NULL
, result
->pw_name
, NULL
))
1027 return NSS_STATUS_SUCCESS
;
1029 else if (status
== NSS_STATUS_RETURN
) /* We couldn't parse the entry */
1030 return NSS_STATUS_NOTFOUND
;
1038 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] != '\0'
1039 && result
->pw_name
[1] != '@')
1041 size_t len
= strlen (result
->pw_name
);
1043 enum nss_status status
;
1045 memcpy (buf
, &result
->pw_name
[1], len
);
1047 status
= getpwuid_plususer (uid
, result
, buffer
, buflen
, errnop
);
1048 if (status
== NSS_STATUS_SUCCESS
&&
1049 innetgr (buf
, NULL
, result
->pw_name
, NULL
))
1050 return NSS_STATUS_NOTFOUND
;
1055 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] != '\0'
1056 && result
->pw_name
[1] != '@')
1058 size_t len
= strlen (result
->pw_name
);
1060 enum nss_status status
;
1062 memcpy (buf
, &result
->pw_name
[1], len
);
1064 status
= getpwuid_plususer (uid
, result
, buffer
, buflen
, errnop
);
1066 if (status
== NSS_STATUS_RETURN
)
1069 if (status
== NSS_STATUS_SUCCESS
)
1071 if (strcmp (buf
, result
->pw_name
) == 0)
1072 return NSS_STATUS_SUCCESS
;
1074 else if (status
== NSS_STATUS_RETURN
) /* We couldn't parse the entry */
1075 return NSS_STATUS_NOTFOUND
;
1083 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '\0')
1085 enum nss_status status
;
1087 status
= getpwuid_plususer (uid
, result
, buffer
, buflen
, errnop
);
1088 if (status
== NSS_STATUS_SUCCESS
) /* We found the entry. */
1090 else if (status
== NSS_STATUS_RETURN
) /* We couldn't parse the entry */
1091 return NSS_STATUS_NOTFOUND
;
1096 return NSS_STATUS_SUCCESS
;
1100 _nss_compat_getpwuid_r (uid_t uid
, struct passwd
*pwd
,
1101 char *buffer
, size_t buflen
, int *errnop
)
1103 enum nss_status result
;
1104 ent_t ent
= { false, false, true, NSS_STATUS_SUCCESS
, NULL
, { NULL
, 0, 0 },
1105 { NULL
, NULL
, 0, 0, NULL
, NULL
, NULL
}};
1107 __libc_lock_lock (lock
);
1110 init_nss_interface ();
1112 __libc_lock_unlock (lock
);
1114 result
= internal_setpwent (&ent
, 0, 0);
1116 if (result
== NSS_STATUS_SUCCESS
)
1117 result
= internal_getpwuid_r (uid
, pwd
, &ent
, buffer
, buflen
, errnop
);
1119 internal_endpwent (&ent
);
1125 /* Support routines for remembering -@netgroup and -user entries.
1126 The names are stored in a single string with `|' as separator. */
1128 blacklist_store_name (const char *name
, ent_t
*ent
)
1130 int namelen
= strlen (name
);
1133 /* first call, setup cache */
1134 if (ent
->blacklist
.size
== 0)
1136 ent
->blacklist
.size
= MAX (BLACKLIST_INITIAL_SIZE
, 2 * namelen
);
1137 ent
->blacklist
.data
= malloc (ent
->blacklist
.size
);
1138 if (ent
->blacklist
.data
== NULL
)
1140 ent
->blacklist
.data
[0] = '|';
1141 ent
->blacklist
.data
[1] = '\0';
1142 ent
->blacklist
.current
= 1;
1146 if (in_blacklist (name
, namelen
, ent
))
1147 return; /* no duplicates */
1149 if (ent
->blacklist
.current
+ namelen
+ 1 >= ent
->blacklist
.size
)
1151 ent
->blacklist
.size
+= MAX (BLACKLIST_INCREMENT
, 2 * namelen
);
1152 tmp
= realloc (ent
->blacklist
.data
, ent
->blacklist
.size
);
1155 free (ent
->blacklist
.data
);
1156 ent
->blacklist
.size
= 0;
1159 ent
->blacklist
.data
= tmp
;
1163 tmp
= stpcpy (ent
->blacklist
.data
+ ent
->blacklist
.current
, name
);
1166 ent
->blacklist
.current
+= namelen
+ 1;
1171 /* Returns TRUE if ent->blacklist contains name, else FALSE. */
1173 in_blacklist (const char *name
, int namelen
, ent_t
*ent
)
1175 char buf
[namelen
+ 3];
1178 if (ent
->blacklist
.data
== NULL
)
1182 cp
= stpcpy (&buf
[1], name
);
1185 return strstr (ent
->blacklist
.data
, buf
) != NULL
;