1 /* Copyright (C) 1996-2014 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, see
17 <http://www.gnu.org/licenses/>. */
26 #include <stdio_ext.h>
28 #include <rpc/types.h>
29 #include <rpcsvc/ypclnt.h>
30 #include <bits/libc-lock.h>
31 #include <kernel-features.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
68 enum nss_status setent_status
;
70 struct blacklist_t blacklist
;
72 struct __netgrent netgrdata
;
74 typedef struct ent_t ent_t
;
76 static ent_t ext_ent
= { false, false, true, NSS_STATUS_SUCCESS
, NULL
,
78 { NULL
, NULL
, 0, 0, NULL
, NULL
, NULL
}};
80 /* Protect global state against multiple changers. */
81 __libc_lock_define_initialized (static, lock
)
83 /* Positive if O_CLOEXEC is supported, negative if it is not supported,
84 zero if it is still undecided. This variable is shared with the
85 other compat functions. */
86 #ifdef __ASSUME_O_CLOEXEC
87 # define __compat_have_cloexec 1
90 extern int __compat_have_cloexec
;
92 # define __compat_have_cloexec -1
96 /* Prototypes for local functions. */
97 static void blacklist_store_name (const char *, ent_t
*);
98 static int in_blacklist (const char *, int, ent_t
*);
100 /* Initialize the NSS interface/functions. The calling function must
103 init_nss_interface (void)
105 if (__nss_database_lookup ("passwd_compat", NULL
, "nis", &ni
) >= 0)
107 nss_setpwent
= __nss_lookup_function (ni
, "setpwent");
108 nss_getpwnam_r
= __nss_lookup_function (ni
, "getpwnam_r");
109 nss_getpwuid_r
= __nss_lookup_function (ni
, "getpwuid_r");
110 nss_getpwent_r
= __nss_lookup_function (ni
, "getpwent_r");
111 nss_endpwent
= __nss_lookup_function (ni
, "endpwent");
116 give_pwd_free (struct passwd
*pwd
)
119 free (pwd
->pw_passwd
);
120 free (pwd
->pw_gecos
);
122 free (pwd
->pw_shell
);
124 memset (pwd
, '\0', sizeof (struct passwd
));
128 pwd_need_buflen (struct passwd
*pwd
)
132 if (pwd
->pw_passwd
!= NULL
)
133 len
+= strlen (pwd
->pw_passwd
) + 1;
135 if (pwd
->pw_gecos
!= NULL
)
136 len
+= strlen (pwd
->pw_gecos
) + 1;
138 if (pwd
->pw_dir
!= NULL
)
139 len
+= strlen (pwd
->pw_dir
) + 1;
141 if (pwd
->pw_shell
!= NULL
)
142 len
+= strlen (pwd
->pw_shell
) + 1;
148 copy_pwd_changes (struct passwd
*dest
, struct passwd
*src
,
149 char *buffer
, size_t buflen
)
151 if (src
->pw_passwd
!= NULL
&& strlen (src
->pw_passwd
))
154 dest
->pw_passwd
= strdup (src
->pw_passwd
);
155 else if (dest
->pw_passwd
&&
156 strlen (dest
->pw_passwd
) >= strlen (src
->pw_passwd
))
157 strcpy (dest
->pw_passwd
, src
->pw_passwd
);
160 dest
->pw_passwd
= buffer
;
161 strcpy (dest
->pw_passwd
, src
->pw_passwd
);
162 buffer
+= strlen (dest
->pw_passwd
) + 1;
163 buflen
= buflen
- (strlen (dest
->pw_passwd
) + 1);
167 if (src
->pw_gecos
!= NULL
&& strlen (src
->pw_gecos
))
170 dest
->pw_gecos
= strdup (src
->pw_gecos
);
171 else if (dest
->pw_gecos
&&
172 strlen (dest
->pw_gecos
) >= strlen (src
->pw_gecos
))
173 strcpy (dest
->pw_gecos
, src
->pw_gecos
);
176 dest
->pw_gecos
= buffer
;
177 strcpy (dest
->pw_gecos
, src
->pw_gecos
);
178 buffer
+= strlen (dest
->pw_gecos
) + 1;
179 buflen
= buflen
- (strlen (dest
->pw_gecos
) + 1);
182 if (src
->pw_dir
!= NULL
&& strlen (src
->pw_dir
))
185 dest
->pw_dir
= strdup (src
->pw_dir
);
186 else if (dest
->pw_dir
&& strlen (dest
->pw_dir
) >= strlen (src
->pw_dir
))
187 strcpy (dest
->pw_dir
, src
->pw_dir
);
190 dest
->pw_dir
= buffer
;
191 strcpy (dest
->pw_dir
, src
->pw_dir
);
192 buffer
+= strlen (dest
->pw_dir
) + 1;
193 buflen
= buflen
- (strlen (dest
->pw_dir
) + 1);
197 if (src
->pw_shell
!= NULL
&& strlen (src
->pw_shell
))
200 dest
->pw_shell
= strdup (src
->pw_shell
);
201 else if (dest
->pw_shell
&&
202 strlen (dest
->pw_shell
) >= strlen (src
->pw_shell
))
203 strcpy (dest
->pw_shell
, src
->pw_shell
);
206 dest
->pw_shell
= buffer
;
207 strcpy (dest
->pw_shell
, src
->pw_shell
);
208 buffer
+= strlen (dest
->pw_shell
) + 1;
209 buflen
= buflen
- (strlen (dest
->pw_shell
) + 1);
214 static enum nss_status
215 internal_setpwent (ent_t
*ent
, int stayopen
, int needent
)
217 enum nss_status status
= NSS_STATUS_SUCCESS
;
219 ent
->first
= ent
->netgroup
= false;
221 ent
->setent_status
= NSS_STATUS_SUCCESS
;
223 /* If something was left over free it. */
225 __internal_endnetgrent (&ent
->netgrdata
);
227 if (ent
->blacklist
.data
!= NULL
)
229 ent
->blacklist
.current
= 1;
230 ent
->blacklist
.data
[0] = '|';
231 ent
->blacklist
.data
[1] = '\0';
234 ent
->blacklist
.current
= 0;
236 if (ent
->stream
== NULL
)
238 ent
->stream
= fopen ("/etc/passwd", "rme");
240 if (ent
->stream
== NULL
)
241 status
= errno
== EAGAIN
? NSS_STATUS_TRYAGAIN
: NSS_STATUS_UNAVAIL
;
244 /* We have to make sure the file is `closed on exec'. */
247 if (__compat_have_cloexec
<= 0)
250 result
= flags
= fcntl (fileno_unlocked (ent
->stream
), F_GETFD
,
254 #if defined O_CLOEXEC && !defined __ASSUME_O_CLOEXEC
255 if (__compat_have_cloexec
== 0)
256 __compat_have_cloexec
= (flags
& FD_CLOEXEC
) ? 1 : -1;
258 if (__compat_have_cloexec
< 0)
262 result
= fcntl (fileno_unlocked (ent
->stream
), F_SETFD
,
270 /* Something went wrong. Close the stream and return a
272 fclose (ent
->stream
);
274 status
= NSS_STATUS_UNAVAIL
;
277 /* We take care of locking ourself. */
278 __fsetlocking (ent
->stream
, FSETLOCKING_BYCALLER
);
282 rewind (ent
->stream
);
284 give_pwd_free (&ent
->pwd
);
286 if (needent
&& status
== NSS_STATUS_SUCCESS
&& nss_setpwent
)
287 ent
->setent_status
= nss_setpwent (stayopen
);
294 _nss_compat_setpwent (int stayopen
)
296 enum nss_status result
;
298 __libc_lock_lock (lock
);
301 init_nss_interface ();
303 result
= internal_setpwent (&ext_ent
, stayopen
, 1);
305 __libc_lock_unlock (lock
);
311 static enum nss_status
312 internal_endpwent (ent_t
*ent
)
317 if (ent
->stream
!= NULL
)
319 fclose (ent
->stream
);
324 __internal_endnetgrent (&ent
->netgrdata
);
326 ent
->first
= ent
->netgroup
= false;
328 if (ent
->blacklist
.data
!= NULL
)
330 ent
->blacklist
.current
= 1;
331 ent
->blacklist
.data
[0] = '|';
332 ent
->blacklist
.data
[1] = '\0';
335 ent
->blacklist
.current
= 0;
337 give_pwd_free (&ent
->pwd
);
339 return NSS_STATUS_SUCCESS
;
343 _nss_compat_endpwent (void)
345 enum nss_status result
;
347 __libc_lock_lock (lock
);
349 result
= internal_endpwent (&ext_ent
);
351 __libc_lock_unlock (lock
);
357 static enum nss_status
358 getpwent_next_nss_netgr (const char *name
, struct passwd
*result
, ent_t
*ent
,
359 char *group
, char *buffer
, size_t buflen
,
362 char *curdomain
= NULL
, *host
, *user
, *domain
, *p2
;
366 /* Leave function if NSS module does not support getpwnam_r,
367 we need this function here. */
369 return NSS_STATUS_UNAVAIL
;
373 memset (&ent
->netgrdata
, 0, sizeof (struct __netgrent
));
374 __internal_setnetgrent (group
, &ent
->netgrdata
);
380 status
= __internal_getnetgrent_r (&host
, &user
, &domain
,
381 &ent
->netgrdata
, buffer
, buflen
,
385 __internal_endnetgrent (&ent
->netgrdata
);
387 give_pwd_free (&ent
->pwd
);
388 return NSS_STATUS_RETURN
;
391 if (user
== NULL
|| user
[0] == '-')
396 if (curdomain
== NULL
397 && yp_get_default_domain (&curdomain
) != YPERR_SUCCESS
)
399 __internal_endnetgrent (&ent
->netgrdata
);
400 ent
->netgroup
= false;
401 give_pwd_free (&ent
->pwd
);
402 return NSS_STATUS_UNAVAIL
;
404 if (strcmp (curdomain
, domain
) != 0)
408 /* If name != NULL, we are called from getpwnam. */
410 if (strcmp (user
, name
) != 0)
413 p2len
= pwd_need_buflen (&ent
->pwd
);
417 return NSS_STATUS_TRYAGAIN
;
419 p2
= buffer
+ (buflen
- p2len
);
422 if (nss_getpwnam_r (user
, result
, buffer
, buflen
, errnop
) !=
426 if (!in_blacklist (result
->pw_name
, strlen (result
->pw_name
), ent
))
428 /* Store the User in the blacklist for possible the "+" at the
429 end of /etc/passwd */
430 blacklist_store_name (result
->pw_name
, ent
);
431 copy_pwd_changes (result
, &ent
->pwd
, p2
, p2len
);
436 return NSS_STATUS_SUCCESS
;
439 /* get the next user from NSS (+ entry) */
440 static enum nss_status
441 getpwent_next_nss (struct passwd
*result
, ent_t
*ent
, char *buffer
,
442 size_t buflen
, int *errnop
)
444 enum nss_status status
;
448 /* Return if NSS module does not support getpwent_r. */
450 return NSS_STATUS_UNAVAIL
;
452 /* If the setpwent call failed, say so. */
453 if (ent
->setent_status
!= NSS_STATUS_SUCCESS
)
454 return ent
->setent_status
;
456 p2len
= pwd_need_buflen (&ent
->pwd
);
460 return NSS_STATUS_TRYAGAIN
;
462 p2
= buffer
+ (buflen
- p2len
);
470 if ((status
= nss_getpwent_r (result
, buffer
, buflen
, errnop
)) !=
474 while (in_blacklist (result
->pw_name
, strlen (result
->pw_name
), ent
));
476 copy_pwd_changes (result
, &ent
->pwd
, p2
, p2len
);
478 return NSS_STATUS_SUCCESS
;
481 /* This function handle the +user entrys in /etc/passwd */
482 static enum nss_status
483 getpwnam_plususer (const char *name
, struct passwd
*result
, ent_t
*ent
,
484 char *buffer
, size_t buflen
, int *errnop
)
487 return NSS_STATUS_UNAVAIL
;
490 memset (&pwd
, '\0', sizeof (struct passwd
));
492 copy_pwd_changes (&pwd
, result
, NULL
, 0);
494 size_t plen
= pwd_need_buflen (&pwd
);
498 return NSS_STATUS_TRYAGAIN
;
500 char *p
= buffer
+ (buflen
- plen
);
503 enum nss_status status
= nss_getpwnam_r (name
, result
, buffer
, buflen
,
505 if (status
!= NSS_STATUS_SUCCESS
)
508 if (in_blacklist (result
->pw_name
, strlen (result
->pw_name
), ent
))
509 return NSS_STATUS_NOTFOUND
;
511 copy_pwd_changes (result
, &pwd
, p
, plen
);
512 give_pwd_free (&pwd
);
513 /* We found the entry. */
514 return NSS_STATUS_SUCCESS
;
517 static enum nss_status
518 getpwent_next_file (struct passwd
*result
, ent_t
*ent
,
519 char *buffer
, size_t buflen
, int *errnop
)
521 struct parser_data
*data
= (void *) buffer
;
530 /* We need at least 3 characters for one line. */
531 if (__glibc_unlikely (buflen
< 3))
535 return NSS_STATUS_TRYAGAIN
;
538 fgetpos (ent
->stream
, &pos
);
539 buffer
[buflen
- 1] = '\xff';
540 p
= fgets_unlocked (buffer
, buflen
, ent
->stream
);
541 if (p
== NULL
&& feof_unlocked (ent
->stream
))
542 return NSS_STATUS_NOTFOUND
;
544 if (p
== NULL
|| __builtin_expect (buffer
[buflen
- 1] != '\xff', 0))
547 fsetpos (ent
->stream
, &pos
);
551 /* Terminate the line for any case. */
552 buffer
[buflen
- 1] = '\0';
554 /* Skip leading blanks. */
558 while (*p
== '\0' || *p
== '#' || /* Ignore empty and comment lines. */
559 /* Parse the line. If it is invalid, loop to
560 get the next line of the file to parse. */
561 !(parse_res
= _nss_files_parse_pwent (p
, result
, data
, buflen
,
564 if (__glibc_unlikely (parse_res
== -1))
565 /* The parser ran out of space. */
568 if (result
->pw_name
[0] != '+' && result
->pw_name
[0] != '-')
569 /* This is a real entry. */
573 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] == '@'
574 && result
->pw_name
[2] != '\0')
576 /* XXX Do not use fixed length buffer. */
578 char *user
, *host
, *domain
;
579 struct __netgrent netgrdata
;
581 bzero (&netgrdata
, sizeof (struct __netgrent
));
582 __internal_setnetgrent (&result
->pw_name
[2], &netgrdata
);
583 while (__internal_getnetgrent_r (&host
, &user
, &domain
, &netgrdata
,
584 buf2
, sizeof (buf2
), errnop
))
586 if (user
!= NULL
&& user
[0] != '-')
587 blacklist_store_name (user
, ent
);
589 __internal_endnetgrent (&netgrdata
);
594 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '@'
595 && result
->pw_name
[2] != '\0')
597 enum nss_status status
;
599 ent
->netgroup
= true;
601 copy_pwd_changes (&ent
->pwd
, result
, NULL
, 0);
603 status
= getpwent_next_nss_netgr (NULL
, result
, ent
,
605 buffer
, buflen
, errnop
);
606 if (status
== NSS_STATUS_RETURN
)
613 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] != '\0'
614 && result
->pw_name
[1] != '@')
616 blacklist_store_name (&result
->pw_name
[1], ent
);
621 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] != '\0'
622 && result
->pw_name
[1] != '@')
624 size_t len
= strlen (result
->pw_name
);
626 enum nss_status status
;
628 /* Store the User in the blacklist for the "+" at the end of
630 memcpy (buf
, &result
->pw_name
[1], len
);
631 status
= getpwnam_plususer (&result
->pw_name
[1], result
, ent
,
632 buffer
, buflen
, errnop
);
633 blacklist_store_name (buf
, ent
);
635 if (status
== NSS_STATUS_SUCCESS
) /* We found the entry. */
637 else if (status
== NSS_STATUS_RETURN
/* We couldn't parse the entry */
638 || status
== NSS_STATUS_NOTFOUND
) /* entry doesn't exist */
642 if (status
== NSS_STATUS_TRYAGAIN
)
644 /* The parser ran out of space */
645 fsetpos (ent
->stream
, &pos
);
653 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '\0')
657 copy_pwd_changes (&ent
->pwd
, result
, NULL
, 0);
659 return getpwent_next_nss (result
, ent
, buffer
, buflen
, errnop
);
663 return NSS_STATUS_SUCCESS
;
667 static enum nss_status
668 internal_getpwent_r (struct passwd
*pw
, ent_t
*ent
, char *buffer
,
669 size_t buflen
, int *errnop
)
673 enum nss_status status
;
675 /* We are searching members in a netgroup */
676 /* Since this is not the first call, we don't need the group name */
677 status
= getpwent_next_nss_netgr (NULL
, pw
, ent
, NULL
, buffer
, buflen
,
679 if (status
== NSS_STATUS_RETURN
)
680 return getpwent_next_file (pw
, ent
, buffer
, buflen
, errnop
);
685 return getpwent_next_file (pw
, ent
, buffer
, buflen
, errnop
);
687 return getpwent_next_nss (pw
, ent
, buffer
, buflen
, errnop
);
692 _nss_compat_getpwent_r (struct passwd
*pwd
, char *buffer
, size_t buflen
,
695 enum nss_status result
= NSS_STATUS_SUCCESS
;
697 __libc_lock_lock (lock
);
699 /* Be prepared that the setpwent function was not called before. */
701 init_nss_interface ();
703 if (ext_ent
.stream
== NULL
)
704 result
= internal_setpwent (&ext_ent
, 1, 1);
706 if (result
== NSS_STATUS_SUCCESS
)
707 result
= internal_getpwent_r (pwd
, &ext_ent
, buffer
, buflen
, errnop
);
709 __libc_lock_unlock (lock
);
714 /* Searches in /etc/passwd and the NIS/NIS+ map for a special user */
715 static enum nss_status
716 internal_getpwnam_r (const char *name
, struct passwd
*result
, ent_t
*ent
,
717 char *buffer
, size_t buflen
, int *errnop
)
719 struct parser_data
*data
= (void *) buffer
;
729 /* We need at least 3 characters for one line. */
730 if (__glibc_unlikely (buflen
< 3))
734 return NSS_STATUS_TRYAGAIN
;
737 fgetpos (ent
->stream
, &pos
);
738 buffer
[buflen
- 1] = '\xff';
739 p
= fgets_unlocked (buffer
, buflen
, ent
->stream
);
740 if (p
== NULL
&& feof_unlocked (ent
->stream
))
742 return NSS_STATUS_NOTFOUND
;
744 if (p
== NULL
|| __builtin_expect (buffer
[buflen
- 1] != '\xff', 0))
747 fsetpos (ent
->stream
, &pos
);
751 /* Terminate the line for any case. */
752 buffer
[buflen
- 1] = '\0';
754 /* Skip leading blanks. */
758 while (*p
== '\0' || *p
== '#' || /* Ignore empty and comment lines. */
759 /* Parse the line. If it is invalid, loop to
760 get the next line of the file to parse. */
761 !(parse_res
= _nss_files_parse_pwent (p
, result
, data
, buflen
,
764 if (__glibc_unlikely (parse_res
== -1))
765 /* The parser ran out of space. */
768 /* This is a real entry. */
769 if (result
->pw_name
[0] != '+' && result
->pw_name
[0] != '-')
771 if (strcmp (result
->pw_name
, name
) == 0)
772 return NSS_STATUS_SUCCESS
;
778 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] == '@'
779 && result
->pw_name
[2] != '\0')
781 if (innetgr (&result
->pw_name
[2], NULL
, name
, NULL
))
782 return NSS_STATUS_NOTFOUND
;
787 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '@'
788 && result
->pw_name
[2] != '\0')
790 enum nss_status status
;
792 if (innetgr (&result
->pw_name
[2], NULL
, name
, NULL
))
794 status
= getpwnam_plususer (name
, result
, ent
, buffer
,
797 if (status
== NSS_STATUS_RETURN
)
806 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] != '\0'
807 && result
->pw_name
[1] != '@')
809 if (strcmp (&result
->pw_name
[1], name
) == 0)
810 return NSS_STATUS_NOTFOUND
;
816 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] != '\0'
817 && result
->pw_name
[1] != '@')
819 if (strcmp (name
, &result
->pw_name
[1]) == 0)
821 enum nss_status status
;
823 status
= getpwnam_plususer (name
, result
, ent
, buffer
, buflen
,
825 if (status
== NSS_STATUS_RETURN
)
826 /* We couldn't parse the entry */
827 return NSS_STATUS_NOTFOUND
;
834 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '\0')
836 enum nss_status status
;
838 status
= getpwnam_plususer (name
, result
, ent
,
839 buffer
, buflen
, errnop
);
840 if (status
== NSS_STATUS_SUCCESS
) /* We found the entry. */
842 else if (status
== NSS_STATUS_RETURN
) /* We couldn't parse the entry */
843 return NSS_STATUS_NOTFOUND
;
848 return NSS_STATUS_SUCCESS
;
852 _nss_compat_getpwnam_r (const char *name
, struct passwd
*pwd
,
853 char *buffer
, size_t buflen
, int *errnop
)
855 enum nss_status result
;
856 ent_t ent
= { false, false, true, NSS_STATUS_SUCCESS
, NULL
, { NULL
, 0, 0 },
857 { NULL
, NULL
, 0, 0, NULL
, NULL
, NULL
}};
859 if (name
[0] == '-' || name
[0] == '+')
860 return NSS_STATUS_NOTFOUND
;
862 __libc_lock_lock (lock
);
865 init_nss_interface ();
867 __libc_lock_unlock (lock
);
869 result
= internal_setpwent (&ent
, 0, 0);
871 if (result
== NSS_STATUS_SUCCESS
)
872 result
= internal_getpwnam_r (name
, pwd
, &ent
, buffer
, buflen
, errnop
);
874 internal_endpwent (&ent
);
879 /* This function handle the + entry in /etc/passwd for getpwuid */
880 static enum nss_status
881 getpwuid_plususer (uid_t uid
, struct passwd
*result
, char *buffer
,
882 size_t buflen
, int *errnop
)
889 return NSS_STATUS_UNAVAIL
;
891 memset (&pwd
, '\0', sizeof (struct passwd
));
893 copy_pwd_changes (&pwd
, result
, NULL
, 0);
895 plen
= pwd_need_buflen (&pwd
);
899 return NSS_STATUS_TRYAGAIN
;
901 p
= buffer
+ (buflen
- plen
);
904 if (nss_getpwuid_r (uid
, result
, buffer
, buflen
, errnop
) ==
907 copy_pwd_changes (result
, &pwd
, p
, plen
);
908 give_pwd_free (&pwd
);
909 /* We found the entry. */
910 return NSS_STATUS_SUCCESS
;
914 /* Give buffer the old len back */
916 give_pwd_free (&pwd
);
918 return NSS_STATUS_RETURN
;
921 /* Searches in /etc/passwd and the NSS subsystem for a special user id */
922 static enum nss_status
923 internal_getpwuid_r (uid_t uid
, struct passwd
*result
, ent_t
*ent
,
924 char *buffer
, size_t buflen
, int *errnop
)
926 struct parser_data
*data
= (void *) buffer
;
936 /* We need at least 3 characters for one line. */
937 if (__glibc_unlikely (buflen
< 3))
941 return NSS_STATUS_TRYAGAIN
;
944 fgetpos (ent
->stream
, &pos
);
945 buffer
[buflen
- 1] = '\xff';
946 p
= fgets_unlocked (buffer
, buflen
, ent
->stream
);
947 if (p
== NULL
&& feof_unlocked (ent
->stream
))
948 return NSS_STATUS_NOTFOUND
;
950 if (p
== NULL
|| __builtin_expect (buffer
[buflen
- 1] != '\xff', 0))
953 fsetpos (ent
->stream
, &pos
);
957 /* Terminate the line for any case. */
958 buffer
[buflen
- 1] = '\0';
960 /* Skip leading blanks. */
964 while (*p
== '\0' || *p
== '#' || /* Ignore empty and comment lines. */
965 /* Parse the line. If it is invalid, loop to
966 get the next line of the file to parse. */
967 !(parse_res
= _nss_files_parse_pwent (p
, result
, data
, buflen
,
970 if (__glibc_unlikely (parse_res
== -1))
971 /* The parser ran out of space. */
974 /* This is a real entry. */
975 if (result
->pw_name
[0] != '+' && result
->pw_name
[0] != '-')
977 if (result
->pw_uid
== uid
)
978 return NSS_STATUS_SUCCESS
;
984 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] == '@'
985 && result
->pw_name
[2] != '\0')
987 /* -1, because we remove first two character of pw_name. */
988 size_t len
= strlen (result
->pw_name
) - 1;
990 enum nss_status status
;
992 memcpy (buf
, &result
->pw_name
[2], len
);
994 status
= getpwuid_plususer (uid
, result
, buffer
, buflen
, errnop
);
995 if (status
== NSS_STATUS_SUCCESS
&&
996 innetgr (buf
, NULL
, result
->pw_name
, NULL
))
997 return NSS_STATUS_NOTFOUND
;
1003 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '@'
1004 && result
->pw_name
[2] != '\0')
1006 /* -1, because we remove first two characters of pw_name. */
1007 size_t len
= strlen (result
->pw_name
) - 1;
1009 enum nss_status status
;
1011 memcpy (buf
, &result
->pw_name
[2], len
);
1013 status
= getpwuid_plususer (uid
, result
, buffer
, buflen
, errnop
);
1015 if (status
== NSS_STATUS_RETURN
)
1018 if (status
== NSS_STATUS_SUCCESS
)
1020 if (innetgr (buf
, NULL
, result
->pw_name
, NULL
))
1021 return NSS_STATUS_SUCCESS
;
1023 else if (status
== NSS_STATUS_RETURN
) /* We couldn't parse the entry */
1024 return NSS_STATUS_NOTFOUND
;
1032 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] != '\0'
1033 && result
->pw_name
[1] != '@')
1035 size_t len
= strlen (result
->pw_name
);
1037 enum nss_status status
;
1039 memcpy (buf
, &result
->pw_name
[1], len
);
1041 status
= getpwuid_plususer (uid
, result
, buffer
, buflen
, errnop
);
1042 if (status
== NSS_STATUS_SUCCESS
&&
1043 innetgr (buf
, NULL
, result
->pw_name
, NULL
))
1044 return NSS_STATUS_NOTFOUND
;
1049 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] != '\0'
1050 && result
->pw_name
[1] != '@')
1052 size_t len
= strlen (result
->pw_name
);
1054 enum nss_status status
;
1056 memcpy (buf
, &result
->pw_name
[1], len
);
1058 status
= getpwuid_plususer (uid
, result
, buffer
, buflen
, errnop
);
1060 if (status
== NSS_STATUS_RETURN
)
1063 if (status
== NSS_STATUS_SUCCESS
)
1065 if (strcmp (buf
, result
->pw_name
) == 0)
1066 return NSS_STATUS_SUCCESS
;
1068 else if (status
== NSS_STATUS_RETURN
) /* We couldn't parse the entry */
1069 return NSS_STATUS_NOTFOUND
;
1077 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '\0')
1079 enum nss_status status
;
1081 status
= getpwuid_plususer (uid
, result
, buffer
, buflen
, errnop
);
1082 if (status
== NSS_STATUS_SUCCESS
) /* We found the entry. */
1084 else if (status
== NSS_STATUS_RETURN
) /* We couldn't parse the entry */
1085 return NSS_STATUS_NOTFOUND
;
1090 return NSS_STATUS_SUCCESS
;
1094 _nss_compat_getpwuid_r (uid_t uid
, struct passwd
*pwd
,
1095 char *buffer
, size_t buflen
, int *errnop
)
1097 enum nss_status result
;
1098 ent_t ent
= { false, false, true, NSS_STATUS_SUCCESS
, NULL
, { NULL
, 0, 0 },
1099 { NULL
, NULL
, 0, 0, NULL
, NULL
, NULL
}};
1101 __libc_lock_lock (lock
);
1104 init_nss_interface ();
1106 __libc_lock_unlock (lock
);
1108 result
= internal_setpwent (&ent
, 0, 0);
1110 if (result
== NSS_STATUS_SUCCESS
)
1111 result
= internal_getpwuid_r (uid
, pwd
, &ent
, buffer
, buflen
, errnop
);
1113 internal_endpwent (&ent
);
1119 /* Support routines for remembering -@netgroup and -user entries.
1120 The names are stored in a single string with `|' as separator. */
1122 blacklist_store_name (const char *name
, ent_t
*ent
)
1124 int namelen
= strlen (name
);
1127 /* first call, setup cache */
1128 if (ent
->blacklist
.size
== 0)
1130 ent
->blacklist
.size
= MAX (BLACKLIST_INITIAL_SIZE
, 2 * namelen
);
1131 ent
->blacklist
.data
= malloc (ent
->blacklist
.size
);
1132 if (ent
->blacklist
.data
== NULL
)
1134 ent
->blacklist
.data
[0] = '|';
1135 ent
->blacklist
.data
[1] = '\0';
1136 ent
->blacklist
.current
= 1;
1140 if (in_blacklist (name
, namelen
, ent
))
1141 return; /* no duplicates */
1143 if (ent
->blacklist
.current
+ namelen
+ 1 >= ent
->blacklist
.size
)
1145 ent
->blacklist
.size
+= MAX (BLACKLIST_INCREMENT
, 2 * namelen
);
1146 tmp
= realloc (ent
->blacklist
.data
, ent
->blacklist
.size
);
1149 free (ent
->blacklist
.data
);
1150 ent
->blacklist
.size
= 0;
1153 ent
->blacklist
.data
= tmp
;
1157 tmp
= stpcpy (ent
->blacklist
.data
+ ent
->blacklist
.current
, name
);
1160 ent
->blacklist
.current
+= namelen
+ 1;
1165 /* Returns TRUE if ent->blacklist contains name, else FALSE. */
1167 in_blacklist (const char *name
, int namelen
, ent_t
*ent
)
1169 char buf
[namelen
+ 3];
1172 if (ent
->blacklist
.data
== NULL
)
1176 cp
= stpcpy (&buf
[1], name
);
1179 return strstr (ent
->blacklist
.data
, buf
) != NULL
;