1 /* Copyright (C) 1996-2017 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 <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 /* Prototypes for local functions. */
84 static void blacklist_store_name (const char *, ent_t
*);
85 static int in_blacklist (const char *, int, ent_t
*);
87 /* Initialize the NSS interface/functions. The calling function must
90 init_nss_interface (void)
92 if (__nss_database_lookup ("passwd_compat", NULL
, "nis", &ni
) >= 0)
94 nss_setpwent
= __nss_lookup_function (ni
, "setpwent");
95 nss_getpwnam_r
= __nss_lookup_function (ni
, "getpwnam_r");
96 nss_getpwuid_r
= __nss_lookup_function (ni
, "getpwuid_r");
97 nss_getpwent_r
= __nss_lookup_function (ni
, "getpwent_r");
98 nss_endpwent
= __nss_lookup_function (ni
, "endpwent");
103 give_pwd_free (struct passwd
*pwd
)
106 free (pwd
->pw_passwd
);
107 free (pwd
->pw_gecos
);
109 free (pwd
->pw_shell
);
111 memset (pwd
, '\0', sizeof (struct passwd
));
115 pwd_need_buflen (struct passwd
*pwd
)
119 if (pwd
->pw_passwd
!= NULL
)
120 len
+= strlen (pwd
->pw_passwd
) + 1;
122 if (pwd
->pw_gecos
!= NULL
)
123 len
+= strlen (pwd
->pw_gecos
) + 1;
125 if (pwd
->pw_dir
!= NULL
)
126 len
+= strlen (pwd
->pw_dir
) + 1;
128 if (pwd
->pw_shell
!= NULL
)
129 len
+= strlen (pwd
->pw_shell
) + 1;
135 copy_pwd_changes (struct passwd
*dest
, struct passwd
*src
,
136 char *buffer
, size_t buflen
)
138 if (src
->pw_passwd
!= NULL
&& strlen (src
->pw_passwd
))
141 dest
->pw_passwd
= strdup (src
->pw_passwd
);
142 else if (dest
->pw_passwd
&&
143 strlen (dest
->pw_passwd
) >= strlen (src
->pw_passwd
))
144 strcpy (dest
->pw_passwd
, src
->pw_passwd
);
147 dest
->pw_passwd
= buffer
;
148 strcpy (dest
->pw_passwd
, src
->pw_passwd
);
149 buffer
+= strlen (dest
->pw_passwd
) + 1;
150 buflen
= buflen
- (strlen (dest
->pw_passwd
) + 1);
154 if (src
->pw_gecos
!= NULL
&& strlen (src
->pw_gecos
))
157 dest
->pw_gecos
= strdup (src
->pw_gecos
);
158 else if (dest
->pw_gecos
&&
159 strlen (dest
->pw_gecos
) >= strlen (src
->pw_gecos
))
160 strcpy (dest
->pw_gecos
, src
->pw_gecos
);
163 dest
->pw_gecos
= buffer
;
164 strcpy (dest
->pw_gecos
, src
->pw_gecos
);
165 buffer
+= strlen (dest
->pw_gecos
) + 1;
166 buflen
= buflen
- (strlen (dest
->pw_gecos
) + 1);
169 if (src
->pw_dir
!= NULL
&& strlen (src
->pw_dir
))
172 dest
->pw_dir
= strdup (src
->pw_dir
);
173 else if (dest
->pw_dir
&& strlen (dest
->pw_dir
) >= strlen (src
->pw_dir
))
174 strcpy (dest
->pw_dir
, src
->pw_dir
);
177 dest
->pw_dir
= buffer
;
178 strcpy (dest
->pw_dir
, src
->pw_dir
);
179 buffer
+= strlen (dest
->pw_dir
) + 1;
180 buflen
= buflen
- (strlen (dest
->pw_dir
) + 1);
184 if (src
->pw_shell
!= NULL
&& strlen (src
->pw_shell
))
187 dest
->pw_shell
= strdup (src
->pw_shell
);
188 else if (dest
->pw_shell
&&
189 strlen (dest
->pw_shell
) >= strlen (src
->pw_shell
))
190 strcpy (dest
->pw_shell
, src
->pw_shell
);
193 dest
->pw_shell
= buffer
;
194 strcpy (dest
->pw_shell
, src
->pw_shell
);
195 buffer
+= strlen (dest
->pw_shell
) + 1;
196 buflen
= buflen
- (strlen (dest
->pw_shell
) + 1);
201 static enum nss_status
202 internal_setpwent (ent_t
*ent
, int stayopen
, int needent
)
204 enum nss_status status
= NSS_STATUS_SUCCESS
;
206 ent
->first
= ent
->netgroup
= false;
208 ent
->setent_status
= NSS_STATUS_SUCCESS
;
210 /* If something was left over free it. */
212 __internal_endnetgrent (&ent
->netgrdata
);
214 if (ent
->blacklist
.data
!= NULL
)
216 ent
->blacklist
.current
= 1;
217 ent
->blacklist
.data
[0] = '|';
218 ent
->blacklist
.data
[1] = '\0';
221 ent
->blacklist
.current
= 0;
223 if (ent
->stream
== NULL
)
225 ent
->stream
= fopen ("/etc/passwd", "rme");
227 if (ent
->stream
== NULL
)
228 status
= errno
== EAGAIN
? NSS_STATUS_TRYAGAIN
: NSS_STATUS_UNAVAIL
;
230 /* We take care of locking ourself. */
231 __fsetlocking (ent
->stream
, FSETLOCKING_BYCALLER
);
234 rewind (ent
->stream
);
236 give_pwd_free (&ent
->pwd
);
238 if (needent
&& status
== NSS_STATUS_SUCCESS
&& nss_setpwent
)
239 ent
->setent_status
= nss_setpwent (stayopen
);
246 _nss_compat_setpwent (int stayopen
)
248 enum nss_status result
;
250 __libc_lock_lock (lock
);
253 init_nss_interface ();
255 result
= internal_setpwent (&ext_ent
, stayopen
, 1);
257 __libc_lock_unlock (lock
);
263 static enum nss_status
264 internal_endpwent (ent_t
*ent
)
266 if (ent
->stream
!= NULL
)
268 fclose (ent
->stream
);
273 __internal_endnetgrent (&ent
->netgrdata
);
275 ent
->first
= ent
->netgroup
= false;
277 if (ent
->blacklist
.data
!= NULL
)
279 ent
->blacklist
.current
= 1;
280 ent
->blacklist
.data
[0] = '|';
281 ent
->blacklist
.data
[1] = '\0';
284 ent
->blacklist
.current
= 0;
286 give_pwd_free (&ent
->pwd
);
288 return NSS_STATUS_SUCCESS
;
292 _nss_compat_endpwent (void)
294 enum nss_status result
;
296 __libc_lock_lock (lock
);
301 result
= internal_endpwent (&ext_ent
);
303 __libc_lock_unlock (lock
);
309 static enum nss_status
310 getpwent_next_nss_netgr (const char *name
, struct passwd
*result
, ent_t
*ent
,
311 char *group
, char *buffer
, size_t buflen
,
314 char *curdomain
= NULL
, *host
, *user
, *domain
, *p2
;
318 /* Leave function if NSS module does not support getpwnam_r,
319 we need this function here. */
321 return NSS_STATUS_UNAVAIL
;
325 memset (&ent
->netgrdata
, 0, sizeof (struct __netgrent
));
326 __internal_setnetgrent (group
, &ent
->netgrdata
);
332 status
= __internal_getnetgrent_r (&host
, &user
, &domain
,
333 &ent
->netgrdata
, buffer
, buflen
,
337 __internal_endnetgrent (&ent
->netgrdata
);
339 give_pwd_free (&ent
->pwd
);
340 return NSS_STATUS_RETURN
;
343 if (user
== NULL
|| user
[0] == '-')
348 if (curdomain
== NULL
349 && yp_get_default_domain (&curdomain
) != YPERR_SUCCESS
)
351 __internal_endnetgrent (&ent
->netgrdata
);
352 ent
->netgroup
= false;
353 give_pwd_free (&ent
->pwd
);
354 return NSS_STATUS_UNAVAIL
;
356 if (strcmp (curdomain
, domain
) != 0)
360 /* If name != NULL, we are called from getpwnam. */
362 if (strcmp (user
, name
) != 0)
365 p2len
= pwd_need_buflen (&ent
->pwd
);
369 return NSS_STATUS_TRYAGAIN
;
371 p2
= buffer
+ (buflen
- p2len
);
374 if (nss_getpwnam_r (user
, result
, buffer
, buflen
, errnop
) !=
378 if (!in_blacklist (result
->pw_name
, strlen (result
->pw_name
), ent
))
380 /* Store the User in the blacklist for possible the "+" at the
381 end of /etc/passwd */
382 blacklist_store_name (result
->pw_name
, ent
);
383 copy_pwd_changes (result
, &ent
->pwd
, p2
, p2len
);
388 return NSS_STATUS_SUCCESS
;
391 /* get the next user from NSS (+ entry) */
392 static enum nss_status
393 getpwent_next_nss (struct passwd
*result
, ent_t
*ent
, char *buffer
,
394 size_t buflen
, int *errnop
)
396 enum nss_status status
;
400 /* Return if NSS module does not support getpwent_r. */
402 return NSS_STATUS_UNAVAIL
;
404 /* If the setpwent call failed, say so. */
405 if (ent
->setent_status
!= NSS_STATUS_SUCCESS
)
406 return ent
->setent_status
;
408 p2len
= pwd_need_buflen (&ent
->pwd
);
412 return NSS_STATUS_TRYAGAIN
;
414 p2
= buffer
+ (buflen
- p2len
);
422 if ((status
= nss_getpwent_r (result
, buffer
, buflen
, errnop
)) !=
426 while (in_blacklist (result
->pw_name
, strlen (result
->pw_name
), ent
));
428 copy_pwd_changes (result
, &ent
->pwd
, p2
, p2len
);
430 return NSS_STATUS_SUCCESS
;
433 /* This function handle the +user entrys in /etc/passwd */
434 static enum nss_status
435 getpwnam_plususer (const char *name
, struct passwd
*result
, ent_t
*ent
,
436 char *buffer
, size_t buflen
, int *errnop
)
439 return NSS_STATUS_UNAVAIL
;
442 memset (&pwd
, '\0', sizeof (struct passwd
));
444 copy_pwd_changes (&pwd
, result
, NULL
, 0);
446 size_t plen
= pwd_need_buflen (&pwd
);
450 return NSS_STATUS_TRYAGAIN
;
452 char *p
= buffer
+ (buflen
- plen
);
455 enum nss_status status
= nss_getpwnam_r (name
, result
, buffer
, buflen
,
457 if (status
!= NSS_STATUS_SUCCESS
)
460 if (in_blacklist (result
->pw_name
, strlen (result
->pw_name
), ent
))
461 return NSS_STATUS_NOTFOUND
;
463 copy_pwd_changes (result
, &pwd
, p
, plen
);
464 give_pwd_free (&pwd
);
465 /* We found the entry. */
466 return NSS_STATUS_SUCCESS
;
469 static enum nss_status
470 getpwent_next_file (struct passwd
*result
, ent_t
*ent
,
471 char *buffer
, size_t buflen
, int *errnop
)
473 struct parser_data
*data
= (void *) buffer
;
482 /* We need at least 3 characters for one line. */
483 if (__glibc_unlikely (buflen
< 3))
487 return NSS_STATUS_TRYAGAIN
;
490 fgetpos (ent
->stream
, &pos
);
491 buffer
[buflen
- 1] = '\xff';
492 p
= fgets_unlocked (buffer
, buflen
, ent
->stream
);
493 if (p
== NULL
&& feof_unlocked (ent
->stream
))
494 return NSS_STATUS_NOTFOUND
;
496 if (p
== NULL
|| __builtin_expect (buffer
[buflen
- 1] != '\xff', 0))
499 fsetpos (ent
->stream
, &pos
);
503 /* Terminate the line for any case. */
504 buffer
[buflen
- 1] = '\0';
506 /* Skip leading blanks. */
510 while (*p
== '\0' || *p
== '#' || /* Ignore empty and comment lines. */
511 /* Parse the line. If it is invalid, loop to
512 get the next line of the file to parse. */
513 !(parse_res
= _nss_files_parse_pwent (p
, result
, data
, buflen
,
516 if (__glibc_unlikely (parse_res
== -1))
517 /* The parser ran out of space. */
520 if (result
->pw_name
[0] != '+' && result
->pw_name
[0] != '-')
521 /* This is a real entry. */
525 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] == '@'
526 && result
->pw_name
[2] != '\0')
528 /* XXX Do not use fixed length buffer. */
530 char *user
, *host
, *domain
;
531 struct __netgrent netgrdata
;
533 memset (&netgrdata
, 0, sizeof (struct __netgrent
));
534 __internal_setnetgrent (&result
->pw_name
[2], &netgrdata
);
535 while (__internal_getnetgrent_r (&host
, &user
, &domain
, &netgrdata
,
536 buf2
, sizeof (buf2
), errnop
))
538 if (user
!= NULL
&& user
[0] != '-')
539 blacklist_store_name (user
, ent
);
541 __internal_endnetgrent (&netgrdata
);
546 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '@'
547 && result
->pw_name
[2] != '\0')
549 enum nss_status status
;
551 ent
->netgroup
= true;
553 copy_pwd_changes (&ent
->pwd
, result
, NULL
, 0);
555 status
= getpwent_next_nss_netgr (NULL
, result
, ent
,
557 buffer
, buflen
, errnop
);
558 if (status
== NSS_STATUS_RETURN
)
565 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] != '\0'
566 && result
->pw_name
[1] != '@')
568 blacklist_store_name (&result
->pw_name
[1], ent
);
573 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] != '\0'
574 && result
->pw_name
[1] != '@')
576 size_t len
= strlen (result
->pw_name
);
578 enum nss_status status
;
580 /* Store the User in the blacklist for the "+" at the end of
582 memcpy (buf
, &result
->pw_name
[1], len
);
583 status
= getpwnam_plususer (&result
->pw_name
[1], result
, ent
,
584 buffer
, buflen
, errnop
);
585 blacklist_store_name (buf
, ent
);
587 if (status
== NSS_STATUS_SUCCESS
) /* We found the entry. */
589 else if (status
== NSS_STATUS_RETURN
/* We couldn't parse the entry */
590 || status
== NSS_STATUS_NOTFOUND
) /* entry doesn't exist */
594 if (status
== NSS_STATUS_TRYAGAIN
)
596 /* The parser ran out of space */
597 fsetpos (ent
->stream
, &pos
);
605 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '\0')
609 copy_pwd_changes (&ent
->pwd
, result
, NULL
, 0);
611 return getpwent_next_nss (result
, ent
, buffer
, buflen
, errnop
);
615 return NSS_STATUS_SUCCESS
;
619 static enum nss_status
620 internal_getpwent_r (struct passwd
*pw
, ent_t
*ent
, char *buffer
,
621 size_t buflen
, int *errnop
)
625 enum nss_status status
;
627 /* We are searching members in a netgroup */
628 /* Since this is not the first call, we don't need the group name */
629 status
= getpwent_next_nss_netgr (NULL
, pw
, ent
, NULL
, buffer
, buflen
,
631 if (status
== NSS_STATUS_RETURN
)
632 return getpwent_next_file (pw
, ent
, buffer
, buflen
, errnop
);
637 return getpwent_next_file (pw
, ent
, buffer
, buflen
, errnop
);
639 return getpwent_next_nss (pw
, ent
, buffer
, buflen
, errnop
);
644 _nss_compat_getpwent_r (struct passwd
*pwd
, char *buffer
, size_t buflen
,
647 enum nss_status result
= NSS_STATUS_SUCCESS
;
649 __libc_lock_lock (lock
);
651 /* Be prepared that the setpwent function was not called before. */
653 init_nss_interface ();
655 if (ext_ent
.stream
== NULL
)
656 result
= internal_setpwent (&ext_ent
, 1, 1);
658 if (result
== NSS_STATUS_SUCCESS
)
659 result
= internal_getpwent_r (pwd
, &ext_ent
, buffer
, buflen
, errnop
);
661 __libc_lock_unlock (lock
);
666 /* Searches in /etc/passwd and the NIS/NIS+ map for a special user */
667 static enum nss_status
668 internal_getpwnam_r (const char *name
, struct passwd
*result
, ent_t
*ent
,
669 char *buffer
, size_t buflen
, int *errnop
)
671 struct parser_data
*data
= (void *) buffer
;
681 /* We need at least 3 characters for one line. */
682 if (__glibc_unlikely (buflen
< 3))
686 return NSS_STATUS_TRYAGAIN
;
689 fgetpos (ent
->stream
, &pos
);
690 buffer
[buflen
- 1] = '\xff';
691 p
= fgets_unlocked (buffer
, buflen
, ent
->stream
);
692 if (p
== NULL
&& feof_unlocked (ent
->stream
))
694 return NSS_STATUS_NOTFOUND
;
696 if (p
== NULL
|| __builtin_expect (buffer
[buflen
- 1] != '\xff', 0))
699 fsetpos (ent
->stream
, &pos
);
703 /* Terminate the line for any case. */
704 buffer
[buflen
- 1] = '\0';
706 /* Skip leading blanks. */
710 while (*p
== '\0' || *p
== '#' || /* Ignore empty and comment lines. */
711 /* Parse the line. If it is invalid, loop to
712 get the next line of the file to parse. */
713 !(parse_res
= _nss_files_parse_pwent (p
, result
, data
, buflen
,
716 if (__glibc_unlikely (parse_res
== -1))
717 /* The parser ran out of space. */
720 /* This is a real entry. */
721 if (result
->pw_name
[0] != '+' && result
->pw_name
[0] != '-')
723 if (strcmp (result
->pw_name
, name
) == 0)
724 return NSS_STATUS_SUCCESS
;
730 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] == '@'
731 && result
->pw_name
[2] != '\0')
733 if (innetgr (&result
->pw_name
[2], NULL
, name
, NULL
))
734 return NSS_STATUS_NOTFOUND
;
739 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '@'
740 && result
->pw_name
[2] != '\0')
742 enum nss_status status
;
744 if (innetgr (&result
->pw_name
[2], NULL
, name
, NULL
))
746 status
= getpwnam_plususer (name
, result
, ent
, buffer
,
749 if (status
== NSS_STATUS_RETURN
)
758 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] != '\0'
759 && result
->pw_name
[1] != '@')
761 if (strcmp (&result
->pw_name
[1], name
) == 0)
762 return NSS_STATUS_NOTFOUND
;
768 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] != '\0'
769 && result
->pw_name
[1] != '@')
771 if (strcmp (name
, &result
->pw_name
[1]) == 0)
773 enum nss_status status
;
775 status
= getpwnam_plususer (name
, result
, ent
, buffer
, buflen
,
777 if (status
== NSS_STATUS_RETURN
)
778 /* We couldn't parse the entry */
779 return NSS_STATUS_NOTFOUND
;
786 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '\0')
788 enum nss_status status
;
790 status
= getpwnam_plususer (name
, result
, ent
,
791 buffer
, buflen
, errnop
);
792 if (status
== NSS_STATUS_SUCCESS
) /* We found the entry. */
794 else if (status
== NSS_STATUS_RETURN
) /* We couldn't parse the entry */
795 return NSS_STATUS_NOTFOUND
;
800 return NSS_STATUS_SUCCESS
;
804 _nss_compat_getpwnam_r (const char *name
, struct passwd
*pwd
,
805 char *buffer
, size_t buflen
, int *errnop
)
807 enum nss_status result
;
808 ent_t ent
= { false, false, true, NSS_STATUS_SUCCESS
, NULL
, { NULL
, 0, 0 },
809 { NULL
, NULL
, 0, 0, NULL
, NULL
, NULL
}};
811 if (name
[0] == '-' || name
[0] == '+')
812 return NSS_STATUS_NOTFOUND
;
814 __libc_lock_lock (lock
);
817 init_nss_interface ();
819 __libc_lock_unlock (lock
);
821 result
= internal_setpwent (&ent
, 0, 0);
823 if (result
== NSS_STATUS_SUCCESS
)
824 result
= internal_getpwnam_r (name
, pwd
, &ent
, buffer
, buflen
, errnop
);
826 internal_endpwent (&ent
);
831 /* This function handle the + entry in /etc/passwd for getpwuid */
832 static enum nss_status
833 getpwuid_plususer (uid_t uid
, struct passwd
*result
, char *buffer
,
834 size_t buflen
, int *errnop
)
841 return NSS_STATUS_UNAVAIL
;
843 memset (&pwd
, '\0', sizeof (struct passwd
));
845 copy_pwd_changes (&pwd
, result
, NULL
, 0);
847 plen
= pwd_need_buflen (&pwd
);
851 return NSS_STATUS_TRYAGAIN
;
853 p
= buffer
+ (buflen
- plen
);
856 if (nss_getpwuid_r (uid
, result
, buffer
, buflen
, errnop
) ==
859 copy_pwd_changes (result
, &pwd
, p
, plen
);
860 give_pwd_free (&pwd
);
861 /* We found the entry. */
862 return NSS_STATUS_SUCCESS
;
866 /* Give buffer the old len back */
868 give_pwd_free (&pwd
);
870 return NSS_STATUS_RETURN
;
873 /* Searches in /etc/passwd and the NSS subsystem for a special user id */
874 static enum nss_status
875 internal_getpwuid_r (uid_t uid
, struct passwd
*result
, ent_t
*ent
,
876 char *buffer
, size_t buflen
, int *errnop
)
878 struct parser_data
*data
= (void *) buffer
;
888 /* We need at least 3 characters for one line. */
889 if (__glibc_unlikely (buflen
< 3))
893 return NSS_STATUS_TRYAGAIN
;
896 fgetpos (ent
->stream
, &pos
);
897 buffer
[buflen
- 1] = '\xff';
898 p
= fgets_unlocked (buffer
, buflen
, ent
->stream
);
899 if (p
== NULL
&& feof_unlocked (ent
->stream
))
900 return NSS_STATUS_NOTFOUND
;
902 if (p
== NULL
|| __builtin_expect (buffer
[buflen
- 1] != '\xff', 0))
905 fsetpos (ent
->stream
, &pos
);
909 /* Terminate the line for any case. */
910 buffer
[buflen
- 1] = '\0';
912 /* Skip leading blanks. */
916 while (*p
== '\0' || *p
== '#' || /* Ignore empty and comment lines. */
917 /* Parse the line. If it is invalid, loop to
918 get the next line of the file to parse. */
919 !(parse_res
= _nss_files_parse_pwent (p
, result
, data
, buflen
,
922 if (__glibc_unlikely (parse_res
== -1))
923 /* The parser ran out of space. */
926 /* This is a real entry. */
927 if (result
->pw_name
[0] != '+' && result
->pw_name
[0] != '-')
929 if (result
->pw_uid
== uid
)
930 return NSS_STATUS_SUCCESS
;
936 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] == '@'
937 && result
->pw_name
[2] != '\0')
939 /* -1, because we remove first two character of pw_name. */
940 size_t len
= strlen (result
->pw_name
) - 1;
942 enum nss_status status
;
944 memcpy (buf
, &result
->pw_name
[2], len
);
946 status
= getpwuid_plususer (uid
, result
, buffer
, buflen
, errnop
);
947 if (status
== NSS_STATUS_SUCCESS
&&
948 innetgr (buf
, NULL
, result
->pw_name
, NULL
))
949 return NSS_STATUS_NOTFOUND
;
955 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '@'
956 && result
->pw_name
[2] != '\0')
958 /* -1, because we remove first two characters of pw_name. */
959 size_t len
= strlen (result
->pw_name
) - 1;
961 enum nss_status status
;
963 memcpy (buf
, &result
->pw_name
[2], len
);
965 status
= getpwuid_plususer (uid
, result
, buffer
, buflen
, errnop
);
967 if (status
== NSS_STATUS_RETURN
)
970 if (status
== NSS_STATUS_SUCCESS
)
972 if (innetgr (buf
, NULL
, result
->pw_name
, NULL
))
973 return NSS_STATUS_SUCCESS
;
975 else if (status
== NSS_STATUS_RETURN
) /* We couldn't parse the entry */
976 return NSS_STATUS_NOTFOUND
;
984 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] != '\0'
985 && result
->pw_name
[1] != '@')
987 size_t len
= strlen (result
->pw_name
);
989 enum nss_status status
;
991 memcpy (buf
, &result
->pw_name
[1], len
);
993 status
= getpwuid_plususer (uid
, result
, buffer
, buflen
, errnop
);
994 if (status
== NSS_STATUS_SUCCESS
&&
995 innetgr (buf
, NULL
, result
->pw_name
, NULL
))
996 return NSS_STATUS_NOTFOUND
;
1001 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] != '\0'
1002 && result
->pw_name
[1] != '@')
1004 size_t len
= strlen (result
->pw_name
);
1006 enum nss_status status
;
1008 memcpy (buf
, &result
->pw_name
[1], len
);
1010 status
= getpwuid_plususer (uid
, result
, buffer
, buflen
, errnop
);
1012 if (status
== NSS_STATUS_RETURN
)
1015 if (status
== NSS_STATUS_SUCCESS
)
1017 if (strcmp (buf
, result
->pw_name
) == 0)
1018 return NSS_STATUS_SUCCESS
;
1020 else if (status
== NSS_STATUS_RETURN
) /* We couldn't parse the entry */
1021 return NSS_STATUS_NOTFOUND
;
1029 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '\0')
1031 enum nss_status status
;
1033 status
= getpwuid_plususer (uid
, result
, buffer
, buflen
, errnop
);
1034 if (status
== NSS_STATUS_SUCCESS
) /* We found the entry. */
1036 else if (status
== NSS_STATUS_RETURN
) /* We couldn't parse the entry */
1037 return NSS_STATUS_NOTFOUND
;
1042 return NSS_STATUS_SUCCESS
;
1046 _nss_compat_getpwuid_r (uid_t uid
, struct passwd
*pwd
,
1047 char *buffer
, size_t buflen
, int *errnop
)
1049 enum nss_status result
;
1050 ent_t ent
= { false, false, true, NSS_STATUS_SUCCESS
, NULL
, { NULL
, 0, 0 },
1051 { NULL
, NULL
, 0, 0, NULL
, NULL
, NULL
}};
1053 __libc_lock_lock (lock
);
1056 init_nss_interface ();
1058 __libc_lock_unlock (lock
);
1060 result
= internal_setpwent (&ent
, 0, 0);
1062 if (result
== NSS_STATUS_SUCCESS
)
1063 result
= internal_getpwuid_r (uid
, pwd
, &ent
, buffer
, buflen
, errnop
);
1065 internal_endpwent (&ent
);
1071 /* Support routines for remembering -@netgroup and -user entries.
1072 The names are stored in a single string with `|' as separator. */
1074 blacklist_store_name (const char *name
, ent_t
*ent
)
1076 int namelen
= strlen (name
);
1079 /* first call, setup cache */
1080 if (ent
->blacklist
.size
== 0)
1082 ent
->blacklist
.size
= MAX (BLACKLIST_INITIAL_SIZE
, 2 * namelen
);
1083 ent
->blacklist
.data
= malloc (ent
->blacklist
.size
);
1084 if (ent
->blacklist
.data
== NULL
)
1086 ent
->blacklist
.data
[0] = '|';
1087 ent
->blacklist
.data
[1] = '\0';
1088 ent
->blacklist
.current
= 1;
1092 if (in_blacklist (name
, namelen
, ent
))
1093 return; /* no duplicates */
1095 if (ent
->blacklist
.current
+ namelen
+ 1 >= ent
->blacklist
.size
)
1097 ent
->blacklist
.size
+= MAX (BLACKLIST_INCREMENT
, 2 * namelen
);
1098 tmp
= realloc (ent
->blacklist
.data
, ent
->blacklist
.size
);
1101 free (ent
->blacklist
.data
);
1102 ent
->blacklist
.size
= 0;
1105 ent
->blacklist
.data
= tmp
;
1109 tmp
= stpcpy (ent
->blacklist
.data
+ ent
->blacklist
.current
, name
);
1112 ent
->blacklist
.current
+= namelen
+ 1;
1117 /* Returns TRUE if ent->blacklist contains name, else FALSE. */
1119 in_blacklist (const char *name
, int namelen
, ent_t
*ent
)
1121 char buf
[namelen
+ 3];
1124 if (ent
->blacklist
.data
== NULL
)
1128 cp
= stpcpy (&buf
[1], name
);
1131 return strstr (ent
->blacklist
.data
, buf
) != NULL
;