1 /* Copyright (C) 1996-1999,2001-2005,2006 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>
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
)
105 if (pwd
->pw_name
!= NULL
)
107 if (pwd
->pw_passwd
!= NULL
)
108 free (pwd
->pw_passwd
);
109 if (pwd
->pw_gecos
!= NULL
)
110 free (pwd
->pw_gecos
);
111 if (pwd
->pw_dir
!= NULL
)
113 if (pwd
->pw_shell
!= NULL
)
114 free (pwd
->pw_shell
);
116 memset (pwd
, '\0', sizeof (struct passwd
));
120 pwd_need_buflen (struct passwd
*pwd
)
124 if (pwd
->pw_passwd
!= NULL
)
125 len
+= strlen (pwd
->pw_passwd
) + 1;
127 if (pwd
->pw_gecos
!= NULL
)
128 len
+= strlen (pwd
->pw_gecos
) + 1;
130 if (pwd
->pw_dir
!= NULL
)
131 len
+= strlen (pwd
->pw_dir
) + 1;
133 if (pwd
->pw_shell
!= NULL
)
134 len
+= strlen (pwd
->pw_shell
) + 1;
140 copy_pwd_changes (struct passwd
*dest
, struct passwd
*src
,
141 char *buffer
, size_t buflen
)
143 if (src
->pw_passwd
!= NULL
&& strlen (src
->pw_passwd
))
146 dest
->pw_passwd
= strdup (src
->pw_passwd
);
147 else if (dest
->pw_passwd
&&
148 strlen (dest
->pw_passwd
) >= strlen (src
->pw_passwd
))
149 strcpy (dest
->pw_passwd
, src
->pw_passwd
);
152 dest
->pw_passwd
= buffer
;
153 strcpy (dest
->pw_passwd
, src
->pw_passwd
);
154 buffer
+= strlen (dest
->pw_passwd
) + 1;
155 buflen
= buflen
- (strlen (dest
->pw_passwd
) + 1);
159 if (src
->pw_gecos
!= NULL
&& strlen (src
->pw_gecos
))
162 dest
->pw_gecos
= strdup (src
->pw_gecos
);
163 else if (dest
->pw_gecos
&&
164 strlen (dest
->pw_gecos
) >= strlen (src
->pw_gecos
))
165 strcpy (dest
->pw_gecos
, src
->pw_gecos
);
168 dest
->pw_gecos
= buffer
;
169 strcpy (dest
->pw_gecos
, src
->pw_gecos
);
170 buffer
+= strlen (dest
->pw_gecos
) + 1;
171 buflen
= buflen
- (strlen (dest
->pw_gecos
) + 1);
174 if (src
->pw_dir
!= NULL
&& strlen (src
->pw_dir
))
177 dest
->pw_dir
= strdup (src
->pw_dir
);
178 else if (dest
->pw_dir
&& strlen (dest
->pw_dir
) >= strlen (src
->pw_dir
))
179 strcpy (dest
->pw_dir
, src
->pw_dir
);
182 dest
->pw_dir
= buffer
;
183 strcpy (dest
->pw_dir
, src
->pw_dir
);
184 buffer
+= strlen (dest
->pw_dir
) + 1;
185 buflen
= buflen
- (strlen (dest
->pw_dir
) + 1);
189 if (src
->pw_shell
!= NULL
&& strlen (src
->pw_shell
))
192 dest
->pw_shell
= strdup (src
->pw_shell
);
193 else if (dest
->pw_shell
&&
194 strlen (dest
->pw_shell
) >= strlen (src
->pw_shell
))
195 strcpy (dest
->pw_shell
, src
->pw_shell
);
198 dest
->pw_shell
= buffer
;
199 strcpy (dest
->pw_shell
, src
->pw_shell
);
200 buffer
+= strlen (dest
->pw_shell
) + 1;
201 buflen
= buflen
- (strlen (dest
->pw_shell
) + 1);
206 static enum nss_status
207 internal_setpwent (ent_t
*ent
, int stayopen
, int needent
)
209 enum nss_status status
= NSS_STATUS_SUCCESS
;
211 ent
->first
= ent
->netgroup
= false;
213 ent
->setent_status
= NSS_STATUS_SUCCESS
;
215 /* If something was left over free it. */
217 __internal_endnetgrent (&ent
->netgrdata
);
219 if (ent
->blacklist
.data
!= NULL
)
221 ent
->blacklist
.current
= 1;
222 ent
->blacklist
.data
[0] = '|';
223 ent
->blacklist
.data
[1] = '\0';
226 ent
->blacklist
.current
= 0;
228 if (ent
->stream
== NULL
)
230 ent
->stream
= fopen ("/etc/passwd", "rm");
232 if (ent
->stream
== NULL
)
233 status
= errno
== EAGAIN
? NSS_STATUS_TRYAGAIN
: NSS_STATUS_UNAVAIL
;
236 /* We have to make sure the file is `closed on exec'. */
239 result
= flags
= fcntl (fileno_unlocked (ent
->stream
), F_GETFD
, 0);
243 result
= fcntl (fileno_unlocked (ent
->stream
), F_SETFD
, flags
);
247 /* Something went wrong. Close the stream and return a
249 fclose (ent
->stream
);
251 status
= NSS_STATUS_UNAVAIL
;
254 /* We take care of locking ourself. */
255 __fsetlocking (ent
->stream
, FSETLOCKING_BYCALLER
);
259 rewind (ent
->stream
);
261 give_pwd_free (&ent
->pwd
);
263 if (needent
&& status
== NSS_STATUS_SUCCESS
&& nss_setpwent
)
264 ent
->setent_status
= nss_setpwent (stayopen
);
271 _nss_compat_setpwent (int stayopen
)
273 enum nss_status result
;
275 __libc_lock_lock (lock
);
278 init_nss_interface ();
280 result
= internal_setpwent (&ext_ent
, stayopen
, 1);
282 __libc_lock_unlock (lock
);
288 static enum nss_status
289 internal_endpwent (ent_t
*ent
)
294 if (ent
->stream
!= NULL
)
296 fclose (ent
->stream
);
301 __internal_endnetgrent (&ent
->netgrdata
);
303 ent
->first
= ent
->netgroup
= false;
305 if (ent
->blacklist
.data
!= NULL
)
307 ent
->blacklist
.current
= 1;
308 ent
->blacklist
.data
[0] = '|';
309 ent
->blacklist
.data
[1] = '\0';
312 ent
->blacklist
.current
= 0;
314 give_pwd_free (&ent
->pwd
);
316 return NSS_STATUS_SUCCESS
;
320 _nss_compat_endpwent (void)
322 enum nss_status result
;
324 __libc_lock_lock (lock
);
326 result
= internal_endpwent (&ext_ent
);
328 __libc_lock_unlock (lock
);
334 static enum nss_status
335 getpwent_next_nss_netgr (const char *name
, struct passwd
*result
, ent_t
*ent
,
336 char *group
, char *buffer
, size_t buflen
,
339 char *curdomain
, *host
, *user
, *domain
, *p2
;
343 /* Leave function if NSS module does not support getpwnam_r,
344 we need this function here. */
346 return NSS_STATUS_UNAVAIL
;
348 if (yp_get_default_domain (&curdomain
) != YPERR_SUCCESS
)
350 ent
->netgroup
= false;
352 give_pwd_free (&ent
->pwd
);
353 return NSS_STATUS_UNAVAIL
;
356 if (ent
->first
== true)
358 memset (&ent
->netgrdata
, 0, sizeof (struct __netgrent
));
359 __internal_setnetgrent (group
, &ent
->netgrdata
);
367 saved_cursor
= ent
->netgrdata
.cursor
;
368 status
= __internal_getnetgrent_r (&host
, &user
, &domain
,
369 &ent
->netgrdata
, buffer
, buflen
,
373 __internal_endnetgrent (&ent
->netgrdata
);
375 give_pwd_free (&ent
->pwd
);
376 return NSS_STATUS_RETURN
;
379 if (user
== NULL
|| user
[0] == '-')
382 if (domain
!= NULL
&& strcmp (curdomain
, domain
) != 0)
385 /* If name != NULL, we are called from getpwnam. */
387 if (strcmp (user
, name
) != 0)
390 p2len
= pwd_need_buflen (&ent
->pwd
);
394 return NSS_STATUS_TRYAGAIN
;
396 p2
= buffer
+ (buflen
- p2len
);
399 if (nss_getpwnam_r (user
, result
, buffer
, buflen
, errnop
) !=
403 if (!in_blacklist (result
->pw_name
, strlen (result
->pw_name
), ent
))
405 /* Store the User in the blacklist for possible the "+" at the
406 end of /etc/passwd */
407 blacklist_store_name (result
->pw_name
, ent
);
408 copy_pwd_changes (result
, &ent
->pwd
, p2
, p2len
);
413 return NSS_STATUS_SUCCESS
;
416 /* get the next user from NSS (+ entry) */
417 static enum nss_status
418 getpwent_next_nss (struct passwd
*result
, ent_t
*ent
, char *buffer
,
419 size_t buflen
, int *errnop
)
421 enum nss_status status
;
425 /* Return if NSS module does not support getpwent_r. */
427 return NSS_STATUS_UNAVAIL
;
429 /* If the setpwent call failed, say so. */
430 if (ent
->setent_status
!= NSS_STATUS_SUCCESS
)
431 return ent
->setent_status
;
433 p2len
= pwd_need_buflen (&ent
->pwd
);
437 return NSS_STATUS_TRYAGAIN
;
439 p2
= buffer
+ (buflen
- p2len
);
447 if ((status
= nss_getpwent_r (result
, buffer
, buflen
, errnop
)) !=
451 while (in_blacklist (result
->pw_name
, strlen (result
->pw_name
), ent
));
453 copy_pwd_changes (result
, &ent
->pwd
, p2
, p2len
);
455 return NSS_STATUS_SUCCESS
;
458 /* This function handle the +user entrys in /etc/passwd */
459 static enum nss_status
460 getpwnam_plususer (const char *name
, struct passwd
*result
, ent_t
*ent
,
461 char *buffer
, size_t buflen
, int *errnop
)
464 return NSS_STATUS_UNAVAIL
;
467 memset (&pwd
, '\0', sizeof (struct passwd
));
469 copy_pwd_changes (&pwd
, result
, NULL
, 0);
471 size_t plen
= pwd_need_buflen (&pwd
);
475 return NSS_STATUS_TRYAGAIN
;
477 char *p
= buffer
+ (buflen
- plen
);
480 enum nss_status status
= nss_getpwnam_r (name
, result
, buffer
, buflen
,
482 if (status
!= NSS_STATUS_SUCCESS
)
485 if (in_blacklist (result
->pw_name
, strlen (result
->pw_name
), ent
))
486 return NSS_STATUS_NOTFOUND
;
488 copy_pwd_changes (result
, &pwd
, p
, plen
);
489 give_pwd_free (&pwd
);
490 /* We found the entry. */
491 return NSS_STATUS_SUCCESS
;
494 static enum nss_status
495 getpwent_next_file (struct passwd
*result
, ent_t
*ent
,
496 char *buffer
, size_t buflen
, int *errnop
)
498 struct parser_data
*data
= (void *) buffer
;
507 /* We need at least 3 characters for one line. */
508 if (__builtin_expect (buflen
< 3, 0))
512 return NSS_STATUS_TRYAGAIN
;
515 fgetpos (ent
->stream
, &pos
);
516 buffer
[buflen
- 1] = '\xff';
517 p
= fgets_unlocked (buffer
, buflen
, ent
->stream
);
518 if (p
== NULL
&& feof_unlocked (ent
->stream
))
519 return NSS_STATUS_NOTFOUND
;
521 if (p
== NULL
|| __builtin_expect (buffer
[buflen
- 1] != '\xff', 0))
524 fsetpos (ent
->stream
, &pos
);
528 /* Terminate the line for any case. */
529 buffer
[buflen
- 1] = '\0';
531 /* Skip leading blanks. */
535 while (*p
== '\0' || *p
== '#' || /* Ignore empty and comment lines. */
536 /* Parse the line. If it is invalid, loop to
537 get the next line of the file to parse. */
538 !(parse_res
= _nss_files_parse_pwent (p
, result
, data
, buflen
,
541 if (__builtin_expect (parse_res
== -1, 0))
542 /* The parser ran out of space. */
545 if (result
->pw_name
[0] != '+' && result
->pw_name
[0] != '-')
546 /* This is a real entry. */
550 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] == '@'
551 && result
->pw_name
[2] != '\0')
553 /* XXX Do not use fixed length buffer. */
555 char *user
, *host
, *domain
;
556 struct __netgrent netgrdata
;
558 bzero (&netgrdata
, sizeof (struct __netgrent
));
559 __internal_setnetgrent (&result
->pw_name
[2], &netgrdata
);
560 while (__internal_getnetgrent_r (&host
, &user
, &domain
, &netgrdata
,
561 buf2
, sizeof (buf2
), errnop
))
563 if (user
!= NULL
&& user
[0] != '-')
564 blacklist_store_name (user
, ent
);
566 __internal_endnetgrent (&netgrdata
);
571 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '@'
572 && result
->pw_name
[2] != '\0')
574 enum nss_status status
;
576 ent
->netgroup
= true;
578 copy_pwd_changes (&ent
->pwd
, result
, NULL
, 0);
580 status
= getpwent_next_nss_netgr (NULL
, result
, ent
,
582 buffer
, buflen
, errnop
);
583 if (status
== NSS_STATUS_RETURN
)
590 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] != '\0'
591 && result
->pw_name
[1] != '@')
593 blacklist_store_name (&result
->pw_name
[1], ent
);
598 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] != '\0'
599 && result
->pw_name
[1] != '@')
601 size_t len
= strlen (result
->pw_name
);
603 enum nss_status status
;
605 /* Store the User in the blacklist for the "+" at the end of
607 memcpy (buf
, &result
->pw_name
[1], len
);
608 status
= getpwnam_plususer (&result
->pw_name
[1], result
, ent
,
609 buffer
, buflen
, errnop
);
610 blacklist_store_name (buf
, ent
);
612 if (status
== NSS_STATUS_SUCCESS
) /* We found the entry. */
614 else if (status
== NSS_STATUS_RETURN
/* We couldn't parse the entry */
615 || status
== NSS_STATUS_NOTFOUND
) /* entry doesn't exist */
619 if (status
== NSS_STATUS_TRYAGAIN
)
621 /* The parser ran out of space */
622 fsetpos (ent
->stream
, &pos
);
630 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '\0')
634 copy_pwd_changes (&ent
->pwd
, result
, NULL
, 0);
636 return getpwent_next_nss (result
, ent
, buffer
, buflen
, errnop
);
640 return NSS_STATUS_SUCCESS
;
644 static enum nss_status
645 internal_getpwent_r (struct passwd
*pw
, ent_t
*ent
, char *buffer
,
646 size_t buflen
, int *errnop
)
650 enum nss_status status
;
652 /* We are searching members in a netgroup */
653 /* Since this is not the first call, we don't need the group name */
654 status
= getpwent_next_nss_netgr (NULL
, pw
, ent
, NULL
, buffer
, buflen
,
656 if (status
== NSS_STATUS_RETURN
)
657 return getpwent_next_file (pw
, ent
, buffer
, buflen
, errnop
);
662 return getpwent_next_file (pw
, ent
, buffer
, buflen
, errnop
);
664 return getpwent_next_nss (pw
, ent
, buffer
, buflen
, errnop
);
669 _nss_compat_getpwent_r (struct passwd
*pwd
, char *buffer
, size_t buflen
,
672 enum nss_status result
= NSS_STATUS_SUCCESS
;
674 __libc_lock_lock (lock
);
676 /* Be prepared that the setpwent function was not called before. */
678 init_nss_interface ();
680 if (ext_ent
.stream
== NULL
)
681 result
= internal_setpwent (&ext_ent
, 1, 1);
683 if (result
== NSS_STATUS_SUCCESS
)
684 result
= internal_getpwent_r (pwd
, &ext_ent
, buffer
, buflen
, errnop
);
686 __libc_lock_unlock (lock
);
691 /* Searches in /etc/passwd and the NIS/NIS+ map for a special user */
692 static enum nss_status
693 internal_getpwnam_r (const char *name
, struct passwd
*result
, ent_t
*ent
,
694 char *buffer
, size_t buflen
, int *errnop
)
696 struct parser_data
*data
= (void *) buffer
;
706 /* We need at least 3 characters for one line. */
707 if (__builtin_expect (buflen
< 3, 0))
711 return NSS_STATUS_TRYAGAIN
;
714 fgetpos (ent
->stream
, &pos
);
715 buffer
[buflen
- 1] = '\xff';
716 p
= fgets_unlocked (buffer
, buflen
, ent
->stream
);
717 if (p
== NULL
&& feof_unlocked (ent
->stream
))
719 return NSS_STATUS_NOTFOUND
;
721 if (p
== NULL
|| __builtin_expect (buffer
[buflen
- 1] != '\xff', 0))
724 fsetpos (ent
->stream
, &pos
);
728 /* Terminate the line for any case. */
729 buffer
[buflen
- 1] = '\0';
731 /* Skip leading blanks. */
735 while (*p
== '\0' || *p
== '#' || /* Ignore empty and comment lines. */
736 /* Parse the line. If it is invalid, loop to
737 get the next line of the file to parse. */
738 !(parse_res
= _nss_files_parse_pwent (p
, result
, data
, buflen
,
741 if (__builtin_expect (parse_res
== -1, 0))
742 /* The parser ran out of space. */
745 /* This is a real entry. */
746 if (result
->pw_name
[0] != '+' && result
->pw_name
[0] != '-')
748 if (strcmp (result
->pw_name
, name
) == 0)
749 return NSS_STATUS_SUCCESS
;
755 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] == '@'
756 && result
->pw_name
[2] != '\0')
758 if (innetgr (&result
->pw_name
[2], NULL
, name
, NULL
))
759 return NSS_STATUS_NOTFOUND
;
764 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '@'
765 && result
->pw_name
[2] != '\0')
767 enum nss_status status
;
769 if (innetgr (&result
->pw_name
[2], NULL
, name
, NULL
))
771 status
= getpwnam_plususer (name
, result
, ent
, buffer
,
774 if (status
== NSS_STATUS_RETURN
)
783 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] != '\0'
784 && result
->pw_name
[1] != '@')
786 if (strcmp (&result
->pw_name
[1], name
) == 0)
787 return NSS_STATUS_NOTFOUND
;
793 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] != '\0'
794 && result
->pw_name
[1] != '@')
796 if (strcmp (name
, &result
->pw_name
[1]) == 0)
798 enum nss_status status
;
800 status
= getpwnam_plususer (name
, result
, ent
, buffer
, buflen
,
802 if (status
== NSS_STATUS_RETURN
)
803 /* We couldn't parse the entry */
804 return NSS_STATUS_NOTFOUND
;
811 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '\0')
813 enum nss_status status
;
815 status
= getpwnam_plususer (name
, result
, ent
,
816 buffer
, buflen
, errnop
);
817 if (status
== NSS_STATUS_SUCCESS
) /* We found the entry. */
819 else if (status
== NSS_STATUS_RETURN
) /* We couldn't parse the entry */
820 return NSS_STATUS_NOTFOUND
;
825 return NSS_STATUS_SUCCESS
;
829 _nss_compat_getpwnam_r (const char *name
, struct passwd
*pwd
,
830 char *buffer
, size_t buflen
, int *errnop
)
832 enum nss_status result
;
833 ent_t ent
= { false, false, true, NSS_STATUS_SUCCESS
, NULL
, { NULL
, 0, 0 },
834 { NULL
, NULL
, 0, 0, NULL
, NULL
, NULL
}};
836 if (name
[0] == '-' || name
[0] == '+')
837 return NSS_STATUS_NOTFOUND
;
839 __libc_lock_lock (lock
);
842 init_nss_interface ();
844 __libc_lock_unlock (lock
);
846 result
= internal_setpwent (&ent
, 0, 0);
848 if (result
== NSS_STATUS_SUCCESS
)
849 result
= internal_getpwnam_r (name
, pwd
, &ent
, buffer
, buflen
, errnop
);
851 internal_endpwent (&ent
);
856 /* This function handle the + entry in /etc/passwd for getpwuid */
857 static enum nss_status
858 getpwuid_plususer (uid_t uid
, struct passwd
*result
, char *buffer
,
859 size_t buflen
, int *errnop
)
866 return NSS_STATUS_UNAVAIL
;
868 memset (&pwd
, '\0', sizeof (struct passwd
));
870 copy_pwd_changes (&pwd
, result
, NULL
, 0);
872 plen
= pwd_need_buflen (&pwd
);
876 return NSS_STATUS_TRYAGAIN
;
878 p
= buffer
+ (buflen
- plen
);
881 if (nss_getpwuid_r (uid
, result
, buffer
, buflen
, errnop
) ==
884 copy_pwd_changes (result
, &pwd
, p
, plen
);
885 give_pwd_free (&pwd
);
886 /* We found the entry. */
887 return NSS_STATUS_SUCCESS
;
891 /* Give buffer the old len back */
893 give_pwd_free (&pwd
);
895 return NSS_STATUS_RETURN
;
898 /* Searches in /etc/passwd and the NSS subsystem for a special user id */
899 static enum nss_status
900 internal_getpwuid_r (uid_t uid
, struct passwd
*result
, ent_t
*ent
,
901 char *buffer
, size_t buflen
, int *errnop
)
903 struct parser_data
*data
= (void *) buffer
;
913 /* We need at least 3 characters for one line. */
914 if (__builtin_expect (buflen
< 3, 0))
918 return NSS_STATUS_TRYAGAIN
;
921 fgetpos (ent
->stream
, &pos
);
922 buffer
[buflen
- 1] = '\xff';
923 p
= fgets_unlocked (buffer
, buflen
, ent
->stream
);
924 if (p
== NULL
&& feof_unlocked (ent
->stream
))
925 return NSS_STATUS_NOTFOUND
;
927 if (p
== NULL
|| __builtin_expect (buffer
[buflen
- 1] != '\xff', 0))
930 fsetpos (ent
->stream
, &pos
);
934 /* Terminate the line for any case. */
935 buffer
[buflen
- 1] = '\0';
937 /* Skip leading blanks. */
941 while (*p
== '\0' || *p
== '#' || /* Ignore empty and comment lines. */
942 /* Parse the line. If it is invalid, loop to
943 get the next line of the file to parse. */
944 !(parse_res
= _nss_files_parse_pwent (p
, result
, data
, buflen
,
947 if (__builtin_expect (parse_res
== -1, 0))
948 /* The parser ran out of space. */
951 /* This is a real entry. */
952 if (result
->pw_name
[0] != '+' && result
->pw_name
[0] != '-')
954 if (result
->pw_uid
== uid
)
955 return NSS_STATUS_SUCCESS
;
961 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] == '@'
962 && result
->pw_name
[2] != '\0')
964 /* -1, because we remove first two character of pw_name. */
965 size_t len
= strlen (result
->pw_name
) - 1;
967 enum nss_status status
;
969 memcpy (buf
, &result
->pw_name
[2], len
);
971 status
= getpwuid_plususer (uid
, result
, buffer
, buflen
, errnop
);
972 if (status
== NSS_STATUS_SUCCESS
&&
973 innetgr (buf
, NULL
, result
->pw_name
, NULL
))
974 return NSS_STATUS_NOTFOUND
;
980 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '@'
981 && result
->pw_name
[2] != '\0')
983 /* -1, because we remove first two characters of pw_name. */
984 size_t len
= strlen (result
->pw_name
) - 1;
986 enum nss_status status
;
988 memcpy (buf
, &result
->pw_name
[2], len
);
990 status
= getpwuid_plususer (uid
, result
, buffer
, buflen
, errnop
);
992 if (status
== NSS_STATUS_RETURN
)
995 if (status
== NSS_STATUS_SUCCESS
)
997 if (innetgr (buf
, NULL
, result
->pw_name
, NULL
))
998 return NSS_STATUS_SUCCESS
;
1000 else if (status
== NSS_STATUS_RETURN
) /* We couldn't parse the entry */
1001 return NSS_STATUS_NOTFOUND
;
1009 if (result
->pw_name
[0] == '-' && result
->pw_name
[1] != '\0'
1010 && result
->pw_name
[1] != '@')
1012 size_t len
= strlen (result
->pw_name
);
1014 enum nss_status status
;
1016 memcpy (buf
, &result
->pw_name
[1], len
);
1018 status
= getpwuid_plususer (uid
, result
, buffer
, buflen
, errnop
);
1019 if (status
== NSS_STATUS_SUCCESS
&&
1020 innetgr (buf
, NULL
, result
->pw_name
, NULL
))
1021 return NSS_STATUS_NOTFOUND
;
1026 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] != '\0'
1027 && result
->pw_name
[1] != '@')
1029 size_t len
= strlen (result
->pw_name
);
1031 enum nss_status status
;
1033 memcpy (buf
, &result
->pw_name
[1], len
);
1035 status
= getpwuid_plususer (uid
, result
, buffer
, buflen
, errnop
);
1037 if (status
== NSS_STATUS_RETURN
)
1040 if (status
== NSS_STATUS_SUCCESS
)
1042 if (strcmp (buf
, result
->pw_name
) == 0)
1043 return NSS_STATUS_SUCCESS
;
1045 else if (status
== NSS_STATUS_RETURN
) /* We couldn't parse the entry */
1046 return NSS_STATUS_NOTFOUND
;
1054 if (result
->pw_name
[0] == '+' && result
->pw_name
[1] == '\0')
1056 enum nss_status status
;
1058 status
= getpwuid_plususer (uid
, result
, buffer
, buflen
, errnop
);
1059 if (status
== NSS_STATUS_SUCCESS
) /* We found the entry. */
1061 else if (status
== NSS_STATUS_RETURN
) /* We couldn't parse the entry */
1062 return NSS_STATUS_NOTFOUND
;
1067 return NSS_STATUS_SUCCESS
;
1071 _nss_compat_getpwuid_r (uid_t uid
, struct passwd
*pwd
,
1072 char *buffer
, size_t buflen
, int *errnop
)
1074 enum nss_status result
;
1075 ent_t ent
= { false, false, true, NSS_STATUS_SUCCESS
, NULL
, { NULL
, 0, 0 },
1076 { NULL
, NULL
, 0, 0, NULL
, NULL
, NULL
}};
1078 __libc_lock_lock (lock
);
1081 init_nss_interface ();
1083 __libc_lock_unlock (lock
);
1085 result
= internal_setpwent (&ent
, 0, 0);
1087 if (result
== NSS_STATUS_SUCCESS
)
1088 result
= internal_getpwuid_r (uid
, pwd
, &ent
, buffer
, buflen
, errnop
);
1090 internal_endpwent (&ent
);
1096 /* Support routines for remembering -@netgroup and -user entries.
1097 The names are stored in a single string with `|' as separator. */
1099 blacklist_store_name (const char *name
, ent_t
*ent
)
1101 int namelen
= strlen (name
);
1104 /* first call, setup cache */
1105 if (ent
->blacklist
.size
== 0)
1107 ent
->blacklist
.size
= MAX (BLACKLIST_INITIAL_SIZE
, 2 * namelen
);
1108 ent
->blacklist
.data
= malloc (ent
->blacklist
.size
);
1109 if (ent
->blacklist
.data
== NULL
)
1111 ent
->blacklist
.data
[0] = '|';
1112 ent
->blacklist
.data
[1] = '\0';
1113 ent
->blacklist
.current
= 1;
1117 if (in_blacklist (name
, namelen
, ent
))
1118 return; /* no duplicates */
1120 if (ent
->blacklist
.current
+ namelen
+ 1 >= ent
->blacklist
.size
)
1122 ent
->blacklist
.size
+= MAX (BLACKLIST_INCREMENT
, 2 * namelen
);
1123 tmp
= realloc (ent
->blacklist
.data
, ent
->blacklist
.size
);
1126 free (ent
->blacklist
.data
);
1127 ent
->blacklist
.size
= 0;
1130 ent
->blacklist
.data
= tmp
;
1134 tmp
= stpcpy (ent
->blacklist
.data
+ ent
->blacklist
.current
, name
);
1137 ent
->blacklist
.current
+= namelen
+ 1;
1142 /* Returns TRUE if ent->blacklist contains name, else FALSE. */
1144 in_blacklist (const char *name
, int namelen
, ent_t
*ent
)
1146 char buf
[namelen
+ 3];
1149 if (ent
->blacklist
.data
== NULL
)
1153 cp
= stpcpy (&buf
[1], name
);
1156 return strstr (ent
->blacklist
.data
, buf
) != NULL
;