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
)
120 free (pwd
->pw_passwd
);
121 free (pwd
->pw_gecos
);
123 free (pwd
->pw_shell
);
125 memset (pwd
, '\0', sizeof (struct passwd
));
129 pwd_need_buflen (struct passwd
*pwd
)
133 if (pwd
->pw_passwd
!= NULL
)
134 len
+= strlen (pwd
->pw_passwd
) + 1;
136 if (pwd
->pw_gecos
!= NULL
)
137 len
+= strlen (pwd
->pw_gecos
) + 1;
139 if (pwd
->pw_dir
!= NULL
)
140 len
+= strlen (pwd
->pw_dir
) + 1;
142 if (pwd
->pw_shell
!= NULL
)
143 len
+= strlen (pwd
->pw_shell
) + 1;
149 copy_pwd_changes (struct passwd
*dest
, struct passwd
*src
,
150 char *buffer
, size_t buflen
)
152 if (src
->pw_passwd
!= NULL
&& strlen (src
->pw_passwd
))
155 dest
->pw_passwd
= strdup (src
->pw_passwd
);
156 else if (dest
->pw_passwd
&&
157 strlen (dest
->pw_passwd
) >= strlen (src
->pw_passwd
))
158 strcpy (dest
->pw_passwd
, src
->pw_passwd
);
161 dest
->pw_passwd
= buffer
;
162 strcpy (dest
->pw_passwd
, src
->pw_passwd
);
163 buffer
+= strlen (dest
->pw_passwd
) + 1;
164 buflen
= buflen
- (strlen (dest
->pw_passwd
) + 1);
168 if (src
->pw_gecos
!= NULL
&& strlen (src
->pw_gecos
))
171 dest
->pw_gecos
= strdup (src
->pw_gecos
);
172 else if (dest
->pw_gecos
&&
173 strlen (dest
->pw_gecos
) >= strlen (src
->pw_gecos
))
174 strcpy (dest
->pw_gecos
, src
->pw_gecos
);
177 dest
->pw_gecos
= buffer
;
178 strcpy (dest
->pw_gecos
, src
->pw_gecos
);
179 buffer
+= strlen (dest
->pw_gecos
) + 1;
180 buflen
= buflen
- (strlen (dest
->pw_gecos
) + 1);
183 if (src
->pw_dir
!= NULL
&& strlen (src
->pw_dir
))
186 dest
->pw_dir
= strdup (src
->pw_dir
);
187 else if (dest
->pw_dir
&& strlen (dest
->pw_dir
) >= strlen (src
->pw_dir
))
188 strcpy (dest
->pw_dir
, src
->pw_dir
);
191 dest
->pw_dir
= buffer
;
192 strcpy (dest
->pw_dir
, src
->pw_dir
);
193 buffer
+= strlen (dest
->pw_dir
) + 1;
194 buflen
= buflen
- (strlen (dest
->pw_dir
) + 1);
198 if (src
->pw_shell
!= NULL
&& strlen (src
->pw_shell
))
201 dest
->pw_shell
= strdup (src
->pw_shell
);
202 else if (dest
->pw_shell
&&
203 strlen (dest
->pw_shell
) >= strlen (src
->pw_shell
))
204 strcpy (dest
->pw_shell
, src
->pw_shell
);
207 dest
->pw_shell
= buffer
;
208 strcpy (dest
->pw_shell
, src
->pw_shell
);
209 buffer
+= strlen (dest
->pw_shell
) + 1;
210 buflen
= buflen
- (strlen (dest
->pw_shell
) + 1);
215 static enum nss_status
216 internal_setpwent (ent_t
*ent
, int stayopen
, int needent
)
218 enum nss_status status
= NSS_STATUS_SUCCESS
;
220 ent
->first
= ent
->netgroup
= false;
222 ent
->setent_status
= NSS_STATUS_SUCCESS
;
224 /* If something was left over free it. */
226 __internal_endnetgrent (&ent
->netgrdata
);
228 if (ent
->blacklist
.data
!= NULL
)
230 ent
->blacklist
.current
= 1;
231 ent
->blacklist
.data
[0] = '|';
232 ent
->blacklist
.data
[1] = '\0';
235 ent
->blacklist
.current
= 0;
237 if (ent
->stream
== NULL
)
239 ent
->stream
= fopen ("/etc/passwd", "rme");
241 if (ent
->stream
== NULL
)
242 status
= errno
== EAGAIN
? NSS_STATUS_TRYAGAIN
: NSS_STATUS_UNAVAIL
;
245 /* We have to make sure the file is `closed on exec'. */
248 if (__compat_have_cloexec
<= 0)
251 result
= flags
= fcntl (fileno_unlocked (ent
->stream
), F_GETFD
,
255 #if defined O_CLOEXEC && !defined __ASSUME_O_CLOEXEC
256 if (__compat_have_cloexec
== 0)
257 __compat_have_cloexec
= (flags
& FD_CLOEXEC
) ? 1 : -1;
259 if (__compat_have_cloexec
< 0)
263 result
= fcntl (fileno_unlocked (ent
->stream
), F_SETFD
,
271 /* Something went wrong. Close the stream and return a
273 fclose (ent
->stream
);
275 status
= NSS_STATUS_UNAVAIL
;
278 /* We take care of locking ourself. */
279 __fsetlocking (ent
->stream
, FSETLOCKING_BYCALLER
);
283 rewind (ent
->stream
);
285 give_pwd_free (&ent
->pwd
);
287 if (needent
&& status
== NSS_STATUS_SUCCESS
&& nss_setpwent
)
288 ent
->setent_status
= nss_setpwent (stayopen
);
295 _nss_compat_setpwent (int stayopen
)
297 enum nss_status result
;
299 __libc_lock_lock (lock
);
302 init_nss_interface ();
304 result
= internal_setpwent (&ext_ent
, stayopen
, 1);
306 __libc_lock_unlock (lock
);
312 static enum nss_status
313 internal_endpwent (ent_t
*ent
)
318 if (ent
->stream
!= NULL
)
320 fclose (ent
->stream
);
325 __internal_endnetgrent (&ent
->netgrdata
);
327 ent
->first
= ent
->netgroup
= false;
329 if (ent
->blacklist
.data
!= NULL
)
331 ent
->blacklist
.current
= 1;
332 ent
->blacklist
.data
[0] = '|';
333 ent
->blacklist
.data
[1] = '\0';
336 ent
->blacklist
.current
= 0;
338 give_pwd_free (&ent
->pwd
);
340 return NSS_STATUS_SUCCESS
;
344 _nss_compat_endpwent (void)
346 enum nss_status result
;
348 __libc_lock_lock (lock
);
350 result
= internal_endpwent (&ext_ent
);
352 __libc_lock_unlock (lock
);
358 static enum nss_status
359 getpwent_next_nss_netgr (const char *name
, struct passwd
*result
, ent_t
*ent
,
360 char *group
, char *buffer
, size_t buflen
,
363 char *curdomain
, *host
, *user
, *domain
, *p2
;
367 /* Leave function if NSS module does not support getpwnam_r,
368 we need this function here. */
370 return NSS_STATUS_UNAVAIL
;
372 if (yp_get_default_domain (&curdomain
) != YPERR_SUCCESS
)
374 ent
->netgroup
= false;
376 give_pwd_free (&ent
->pwd
);
377 return NSS_STATUS_UNAVAIL
;
380 if (ent
->first
== true)
382 memset (&ent
->netgrdata
, 0, sizeof (struct __netgrent
));
383 __internal_setnetgrent (group
, &ent
->netgrdata
);
391 saved_cursor
= ent
->netgrdata
.cursor
;
392 status
= __internal_getnetgrent_r (&host
, &user
, &domain
,
393 &ent
->netgrdata
, buffer
, buflen
,
397 __internal_endnetgrent (&ent
->netgrdata
);
399 give_pwd_free (&ent
->pwd
);
400 return NSS_STATUS_RETURN
;
403 if (user
== NULL
|| user
[0] == '-')
406 if (domain
!= NULL
&& strcmp (curdomain
, domain
) != 0)
409 /* If name != NULL, we are called from getpwnam. */
411 if (strcmp (user
, name
) != 0)
414 p2len
= pwd_need_buflen (&ent
->pwd
);
418 return NSS_STATUS_TRYAGAIN
;
420 p2
= buffer
+ (buflen
- p2len
);
423 if (nss_getpwnam_r (user
, result
, buffer
, buflen
, errnop
) !=
427 if (!in_blacklist (result
->pw_name
, strlen (result
->pw_name
), ent
))
429 /* Store the User in the blacklist for possible the "+" at the
430 end of /etc/passwd */
431 blacklist_store_name (result
->pw_name
, ent
);
432 copy_pwd_changes (result
, &ent
->pwd
, p2
, p2len
);
437 return NSS_STATUS_SUCCESS
;
440 /* get the next user from NSS (+ entry) */
441 static enum nss_status
442 getpwent_next_nss (struct passwd
*result
, ent_t
*ent
, char *buffer
,
443 size_t buflen
, int *errnop
)
445 enum nss_status status
;
449 /* Return if NSS module does not support getpwent_r. */
451 return NSS_STATUS_UNAVAIL
;
453 /* If the setpwent call failed, say so. */
454 if (ent
->setent_status
!= NSS_STATUS_SUCCESS
)
455 return ent
->setent_status
;
457 p2len
= pwd_need_buflen (&ent
->pwd
);
461 return NSS_STATUS_TRYAGAIN
;
463 p2
= buffer
+ (buflen
- p2len
);
471 if ((status
= nss_getpwent_r (result
, buffer
, buflen
, errnop
)) !=
475 while (in_blacklist (result
->pw_name
, strlen (result
->pw_name
), ent
));
477 copy_pwd_changes (result
, &ent
->pwd
, p2
, p2len
);
479 return NSS_STATUS_SUCCESS
;
482 /* This function handle the +user entrys in /etc/passwd */
483 static enum nss_status
484 getpwnam_plususer (const char *name
, struct passwd
*result
, ent_t
*ent
,
485 char *buffer
, size_t buflen
, int *errnop
)
488 return NSS_STATUS_UNAVAIL
;
491 memset (&pwd
, '\0', sizeof (struct passwd
));
493 copy_pwd_changes (&pwd
, result
, NULL
, 0);
495 size_t plen
= pwd_need_buflen (&pwd
);
499 return NSS_STATUS_TRYAGAIN
;
501 char *p
= buffer
+ (buflen
- plen
);
504 enum nss_status status
= nss_getpwnam_r (name
, result
, buffer
, buflen
,
506 if (status
!= NSS_STATUS_SUCCESS
)
509 if (in_blacklist (result
->pw_name
, strlen (result
->pw_name
), ent
))
510 return NSS_STATUS_NOTFOUND
;
512 copy_pwd_changes (result
, &pwd
, p
, plen
);
513 give_pwd_free (&pwd
);
514 /* We found the entry. */
515 return NSS_STATUS_SUCCESS
;
518 static enum nss_status
519 getpwent_next_file (struct passwd
*result
, ent_t
*ent
,
520 char *buffer
, size_t buflen
, int *errnop
)
522 struct parser_data
*data
= (void *) buffer
;
531 /* We need at least 3 characters for one line. */
532 if (__builtin_expect (buflen
< 3, 0))
536 return NSS_STATUS_TRYAGAIN
;
539 fgetpos (ent
->stream
, &pos
);
540 buffer
[buflen
- 1] = '\xff';
541 p
= fgets_unlocked (buffer
, buflen
, ent
->stream
);
542 if (p
== NULL
&& feof_unlocked (ent
->stream
))
543 return NSS_STATUS_NOTFOUND
;
545 if (p
== NULL
|| __builtin_expect (buffer
[buflen
- 1] != '\xff', 0))
548 fsetpos (ent
->stream
, &pos
);
552 /* Terminate the line for any case. */
553 buffer
[buflen
- 1] = '\0';
555 /* Skip leading blanks. */
559 while (*p
== '\0' || *p
== '#' || /* Ignore empty and comment lines. */
560 /* Parse the line. If it is invalid, loop to
561 get the next line of the file to parse. */
562 !(parse_res
= _nss_files_parse_pwent (p
, result
, data
, buflen
,
565 if (__builtin_expect (parse_res
== -1, 0))
566 /* The parser ran out of space. */
569 if (result
->pw_name
[0] != '+' && result
->pw_name
[0] != '-')
570 /* This is a real entry. */
574 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] == '@'
575 && result
->pw_name
[2] != '\0')
577 /* XXX Do not use fixed length buffer. */
579 char *user
, *host
, *domain
;
580 struct __netgrent netgrdata
;
582 bzero (&netgrdata
, sizeof (struct __netgrent
));
583 __internal_setnetgrent (&result
->pw_name
[2], &netgrdata
);
584 while (__internal_getnetgrent_r (&host
, &user
, &domain
, &netgrdata
,
585 buf2
, sizeof (buf2
), errnop
))
587 if (user
!= NULL
&& user
[0] != '-')
588 blacklist_store_name (user
, ent
);
590 __internal_endnetgrent (&netgrdata
);
595 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '@'
596 && result
->pw_name
[2] != '\0')
598 enum nss_status status
;
600 ent
->netgroup
= true;
602 copy_pwd_changes (&ent
->pwd
, result
, NULL
, 0);
604 status
= getpwent_next_nss_netgr (NULL
, result
, ent
,
606 buffer
, buflen
, errnop
);
607 if (status
== NSS_STATUS_RETURN
)
614 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] != '\0'
615 && result
->pw_name
[1] != '@')
617 blacklist_store_name (&result
->pw_name
[1], ent
);
622 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] != '\0'
623 && result
->pw_name
[1] != '@')
625 size_t len
= strlen (result
->pw_name
);
627 enum nss_status status
;
629 /* Store the User in the blacklist for the "+" at the end of
631 memcpy (buf
, &result
->pw_name
[1], len
);
632 status
= getpwnam_plususer (&result
->pw_name
[1], result
, ent
,
633 buffer
, buflen
, errnop
);
634 blacklist_store_name (buf
, ent
);
636 if (status
== NSS_STATUS_SUCCESS
) /* We found the entry. */
638 else if (status
== NSS_STATUS_RETURN
/* We couldn't parse the entry */
639 || status
== NSS_STATUS_NOTFOUND
) /* entry doesn't exist */
643 if (status
== NSS_STATUS_TRYAGAIN
)
645 /* The parser ran out of space */
646 fsetpos (ent
->stream
, &pos
);
654 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '\0')
658 copy_pwd_changes (&ent
->pwd
, result
, NULL
, 0);
660 return getpwent_next_nss (result
, ent
, buffer
, buflen
, errnop
);
664 return NSS_STATUS_SUCCESS
;
668 static enum nss_status
669 internal_getpwent_r (struct passwd
*pw
, ent_t
*ent
, char *buffer
,
670 size_t buflen
, int *errnop
)
674 enum nss_status status
;
676 /* We are searching members in a netgroup */
677 /* Since this is not the first call, we don't need the group name */
678 status
= getpwent_next_nss_netgr (NULL
, pw
, ent
, NULL
, buffer
, buflen
,
680 if (status
== NSS_STATUS_RETURN
)
681 return getpwent_next_file (pw
, ent
, buffer
, buflen
, errnop
);
686 return getpwent_next_file (pw
, ent
, buffer
, buflen
, errnop
);
688 return getpwent_next_nss (pw
, ent
, buffer
, buflen
, errnop
);
693 _nss_compat_getpwent_r (struct passwd
*pwd
, char *buffer
, size_t buflen
,
696 enum nss_status result
= NSS_STATUS_SUCCESS
;
698 __libc_lock_lock (lock
);
700 /* Be prepared that the setpwent function was not called before. */
702 init_nss_interface ();
704 if (ext_ent
.stream
== NULL
)
705 result
= internal_setpwent (&ext_ent
, 1, 1);
707 if (result
== NSS_STATUS_SUCCESS
)
708 result
= internal_getpwent_r (pwd
, &ext_ent
, buffer
, buflen
, errnop
);
710 __libc_lock_unlock (lock
);
715 /* Searches in /etc/passwd and the NIS/NIS+ map for a special user */
716 static enum nss_status
717 internal_getpwnam_r (const char *name
, struct passwd
*result
, ent_t
*ent
,
718 char *buffer
, size_t buflen
, int *errnop
)
720 struct parser_data
*data
= (void *) buffer
;
730 /* We need at least 3 characters for one line. */
731 if (__builtin_expect (buflen
< 3, 0))
735 return NSS_STATUS_TRYAGAIN
;
738 fgetpos (ent
->stream
, &pos
);
739 buffer
[buflen
- 1] = '\xff';
740 p
= fgets_unlocked (buffer
, buflen
, ent
->stream
);
741 if (p
== NULL
&& feof_unlocked (ent
->stream
))
743 return NSS_STATUS_NOTFOUND
;
745 if (p
== NULL
|| __builtin_expect (buffer
[buflen
- 1] != '\xff', 0))
748 fsetpos (ent
->stream
, &pos
);
752 /* Terminate the line for any case. */
753 buffer
[buflen
- 1] = '\0';
755 /* Skip leading blanks. */
759 while (*p
== '\0' || *p
== '#' || /* Ignore empty and comment lines. */
760 /* Parse the line. If it is invalid, loop to
761 get the next line of the file to parse. */
762 !(parse_res
= _nss_files_parse_pwent (p
, result
, data
, buflen
,
765 if (__builtin_expect (parse_res
== -1, 0))
766 /* The parser ran out of space. */
769 /* This is a real entry. */
770 if (result
->pw_name
[0] != '+' && result
->pw_name
[0] != '-')
772 if (strcmp (result
->pw_name
, name
) == 0)
773 return NSS_STATUS_SUCCESS
;
779 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] == '@'
780 && result
->pw_name
[2] != '\0')
782 if (innetgr (&result
->pw_name
[2], NULL
, name
, NULL
))
783 return NSS_STATUS_NOTFOUND
;
788 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '@'
789 && result
->pw_name
[2] != '\0')
791 enum nss_status status
;
793 if (innetgr (&result
->pw_name
[2], NULL
, name
, NULL
))
795 status
= getpwnam_plususer (name
, result
, ent
, buffer
,
798 if (status
== NSS_STATUS_RETURN
)
807 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] != '\0'
808 && result
->pw_name
[1] != '@')
810 if (strcmp (&result
->pw_name
[1], name
) == 0)
811 return NSS_STATUS_NOTFOUND
;
817 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] != '\0'
818 && result
->pw_name
[1] != '@')
820 if (strcmp (name
, &result
->pw_name
[1]) == 0)
822 enum nss_status status
;
824 status
= getpwnam_plususer (name
, result
, ent
, buffer
, buflen
,
826 if (status
== NSS_STATUS_RETURN
)
827 /* We couldn't parse the entry */
828 return NSS_STATUS_NOTFOUND
;
835 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '\0')
837 enum nss_status status
;
839 status
= getpwnam_plususer (name
, result
, ent
,
840 buffer
, buflen
, errnop
);
841 if (status
== NSS_STATUS_SUCCESS
) /* We found the entry. */
843 else if (status
== NSS_STATUS_RETURN
) /* We couldn't parse the entry */
844 return NSS_STATUS_NOTFOUND
;
849 return NSS_STATUS_SUCCESS
;
853 _nss_compat_getpwnam_r (const char *name
, struct passwd
*pwd
,
854 char *buffer
, size_t buflen
, int *errnop
)
856 enum nss_status result
;
857 ent_t ent
= { false, false, true, NSS_STATUS_SUCCESS
, NULL
, { NULL
, 0, 0 },
858 { NULL
, NULL
, 0, 0, NULL
, NULL
, NULL
}};
860 if (name
[0] == '-' || name
[0] == '+')
861 return NSS_STATUS_NOTFOUND
;
863 __libc_lock_lock (lock
);
866 init_nss_interface ();
868 __libc_lock_unlock (lock
);
870 result
= internal_setpwent (&ent
, 0, 0);
872 if (result
== NSS_STATUS_SUCCESS
)
873 result
= internal_getpwnam_r (name
, pwd
, &ent
, buffer
, buflen
, errnop
);
875 internal_endpwent (&ent
);
880 /* This function handle the + entry in /etc/passwd for getpwuid */
881 static enum nss_status
882 getpwuid_plususer (uid_t uid
, struct passwd
*result
, char *buffer
,
883 size_t buflen
, int *errnop
)
890 return NSS_STATUS_UNAVAIL
;
892 memset (&pwd
, '\0', sizeof (struct passwd
));
894 copy_pwd_changes (&pwd
, result
, NULL
, 0);
896 plen
= pwd_need_buflen (&pwd
);
900 return NSS_STATUS_TRYAGAIN
;
902 p
= buffer
+ (buflen
- plen
);
905 if (nss_getpwuid_r (uid
, result
, buffer
, buflen
, errnop
) ==
908 copy_pwd_changes (result
, &pwd
, p
, plen
);
909 give_pwd_free (&pwd
);
910 /* We found the entry. */
911 return NSS_STATUS_SUCCESS
;
915 /* Give buffer the old len back */
917 give_pwd_free (&pwd
);
919 return NSS_STATUS_RETURN
;
922 /* Searches in /etc/passwd and the NSS subsystem for a special user id */
923 static enum nss_status
924 internal_getpwuid_r (uid_t uid
, struct passwd
*result
, ent_t
*ent
,
925 char *buffer
, size_t buflen
, int *errnop
)
927 struct parser_data
*data
= (void *) buffer
;
937 /* We need at least 3 characters for one line. */
938 if (__builtin_expect (buflen
< 3, 0))
942 return NSS_STATUS_TRYAGAIN
;
945 fgetpos (ent
->stream
, &pos
);
946 buffer
[buflen
- 1] = '\xff';
947 p
= fgets_unlocked (buffer
, buflen
, ent
->stream
);
948 if (p
== NULL
&& feof_unlocked (ent
->stream
))
949 return NSS_STATUS_NOTFOUND
;
951 if (p
== NULL
|| __builtin_expect (buffer
[buflen
- 1] != '\xff', 0))
954 fsetpos (ent
->stream
, &pos
);
958 /* Terminate the line for any case. */
959 buffer
[buflen
- 1] = '\0';
961 /* Skip leading blanks. */
965 while (*p
== '\0' || *p
== '#' || /* Ignore empty and comment lines. */
966 /* Parse the line. If it is invalid, loop to
967 get the next line of the file to parse. */
968 !(parse_res
= _nss_files_parse_pwent (p
, result
, data
, buflen
,
971 if (__builtin_expect (parse_res
== -1, 0))
972 /* The parser ran out of space. */
975 /* This is a real entry. */
976 if (result
->pw_name
[0] != '+' && result
->pw_name
[0] != '-')
978 if (result
->pw_uid
== uid
)
979 return NSS_STATUS_SUCCESS
;
985 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] == '@'
986 && result
->pw_name
[2] != '\0')
988 /* -1, because we remove first two character of pw_name. */
989 size_t len
= strlen (result
->pw_name
) - 1;
991 enum nss_status status
;
993 memcpy (buf
, &result
->pw_name
[2], len
);
995 status
= getpwuid_plususer (uid
, result
, buffer
, buflen
, errnop
);
996 if (status
== NSS_STATUS_SUCCESS
&&
997 innetgr (buf
, NULL
, result
->pw_name
, NULL
))
998 return NSS_STATUS_NOTFOUND
;
1004 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '@'
1005 && result
->pw_name
[2] != '\0')
1007 /* -1, because we remove first two characters of pw_name. */
1008 size_t len
= strlen (result
->pw_name
) - 1;
1010 enum nss_status status
;
1012 memcpy (buf
, &result
->pw_name
[2], len
);
1014 status
= getpwuid_plususer (uid
, result
, buffer
, buflen
, errnop
);
1016 if (status
== NSS_STATUS_RETURN
)
1019 if (status
== NSS_STATUS_SUCCESS
)
1021 if (innetgr (buf
, NULL
, result
->pw_name
, NULL
))
1022 return NSS_STATUS_SUCCESS
;
1024 else if (status
== NSS_STATUS_RETURN
) /* We couldn't parse the entry */
1025 return NSS_STATUS_NOTFOUND
;
1033 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] != '\0'
1034 && result
->pw_name
[1] != '@')
1036 size_t len
= strlen (result
->pw_name
);
1038 enum nss_status status
;
1040 memcpy (buf
, &result
->pw_name
[1], len
);
1042 status
= getpwuid_plususer (uid
, result
, buffer
, buflen
, errnop
);
1043 if (status
== NSS_STATUS_SUCCESS
&&
1044 innetgr (buf
, NULL
, result
->pw_name
, NULL
))
1045 return NSS_STATUS_NOTFOUND
;
1050 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] != '\0'
1051 && result
->pw_name
[1] != '@')
1053 size_t len
= strlen (result
->pw_name
);
1055 enum nss_status status
;
1057 memcpy (buf
, &result
->pw_name
[1], len
);
1059 status
= getpwuid_plususer (uid
, result
, buffer
, buflen
, errnop
);
1061 if (status
== NSS_STATUS_RETURN
)
1064 if (status
== NSS_STATUS_SUCCESS
)
1066 if (strcmp (buf
, result
->pw_name
) == 0)
1067 return NSS_STATUS_SUCCESS
;
1069 else if (status
== NSS_STATUS_RETURN
) /* We couldn't parse the entry */
1070 return NSS_STATUS_NOTFOUND
;
1078 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '\0')
1080 enum nss_status status
;
1082 status
= getpwuid_plususer (uid
, result
, buffer
, buflen
, errnop
);
1083 if (status
== NSS_STATUS_SUCCESS
) /* We found the entry. */
1085 else if (status
== NSS_STATUS_RETURN
) /* We couldn't parse the entry */
1086 return NSS_STATUS_NOTFOUND
;
1091 return NSS_STATUS_SUCCESS
;
1095 _nss_compat_getpwuid_r (uid_t uid
, struct passwd
*pwd
,
1096 char *buffer
, size_t buflen
, int *errnop
)
1098 enum nss_status result
;
1099 ent_t ent
= { false, false, true, NSS_STATUS_SUCCESS
, NULL
, { NULL
, 0, 0 },
1100 { NULL
, NULL
, 0, 0, NULL
, NULL
, NULL
}};
1102 __libc_lock_lock (lock
);
1105 init_nss_interface ();
1107 __libc_lock_unlock (lock
);
1109 result
= internal_setpwent (&ent
, 0, 0);
1111 if (result
== NSS_STATUS_SUCCESS
)
1112 result
= internal_getpwuid_r (uid
, pwd
, &ent
, buffer
, buflen
, errnop
);
1114 internal_endpwent (&ent
);
1120 /* Support routines for remembering -@netgroup and -user entries.
1121 The names are stored in a single string with `|' as separator. */
1123 blacklist_store_name (const char *name
, ent_t
*ent
)
1125 int namelen
= strlen (name
);
1128 /* first call, setup cache */
1129 if (ent
->blacklist
.size
== 0)
1131 ent
->blacklist
.size
= MAX (BLACKLIST_INITIAL_SIZE
, 2 * namelen
);
1132 ent
->blacklist
.data
= malloc (ent
->blacklist
.size
);
1133 if (ent
->blacklist
.data
== NULL
)
1135 ent
->blacklist
.data
[0] = '|';
1136 ent
->blacklist
.data
[1] = '\0';
1137 ent
->blacklist
.current
= 1;
1141 if (in_blacklist (name
, namelen
, ent
))
1142 return; /* no duplicates */
1144 if (ent
->blacklist
.current
+ namelen
+ 1 >= ent
->blacklist
.size
)
1146 ent
->blacklist
.size
+= MAX (BLACKLIST_INCREMENT
, 2 * namelen
);
1147 tmp
= realloc (ent
->blacklist
.data
, ent
->blacklist
.size
);
1150 free (ent
->blacklist
.data
);
1151 ent
->blacklist
.size
= 0;
1154 ent
->blacklist
.data
= tmp
;
1158 tmp
= stpcpy (ent
->blacklist
.data
+ ent
->blacklist
.current
, name
);
1161 ent
->blacklist
.current
+= namelen
+ 1;
1166 /* Returns TRUE if ent->blacklist contains name, else FALSE. */
1168 in_blacklist (const char *name
, int namelen
, ent_t
*ent
)
1170 char buf
[namelen
+ 3];
1173 if (ent
->blacklist
.data
== NULL
)
1177 cp
= stpcpy (&buf
[1], name
);
1180 return strstr (ent
->blacklist
.data
, buf
) != NULL
;