1 /* Copyright (C) 1996-2022 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; if not, see
16 <https://www.gnu.org/licenses/>. */
25 #include <stdio_ext.h>
27 #include <libc-lock.h>
28 #include <kernel-features.h>
29 #include <nss_files.h>
32 #include "nisdomain.h"
34 NSS_DECLARE_MODULE_FUNCTIONS (compat
)
36 static nss_action_list ni
;
37 static enum nss_status (*setpwent_impl
) (int stayopen
);
38 static enum nss_status (*getpwnam_r_impl
) (const char *name
,
39 struct passwd
* pwd
, char *buffer
,
40 size_t buflen
, int *errnop
);
41 static enum nss_status (*getpwuid_r_impl
) (uid_t uid
, struct passwd
* pwd
,
42 char *buffer
, size_t buflen
,
44 static enum nss_status (*getpwent_r_impl
) (struct passwd
* pwd
, char *buffer
,
45 size_t buflen
, int *errnop
);
46 static enum nss_status (*endpwent_impl
) (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 /* Prototypes for local functions. */
85 static void blacklist_store_name (const char *, ent_t
*);
86 static bool in_blacklist (const char *, int, ent_t
*);
88 /* Initialize the NSS interface/functions. The calling function must
91 init_nss_interface (void)
93 if (__nss_database_get (nss_database_passwd_compat
, &ni
))
95 setpwent_impl
= __nss_lookup_function (ni
, "setpwent");
96 getpwnam_r_impl
= __nss_lookup_function (ni
, "getpwnam_r");
97 getpwuid_r_impl
= __nss_lookup_function (ni
, "getpwuid_r");
98 getpwent_r_impl
= __nss_lookup_function (ni
, "getpwent_r");
99 endpwent_impl
= __nss_lookup_function (ni
, "endpwent");
104 give_pwd_free (struct passwd
*pwd
)
107 free (pwd
->pw_passwd
);
108 free (pwd
->pw_gecos
);
110 free (pwd
->pw_shell
);
112 memset (pwd
, '\0', sizeof (struct passwd
));
116 pwd_need_buflen (struct passwd
*pwd
)
120 if (pwd
->pw_passwd
!= NULL
)
121 len
+= strlen (pwd
->pw_passwd
) + 1;
123 if (pwd
->pw_gecos
!= NULL
)
124 len
+= strlen (pwd
->pw_gecos
) + 1;
126 if (pwd
->pw_dir
!= NULL
)
127 len
+= strlen (pwd
->pw_dir
) + 1;
129 if (pwd
->pw_shell
!= NULL
)
130 len
+= strlen (pwd
->pw_shell
) + 1;
136 copy_pwd_changes (struct passwd
*dest
, struct passwd
*src
,
137 char *buffer
, size_t buflen
)
139 if (src
->pw_passwd
!= NULL
&& strlen (src
->pw_passwd
))
142 dest
->pw_passwd
= strdup (src
->pw_passwd
);
143 else if (dest
->pw_passwd
144 && strlen (dest
->pw_passwd
) >= strlen (src
->pw_passwd
))
145 strcpy (dest
->pw_passwd
, src
->pw_passwd
);
148 dest
->pw_passwd
= buffer
;
149 strcpy (dest
->pw_passwd
, src
->pw_passwd
);
150 buffer
+= strlen (dest
->pw_passwd
) + 1;
151 buflen
= buflen
- (strlen (dest
->pw_passwd
) + 1);
155 if (src
->pw_gecos
!= NULL
&& strlen (src
->pw_gecos
))
158 dest
->pw_gecos
= strdup (src
->pw_gecos
);
159 else if (dest
->pw_gecos
160 && strlen (dest
->pw_gecos
) >= strlen (src
->pw_gecos
))
161 strcpy (dest
->pw_gecos
, src
->pw_gecos
);
164 dest
->pw_gecos
= buffer
;
165 strcpy (dest
->pw_gecos
, src
->pw_gecos
);
166 buffer
+= strlen (dest
->pw_gecos
) + 1;
167 buflen
= buflen
- (strlen (dest
->pw_gecos
) + 1);
170 if (src
->pw_dir
!= NULL
&& strlen (src
->pw_dir
))
173 dest
->pw_dir
= strdup (src
->pw_dir
);
174 else if (dest
->pw_dir
&& strlen (dest
->pw_dir
) >= strlen (src
->pw_dir
))
175 strcpy (dest
->pw_dir
, src
->pw_dir
);
178 dest
->pw_dir
= buffer
;
179 strcpy (dest
->pw_dir
, src
->pw_dir
);
180 buffer
+= strlen (dest
->pw_dir
) + 1;
181 buflen
= buflen
- (strlen (dest
->pw_dir
) + 1);
185 if (src
->pw_shell
!= NULL
&& strlen (src
->pw_shell
))
188 dest
->pw_shell
= strdup (src
->pw_shell
);
189 else if (dest
->pw_shell
190 && strlen (dest
->pw_shell
) >= strlen (src
->pw_shell
))
191 strcpy (dest
->pw_shell
, src
->pw_shell
);
194 dest
->pw_shell
= buffer
;
195 strcpy (dest
->pw_shell
, src
->pw_shell
);
196 buffer
+= strlen (dest
->pw_shell
) + 1;
197 buflen
= buflen
- (strlen (dest
->pw_shell
) + 1);
202 static enum nss_status
203 internal_setpwent (ent_t
*ent
, int stayopen
, int needent
)
205 enum nss_status status
= NSS_STATUS_SUCCESS
;
207 ent
->first
= ent
->netgroup
= false;
209 ent
->setent_status
= NSS_STATUS_SUCCESS
;
211 /* If something was left over free it. */
213 __internal_endnetgrent (&ent
->netgrdata
);
215 if (ent
->blacklist
.data
!= NULL
)
217 ent
->blacklist
.current
= 1;
218 ent
->blacklist
.data
[0] = '|';
219 ent
->blacklist
.data
[1] = '\0';
222 ent
->blacklist
.current
= 0;
224 if (ent
->stream
== NULL
)
226 ent
->stream
= __nss_files_fopen ("/etc/passwd");
228 if (ent
->stream
== NULL
)
229 status
= errno
== EAGAIN
? NSS_STATUS_TRYAGAIN
: NSS_STATUS_UNAVAIL
;
232 rewind (ent
->stream
);
234 give_pwd_free (&ent
->pwd
);
236 if (needent
&& status
== NSS_STATUS_SUCCESS
&& setpwent_impl
)
237 ent
->setent_status
= setpwent_impl (stayopen
);
244 _nss_compat_setpwent (int stayopen
)
246 enum nss_status result
;
248 __libc_lock_lock (lock
);
251 init_nss_interface ();
253 result
= internal_setpwent (&ext_ent
, stayopen
, 1);
255 __libc_lock_unlock (lock
);
261 static enum nss_status __attribute_warn_unused_result__
262 internal_endpwent (ent_t
*ent
)
264 if (ent
->stream
!= NULL
)
266 fclose (ent
->stream
);
271 __internal_endnetgrent (&ent
->netgrdata
);
273 ent
->first
= ent
->netgroup
= false;
275 if (ent
->blacklist
.data
!= NULL
)
277 ent
->blacklist
.current
= 1;
278 ent
->blacklist
.data
[0] = '|';
279 ent
->blacklist
.data
[1] = '\0';
282 ent
->blacklist
.current
= 0;
284 give_pwd_free (&ent
->pwd
);
286 return NSS_STATUS_SUCCESS
;
289 /* Like internal_endpwent, but preserve errno in all cases. */
291 internal_endpwent_noerror (ent_t
*ent
)
293 int saved_errno
= errno
;
294 enum nss_status unused
__attribute__ ((unused
)) = internal_endpwent (ent
);
295 __set_errno (saved_errno
);
299 _nss_compat_endpwent (void)
301 enum nss_status result
;
303 __libc_lock_lock (lock
);
308 result
= internal_endpwent (&ext_ent
);
310 __libc_lock_unlock (lock
);
316 static enum nss_status
317 getpwent_next_nss_netgr (const char *name
, struct passwd
*result
, ent_t
*ent
,
318 char *group
, char *buffer
, size_t buflen
,
321 char *curdomain
= NULL
, *host
, *user
, *domain
, *p2
;
325 /* Leave function if NSS module does not support getpwnam_r,
326 we need this function here. */
327 if (!getpwnam_r_impl
)
328 return NSS_STATUS_UNAVAIL
;
332 memset (&ent
->netgrdata
, 0, sizeof (struct __netgrent
));
333 __internal_setnetgrent (group
, &ent
->netgrdata
);
339 status
= __internal_getnetgrent_r (&host
, &user
, &domain
,
340 &ent
->netgrdata
, buffer
, buflen
,
344 __internal_endnetgrent (&ent
->netgrdata
);
346 give_pwd_free (&ent
->pwd
);
347 return NSS_STATUS_RETURN
;
350 if (user
== NULL
|| user
[0] == '-')
355 if (curdomain
== NULL
356 && __nss_get_default_domain (&curdomain
) != 0)
358 __internal_endnetgrent (&ent
->netgrdata
);
359 ent
->netgroup
= false;
360 give_pwd_free (&ent
->pwd
);
361 return NSS_STATUS_UNAVAIL
;
363 if (strcmp (curdomain
, domain
) != 0)
367 /* If name != NULL, we are called from getpwnam. */
369 if (strcmp (user
, name
) != 0)
372 p2len
= pwd_need_buflen (&ent
->pwd
);
376 return NSS_STATUS_TRYAGAIN
;
378 p2
= buffer
+ (buflen
- p2len
);
381 if (getpwnam_r_impl (user
, result
, buffer
, buflen
, errnop
)
382 != NSS_STATUS_SUCCESS
)
385 if (!in_blacklist (result
->pw_name
, strlen (result
->pw_name
), ent
))
387 /* Store the User in the blacklist for possible the "+" at the
388 end of /etc/passwd */
389 blacklist_store_name (result
->pw_name
, ent
);
390 copy_pwd_changes (result
, &ent
->pwd
, p2
, p2len
);
395 return NSS_STATUS_SUCCESS
;
398 /* get the next user from NSS (+ entry) */
399 static enum nss_status
400 getpwent_next_nss (struct passwd
*result
, ent_t
*ent
, char *buffer
,
401 size_t buflen
, int *errnop
)
403 enum nss_status status
;
407 /* Return if NSS module does not support getpwent_r. */
408 if (!getpwent_r_impl
)
409 return NSS_STATUS_UNAVAIL
;
411 /* If the setpwent call failed, say so. */
412 if (ent
->setent_status
!= NSS_STATUS_SUCCESS
)
413 return ent
->setent_status
;
415 p2len
= pwd_need_buflen (&ent
->pwd
);
419 return NSS_STATUS_TRYAGAIN
;
421 p2
= buffer
+ (buflen
- p2len
);
429 if ((status
= getpwent_r_impl (result
, buffer
, buflen
, errnop
))
430 != NSS_STATUS_SUCCESS
)
433 while (in_blacklist (result
->pw_name
, strlen (result
->pw_name
), ent
));
435 copy_pwd_changes (result
, &ent
->pwd
, p2
, p2len
);
437 return NSS_STATUS_SUCCESS
;
440 /* This function handle the +user entrys in /etc/passwd */
441 static enum nss_status
442 getpwnam_plususer (const char *name
, struct passwd
*result
, ent_t
*ent
,
443 char *buffer
, size_t buflen
, int *errnop
)
445 if (!getpwnam_r_impl
)
446 return NSS_STATUS_UNAVAIL
;
449 memset (&pwd
, '\0', sizeof (struct passwd
));
451 copy_pwd_changes (&pwd
, result
, NULL
, 0);
453 size_t plen
= pwd_need_buflen (&pwd
);
457 return NSS_STATUS_TRYAGAIN
;
459 char *p
= buffer
+ (buflen
- plen
);
462 enum nss_status status
= getpwnam_r_impl (name
, result
, buffer
, buflen
,
464 if (status
!= NSS_STATUS_SUCCESS
)
467 if (in_blacklist (result
->pw_name
, strlen (result
->pw_name
), ent
))
468 return NSS_STATUS_NOTFOUND
;
470 copy_pwd_changes (result
, &pwd
, p
, plen
);
471 give_pwd_free (&pwd
);
472 /* We found the entry. */
473 return NSS_STATUS_SUCCESS
;
476 static enum nss_status
477 getpwent_next_file (struct passwd
*result
, ent_t
*ent
,
478 char *buffer
, size_t buflen
, int *errnop
)
480 struct parser_data
*data
= (void *) buffer
;
489 /* We need at least 3 characters for one line. */
490 if (__glibc_unlikely (buflen
< 3))
494 return NSS_STATUS_TRYAGAIN
;
497 fgetpos (ent
->stream
, &pos
);
498 buffer
[buflen
- 1] = '\xff';
499 p
= fgets_unlocked (buffer
, buflen
, ent
->stream
);
500 if (p
== NULL
&& feof_unlocked (ent
->stream
))
501 return NSS_STATUS_NOTFOUND
;
503 if (p
== NULL
|| __builtin_expect (buffer
[buflen
- 1] != '\xff', 0))
506 fsetpos (ent
->stream
, &pos
);
510 /* Terminate the line for any case. */
511 buffer
[buflen
- 1] = '\0';
513 /* Skip leading blanks. */
517 while (*p
== '\0' || *p
== '#' /* Ignore empty and comment lines. */
518 /* Parse the line. If it is invalid, loop to
519 get the next line of the file to parse. */
520 || !(parse_res
= _nss_files_parse_pwent (p
, result
, data
, buflen
,
523 if (__glibc_unlikely (parse_res
== -1))
524 /* The parser ran out of space. */
527 if (result
->pw_name
[0] != '+' && result
->pw_name
[0] != '-')
528 /* This is a real entry. */
532 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] == '@'
533 && result
->pw_name
[2] != '\0')
535 /* XXX Do not use fixed length buffer. */
537 char *user
, *host
, *domain
;
538 struct __netgrent netgrdata
;
540 memset (&netgrdata
, 0, sizeof (struct __netgrent
));
541 __internal_setnetgrent (&result
->pw_name
[2], &netgrdata
);
542 while (__internal_getnetgrent_r (&host
, &user
, &domain
, &netgrdata
,
543 buf2
, sizeof (buf2
), errnop
))
545 if (user
!= NULL
&& user
[0] != '-')
546 blacklist_store_name (user
, ent
);
548 __internal_endnetgrent (&netgrdata
);
553 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '@'
554 && result
->pw_name
[2] != '\0')
556 enum nss_status status
;
558 ent
->netgroup
= true;
560 copy_pwd_changes (&ent
->pwd
, result
, NULL
, 0);
562 status
= getpwent_next_nss_netgr (NULL
, result
, ent
,
564 buffer
, buflen
, errnop
);
565 if (status
== NSS_STATUS_RETURN
)
572 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] != '\0'
573 && result
->pw_name
[1] != '@')
575 blacklist_store_name (&result
->pw_name
[1], ent
);
580 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] != '\0'
581 && result
->pw_name
[1] != '@')
583 size_t len
= strlen (result
->pw_name
);
585 enum nss_status status
;
587 /* Store the User in the blacklist for the "+" at the end of
589 memcpy (buf
, &result
->pw_name
[1], len
);
590 status
= getpwnam_plususer (&result
->pw_name
[1], result
, ent
,
591 buffer
, buflen
, errnop
);
592 blacklist_store_name (buf
, ent
);
594 if (status
== NSS_STATUS_SUCCESS
) /* We found the entry. */
596 else if (status
== NSS_STATUS_RETURN
/* We couldn't parse the entry */
597 || status
== NSS_STATUS_NOTFOUND
) /* entry doesn't exist */
601 if (status
== NSS_STATUS_TRYAGAIN
)
603 /* The parser ran out of space */
604 fsetpos (ent
->stream
, &pos
);
612 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '\0')
616 copy_pwd_changes (&ent
->pwd
, result
, NULL
, 0);
618 return getpwent_next_nss (result
, ent
, buffer
, buflen
, errnop
);
622 return NSS_STATUS_SUCCESS
;
626 static enum nss_status
627 internal_getpwent_r (struct passwd
*pw
, ent_t
*ent
, char *buffer
,
628 size_t buflen
, int *errnop
)
632 enum nss_status status
;
634 /* We are searching members in a netgroup */
635 /* Since this is not the first call, we don't need the group name */
636 status
= getpwent_next_nss_netgr (NULL
, pw
, ent
, NULL
, buffer
, buflen
,
638 if (status
== NSS_STATUS_RETURN
)
639 return getpwent_next_file (pw
, ent
, buffer
, buflen
, errnop
);
644 return getpwent_next_file (pw
, ent
, buffer
, buflen
, errnop
);
646 return getpwent_next_nss (pw
, ent
, buffer
, buflen
, errnop
);
651 _nss_compat_getpwent_r (struct passwd
*pwd
, char *buffer
, size_t buflen
,
654 enum nss_status result
= NSS_STATUS_SUCCESS
;
656 __libc_lock_lock (lock
);
658 /* Be prepared that the setpwent function was not called before. */
660 init_nss_interface ();
662 if (ext_ent
.stream
== NULL
)
663 result
= internal_setpwent (&ext_ent
, 1, 1);
665 if (result
== NSS_STATUS_SUCCESS
)
666 result
= internal_getpwent_r (pwd
, &ext_ent
, buffer
, buflen
, errnop
);
668 __libc_lock_unlock (lock
);
673 /* Searches in /etc/passwd and the NIS/NIS+ map for a special user */
674 static enum nss_status
675 internal_getpwnam_r (const char *name
, struct passwd
*result
, ent_t
*ent
,
676 char *buffer
, size_t buflen
, int *errnop
)
678 struct parser_data
*data
= (void *) buffer
;
688 /* We need at least 3 characters for one line. */
689 if (__glibc_unlikely (buflen
< 3))
693 return NSS_STATUS_TRYAGAIN
;
696 fgetpos (ent
->stream
, &pos
);
697 buffer
[buflen
- 1] = '\xff';
698 p
= fgets_unlocked (buffer
, buflen
, ent
->stream
);
699 if (p
== NULL
&& feof_unlocked (ent
->stream
))
701 return NSS_STATUS_NOTFOUND
;
703 if (p
== NULL
|| __builtin_expect (buffer
[buflen
- 1] != '\xff', 0))
706 fsetpos (ent
->stream
, &pos
);
710 /* Terminate the line for any case. */
711 buffer
[buflen
- 1] = '\0';
713 /* Skip leading blanks. */
717 while (*p
== '\0' || *p
== '#' /* Ignore empty and comment lines. */
718 /* Parse the line. If it is invalid, loop to
719 get the next line of the file to parse. */
720 || !(parse_res
= _nss_files_parse_pwent (p
, result
, data
, buflen
,
723 if (__glibc_unlikely (parse_res
== -1))
724 /* The parser ran out of space. */
727 /* This is a real entry. */
728 if (result
->pw_name
[0] != '+' && result
->pw_name
[0] != '-')
730 if (strcmp (result
->pw_name
, name
) == 0)
731 return NSS_STATUS_SUCCESS
;
737 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] == '@'
738 && result
->pw_name
[2] != '\0')
740 if (innetgr (&result
->pw_name
[2], NULL
, name
, NULL
))
741 return NSS_STATUS_NOTFOUND
;
746 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '@'
747 && result
->pw_name
[2] != '\0')
749 enum nss_status status
;
751 if (innetgr (&result
->pw_name
[2], NULL
, name
, NULL
))
753 status
= getpwnam_plususer (name
, result
, ent
, buffer
,
756 if (status
== NSS_STATUS_RETURN
)
765 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] != '\0'
766 && result
->pw_name
[1] != '@')
768 if (strcmp (&result
->pw_name
[1], name
) == 0)
769 return NSS_STATUS_NOTFOUND
;
775 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] != '\0'
776 && result
->pw_name
[1] != '@')
778 if (strcmp (name
, &result
->pw_name
[1]) == 0)
780 enum nss_status status
;
782 status
= getpwnam_plususer (name
, result
, ent
, buffer
, buflen
,
784 if (status
== NSS_STATUS_RETURN
)
785 /* We couldn't parse the entry */
786 return NSS_STATUS_NOTFOUND
;
793 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '\0')
795 enum nss_status status
;
797 status
= getpwnam_plususer (name
, result
, ent
,
798 buffer
, buflen
, errnop
);
799 if (status
== NSS_STATUS_SUCCESS
) /* We found the entry. */
801 else if (status
== NSS_STATUS_RETURN
) /* We couldn't parse the entry */
802 return NSS_STATUS_NOTFOUND
;
807 return NSS_STATUS_SUCCESS
;
811 _nss_compat_getpwnam_r (const char *name
, struct passwd
*pwd
,
812 char *buffer
, size_t buflen
, int *errnop
)
814 enum nss_status result
;
815 ent_t ent
= { false, false, true, NSS_STATUS_SUCCESS
, NULL
, { NULL
, 0, 0 },
816 { NULL
, NULL
, 0, 0, NULL
, NULL
, NULL
}};
818 if (name
[0] == '-' || name
[0] == '+')
819 return NSS_STATUS_NOTFOUND
;
821 __libc_lock_lock (lock
);
824 init_nss_interface ();
826 __libc_lock_unlock (lock
);
828 result
= internal_setpwent (&ent
, 0, 0);
830 if (result
== NSS_STATUS_SUCCESS
)
831 result
= internal_getpwnam_r (name
, pwd
, &ent
, buffer
, buflen
, errnop
);
833 internal_endpwent_noerror (&ent
);
838 /* This function handle the + entry in /etc/passwd for getpwuid */
839 static enum nss_status
840 getpwuid_plususer (uid_t uid
, struct passwd
*result
, char *buffer
,
841 size_t buflen
, int *errnop
)
847 if (!getpwuid_r_impl
)
848 return NSS_STATUS_UNAVAIL
;
850 memset (&pwd
, '\0', sizeof (struct passwd
));
852 copy_pwd_changes (&pwd
, result
, NULL
, 0);
854 plen
= pwd_need_buflen (&pwd
);
858 return NSS_STATUS_TRYAGAIN
;
860 p
= buffer
+ (buflen
- plen
);
863 if (getpwuid_r_impl (uid
, result
, buffer
, buflen
, errnop
) ==
866 copy_pwd_changes (result
, &pwd
, p
, plen
);
867 give_pwd_free (&pwd
);
868 /* We found the entry. */
869 return NSS_STATUS_SUCCESS
;
873 /* Give buffer the old len back */
875 give_pwd_free (&pwd
);
877 return NSS_STATUS_RETURN
;
880 /* Searches in /etc/passwd and the NSS subsystem for a special user id */
881 static enum nss_status
882 internal_getpwuid_r (uid_t uid
, struct passwd
*result
, ent_t
*ent
,
883 char *buffer
, size_t buflen
, int *errnop
)
885 struct parser_data
*data
= (void *) buffer
;
895 /* We need at least 3 characters for one line. */
896 if (__glibc_unlikely (buflen
< 3))
900 return NSS_STATUS_TRYAGAIN
;
903 fgetpos (ent
->stream
, &pos
);
904 buffer
[buflen
- 1] = '\xff';
905 p
= fgets_unlocked (buffer
, buflen
, ent
->stream
);
906 if (p
== NULL
&& feof_unlocked (ent
->stream
))
907 return NSS_STATUS_NOTFOUND
;
909 if (p
== NULL
|| __builtin_expect (buffer
[buflen
- 1] != '\xff', 0))
912 fsetpos (ent
->stream
, &pos
);
916 /* Terminate the line for any case. */
917 buffer
[buflen
- 1] = '\0';
919 /* Skip leading blanks. */
923 while (*p
== '\0' || *p
== '#' /* Ignore empty and comment lines. */
924 /* Parse the line. If it is invalid, loop to
925 get the next line of the file to parse. */
926 || !(parse_res
= _nss_files_parse_pwent (p
, result
, data
, buflen
,
929 if (__glibc_unlikely (parse_res
== -1))
930 /* The parser ran out of space. */
933 /* This is a real entry. */
934 if (result
->pw_name
[0] != '+' && result
->pw_name
[0] != '-')
936 if (result
->pw_uid
== uid
)
937 return NSS_STATUS_SUCCESS
;
943 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] == '@'
944 && result
->pw_name
[2] != '\0')
946 /* -1, because we remove first two character of pw_name. */
947 size_t len
= strlen (result
->pw_name
) - 1;
949 enum nss_status status
;
951 memcpy (buf
, &result
->pw_name
[2], len
);
953 status
= getpwuid_plususer (uid
, result
, buffer
, buflen
, errnop
);
954 if (status
== NSS_STATUS_SUCCESS
955 && innetgr (buf
, NULL
, result
->pw_name
, NULL
))
956 return NSS_STATUS_NOTFOUND
;
962 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '@'
963 && result
->pw_name
[2] != '\0')
965 /* -1, because we remove first two characters of pw_name. */
966 size_t len
= strlen (result
->pw_name
) - 1;
968 enum nss_status status
;
970 memcpy (buf
, &result
->pw_name
[2], len
);
972 status
= getpwuid_plususer (uid
, result
, buffer
, buflen
, errnop
);
974 if (status
== NSS_STATUS_RETURN
)
977 if (status
== NSS_STATUS_SUCCESS
)
979 if (innetgr (buf
, NULL
, result
->pw_name
, NULL
))
980 return NSS_STATUS_SUCCESS
;
982 else if (status
== NSS_STATUS_RETURN
) /* We couldn't parse the entry */
983 return NSS_STATUS_NOTFOUND
;
991 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] != '\0'
992 && result
->pw_name
[1] != '@')
994 size_t len
= strlen (result
->pw_name
);
996 enum nss_status status
;
998 memcpy (buf
, &result
->pw_name
[1], 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
;
1008 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] != '\0'
1009 && result
->pw_name
[1] != '@')
1011 size_t len
= strlen (result
->pw_name
);
1013 enum nss_status status
;
1015 memcpy (buf
, &result
->pw_name
[1], len
);
1017 status
= getpwuid_plususer (uid
, result
, buffer
, buflen
, errnop
);
1019 if (status
== NSS_STATUS_RETURN
)
1022 if (status
== NSS_STATUS_SUCCESS
)
1024 if (strcmp (buf
, result
->pw_name
) == 0)
1025 return NSS_STATUS_SUCCESS
;
1027 else if (status
== NSS_STATUS_RETURN
) /* We couldn't parse the entry */
1028 return NSS_STATUS_NOTFOUND
;
1036 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '\0')
1038 enum nss_status status
;
1040 status
= getpwuid_plususer (uid
, result
, buffer
, buflen
, errnop
);
1041 if (status
== NSS_STATUS_SUCCESS
) /* We found the entry. */
1043 else if (status
== NSS_STATUS_RETURN
) /* We couldn't parse the entry */
1044 return NSS_STATUS_NOTFOUND
;
1049 return NSS_STATUS_SUCCESS
;
1053 _nss_compat_getpwuid_r (uid_t uid
, struct passwd
*pwd
,
1054 char *buffer
, size_t buflen
, int *errnop
)
1056 enum nss_status result
;
1057 ent_t ent
= { false, false, true, NSS_STATUS_SUCCESS
, NULL
, { NULL
, 0, 0 },
1058 { NULL
, NULL
, 0, 0, NULL
, NULL
, NULL
}};
1060 __libc_lock_lock (lock
);
1063 init_nss_interface ();
1065 __libc_lock_unlock (lock
);
1067 result
= internal_setpwent (&ent
, 0, 0);
1069 if (result
== NSS_STATUS_SUCCESS
)
1070 result
= internal_getpwuid_r (uid
, pwd
, &ent
, buffer
, buflen
, errnop
);
1072 internal_endpwent_noerror (&ent
);
1078 /* Support routines for remembering -@netgroup and -user entries.
1079 The names are stored in a single string with `|' as separator. */
1081 blacklist_store_name (const char *name
, ent_t
*ent
)
1083 int namelen
= strlen (name
);
1086 /* first call, setup cache */
1087 if (ent
->blacklist
.size
== 0)
1089 ent
->blacklist
.size
= MAX (BLACKLIST_INITIAL_SIZE
, 2 * namelen
);
1090 ent
->blacklist
.data
= malloc (ent
->blacklist
.size
);
1091 if (ent
->blacklist
.data
== NULL
)
1093 ent
->blacklist
.data
[0] = '|';
1094 ent
->blacklist
.data
[1] = '\0';
1095 ent
->blacklist
.current
= 1;
1099 if (in_blacklist (name
, namelen
, ent
))
1100 return; /* no duplicates */
1102 if (ent
->blacklist
.current
+ namelen
+ 1 >= ent
->blacklist
.size
)
1104 ent
->blacklist
.size
+= MAX (BLACKLIST_INCREMENT
, 2 * namelen
);
1105 tmp
= realloc (ent
->blacklist
.data
, ent
->blacklist
.size
);
1108 free (ent
->blacklist
.data
);
1109 ent
->blacklist
.size
= 0;
1112 ent
->blacklist
.data
= tmp
;
1116 tmp
= stpcpy (ent
->blacklist
.data
+ ent
->blacklist
.current
, name
);
1119 ent
->blacklist
.current
+= namelen
+ 1;
1124 /* Returns whether ent->blacklist contains name. */
1126 in_blacklist (const char *name
, int namelen
, ent_t
*ent
)
1128 char buf
[namelen
+ 3];
1131 if (ent
->blacklist
.data
== NULL
)
1135 cp
= stpcpy (&buf
[1], name
);
1138 return strstr (ent
->blacklist
.data
, buf
) != NULL
;