1 /* Copyright (C) 1996, 1997, 1998, 1999 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 Library General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 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 Library General Public License for more details.
15 You should have received a copy of the GNU Library General Public
16 License along with the GNU C Library; see the file COPYING.LIB. If not,
17 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA. */
27 #include <bits/libc-lock.h>
28 #include <rpcsvc/yp.h>
29 #include <rpcsvc/ypclnt.h>
30 #include <rpcsvc/nis.h>
34 #include "nss-nisplus.h"
35 #include "nisplus-parser.h"
37 static service_user
*ni
= NULL
;
38 static bool_t use_nisplus
= FALSE
; /* default: passwd_compat: nis */
39 static nis_name pwdtable
= NULL
; /* Name of the password table */
40 static size_t pwdtablelen
= 0;
42 /* Get the declaration of the parser function. */
44 #define STRUCTURE spwd
46 #include <nss/nss_files/files-parse.c>
48 /* Structure for remembering -@netgroup and -user members ... */
49 #define BLACKLIST_INITIAL_SIZE 512
50 #define BLACKLIST_INCREMENT 256
67 struct blacklist_t blacklist
;
69 struct __netgrent netgrdata
;
71 typedef struct ent_t ent_t
;
73 static ent_t ext_ent
= {0, 0, 0, NULL
, 0, NULL
, NULL
, {NULL
, 0, 0},
74 {NULL
, NULL
, 0, 0, 0, 0, 0, 0, 0}};
76 /* Protect global state against multiple changers. */
77 __libc_lock_define_initialized (static, lock
)
79 /* Prototypes for local functions. */
80 static void blacklist_store_name (const char *, ent_t
*);
81 static int in_blacklist (const char *, int, ent_t
*);
84 give_spwd_free (struct spwd
*pwd
)
86 if (pwd
->sp_namp
!= NULL
)
88 if (pwd
->sp_pwdp
!= NULL
)
91 memset (pwd
, '\0', sizeof (struct spwd
));
99 spwd_need_buflen (struct spwd
*pwd
)
103 if (pwd
->sp_pwdp
!= NULL
)
104 len
+= strlen (pwd
->sp_pwdp
) + 1;
110 copy_spwd_changes (struct spwd
*dest
, struct spwd
*src
,
111 char *buffer
, size_t buflen
)
113 if (src
->sp_pwdp
!= NULL
&& strlen (src
->sp_pwdp
))
116 dest
->sp_pwdp
= strdup (src
->sp_pwdp
);
117 else if (dest
->sp_pwdp
&&
118 strlen (dest
->sp_pwdp
) >= strlen (src
->sp_pwdp
))
119 strcpy (dest
->sp_pwdp
, src
->sp_pwdp
);
122 dest
->sp_pwdp
= buffer
;
123 strcpy (dest
->sp_pwdp
, src
->sp_pwdp
);
124 buffer
+= strlen (dest
->sp_pwdp
) + 1;
125 buflen
= buflen
- (strlen (dest
->sp_pwdp
) + 1);
128 if (src
->sp_lstchg
!= 0)
129 dest
->sp_lstchg
= src
->sp_lstchg
;
130 if (src
->sp_min
!= 0)
131 dest
->sp_min
= src
->sp_min
;
132 if (src
->sp_max
!= 0)
133 dest
->sp_max
= src
->sp_max
;
134 if (src
->sp_warn
!= -1)
135 dest
->sp_warn
= src
->sp_warn
;
136 if (src
->sp_inact
!= -1)
137 dest
->sp_inact
= src
->sp_inact
;
138 if (src
->sp_expire
!= -1)
139 dest
->sp_expire
= src
->sp_expire
;
140 if (src
->sp_flag
!= ~0ul)
141 dest
->sp_flag
= src
->sp_flag
;
144 static enum nss_status
145 internal_setspent (ent_t
*ent
)
147 enum nss_status status
= NSS_STATUS_SUCCESS
;
149 ent
->nis
= ent
->first
= ent
->netgroup
= 0;
151 /* If something was left over free it. */
153 __internal_endnetgrent (&ent
->netgrdata
);
155 if (ent
->oldkey
!= NULL
)
162 if (ent
->result
!= NULL
)
164 nis_freeresult (ent
->result
);
168 if (pwdtable
== NULL
)
170 static const char key
[] = "passwd.org_dir.";
171 const char *local_dir
= nis_local_directory ();
172 size_t len_local_dir
= strlen (local_dir
);
174 pwdtable
= malloc (sizeof (key
) + len_local_dir
);
175 if (pwdtable
== NULL
)
176 return NSS_STATUS_TRYAGAIN
;
178 pwdtablelen
= ((char *) mempcpy (mempcpy (pwdtable
,
179 key
, sizeof (key
) - 1),
180 local_dir
, len_local_dir
+ 1)
184 if (ent
->blacklist
.data
!= NULL
)
186 ent
->blacklist
.current
= 1;
187 ent
->blacklist
.data
[0] = '|';
188 ent
->blacklist
.data
[1] = '\0';
191 ent
->blacklist
.current
= 0;
193 if (ent
->stream
== NULL
)
195 ent
->stream
= fopen ("/etc/shadow", "r");
197 if (ent
->stream
== NULL
)
198 status
= errno
== EAGAIN
? NSS_STATUS_TRYAGAIN
: NSS_STATUS_UNAVAIL
;
201 /* We have to make sure the file is `closed on exec'. */
204 result
= flags
= fcntl (fileno (ent
->stream
), F_GETFD
, 0);
208 result
= fcntl (fileno (ent
->stream
), F_SETFD
, flags
);
212 /* Something went wrong. Close the stream and return a
214 fclose (ent
->stream
);
216 status
= NSS_STATUS_UNAVAIL
;
221 rewind (ent
->stream
);
223 give_spwd_free (&ent
->pwd
);
230 _nss_compat_setspent (void)
232 enum nss_status result
;
234 __libc_lock_lock (lock
);
238 __nss_database_lookup ("shadow_compat", "passwd_compat", "nis", &ni
);
239 use_nisplus
= (strcmp (ni
->name
, "nisplus") == 0);
242 result
= internal_setspent (&ext_ent
);
244 __libc_lock_unlock (lock
);
250 static enum nss_status
251 internal_endspent (ent_t
*ent
)
253 if (ent
->stream
!= NULL
)
255 fclose (ent
->stream
);
260 __internal_endnetgrent (&ent
->netgrdata
);
262 ent
->nis
= ent
->first
= ent
->netgroup
= 0;
264 if (ent
->oldkey
!= NULL
)
271 if (ent
->result
!= NULL
)
273 nis_freeresult (ent
->result
);
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_spwd_free (&ent
->pwd
);
288 return NSS_STATUS_SUCCESS
;
292 _nss_compat_endspent (void)
294 enum nss_status result
;
296 __libc_lock_lock (lock
);
298 result
= internal_endspent (&ext_ent
);
300 __libc_lock_unlock (lock
);
306 static enum nss_status
307 getspent_next_nis_netgr (const char *name
, struct spwd
*result
, ent_t
*ent
,
308 char *group
, char *buffer
, size_t buflen
, int *errnop
)
310 struct parser_data
*data
= (void *) buffer
;
311 char *ypdomain
, *host
, *user
, *domain
, *outval
, *p
, *p2
;
312 int status
, outvallen
;
315 if (yp_get_default_domain (&ypdomain
) != YPERR_SUCCESS
)
319 give_spwd_free (&ent
->pwd
);
320 return NSS_STATUS_UNAVAIL
;
323 if (ent
->first
== TRUE
)
325 bzero (&ent
->netgrdata
, sizeof (struct __netgrent
));
326 __internal_setnetgrent (group
, &ent
->netgrdata
);
335 saved_cursor
= ent
->netgrdata
.cursor
;
336 status
= __internal_getnetgrent_r (&host
, &user
, &domain
,
337 &ent
->netgrdata
, buffer
, buflen
,
341 __internal_endnetgrent (&ent
->netgrdata
);
343 give_spwd_free (&ent
->pwd
);
344 return NSS_STATUS_RETURN
;
347 if (user
== NULL
|| user
[0] == '-')
350 if (domain
!= NULL
&& strcmp (ypdomain
, domain
) != 0)
353 /* If name != NULL, we are called from getpwnam */
355 if (strcmp (user
, name
) != 0)
358 if (yp_match (ypdomain
, "shadow.byname", user
,
359 strlen (user
), &outval
, &outvallen
)
363 p2len
= spwd_need_buflen (&ent
->pwd
);
368 return NSS_STATUS_TRYAGAIN
;
370 p2
= buffer
+ (buflen
- p2len
);
372 if (buflen
< ((size_t) outval
+ 1))
376 return NSS_STATUS_TRYAGAIN
;
378 p
= strncpy (buffer
, outval
, buflen
);
382 parse_res
= _nss_files_parse_spent (p
, result
, data
, buflen
, errnop
);
385 ent
->netgrdata
.cursor
= saved_cursor
;
386 return NSS_STATUS_TRYAGAIN
;
391 /* Store the User in the blacklist for the "+" at the end of
393 blacklist_store_name (result
->sp_namp
, ent
);
394 copy_spwd_changes (result
, &ent
->pwd
, p2
, p2len
);
399 return NSS_STATUS_SUCCESS
;
402 static enum nss_status
403 getspent_next_nisplus_netgr (const char *name
, struct spwd
*result
,
404 ent_t
*ent
, char *group
, char *buffer
,
405 size_t buflen
, int *errnop
)
407 char *ypdomain
, *host
, *user
, *domain
, *p2
;
408 int status
, parse_res
;
412 /* Maybe we should use domainname here ? We need the current
413 domainname for the domain field in netgroups */
414 if (yp_get_default_domain (&ypdomain
) != YPERR_SUCCESS
)
418 give_spwd_free (&ent
->pwd
);
419 return NSS_STATUS_UNAVAIL
;
422 if (ent
->first
== TRUE
)
424 bzero (&ent
->netgrdata
, sizeof (struct __netgrent
));
425 __internal_setnetgrent (group
, &ent
->netgrdata
);
433 saved_cursor
= ent
->netgrdata
.cursor
;
434 status
= __internal_getnetgrent_r (&host
, &user
, &domain
,
435 &ent
->netgrdata
, buffer
, buflen
,
439 __internal_endnetgrent (&ent
->netgrdata
);
441 give_spwd_free (&ent
->pwd
);
442 return NSS_STATUS_RETURN
;
445 if (user
== NULL
|| user
[0] == '-')
448 if (domain
!= NULL
&& strcmp (ypdomain
, domain
) != 0)
451 /* If name != NULL, we are called from getpwnam */
453 if (strcmp (user
, name
) != 0)
456 p2len
= spwd_need_buflen (&ent
->pwd
);
460 return NSS_STATUS_TRYAGAIN
;
462 p2
= buffer
+ (buflen
- p2len
);
465 char buf
[strlen (user
) + 30 + pwdtablelen
];
466 sprintf (buf
, "[name=%s],%s", user
, pwdtable
);
467 nisres
= nis_list (buf
, FOLLOW_LINKS
| FOLLOW_PATH
, NULL
, NULL
);
469 if (niserr2nss (nisres
->status
) != NSS_STATUS_SUCCESS
)
471 nis_freeresult (nisres
);
474 parse_res
= _nss_nisplus_parse_spent (nisres
, result
, buffer
,
478 nis_freeresult (nisres
);
480 return NSS_STATUS_TRYAGAIN
;
482 nis_freeresult (nisres
);
486 /* Store the User in the blacklist for the "+" at the end of
488 blacklist_store_name (result
->sp_namp
, ent
);
489 copy_spwd_changes (result
, &ent
->pwd
, p2
, p2len
);
494 return NSS_STATUS_SUCCESS
;
497 static enum nss_status
498 getspent_next_nisplus (struct spwd
*result
, ent_t
*ent
, char *buffer
,
499 size_t buflen
, int *errnop
)
505 p2len
= spwd_need_buflen (&ent
->pwd
);
509 return NSS_STATUS_TRYAGAIN
;
511 p2
= buffer
+ (buflen
- p2len
);
516 nis_result
*saved_res
;
521 saved_res
= ent
->result
;
523 ent
->result
= nis_first_entry (pwdtable
);
524 if (niserr2nss (ent
->result
->status
) != NSS_STATUS_SUCCESS
)
527 give_spwd_free (&ent
->pwd
);
528 return niserr2nss (ent
->result
->status
);
537 saved_res
= ent
->result
;
539 res
= nis_next_entry (pwdtable
, &ent
->result
->cookie
);
541 if (niserr2nss (ent
->result
->status
) != NSS_STATUS_SUCCESS
)
543 nis_freeresult (saved_res
);
545 give_spwd_free (&ent
->pwd
);
546 return niserr2nss (ent
->result
->status
);
549 parse_res
= _nss_nisplus_parse_spent (ent
->result
, result
, buffer
,
553 ent
->first
= saved_first
;
554 nis_freeresult (ent
->result
);
555 ent
->result
= saved_res
;
557 return NSS_STATUS_TRYAGAIN
;
562 nis_freeresult (saved_res
);
565 in_blacklist (result
->sp_namp
, strlen (result
->sp_namp
), ent
))
566 parse_res
= 0; /* if result->pw_name in blacklist,search next entry */
570 copy_spwd_changes (result
, &ent
->pwd
, p2
, p2len
);
572 return NSS_STATUS_SUCCESS
;
576 static enum nss_status
577 getspent_next_nis (struct spwd
*result
, ent_t
*ent
,
578 char *buffer
, size_t buflen
, int *errnop
)
580 struct parser_data
*data
= (void *) buffer
;
581 char *domain
, *outkey
, *outval
, *p
, *p2
;
582 int outkeylen
, outvallen
, parse_res
;
585 if (yp_get_default_domain (&domain
) != YPERR_SUCCESS
)
588 give_spwd_free (&ent
->pwd
);
589 return NSS_STATUS_UNAVAIL
;
592 p2len
= spwd_need_buflen (&ent
->pwd
);
596 return NSS_STATUS_TRYAGAIN
;
598 p2
= buffer
+ (buflen
- p2len
);
608 if (yp_first (domain
, "shadow.byname", &outkey
, &outkeylen
,
609 &outval
, &outvallen
) != YPERR_SUCCESS
)
612 give_spwd_free (&ent
->pwd
);
613 return NSS_STATUS_UNAVAIL
;
616 if (buflen
< ((size_t) outvallen
+ 1))
620 return NSS_STATUS_TRYAGAIN
;
624 saved_oldkey
= ent
->oldkey
;
625 saved_oldlen
= ent
->oldkeylen
;
626 ent
->oldkey
= outkey
;
627 ent
->oldkeylen
= outkeylen
;
632 if (yp_next (domain
, "shadow.byname", ent
->oldkey
, ent
->oldkeylen
,
633 &outkey
, &outkeylen
, &outval
, &outvallen
)
637 give_spwd_free (&ent
->pwd
);
639 return NSS_STATUS_NOTFOUND
;
642 if (buflen
< ((size_t) outvallen
+ 1))
646 return NSS_STATUS_TRYAGAIN
;
650 saved_oldkey
= ent
->oldkey
;
651 saved_oldlen
= ent
->oldkeylen
;
652 ent
->oldkey
= outkey
;
653 ent
->oldkeylen
= outkeylen
;
656 /* Copy the found data to our buffer */
657 p
= strncpy (buffer
, outval
, buflen
);
659 /* ...and free the data. */
664 parse_res
= _nss_files_parse_spent (p
, result
, data
, buflen
, errnop
);
668 ent
->oldkey
= saved_oldkey
;
669 ent
->oldkeylen
= saved_oldlen
;
670 ent
->first
= saved_first
;
672 return NSS_STATUS_TRYAGAIN
;
680 in_blacklist (result
->sp_namp
, strlen (result
->sp_namp
), ent
))
685 copy_spwd_changes (result
, &ent
->pwd
, p2
, p2len
);
687 return NSS_STATUS_SUCCESS
;
690 /* This function handle the +user entrys in /etc/shadow */
691 static enum nss_status
692 getspnam_plususer (const char *name
, struct spwd
*result
, char *buffer
,
693 size_t buflen
, int *errnop
)
695 struct parser_data
*data
= (void *) buffer
;
701 memset (&pwd
, '\0', sizeof (struct spwd
));
707 copy_spwd_changes (&pwd
, result
, NULL
, 0);
709 plen
= spwd_need_buflen (&pwd
);
713 return NSS_STATUS_TRYAGAIN
;
715 p
= buffer
+ (buflen
- plen
);
718 if (use_nisplus
) /* Do the NIS+ query here */
721 char buf
[strlen (name
) + 24 + pwdtablelen
];
723 sprintf(buf
, "[name=%s],%s", name
, pwdtable
);
724 res
= nis_list(buf
, 0, NULL
, NULL
);
725 if (niserr2nss (res
->status
) != NSS_STATUS_SUCCESS
)
727 enum nss_status status
= niserr2nss (res
->status
);
729 nis_freeresult (res
);
732 parse_res
= _nss_nisplus_parse_spent (res
, result
, buffer
,
736 nis_freeresult (res
);
738 return NSS_STATUS_TRYAGAIN
;
740 nis_freeresult (res
);
744 char *domain
, *outval
, *ptr
;
747 if (yp_get_default_domain (&domain
) != YPERR_SUCCESS
)
750 return NSS_STATUS_NOTFOUND
;
752 if (yp_match (domain
, "shadow.byname", name
, strlen (name
),
753 &outval
, &outvallen
) != YPERR_SUCCESS
)
756 return NSS_STATUS_NOTFOUND
;
758 if (buflen
< ((size_t) outvallen
+ 1))
762 return NSS_STATUS_TRYAGAIN
;
765 ptr
= strncpy (buffer
, outval
, buflen
);
767 while (isspace (*ptr
))
769 parse_res
= _nss_files_parse_spent (ptr
, result
, data
, buflen
, errnop
);
771 return NSS_STATUS_TRYAGAIN
;
776 copy_spwd_changes (result
, &pwd
, p
, plen
);
777 give_spwd_free (&pwd
);
778 /* We found the entry. */
779 return NSS_STATUS_SUCCESS
;
783 /* Give buffer the old len back */
785 give_spwd_free (&pwd
);
787 return NSS_STATUS_RETURN
;
790 static enum nss_status
791 getspent_next_file (struct spwd
*result
, ent_t
*ent
,
792 char *buffer
, size_t buflen
, int *errnop
)
794 struct parser_data
*data
= (void *) buffer
;
803 fgetpos (ent
->stream
, &pos
);
804 buffer
[buflen
- 1] = '\xff';
805 p
= fgets (buffer
, buflen
, ent
->stream
);
806 if (p
== NULL
&& feof (ent
->stream
))
809 return NSS_STATUS_NOTFOUND
;
811 if (p
== NULL
|| buffer
[buflen
- 1] != '\xff')
813 fsetpos (ent
->stream
, &pos
);
815 return NSS_STATUS_TRYAGAIN
;
818 /* Skip leading blanks. */
822 while (*p
== '\0' || *p
== '#' /* Ignore empty and comment lines. */
823 /* Parse the line. If it is invalid, loop to
824 get the next line of the file to parse. */
825 || !(parse_res
= _nss_files_parse_spent (p
, result
, data
,
830 /* The parser ran out of space. */
831 fsetpos (ent
->stream
, &pos
);
833 return NSS_STATUS_TRYAGAIN
;
836 if (result
->sp_namp
[0] != '+' && result
->sp_namp
[0] != '-')
837 /* This is a real entry. */
841 if (result
->sp_namp
[0] == '-' && result
->sp_namp
[1] == '@'
842 && result
->sp_namp
[2] != '\0')
844 /* XXX Do not use fixed length buffers. */
846 char *user
, *host
, *domain
;
847 struct __netgrent netgrdata
;
849 bzero (&netgrdata
, sizeof (struct __netgrent
));
850 __internal_setnetgrent (&result
->sp_namp
[2], &netgrdata
);
851 while (__internal_getnetgrent_r (&host
, &user
, &domain
,
852 &netgrdata
, buf2
, sizeof (buf2
),
855 if (user
!= NULL
&& user
[0] != '-')
856 blacklist_store_name (user
, ent
);
858 __internal_endnetgrent (&netgrdata
);
863 if (result
->sp_namp
[0] == '+' && result
->sp_namp
[1] == '@'
864 && result
->sp_namp
[2] != '\0')
868 ent
->netgroup
= TRUE
;
870 copy_spwd_changes (&ent
->pwd
, result
, NULL
, 0);
873 status
= getspent_next_nisplus_netgr (NULL
, result
, ent
,
875 buffer
, buflen
, errnop
);
877 status
= getspent_next_nis_netgr (NULL
, result
, ent
,
879 buffer
, buflen
, errnop
);
880 if (status
== NSS_STATUS_RETURN
)
887 if (result
->sp_namp
[0] == '-' && result
->sp_namp
[1] != '\0'
888 && result
->sp_namp
[1] != '@')
890 blacklist_store_name (&result
->sp_namp
[1], ent
);
895 if (result
->sp_namp
[0] == '+' && result
->sp_namp
[1] != '\0'
896 && result
->sp_namp
[1] != '@')
898 enum nss_status status
;
900 /* Store the User in the blacklist for the "+" at the end of
902 blacklist_store_name (&result
->sp_namp
[1], ent
);
903 status
= getspnam_plususer (&result
->sp_namp
[1], result
, buffer
,
905 if (status
== NSS_STATUS_SUCCESS
) /* We found the entry. */
908 if (status
== NSS_STATUS_RETURN
/* We couldn't parse the entry */
909 || status
== NSS_STATUS_NOTFOUND
) /* entry doesn't exist */
913 if (status
== NSS_STATUS_TRYAGAIN
)
915 fsetpos (ent
->stream
, &pos
);
923 if (result
->sp_namp
[0] == '+' && result
->sp_namp
[1] == '\0')
927 copy_spwd_changes (&ent
->pwd
, result
, NULL
, 0);
930 return getspent_next_nisplus (result
, ent
, buffer
, buflen
, errnop
);
932 return getspent_next_nis (result
, ent
, buffer
, buflen
, errnop
);
936 return NSS_STATUS_SUCCESS
;
940 static enum nss_status
941 internal_getspent_r (struct spwd
*pw
, ent_t
*ent
,
942 char *buffer
, size_t buflen
, int *errnop
)
948 /* We are searching members in a netgroup */
949 /* Since this is not the first call, we don't need the group name */
951 status
= getspent_next_nisplus_netgr (NULL
, pw
, ent
, NULL
, buffer
,
954 status
= getspent_next_nis_netgr (NULL
, pw
, ent
, NULL
, buffer
, buflen
,
956 if (status
== NSS_STATUS_RETURN
)
957 return getspent_next_file (pw
, ent
, buffer
, buflen
, errnop
);
965 return getspent_next_nisplus (pw
, ent
, buffer
, buflen
, errnop
);
967 return getspent_next_nis (pw
, ent
, buffer
, buflen
, errnop
);
970 return getspent_next_file (pw
, ent
, buffer
, buflen
, errnop
);
974 _nss_compat_getspent_r (struct spwd
*pwd
, char *buffer
, size_t buflen
,
977 enum nss_status status
= NSS_STATUS_SUCCESS
;
979 __libc_lock_lock (lock
);
983 __nss_database_lookup ("shadow_compat", "passwd_compat", "nis", &ni
);
984 use_nisplus
= (strcmp (ni
->name
, "nisplus") == 0);
987 /* Be prepared that the setspent function was not called before. */
988 if (ext_ent
.stream
== NULL
)
989 status
= internal_setspent (&ext_ent
);
991 if (status
== NSS_STATUS_SUCCESS
)
992 status
= internal_getspent_r (pwd
, &ext_ent
, buffer
, buflen
, errnop
);
994 __libc_lock_unlock (lock
);
999 /* Searches in /etc/passwd and the NIS/NIS+ map for a special user */
1000 static enum nss_status
1001 internal_getspnam_r (const char *name
, struct spwd
*result
, ent_t
*ent
,
1002 char *buffer
, size_t buflen
, int *errnop
)
1004 struct parser_data
*data
= (void *) buffer
;
1014 fgetpos (ent
->stream
, &pos
);
1015 buffer
[buflen
- 1] = '\xff';
1016 p
= fgets (buffer
, buflen
, ent
->stream
);
1017 if (p
== NULL
&& feof (ent
->stream
))
1020 return NSS_STATUS_NOTFOUND
;
1022 if (p
== NULL
|| buffer
[buflen
- 1] != '\xff')
1024 fsetpos (ent
->stream
, &pos
);
1026 return NSS_STATUS_TRYAGAIN
;
1029 /* Skip leading blanks. */
1030 while (isspace (*p
))
1033 while (*p
== '\0' || *p
== '#' || /* Ignore empty and comment lines. */
1034 /* Parse the line. If it is invalid, loop to
1035 get the next line of the file to parse. */
1036 !(parse_res
= _nss_files_parse_spent (p
, result
, data
, buflen
,
1039 if (parse_res
== -1)
1041 /* The parser ran out of space. */
1042 fsetpos (ent
->stream
, &pos
);
1044 return NSS_STATUS_TRYAGAIN
;
1047 /* This is a real entry. */
1048 if (result
->sp_namp
[0] != '+' && result
->sp_namp
[0] != '-')
1050 if (strcmp (result
->sp_namp
, name
) == 0)
1051 return NSS_STATUS_SUCCESS
;
1057 if (result
->sp_namp
[0] == '-' && result
->sp_namp
[1] == '@'
1058 && result
->sp_namp
[2] != '\0')
1060 /* XXX Do not use fixed length buffers. */
1062 char *user
, *host
, *domain
;
1063 struct __netgrent netgrdata
;
1065 bzero (&netgrdata
, sizeof (struct __netgrent
));
1066 __internal_setnetgrent (&result
->sp_namp
[2], &netgrdata
);
1067 while (__internal_getnetgrent_r (&host
, &user
, &domain
, &netgrdata
,
1068 buf2
, sizeof (buf2
), errnop
))
1070 if (user
!= NULL
&& user
[0] != '-')
1071 if (strcmp (user
, name
) == 0)
1074 return NSS_STATUS_NOTFOUND
;
1077 __internal_endnetgrent (&netgrdata
);
1082 if (result
->sp_namp
[0] == '+' && result
->sp_namp
[1] == '@'
1083 && result
->sp_namp
[2] != '\0')
1085 char *buf
= strdupa (&result
->sp_namp
[2]);
1088 ent
->netgroup
= TRUE
;
1090 copy_spwd_changes (&ent
->pwd
, result
, NULL
, 0);
1095 status
= getspent_next_nisplus_netgr (name
, result
, ent
, buf
,
1096 buffer
, buflen
, errnop
);
1098 status
= getspent_next_nis_netgr (name
, result
, ent
, buf
,
1099 buffer
, buflen
, errnop
);
1100 if (status
== NSS_STATUS_RETURN
)
1103 if (status
== NSS_STATUS_SUCCESS
1104 && strcmp (result
->sp_namp
, name
) == 0)
1105 return NSS_STATUS_SUCCESS
;
1106 } while (status
== NSS_STATUS_SUCCESS
);
1111 if (result
->sp_namp
[0] == '-' && result
->sp_namp
[1] != '\0'
1112 && result
->sp_namp
[1] != '@')
1114 if (strcmp (&result
->sp_namp
[1], name
) == 0)
1115 return NSS_STATUS_NOTFOUND
;
1121 if (result
->sp_namp
[0] == '+' && result
->sp_namp
[1] != '\0'
1122 && result
->sp_namp
[1] != '@')
1124 if (strcmp (name
, &result
->sp_namp
[1]) == 0)
1126 enum nss_status status
;
1128 status
= getspnam_plususer (name
, result
, buffer
, buflen
,
1130 if (status
== NSS_STATUS_RETURN
)
1131 /* We couldn't parse the entry */
1132 return NSS_STATUS_NOTFOUND
;
1139 if (result
->sp_namp
[0] == '+' && result
->sp_namp
[1] == '\0')
1141 enum nss_status status
;
1143 status
= getspnam_plususer (name
, result
, buffer
, buflen
, errnop
);
1144 if (status
== NSS_STATUS_RETURN
) /* We couldn't parse the entry */
1145 return NSS_STATUS_NOTFOUND
;
1150 return NSS_STATUS_SUCCESS
;
1154 _nss_compat_getspnam_r (const char *name
, struct spwd
*pwd
,
1155 char *buffer
, size_t buflen
, int *errnop
)
1157 ent_t ent
= {0, 0, 0, NULL
, 0, NULL
, NULL
, {NULL
, 0, 0},
1158 {NULL
, NULL
, 0, 0, 0, 0, 0, 0, 0}};
1159 enum nss_status status
;
1161 if (name
[0] == '-' || name
[0] == '+')
1162 return NSS_STATUS_NOTFOUND
;
1166 __nss_database_lookup ("shadow_compat", "passwd_compat", "nis", &ni
);
1167 use_nisplus
= (strcmp (ni
->name
, "nisplus") == 0);
1170 status
= internal_setspent (&ent
);
1171 if (status
!= NSS_STATUS_SUCCESS
)
1174 status
= internal_getspnam_r (name
, pwd
, &ent
, buffer
, buflen
, errnop
);
1176 internal_endspent (&ent
);
1181 /* Support routines for remembering -@netgroup and -user entries.
1182 The names are stored in a single string with `|' as separator. */
1184 blacklist_store_name (const char *name
, ent_t
*ent
)
1186 int namelen
= strlen (name
);
1189 /* first call, setup cache */
1190 if (ent
->blacklist
.size
== 0)
1192 ent
->blacklist
.size
= MAX (BLACKLIST_INITIAL_SIZE
, 2 * namelen
);
1193 ent
->blacklist
.data
= malloc (ent
->blacklist
.size
);
1194 if (ent
->blacklist
.data
== NULL
)
1196 ent
->blacklist
.data
[0] = '|';
1197 ent
->blacklist
.data
[1] = '\0';
1198 ent
->blacklist
.current
= 1;
1202 if (in_blacklist (name
, namelen
, ent
))
1203 return; /* no duplicates */
1205 if (ent
->blacklist
.current
+ namelen
+ 1 >= ent
->blacklist
.size
)
1207 ent
->blacklist
.size
+= MAX (BLACKLIST_INCREMENT
, 2 * namelen
);
1208 tmp
= realloc (ent
->blacklist
.data
, ent
->blacklist
.size
);
1211 free (ent
->blacklist
.data
);
1212 ent
->blacklist
.size
= 0;
1215 ent
->blacklist
.data
= tmp
;
1219 tmp
= stpcpy (ent
->blacklist
.data
+ ent
->blacklist
.current
, name
);
1222 ent
->blacklist
.current
+= namelen
+ 1;
1227 /* Returns TRUE if ent->blacklist contains name, else FALSE. */
1229 in_blacklist (const char *name
, int namelen
, ent_t
*ent
)
1231 char buf
[namelen
+ 3];
1234 if (ent
->blacklist
.data
== NULL
)
1238 cp
= stpcpy (&buf
[1], name
);
1241 return strstr (ent
->blacklist
.data
, buf
) != NULL
;