diff options
Diffstat (limited to 'lib/libc/gen')
-rw-r--r-- | lib/libc/gen/Makefile.inc | 2 | ||||
-rw-r--r-- | lib/libc/gen/getgrent.3 | 36 | ||||
-rw-r--r-- | lib/libc/gen/getgrent.c | 903 | ||||
-rw-r--r-- | lib/libc/gen/getpwent.3 | 32 | ||||
-rw-r--r-- | lib/libc/gen/getpwent.c | 1665 | ||||
-rw-r--r-- | lib/libc/gen/getusershell.3 | 26 | ||||
-rw-r--r-- | lib/libc/gen/getusershell.c | 249 | ||||
-rw-r--r-- | lib/libc/gen/pw_scan.c | 56 | ||||
-rw-r--r-- | lib/libc/gen/pw_scan.h | 5 |
9 files changed, 1790 insertions, 1184 deletions
diff --git a/lib/libc/gen/Makefile.inc b/lib/libc/gen/Makefile.inc index 9d5452a986032..c63edcd7d4c66 100644 --- a/lib/libc/gen/Makefile.inc +++ b/lib/libc/gen/Makefile.inc @@ -19,7 +19,7 @@ SRCS+= _rand48.c _spinlock_stub.c alarm.c arc4random.c assert.c \ lockf.c lrand48.c mrand48.c msgctl.c \ msgget.c msgrcv.c msgsnd.c nice.c \ nlist.c nrand48.c ntp_gettime.c opendir.c \ - pause.c popen.c psignal.c pwcache.c raise.c readdir.c rewinddir.c \ + pause.c popen.c psignal.c pw_scan.c pwcache.c raise.c readdir.c rewinddir.c \ posixshm.c \ scandir.c seed48.c seekdir.c semconfig.c semctl.c semget.c semop.c \ setdomainname.c sethostname.c setjmperr.c setmode.c setproctitle.c \ diff --git a/lib/libc/gen/getgrent.3 b/lib/libc/gen/getgrent.3 index bb3f56064bafd..d070d8cd31953 100644 --- a/lib/libc/gen/getgrent.3 +++ b/lib/libc/gen/getgrent.3 @@ -125,25 +125,6 @@ The .Fn endgrent function closes any open files. -.Sh YP/NIS INTERACTION -When the -.Xr yp 4 -group database is enabled, the -.Fn getgrnam -and -.Fn getgrgid -functions use the YP maps -.Dq Li group.byname -and -.Dq Li group.bygid , -respectively, if the requested group is not found in the local -.Pa /etc/group -file. The -.Fn getgrent -function will step through the YP map -.Dq Li group.byname -if the entire map is enabled as described in -.Xr group 5 . .Sh RETURN VALUES The functions .Fn getgrent , @@ -171,7 +152,8 @@ group database file .Sh SEE ALSO .Xr getpwent 3 , .Xr yp 4 , -.Xr group 5 +.Xr group 5 , +.Xr nsswitch.conf 5 .Sh HISTORY The functions .Fn endgrent , @@ -206,3 +188,17 @@ a pointer to that object. Subsequent calls to the same function will modify the same object. +.Pp +The functions +.Fn getgrent , +.Fn endgrent , +.Fn setgroupent , +and +.Fn setgrent +are fairly useless in a networked environment and should be +avoided, if possible. +.Fn getgrent +makes no attempt to suppress duplicate information if multiple +sources are specified in +.Xr nsswitch.conf 5 . + diff --git a/lib/libc/gen/getgrent.c b/lib/libc/gen/getgrent.c index 5b5c9dac1f83e..1f988644fdf26 100644 --- a/lib/libc/gen/getgrent.c +++ b/lib/libc/gen/getgrent.c @@ -1,6 +1,9 @@ +/* $NetBSD: getgrent.c,v 1.34.2.1 1999/04/27 14:10:58 perry Exp $ */ + /* * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. + * Portions Copyright (c) 1994, Jason Downs. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -31,76 +34,95 @@ * SUCH DAMAGE. */ +#include <sys/cdefs.h> #if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)getgrent.c 8.2 (Berkeley) 3/21/94"; +static char rcsid[] = + "$FreeBSD$"; #endif /* LIBC_SCCS and not lint */ #include <sys/types.h> + +#include <errno.h> +#include <grp.h> +#include <limits.h> +#include <nsswitch.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <grp.h> +#include <syslog.h> -static FILE *_gr_fp; -static struct group _gr_group; -static int _gr_stayopen; -static int grscan(), start_gr(); +#ifdef HESIOD +#include <hesiod.h> +#include <arpa/nameser.h> +#endif #ifdef YP #include <rpc/rpc.h> #include <rpcsvc/yp_prot.h> #include <rpcsvc/ypclnt.h> -static int _gr_stepping_yp; -static int _gr_yp_enabled; -static int _getypgroup(struct group *, const char *, char *); -static int _nextypgroup(struct group *); #endif +#if defined(YP) || defined(HESIOD) +#define _GROUP_COMPAT +#endif + +static FILE *_gr_fp; +static struct group _gr_group; +static int _gr_stayopen; +static int _gr_filesdone; + +static void grcleanup __P((void)); +static int grscan __P((int, gid_t, const char *)); +static char *getline __P((void)); +static int copyline __P((const char*)); +static int matchline __P((int, gid_t, const char *)); +static int start_gr __P((void)); + + + + /* initial size for malloc and increase steps for realloc */ #define MAXGRP 64 #define MAXLINELENGTH 256 -static char **members; /* list of group members */ -static int maxgrp; /* current length of **mebers */ -static char *line; /* temp buffer for group line */ -static int maxlinelength; /* current length of *line */ +#ifdef HESIOD +#if MAXLINELENGTH < NS_MAXLABEL + 1 +#error "MAXLINELENGTH must be at least NS_MAXLABEL + 1" +#endif +#endif -/* - * Lines longer than MAXLINELENGTHLIMIT will be count as an error. +static char **members; /* list of group members */ +static int maxgrp; /* current length of **members */ +static char *line; /* buffer for group line */ +static int maxlinelength; /* current length of *line */ + +/* + * Lines longer than MAXLINELENGTHLIMIT will be counted as an error. * <= 0 disable check for maximum line length * 256K is enough for 64,000 uids */ #define MAXLINELENGTHLIMIT (256 * 1024) -#define GROUP_IGNORE_COMMENTS 1 /* allow comments in /etc/group */ - -struct group * -getgrent() -{ - if (!_gr_fp && !start_gr()) { - return NULL; - } #ifdef YP - if (_gr_stepping_yp) { - if (_nextypgroup(&_gr_group)) - return(&_gr_group); - } -tryagain: +static char *__ypcurrent, *__ypdomain; +static int __ypcurrentlen; +static int _gr_ypdone; #endif - if (!grscan(0, 0, NULL)) - return(NULL); -#ifdef YP - if(_gr_group.gr_name[0] == '+' && _gr_group.gr_name[1]) { - _getypgroup(&_gr_group, &_gr_group.gr_name[1], - "group.byname"); - } else if(_gr_group.gr_name[0] == '+') { - if (!_nextypgroup(&_gr_group)) - goto tryagain; - else - return(&_gr_group); - } +#ifdef HESIOD +static int _gr_hesnum; +#endif + +#ifdef _GROUP_COMPAT +enum _grmode { GRMODE_NONE, GRMODE_FULL, GRMODE_NAME }; +static enum _grmode __grmode; #endif - return(&_gr_group); + +struct group * +getgrent() +{ + if ((!_gr_fp && !start_gr()) || !grscan(0, 0, NULL)) + return (NULL); + return &_gr_group; } struct group * @@ -110,106 +132,71 @@ getgrnam(name) int rval; if (!start_gr()) - return(NULL); -#ifdef YP - tryagain: -#endif + return NULL; rval = grscan(1, 0, name); -#ifdef YP - if(rval == -1 && (_gr_yp_enabled < 0 || (_gr_yp_enabled && - _gr_group.gr_name[0] == '+'))) { - if (!(rval = _getypgroup(&_gr_group, name, "group.byname"))) - goto tryagain; - } -#endif if (!_gr_stayopen) endgrent(); - return(rval ? &_gr_group : NULL); + return (rval) ? &_gr_group : NULL; } struct group * -#ifdef __STDC__ -getgrgid(gid_t gid) -#else getgrgid(gid) gid_t gid; -#endif { int rval; if (!start_gr()) - return(NULL); -#ifdef YP - tryagain: -#endif + return NULL; rval = grscan(1, gid, NULL); -#ifdef YP - if(rval == -1 && _gr_yp_enabled) { - char buf[16]; - snprintf(buf, sizeof buf, "%d", (unsigned)gid); - if (!(rval = _getypgroup(&_gr_group, buf, "group.bygid"))) - goto tryagain; - } -#endif if (!_gr_stayopen) endgrent(); - return(rval ? &_gr_group : NULL); + return (rval) ? &_gr_group : NULL; } -static int -start_gr() +void +grcleanup() { - if (_gr_fp) { - rewind(_gr_fp); - return(1); - } - _gr_fp = fopen(_PATH_GROUP, "r"); - if(!_gr_fp) return 0; + _gr_filesdone = 0; #ifdef YP - /* - * This is a disgusting hack, used to determine when YP is enabled. - * This would be easier if we had a group database to go along with - * the password database. - */ - { - char *line; - size_t linelen; - _gr_yp_enabled = 0; - while((line = fgetln(_gr_fp, &linelen)) != NULL) { - if(line[0] == '+') { - if(line[1] && line[1] != ':' && !_gr_yp_enabled) { - _gr_yp_enabled = 1; - } else { - _gr_yp_enabled = -1; - break; - } - } - } - rewind(_gr_fp); - } + if (__ypcurrent) + free(__ypcurrent); + __ypcurrent = NULL; + _gr_ypdone = 0; +#endif +#ifdef HESIOD + _gr_hesnum = 0; +#endif +#ifdef _GROUP_COMPAT + __grmode = GRMODE_NONE; #endif +} +static int +start_gr() +{ + grcleanup(); if (maxlinelength == 0) { - if ((line = (char *)malloc(sizeof(char) * - MAXLINELENGTH)) == NULL) - return(0); - maxlinelength += MAXLINELENGTH; + if ((line = (char *)malloc(MAXLINELENGTH)) == NULL) + return 0; + maxlinelength = MAXLINELENGTH; } - if (maxgrp == 0) { - if ((members = (char **)malloc(sizeof(char **) * + if ((members = (char **) malloc(sizeof(char**) * MAXGRP)) == NULL) - return(0); - maxgrp += MAXGRP; + return 0; + maxgrp = MAXGRP; } - - return 1; + if (_gr_fp) { + rewind(_gr_fp); + return 1; + } + return (_gr_fp = fopen(_PATH_GROUP, "r")) ? 1 : 0; } int -setgrent() +setgrent(void) { - return(setgroupent(0)); + return setgroupent(0); } int @@ -217,337 +204,503 @@ setgroupent(stayopen) int stayopen; { if (!start_gr()) - return(0); + return 0; _gr_stayopen = stayopen; -#ifdef YP - _gr_stepping_yp = 0; -#endif - return(1); + return 1; } void endgrent() { -#ifdef YP - _gr_stepping_yp = 0; -#endif + grcleanup(); if (_gr_fp) { (void)fclose(_gr_fp); _gr_fp = NULL; } } + +static int _local_grscan __P((void *, void *, va_list)); + +/*ARGSUSED*/ static int -grscan(search, gid, name) - register int search, gid; - register char *name; +_local_grscan(rv, cb_data, ap) + void *rv; + void *cb_data; + va_list ap; { - register char *cp, **m; - char *bp; - + int search = va_arg(ap, int); + gid_t gid = va_arg(ap, gid_t); + const char *name = va_arg(ap, const char *); -#ifdef YP - int _ypfound; -#endif + if (_gr_filesdone) + return NS_NOTFOUND; for (;;) { -#ifdef YP - _ypfound = 0; -#endif - if (fgets(line, maxlinelength, _gr_fp) == NULL) - return(0); - - if (!index(line, '\n')) { - do { - if (feof(_gr_fp)) - return(0); - - /* don't allocate infinite memory */ - if (MAXLINELENGTHLIMIT > 0 && - maxlinelength >= MAXLINELENGTHLIMIT) - return(0); - - if ((line = (char *)reallocf(line, - sizeof(char) * - (maxlinelength + MAXLINELENGTH))) == NULL) - return(0); - - if (fgets(line + maxlinelength - 1, - MAXLINELENGTH + 1, _gr_fp) == NULL) - return(0); - - maxlinelength += MAXLINELENGTH; - } while (!index(line + maxlinelength - - MAXLINELENGTH - 1, '\n')); + if (getline() == NULL) { + if (!search) + _gr_filesdone = 1; + return NS_NOTFOUND; } + if (matchline(search, gid, name)) + return NS_SUCCESS; + } + /* NOTREACHED */ +} -#ifdef GROUP_IGNORE_COMMENTS - /* - * Ignore comments: ^[ \t]*# - */ - for (cp = line; *cp != '\0'; cp++) - if (*cp != ' ' && *cp != '\t') - break; - if (*cp == '#' || *cp == '\0') - continue; -#endif +#ifdef HESIOD +static int _dns_grscan __P((void *, void *, va_list)); - bp = line; +/*ARGSUSED*/ +static int +_dns_grscan(rv, cb_data, ap) + void *rv; + void *cb_data; + va_list ap; +{ + int search = va_arg(ap, int); + gid_t gid = va_arg(ap, gid_t); + const char *name = va_arg(ap, const char *); - if ((_gr_group.gr_name = strsep(&bp, ":\n")) == NULL) - break; -#ifdef YP - /* - * XXX We need to be careful to avoid proceeding - * past this point under certain circumstances or - * we risk dereferencing null pointers down below. - */ - if (_gr_group.gr_name[0] == '+') { - if (strlen(_gr_group.gr_name) == 1) { - switch(search) { - case 0: - return(1); - case 1: - return(-1); - default: - return(0); - } - } else { - cp = &_gr_group.gr_name[1]; - if (search && name != NULL) - if (strcmp(cp, name)) - continue; - if (!_getypgroup(&_gr_group, cp, - "group.byname")) - continue; - if (search && name == NULL) - if (gid != _gr_group.gr_gid) - continue; - /* We're going to override -- tell the world. */ - _ypfound++; - } + char **hp; + void *context; + int r; + size_t sz; + + r = NS_UNAVAIL; + if (!search && _gr_hesnum == -1) + return NS_NOTFOUND; + if (hesiod_init(&context) == -1) + return (r); + + for (;;) { + if (search) { + if (name) + strlcpy(line, name, maxlinelength); + else + snprintf(line, maxlinelength, "%u", + (unsigned int)gid); + } else { + snprintf(line, maxlinelength, "group-%u", _gr_hesnum); + _gr_hesnum++; } -#else - if (_gr_group.gr_name[0] == '+') - continue; -#endif /* YP */ - if (search && name) { - if(strcmp(_gr_group.gr_name, name)) { - continue; + + hp = hesiod_resolve(context, line, "group"); + if (hp == NULL) { + if (errno == ENOENT) { + if (!search) + _gr_hesnum = -1; + r = NS_NOTFOUND; } + break; } -#ifdef YP - if ((cp = strsep(&bp, ":\n")) == NULL) - if (_ypfound) - return(1); - else - break; - if (strlen(cp) || !_ypfound) - _gr_group.gr_passwd = cp; -#else - if ((_gr_group.gr_passwd = strsep(&bp, ":\n")) == NULL) + + /* only check first elem */ + if (copyline(hp[0]) == 0) + return NS_UNAVAIL; + hesiod_free_list(context, hp); + if (matchline(search, gid, name)) { + r = NS_SUCCESS; break; -#endif - if (!(cp = strsep(&bp, ":\n"))) -#ifdef YP - if (_ypfound) - return(1); - else -#endif - continue; -#ifdef YP - /* - * Hurm. Should we be doing this? We allow UIDs to - * be overridden -- what about GIDs? - */ - if (!_ypfound) -#endif - _gr_group.gr_gid = atoi(cp); - if (search && name == NULL && _gr_group.gr_gid != gid) - continue; - cp = NULL; - if (bp == NULL) /* !!! Must check for this! */ + } else if (search) { + r = NS_NOTFOUND; break; + } + } + hesiod_end(context); + return (r); +} +#endif + #ifdef YP - if ((cp = strsep(&bp, ":\n")) == NULL) +static int _nis_grscan __P((void *, void *, va_list)); + +/*ARGSUSED*/ +static int +_nis_grscan(rv, cb_data, ap) + void *rv; + void *cb_data; + va_list ap; +{ + int search = va_arg(ap, int); + gid_t gid = va_arg(ap, gid_t); + const char *name = va_arg(ap, const char *); + + char *key, *data; + int keylen, datalen; + int r; + size_t sz; + + if(__ypdomain == NULL) { + switch (yp_get_default_domain(&__ypdomain)) { + case 0: break; + case YPERR_RESRC: + return NS_TRYAGAIN; + default: + return NS_UNAVAIL; + } + } - if (!strlen(cp) && _ypfound) - return(1); + if (search) { /* specific group or gid */ + if (name) + strlcpy(line, name, maxlinelength); else - members[0] = NULL; - bp = cp; - cp = NULL; -#endif - for (m = members; ; bp++) { - if (m == (members + maxgrp - 1)) { - if ((members = (char **) - reallocf(members, - sizeof(char **) * - (maxgrp + MAXGRP))) == NULL) - return(0); - m = members + maxgrp - 1; - maxgrp += MAXGRP; - } - if (*bp == ',') { - if (cp) { - *bp = '\0'; - *m++ = cp; - cp = NULL; - } - } else if (*bp == '\0' || *bp == '\n' || *bp == ' ') { - if (cp) { - *bp = '\0'; - *m++ = cp; - } + snprintf(line, maxlinelength, "%u", (unsigned int)gid); + data = NULL; + r = yp_match(__ypdomain, + (name) ? "group.byname" : "group.bygid", + line, (int)strlen(line), &data, &datalen); + switch (r) { + case 0: + break; + case YPERR_KEY: + if (data) + free(data); + return NS_NOTFOUND; + default: + if (data) + free(data); + return NS_UNAVAIL; + } + data[datalen] = '\0'; /* clear trailing \n */ + if (copyline(data) == 0) + return NS_UNAVAIL; + free(data); + if (matchline(search, gid, name)) + return NS_SUCCESS; + else + return NS_NOTFOUND; + } + + /* ! search */ + if (_gr_ypdone) + return NS_NOTFOUND; + for (;;) { + data = NULL; + if(__ypcurrent) { + key = NULL; + r = yp_next(__ypdomain, "group.byname", + __ypcurrent, __ypcurrentlen, + &key, &keylen, &data, &datalen); + free(__ypcurrent); + switch (r) { + case 0: break; - } else if (cp == NULL) - cp = bp; - + case YPERR_NOMORE: + __ypcurrent = NULL; + if (key) + free(key); + if (data) + free(data); + _gr_ypdone = 1; + return NS_NOTFOUND; + default: + if (key) + free(key); + if (data) + free(data); + return NS_UNAVAIL; + } + __ypcurrent = key; + __ypcurrentlen = keylen; + } else { + if (yp_first(__ypdomain, "group.byname", + &__ypcurrent, &__ypcurrentlen, + &data, &datalen)) { + if (data); + free(data); + return NS_UNAVAIL; + } } - _gr_group.gr_mem = members; - *m = NULL; - return(1); + data[datalen] = '\0'; /* clear trailing \n */ + if (copyline(data) == 0) + return NS_UNAVAIL; + free(data); + if (matchline(search, gid, name)) + return NS_SUCCESS; } /* NOTREACHED */ - return (0); } +#endif -#ifdef YP +#ifdef _GROUP_COMPAT +/* + * log an error if "files" or "compat" is specified in group_compat database + */ +static int _bad_grscan __P((void *, void *, va_list)); +/*ARGSUSED*/ static int -_gr_breakout_yp(struct group *gr, char *result) +_bad_grscan(rv, cb_data, ap) + void *rv; + void *cb_data; + va_list ap; { - char *s, *cp; - char **m; + static int warned; - /* - * XXX If 's' ends up being a NULL pointer, punt on this group. - * It means the NIS group entry is badly formatted and should - * be skipped. - */ - if ((s = strsep(&result, ":")) == NULL) return 0; /* name */ - gr->gr_name = s; + if (!warned) { + syslog(LOG_ERR, + "nsswitch.conf group_compat database can't use '%s'", + (char *)cb_data); + } + warned = 1; + return NS_UNAVAIL; +} - if ((s = strsep(&result, ":")) == NULL) return 0; /* password */ - gr->gr_passwd = s; +/* + * when a name lookup in compat mode is required, look it up in group_compat + * nsswitch database. only Hesiod and NIS is supported - it doesn't make + * sense to lookup compat names from 'files' or 'compat' + */ - if ((s = strsep(&result, ":")) == NULL) return 0; /* gid */ - gr->gr_gid = atoi(s); +static int __grscancompat __P((int, gid_t, const char *)); + +static int +__grscancompat(search, gid, name) + int search; + gid_t gid; + const char *name; +{ + static const ns_dtab dtab[] = { + NS_FILES_CB(_bad_grscan, "files") + NS_DNS_CB(_dns_grscan, NULL) + NS_NIS_CB(_nis_grscan, NULL) + NS_COMPAT_CB(_bad_grscan, "compat") + { 0 } + }; + static const ns_src defaultnis[] = { + { NSSRC_NIS, NS_SUCCESS }, + { 0 } + }; + + return (nsdispatch(NULL, dtab, NSDB_GROUP_COMPAT, "grscancompat", + defaultnis, search, gid, name)); +} +#endif - if ((s = result) == NULL) return 0; - cp = 0; - for (m = members; ; s++) { - if (m == members + maxgrp - 1) { - if ((members = (char **)reallocf(members, - sizeof(char **) * (maxgrp + MAXGRP))) == NULL) - return(0); - m = members + maxgrp - 1; +static int _compat_grscan __P((void *, void *, va_list)); + +/*ARGSUSED*/ +static int +_compat_grscan(rv, cb_data, ap) + void *rv; + void *cb_data; + va_list ap; +{ + int search = va_arg(ap, int); + gid_t gid = va_arg(ap, gid_t); + const char *name = va_arg(ap, const char *); + +#ifdef _GROUP_COMPAT + static char *grname = NULL; +#endif + + for (;;) { +#ifdef _GROUP_COMPAT + if(__grmode != GRMODE_NONE) { + int r; + + switch(__grmode) { + case GRMODE_FULL: + r = __grscancompat(search, gid, name); + if (r == NS_SUCCESS) + return r; + __grmode = GRMODE_NONE; + break; + case GRMODE_NAME: + if(grname == (char *)NULL) { + __grmode = GRMODE_NONE; + break; + } + r = __grscancompat(1, 0, grname); + free(grname); + grname = (char *)NULL; + if (r != NS_SUCCESS) + break; + if (!search) + return NS_SUCCESS; + if (name) { + if (! strcmp(_gr_group.gr_name, name)) + return NS_SUCCESS; + } else { + if (_gr_group.gr_gid == gid) + return NS_SUCCESS; + } + break; + case GRMODE_NONE: + abort(); + } + continue; + } +#endif /* _GROUP_COMPAT */ + + if (getline() == NULL) + return NS_NOTFOUND; + +#ifdef _GROUP_COMPAT + if (line[0] == '+') { + char *tptr, *bp; + + switch(line[1]) { + case ':': + case '\0': + case '\n': + __grmode = GRMODE_FULL; + break; + default: + __grmode = GRMODE_NAME; + bp = line; + tptr = strsep(&bp, ":\n"); + grname = strdup(tptr + 1); + break; + } + continue; + } +#endif /* _GROUP_COMPAT */ + if (matchline(search, gid, name)) + return NS_SUCCESS; + } + /* NOTREACHED */ +} + +static int +grscan(search, gid, name) + int search; + gid_t gid; + const char *name; +{ + int r; + static const ns_dtab dtab[] = { + NS_FILES_CB(_local_grscan, NULL) + NS_DNS_CB(_dns_grscan, NULL) + NS_NIS_CB(_nis_grscan, NULL) + NS_COMPAT_CB(_compat_grscan, NULL) + { 0 } + }; + static const ns_src compatsrc[] = { + { NSSRC_COMPAT, NS_SUCCESS }, + { 0 } + }; + + r = nsdispatch(NULL, dtab, NSDB_GROUP, "grscan", compatsrc, + search, gid, name); + return (r == NS_SUCCESS) ? 1 : 0; +} + +static int +matchline(search, gid, name) + int search; + gid_t gid; + const char *name; +{ + unsigned long id; + char **m; + char *cp, *bp, *ep; + + if (line[0] == '+') + return 0; /* sanity check to prevent recursion */ + bp = line; + _gr_group.gr_name = strsep(&bp, ":\n"); + if (search && name && strcmp(_gr_group.gr_name, name)) + return 0; + _gr_group.gr_passwd = strsep(&bp, ":\n"); + if (!(cp = strsep(&bp, ":\n"))) + return 0; + id = strtoul(cp, &ep, 10); + if (*ep != '\0') + return 0; + _gr_group.gr_gid = (gid_t)id; + if (search && name == NULL && _gr_group.gr_gid != gid) + return 0; + cp = NULL; + if (bp == NULL) + return 0; + for (_gr_group.gr_mem = m = members;; bp++) { + if (m == &members[maxgrp - 1]) { + members = (char **) reallocf(members, sizeof(char **) * + (maxgrp + MAXGRP)); + if (members == NULL) + return 0; + _gr_group.gr_mem = members; + m = &members[maxgrp - 1]; maxgrp += MAXGRP; } - if (*s == ',') { + if (*bp == ',') { if (cp) { - *s = '\0'; + *bp = '\0'; *m++ = cp; cp = NULL; } - } else if (*s == '\0' || *s == '\n' || *s == ' ') { + } else if (*bp == '\0' || *bp == '\n' || *bp == ' ') { if (cp) { - *s = '\0'; + *bp = '\0'; *m++ = cp; } break; - } else if (cp == NULL) { - cp = s; - } - } - _gr_group.gr_mem = members; + } else if (cp == NULL) + cp = bp; + } *m = NULL; - - return 1; + return 1; } -static char *_gr_yp_domain; - -static int -_getypgroup(struct group *gr, const char *name, char *map) +static char * +getline(void) { - char *result, *s; - static char resultbuf[YPMAXRECORD + 2]; - int resultlen; + const char *cp; - if(!_gr_yp_domain) { - if(yp_get_default_domain(&_gr_yp_domain)) - return 0; + tryagain: + if (fgets(line, maxlinelength, _gr_fp) == NULL) + return NULL; + if (index(line, '\n') == NULL) { + do { + if (feof(_gr_fp)) + return NULL; + if (MAXLINELENGTHLIMIT > 0 && + maxlinelength >= MAXLINELENGTHLIMIT) + return NULL; + line = (char *)reallocf(line, maxlinelength + + MAXLINELENGTH); + if (line == NULL) + return NULL; + if (fgets(line + maxlinelength - 1, + MAXLINELENGTH + 1, _gr_fp) == NULL) + return NULL; + maxlinelength += MAXLINELENGTH; + } while (index(line + maxlinelength - MAXLINELENGTH - 1, + '\n') == NULL); } - if(yp_match(_gr_yp_domain, map, name, strlen(name), - &result, &resultlen)) - return 0; - - s = strchr(result, '\n'); - if(s) *s = '\0'; - if(resultlen >= sizeof resultbuf) return 0; - strncpy(resultbuf, result, resultlen); - resultbuf[resultlen] = '\0'; - free(result); - return(_gr_breakout_yp(gr, resultbuf)); + /* + * Ignore comments: ^[ \t]*# + */ + for (cp = line; *cp != '\0'; cp++) + if (*cp != ' ' && *cp != '\t') + break; + if (*cp == '#' || *cp == '\0') + goto tryagain; + if (cp != line) /* skip white space at beginning of line */ + bcopy(cp, line, strlen(cp)); + + return line; } - static int -_nextypgroup(struct group *gr) +copyline(const char *src) { - static char *key; - static int keylen; - char *lastkey, *result; - static char resultbuf[YPMAXRECORD + 2]; - int resultlen; - int rv; - - if(!_gr_yp_domain) { - if(yp_get_default_domain(&_gr_yp_domain)) - return 0; - } + size_t sz; - if(!_gr_stepping_yp) { - if(key) free(key); - rv = yp_first(_gr_yp_domain, "group.byname", - &key, &keylen, &result, &resultlen); - if(rv) { - return 0; - } - _gr_stepping_yp = 1; - goto unpack; - } else { -tryagain: - lastkey = key; - rv = yp_next(_gr_yp_domain, "group.byname", key, keylen, - &key, &keylen, &result, &resultlen); - free(lastkey); -unpack: - if(rv) { - _gr_stepping_yp = 0; + sz = strlen(src); + if (sz > maxlinelength - 1) { + sz = ((sz/MAXLINELENGTH)+1) * MAXLINELENGTH; + if ((line = (char *) reallocf(line, sz)) == NULL) return 0; - } - - if(resultlen > sizeof(resultbuf)) { - free(result); - goto tryagain; - } - - strncpy(resultbuf, result, resultlen); - resultbuf[resultlen] = '\0'; - free(result); - if((result = strchr(resultbuf, '\n')) != NULL) - *result = '\0'; - if (_gr_breakout_yp(gr, resultbuf)) - return(1); - else - goto tryagain; + maxlinelength = sz; } + strlcpy(line, src, maxlinelength); + return 1; } -#endif /* YP */ diff --git a/lib/libc/gen/getpwent.3 b/lib/libc/gen/getpwent.3 index 40842897e0ab0..b606b44f8491a 100644 --- a/lib/libc/gen/getpwent.3 +++ b/lib/libc/gen/getpwent.3 @@ -137,24 +137,6 @@ If the process which calls them has an effective uid of 0, the encrypted password will be returned, otherwise, the password field of the returned structure will point to the string .Ql * . -.Sh YP/NIS INTERACTION -When the -.Xr yp 4 -password database is enabled, the -.Fn getpwnam -and -.Fn getpwuid -functions use the YP maps -.Dq Li passwd.byname -and -.Dq Li passwd.byuid , -respectively, if the requested password entry is not found in the -local database. The -.Fn getpwent -function will step through the YP map -.Dq Li passwd.byname -if the entire map is enabled as described in -.Xr passwd 5 . .Sh RETURN VALUES The functions .Fn getpwent , @@ -187,6 +169,7 @@ A Version 7 format password file .Xr getlogin 2 , .Xr getgrent 3 , .Xr yp 4 , +.Xr nsswitch.conf 5 , .Xr passwd 5 , .Xr pwd_mkdb 8 , .Xr vipw 8 @@ -220,3 +203,16 @@ a pointer to that object. Subsequent calls to the same function will modify the same object. +.Pp +The functions +.Fn getpwent , +.Fn endpwent , +.Fn setpassent , +and +.Fn setpwent +are fairly useless in a networked environment and should be +avoided, if possible. +.Fn getpwent +makes no attempt to suppress duplicate information if multiple +sources are specified in +.Xr nsswitch.conf 5 diff --git a/lib/libc/gen/getpwent.c b/lib/libc/gen/getpwent.c index 00e6ca39c69f3..3c8620e0f23cb 100644 --- a/lib/libc/gen/getpwent.c +++ b/lib/libc/gen/getpwent.c @@ -1,6 +1,9 @@ +/* $NetBSD: getpwent.c,v 1.40.2.2 1999/04/27 22:09:45 perry Exp $ */ + /* * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. + * Portions Copyright (c) 1994, 1995, Jason Downs. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -29,15 +32,14 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * - * $FreeBSD$ */ +#include <sys/cdefs.h> #if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)getpwent.c 8.2 (Berkeley) 4/27/95"; +static const char *rcsid[] = + "$FreeBSD$"; #endif /* LIBC_SCCS and not lint */ -#include <stdio.h> #include <sys/param.h> #include <fcntl.h> #include <db.h> @@ -49,11 +51,27 @@ static char sccsid[] = "@(#)getpwent.c 8.2 (Berkeley) 4/27/95"; #include <stdlib.h> #include <string.h> #include <limits.h> -#include <grp.h> +#include <nsswitch.h> +#ifdef HESIOD +#include <hesiod.h> +#endif +#ifdef YP +#include <machine/param.h> +#include <stdio.h> +#include <rpc/rpc.h> +#include <rpcsvc/yp_prot.h> +#include <rpcsvc/ypclnt.h> +#endif + +extern void setnetgrent __P((char *)); +extern int getnetgrent __P((char **, char **, char **)); +extern int innetgr __P((const char *, const char *, const char *, const char *)); -extern void setnetgrent __P(( char * )); -extern int getnetgrent __P(( char **, char **, char ** )); -extern int innetgr __P(( const char *, const char *, const char *, const char * )); +#include "pw_scan.h" + +#if defined(YP) || defined(HESIOD) +#define _PASSWD_COMPAT +#endif /* * The lookup techniques and data extraction code here must be kept @@ -62,799 +80,1096 @@ extern int innetgr __P(( const char *, const char *, const char *, const char * static struct passwd _pw_passwd; /* password structure */ static DB *_pw_db; /* password database */ -static int _pw_keynum; /* key counter */ +static int _pw_keynum; /* key counter. no more records if -1 */ static int _pw_stayopen; /* keep fd's open */ -#ifdef YP -#include <rpc/rpc.h> -#include <rpcsvc/yp_prot.h> -#include <rpcsvc/ypclnt.h> +static int _pw_flags; /* password flags */ -static struct passwd _pw_copy; -static DBT empty = { NULL, 0 }; -static DB *_ypcache = (DB *)NULL; -static int _yp_exclusions = 0; -static int _yp_enabled = -1; -static int _pw_stepping_yp; /* set true when stepping thru map */ -static char _ypnam[YPMAXRECORD]; -#define YP_HAVE_MASTER 2 -#define YP_HAVE_ADJUNCT 1 -#define YP_HAVE_NONE 0 -static int _gotmaster; -static char *_pw_yp_domain; -static inline int unwind __P(( char * )); -static void _ypinitdb __P(( void )); -static int _havemaster __P((char *)); -static int _getyppass __P((struct passwd *, const char *, const char * )); -static int _nextyppass __P((struct passwd *)); -static inline int lookup __P((const char *)); -static inline void store __P((const char *)); -static inline int ingr __P((const char *, const char*)); -static inline int verf __P((const char *)); -static char * _get_adjunct_pw __P((const char *)); -#endif -static int __hashpw(DBT *); -static int __initdb(void); - -struct passwd * -getpwent() -{ - DBT key; - char bf[sizeof(_pw_keynum) + 1]; - int rv; +static int __hashpw __P((DBT *)); +static int __initdb __P((void)); - if (!_pw_db && !__initdb()) - return((struct passwd *)NULL); +static const ns_src compatsrc[] = { + { NSSRC_COMPAT, NS_SUCCESS }, + { 0 } +}; #ifdef YP - if(_pw_stepping_yp) { - _pw_passwd = _pw_copy; - if (unwind((char *)&_ypnam)) - return(&_pw_passwd); - } +static char *__ypcurrent, *__ypdomain; +static int __ypcurrentlen; +static int _pw_ypdone; /* non-zero if no more yp records */ #endif -tryagain: - ++_pw_keynum; - bf[0] = _PW_KEYBYNUM; - bcopy((char *)&_pw_keynum, bf + 1, sizeof(_pw_keynum)); - key.data = (u_char *)bf; - key.size = sizeof(_pw_keynum) + 1; - rv = __hashpw(&key); - if(!rv) return (struct passwd *)NULL; -#ifdef YP - if(_pw_passwd.pw_name[0] == '+' || _pw_passwd.pw_name[0] == '-') { - if (_yp_enabled == -1) - _ypinitdb(); - bzero((char *)&_ypnam, sizeof(_ypnam)); - bcopy(_pw_passwd.pw_name, _ypnam, - strlen(_pw_passwd.pw_name)); - _pw_copy = _pw_passwd; - if (unwind((char *)&_ypnam) == 0) - goto tryagain; - else - return(&_pw_passwd); - } -#else - /* Ignore YP password file entries when YP is disabled. */ - if(_pw_passwd.pw_name[0] == '+' || _pw_passwd.pw_name[0] == '-') { - goto tryagain; - } +#ifdef HESIOD +static int _pw_hesnum; /* hes counter. no more records if -1 */ #endif - return(&_pw_passwd); -} -struct passwd * -getpwnam(name) +#ifdef _PASSWD_COMPAT +enum _pwmode { PWMODE_NONE, PWMODE_FULL, PWMODE_USER, PWMODE_NETGRP }; +static enum _pwmode __pwmode; + +enum _ypmap { YPMAP_NONE, YPMAP_ADJUNCT, YPMAP_MASTER }; + +static struct passwd *__pwproto = (struct passwd *)NULL; +static int __pwproto_flags; +static char line[1024]; +static long prbuf[1024 / sizeof(long)]; +static DB *__pwexclude = (DB *)NULL; + +static int __pwexclude_add __P((const char *)); +static int __pwexclude_is __P((const char *)); +static void __pwproto_set __P((void)); +static int __ypmaptype __P((void)); +static int __pwparse __P((struct passwd *, char *)); + + /* macros for deciding which YP maps to use. */ +#define PASSWD_BYNAME (__ypmaptype() == YPMAP_MASTER \ + ? "master.passwd.byname" : "passwd.byname") +#define PASSWD_BYUID (__ypmaptype() == YPMAP_MASTER \ + ? "master.passwd.byuid" : "passwd.byuid") + +/* + * add a name to the compat mode exclude list + */ +static int +__pwexclude_add(name) const char *name; { DBT key; - int len, rval; - char bf[UT_NAMESIZE + 2]; + DBT data; - if (!_pw_db && !__initdb()) - return((struct passwd *)NULL); + /* initialize the exclusion table if needed. */ + if(__pwexclude == (DB *)NULL) { + __pwexclude = dbopen(NULL, O_RDWR, 600, DB_HASH, NULL); + if(__pwexclude == (DB *)NULL) + return 1; + } - bf[0] = _PW_KEYBYNAME; - len = strlen(name); - if (len > UT_NAMESIZE) - return(NULL); - bcopy(name, bf + 1, len); - key.data = (u_char *)bf; - key.size = len + 1; - rval = __hashpw(&key); + /* set up the key */ + key.size = strlen(name); + /* LINTED key does not get modified */ + key.data = (char *)name; -#ifdef YP - if (!rval) { - if (_yp_enabled == -1) - _ypinitdb(); - if (_yp_enabled) - rval = _getyppass(&_pw_passwd, name, "passwd.byname"); - } -#endif - /* - * Prevent login attempts when YP is not enabled but YP entries - * are in /etc/master.passwd. - */ - if (rval && (_pw_passwd.pw_name[0] == '+'|| - _pw_passwd.pw_name[0] == '-')) rval = 0; + /* data is nothing. */ + data.data = NULL; + data.size = 0; - if (!_pw_stayopen) - endpwent(); - return(rval ? &_pw_passwd : (struct passwd *)NULL); + /* store it */ + if((__pwexclude->put)(__pwexclude, &key, &data, 0) == -1) + return 1; + + return 0; } -struct passwd * -getpwuid(uid) - uid_t uid; +/* + * test if a name is on the compat mode exclude list + */ +static int +__pwexclude_is(name) + const char *name; { DBT key; - int keyuid, rval; - char bf[sizeof(keyuid) + 1]; - - if (!_pw_db && !__initdb()) - return((struct passwd *)NULL); + DBT data; - bf[0] = _PW_KEYBYUID; - keyuid = uid; - bcopy(&keyuid, bf + 1, sizeof(keyuid)); - key.data = (u_char *)bf; - key.size = sizeof(keyuid) + 1; - rval = __hashpw(&key); + if(__pwexclude == (DB *)NULL) + return 0; /* nothing excluded */ -#ifdef YP - if (!rval) { - if (_yp_enabled == -1) - _ypinitdb(); - if (_yp_enabled) { - char ypbuf[16]; /* big enough for 32-bit uids */ - snprintf(ypbuf, sizeof ypbuf, "%u", (unsigned)uid); - rval = _getyppass(&_pw_passwd, ypbuf, "passwd.byuid"); - } - } -#endif - /* - * Prevent login attempts when YP is not enabled but YP entries - * are in /etc/master.passwd. - */ - if (rval && (_pw_passwd.pw_name[0] == '+'|| - _pw_passwd.pw_name[0] == '-')) rval = 0; + /* set up the key */ + key.size = strlen(name); + /* LINTED key does not get modified */ + key.data = (char *)name; - if (!_pw_stayopen) - endpwent(); - return(rval ? &_pw_passwd : (struct passwd *)NULL); + if((__pwexclude->get)(__pwexclude, &key, &data, 0) == 0) + return 1; /* excluded */ + + return 0; } -int -setpassent(stayopen) - int stayopen; +/* + * setup the compat mode prototype template + */ +static void +__pwproto_set() { - _pw_keynum = 0; -#ifdef YP - _pw_stepping_yp = 0; - if (stayopen) - setgroupent(1); -#endif - _pw_stayopen = stayopen; - return(1); + char *ptr; + struct passwd *pw = &_pw_passwd; + + /* make this the new prototype */ + ptr = (char *)(void *)prbuf; + + /* first allocate the struct. */ + __pwproto = (struct passwd *)(void *)ptr; + ptr += sizeof(struct passwd); + + /* name */ + if(pw->pw_name && (pw->pw_name)[0]) { + ptr = (char *)ALIGN((u_long)ptr); + memmove(ptr, pw->pw_name, strlen(pw->pw_name) + 1); + __pwproto->pw_name = ptr; + ptr += (strlen(pw->pw_name) + 1); + } else + __pwproto->pw_name = (char *)NULL; + + /* password */ + if(pw->pw_passwd && (pw->pw_passwd)[0]) { + ptr = (char *)ALIGN((u_long)ptr); + memmove(ptr, pw->pw_passwd, strlen(pw->pw_passwd) + 1); + __pwproto->pw_passwd = ptr; + ptr += (strlen(pw->pw_passwd) + 1); + } else + __pwproto->pw_passwd = (char *)NULL; + + /* uid */ + __pwproto->pw_uid = pw->pw_uid; + + /* gid */ + __pwproto->pw_gid = pw->pw_gid; + + /* change (ignored anyway) */ + __pwproto->pw_change = pw->pw_change; + + /* class (ignored anyway) */ + __pwproto->pw_class = ""; + + /* gecos */ + if(pw->pw_gecos && (pw->pw_gecos)[0]) { + ptr = (char *)ALIGN((u_long)ptr); + memmove(ptr, pw->pw_gecos, strlen(pw->pw_gecos) + 1); + __pwproto->pw_gecos = ptr; + ptr += (strlen(pw->pw_gecos) + 1); + } else + __pwproto->pw_gecos = (char *)NULL; + + /* dir */ + if(pw->pw_dir && (pw->pw_dir)[0]) { + ptr = (char *)ALIGN((u_long)ptr); + memmove(ptr, pw->pw_dir, strlen(pw->pw_dir) + 1); + __pwproto->pw_dir = ptr; + ptr += (strlen(pw->pw_dir) + 1); + } else + __pwproto->pw_dir = (char *)NULL; + + /* shell */ + if(pw->pw_shell && (pw->pw_shell)[0]) { + ptr = (char *)ALIGN((u_long)ptr); + memmove(ptr, pw->pw_shell, strlen(pw->pw_shell) + 1); + __pwproto->pw_shell = ptr; + ptr += (strlen(pw->pw_shell) + 1); + } else + __pwproto->pw_shell = (char *)NULL; + + /* expire (ignored anyway) */ + __pwproto->pw_expire = pw->pw_expire; + + /* flags */ + __pwproto_flags = _pw_flags; } -void -setpwent() +static int +__ypmaptype() { - (void)setpassent(0); -} + static int maptype = -1; + int order, r; -void -endpwent() -{ - _pw_keynum = 0; -#ifdef YP - _pw_stepping_yp = 0; -#endif - if (_pw_db) { - (void)(_pw_db->close)(_pw_db); - _pw_db = (DB *)NULL; - } -#ifdef YP - if (_ypcache) { - (void)(_ypcache->close)(_ypcache); - _ypcache = (DB *)NULL; - _yp_exclusions = 0; - } - /* Fix for PR #12008 */ - _yp_enabled = -1; -#endif -} + if (maptype != -1) + return (maptype); -static int -__initdb() -{ - static int warned; - char *p; + maptype = YPMAP_NONE; + if (geteuid() != 0) + return (maptype); - p = (geteuid()) ? _PATH_MP_DB : _PATH_SMP_DB; - _pw_db = dbopen(p, O_RDONLY, 0, DB_HASH, NULL); - if (_pw_db) - return(1); - if (!warned++) - syslog(LOG_ERR, "%s: %m", p); - return(0); -} + if (!__ypdomain) { + if( _yp_check(&__ypdomain) == 0) + return (maptype); + } -static int -__hashpw(key) - DBT *key; -{ - register char *p, *t; - static u_int max; - static char *line; - DBT data; + r = yp_order(__ypdomain, "master.passwd.byname", &order); + if (r == 0) { + maptype = YPMAP_MASTER; + return (maptype); + } - if ((_pw_db->get)(_pw_db, key, &data, 0)) - return(0); - p = (char *)data.data; + /* + * NIS+ in YP compat mode doesn't support + * YPPROC_ORDER -- no point in continuing. + */ + if (r == YPERR_YPERR) + return (maptype); - /* Increase buffer size for long lines if necessary. */ - if (data.size > max) { - max = data.size + 1024; - if (!(line = reallocf(line, max))) - return(0); + /* master.passwd doesn't exist -- try passwd.adjunct */ + if (r == YPERR_MAP) { + r = yp_order(__ypdomain, "passwd.adjunct.byname", &order); + if (r == 0) + maptype = YPMAP_ADJUNCT; + return (maptype); } - /* THIS CODE MUST MATCH THAT IN pwd_mkdb. */ - t = line; -#define EXPAND(e) e = t; while ( (*t++ = *p++) ); -#define SCALAR(v) memmove(&(v), p, sizeof v); p += sizeof v - EXPAND(_pw_passwd.pw_name); - EXPAND(_pw_passwd.pw_passwd); - SCALAR(_pw_passwd.pw_uid); - SCALAR(_pw_passwd.pw_gid); - SCALAR(_pw_passwd.pw_change); - EXPAND(_pw_passwd.pw_class); - EXPAND(_pw_passwd.pw_gecos); - EXPAND(_pw_passwd.pw_dir); - EXPAND(_pw_passwd.pw_shell); - SCALAR(_pw_passwd.pw_expire); - bcopy(p, (char *)&_pw_passwd.pw_fields, sizeof _pw_passwd.pw_fields); - p += sizeof _pw_passwd.pw_fields; - return(1); + return (maptype); } -#ifdef YP - -static void -_ypinitdb() +/* + * parse a passwd file line (from NIS or HESIOD). + * assumed to be `old-style' if maptype != YPMAP_MASTER. + */ +static int +__pwparse(pw, s) + struct passwd *pw; + char *s; { - DBT key, data; - char buf[] = { _PW_KEYYPENABLED }; - key.data = buf; - key.size = 1; - _yp_enabled = 0; - if ((_pw_db->get)(_pw_db, &key, &data, 0) == 0) { - _yp_enabled = (int)*((char *)data.data) - 2; - /* Don't even bother with this if we aren't root. */ - if (!geteuid()) { - if (!_pw_yp_domain) - if (yp_get_default_domain(&_pw_yp_domain)) - return; - _gotmaster = _havemaster(_pw_yp_domain); - } else _gotmaster = YP_HAVE_NONE; - /* - * Create a DB hash database in memory. Bet you didn't know you - * could do a dbopen() with a NULL filename, did you. - */ - if (_ypcache == (DB *)NULL) - _ypcache = dbopen(NULL, O_RDWR, 600, DB_HASH, NULL); + static char adjunctpw[YPMAXRECORD + 2]; + int flags, maptype; + + maptype = __ypmaptype(); + flags = 0; + if (maptype == YPMAP_MASTER) + flags |= _PWSCAN_MASTER; + if (! __pw_scan(s, pw, flags)) + return 1; + + /* now let the prototype override, if set. */ + if(__pwproto != (struct passwd *)NULL) { +#ifdef PW_OVERRIDE_PASSWD + if(__pwproto_flags & _PWF_PASSWD) + pw->pw_passwd = __pwproto->pw_passwd; +#endif + if(__pwproto_flags & _PWF_UID) + pw->pw_uid = __pwproto->pw_uid; + if(__pwproto_flags & _PWF_GID) + pw->pw_gid = __pwproto->pw_gid; + if(__pwproto_flags & _PWF_GECOS) + pw->pw_gecos = __pwproto->pw_gecos; + if(__pwproto_flags & _PWF_DIR) + pw->pw_dir = __pwproto->pw_dir; + if(__pwproto_flags & _PWF_SHELL) + pw->pw_shell = __pwproto->pw_shell; } + if ((maptype == YPMAP_ADJUNCT) && + (strstr(pw->pw_passwd, "##") != NULL)) { + char *data, *bp; + int datalen; + + if (yp_match(__ypdomain, "passwd.adjunct.byname", pw->pw_name, + (int)strlen(pw->pw_name), &data, &datalen) == 0) { + if (datalen > sizeof(adjunctpw) - 1) + datalen = sizeof(adjunctpw) - 1; + strncpy(adjunctpw, data, (size_t)datalen); + + /* skip name to get password */ + if ((bp = strsep(&data, ":")) != NULL && + (bp = strsep(&data, ":")) != NULL) + pw->pw_passwd = bp; + } + } + return 0; } +#endif /* _PASSWD_COMPAT */ /* - * See if a user is in the blackballed list. + * local files implementation of getpw*() + * varargs: type, [ uid (type == _PW_KEYBYUID) | name (type == _PW_KEYBYNAME) ] */ -static inline int -lookup(name) - const char *name; +static int _local_getpw __P((void *, void *, va_list)); + +/*ARGSUSED*/ +static int +_local_getpw(rv, cb_data, ap) + void *rv; + void *cb_data; + va_list ap; { - DBT key; + DBT key; + char bf[/*CONSTCOND*/ MAX(MAXLOGNAME, sizeof(_pw_keynum)) + 1]; + uid_t uid; + int search, len, rval; + const char *name; - if (!_yp_exclusions) - return(0); + if (!_pw_db && !__initdb()) + return NS_UNAVAIL; + + search = va_arg(ap, int); + bf[0] = search; + switch (search) { + case _PW_KEYBYNUM: + if (_pw_keynum == -1) + return NS_NOTFOUND; /* no more local records */ + ++_pw_keynum; + memmove(bf + 1, &_pw_keynum, sizeof(_pw_keynum)); + key.size = sizeof(_pw_keynum) + 1; + break; + case _PW_KEYBYNAME: + name = va_arg(ap, const char *); + len = strlen(name); + memmove(bf + 1, name, (size_t)MIN(len, MAXLOGNAME)); + key.size = len + 1; + break; + case _PW_KEYBYUID: + uid = va_arg(ap, uid_t); + memmove(bf + 1, &uid, sizeof(len)); + key.size = sizeof(uid) + 1; + break; + default: + abort(); + } - key.data = (char *)name; - key.size = strlen(name); + key.data = (u_char *)bf; + rval = __hashpw(&key); + if (rval == NS_NOTFOUND && search == _PW_KEYBYNUM) + _pw_keynum = -1; /* flag `no more local records' */ - if ((_ypcache->get)(_ypcache, &key, &empty, 0)) { - return(0); + if (!_pw_stayopen && (search != _PW_KEYBYNUM)) { + (void)(_pw_db->close)(_pw_db); + _pw_db = (DB *)NULL; } - - return(1); + return (rval); } +#ifdef HESIOD /* - * Store a blackballed user in an in-core hash database. + * hesiod implementation of getpw*() + * varargs: type, [ uid (type == _PW_KEYBYUID) | name (type == _PW_KEYBYNAME) ] */ -static inline void -store(key) - const char *key; -{ - DBT lkey; -/* - if (lookup(key)) - return; -*/ - - _yp_exclusions = 1; +static int _dns_getpw __P((void *, void *, va_list)); - lkey.data = (char *)key; - lkey.size = strlen(key); +/*ARGSUSED*/ +static int +_dns_getpw(rv, cb_data, ap) + void *rv; + void *cb_data; + va_list ap; +{ + const char *name; + uid_t uid; + int search; + + const char *map; + char **hp; + void *context; + int r; + + search = va_arg(ap, int); + nextdnsbynum: + switch (search) { + case _PW_KEYBYNUM: + if (_pw_hesnum == -1) + return NS_NOTFOUND; /* no more hesiod records */ + snprintf(line, sizeof(line) - 1, "passwd-%u", _pw_hesnum); + _pw_hesnum++; + map = "passwd"; + break; + case _PW_KEYBYNAME: + name = va_arg(ap, const char *); + strncpy(line, name, sizeof(line)); + map = "passwd"; + break; + case _PW_KEYBYUID: + uid = va_arg(ap, uid_t); + snprintf(line, sizeof(line), "%u", (unsigned int)uid); + map = "uid"; /* XXX this is `passwd' on ultrix */ + break; + default: + abort(); + } + line[sizeof(line) - 1] = '\0'; + + r = NS_UNAVAIL; + if (hesiod_init(&context) == -1) + return (r); + + hp = hesiod_resolve(context, line, map); + if (hp == NULL) { + if (errno == ENOENT) { + /* flag `no more hesiod records' */ + if (search == _PW_KEYBYNUM) + _pw_hesnum = -1; + r = NS_NOTFOUND; + } + goto cleanup_dns_getpw; + } - (void)(_ypcache->put)(_ypcache, &lkey, &empty, R_NOOVERWRITE); + strncpy(line, hp[0], sizeof(line)); /* only check first elem */ + line[sizeof(line) - 1] = '\0'; + hesiod_free_list(context, hp); + if (__pwparse(&_pw_passwd, line)) { + if (search == _PW_KEYBYNUM) + goto nextdnsbynum; /* skip dogdy entries */ + r = NS_UNAVAIL; + } else + r = NS_SUCCESS; + cleanup_dns_getpw: + hesiod_end(context); + return (r); } +#endif +#ifdef YP /* - * Parse the + entries in the password database and do appropriate - * NIS lookups. While ugly to look at, this is optimized to do only - * as many lookups as are absolutely necessary in any given case. - * Basically, the getpwent() function will feed us + and - lines - * as they appear in the database. For + lines, we do netgroup/group - * and user lookups to find all usernames that match the rule and - * extract them from the NIS passwd maps. For - lines, we save the - * matching names in a database and a) exlude them, and b) make sure - * we don't consider them when processing other + lines that appear - * later. + * nis implementation of getpw*() + * varargs: type, [ uid (type == _PW_KEYBYUID) | name (type == _PW_KEYBYNAME) ] */ -static inline int -unwind(grp) - char *grp; +static int _nis_getpw __P((void *, void *, va_list)); + +/*ARGSUSED*/ +static int +_nis_getpw(rv, cb_data, ap) + void *rv; + void *cb_data; + va_list ap; { - char *user, *host, *domain; - static int latch = 0; - static struct group *gr = NULL; - int rv = 0; - - if (grp[0] == '+') { - if (strlen(grp) == 1) { - return(_nextyppass(&_pw_passwd)); + const char *name; + uid_t uid; + int search; + char *key, *data; + char *map; + int keylen, datalen, r, rval; + + if(__ypdomain == NULL) { + if(_yp_check(&__ypdomain) == 0) + return NS_UNAVAIL; + } + + map = PASSWD_BYNAME; + search = va_arg(ap, int); + switch (search) { + case _PW_KEYBYNUM: + break; + case _PW_KEYBYNAME: + name = va_arg(ap, const char *); + strncpy(line, name, sizeof(line)); + break; + case _PW_KEYBYUID: + uid = va_arg(ap, uid_t); + snprintf(line, sizeof(line), "%u", (unsigned int)uid); + map = PASSWD_BYUID; + break; + default: + abort(); + } + line[sizeof(line) - 1] = '\0'; + rval = NS_UNAVAIL; + if (search != _PW_KEYBYNUM) { + data = NULL; + r = yp_match(__ypdomain, map, line, (int)strlen(line), + &data, &datalen); + if (r == YPERR_KEY) + rval = NS_NOTFOUND; + if (r != 0) { + if (data) + free(data); + return (rval); } - if (grp[1] == '@') { - _pw_stepping_yp = 1; -grpagain: - if (gr != NULL) { - if (*gr->gr_mem != NULL) { - if (lookup(*gr->gr_mem)) { - gr->gr_mem++; - goto grpagain; - } - rv = _getyppass(&_pw_passwd, - *gr->gr_mem, - "passwd.byname"); - gr->gr_mem++; - return(rv); - } else { - latch = 0; - _pw_stepping_yp = 0; - gr = NULL; - return(0); - } - } - if (!latch) { - setnetgrent(grp+2); - latch++; - } -again: - if (getnetgrent(&host, &user, &domain) == 0) { - if ((gr = getgrnam(grp+2)) != NULL) - goto grpagain; - latch = 0; - _pw_stepping_yp = 0; - return(0); - } else { - if (lookup(user)) - goto again; - if (_getyppass(&_pw_passwd, user, - "passwd.byname")) - return(1); - else - goto again; + data[datalen] = '\0'; /* clear trailing \n */ + strncpy(line, data, sizeof(line)); + line[sizeof(line) - 1] = '\0'; + free(data); + if (__pwparse(&_pw_passwd, line)) + return NS_UNAVAIL; + return NS_SUCCESS; + } + + if (_pw_ypdone) + return NS_NOTFOUND; + for (;;) { + data = key = NULL; + if (__ypcurrent) { + r = yp_next(__ypdomain, map, + __ypcurrent, __ypcurrentlen, + &key, &keylen, &data, &datalen); + free(__ypcurrent); + switch (r) { + case 0: + __ypcurrent = key; + __ypcurrentlen = keylen; + break; + case YPERR_NOMORE: + __ypcurrent = NULL; + /* flag `no more yp records' */ + _pw_ypdone = 1; + rval = NS_NOTFOUND; } } else { - if (lookup(grp+1)) - return(0); - return(_getyppass(&_pw_passwd, grp+1, "passwd.byname")); + r = yp_first(__ypdomain, map, &__ypcurrent, + &__ypcurrentlen, &data, &datalen); } - } else { - if (grp[1] == '@') { - setnetgrent(grp+2); - rv = 0; - while(getnetgrent(&host, &user, &domain) != 0) { - store(user); - rv++; - } - if (!rv && (gr = getgrnam(grp+2)) != NULL) { - while(*gr->gr_mem) { - store(*gr->gr_mem); - gr->gr_mem++; - } - } - } else { - store(grp+1); + if (r != 0) { + if (key) + free(key); + if (data) + free(data); + return (rval); } + data[datalen] = '\0'; /* clear trailing \n */ + strncpy(line, data, sizeof(line)); + line[sizeof(line) - 1] = '\0'; + free(data); + if (! __pwparse(&_pw_passwd, line)) + return NS_SUCCESS; } - return(0); -} + /* NOTREACHED */ +} /* _nis_getpw */ +#endif +#ifdef _PASSWD_COMPAT /* - * See if a user is a member of a particular group. + * See if the compat token is in the database. Only works if pwd_mkdb knows + * about the token. */ -static inline int -ingr(grp, name) - const char *grp; - const char *name; +static int __has_compatpw __P((void)); + +static int +__has_compatpw() { - register struct group *gr; + DBT key, data; + DBT pkey, pdata; + char bf[MAXLOGNAME]; + u_char cyp[] = { _PW_KEYYPENABLED }; - if ((gr = getgrnam(grp)) == NULL) - return(0); + /*LINTED*/ + key.data = cyp; + key.size = 1; - while(*gr->gr_mem) { - if (!strcmp(*gr->gr_mem, name)) - return(1); - gr->gr_mem++; - } + /* Pre-token database support. */ + bf[0] = _PW_KEYBYNAME; + bf[1] = '+'; + pkey.data = (u_char *)bf; + pkey.size = 2; - return(0); + if ((_pw_db->get)(_pw_db, &key, &data, 0) + && (_pw_db->get)(_pw_db, &pkey, &pdata, 0)) + return 0; /* No compat token */ + return 1; } /* - * Check a user against the +@netgroup/-@netgroup lines listed in - * the local password database. Also checks +user/-user lines. - * If no netgroup exists that matches +@netgroup/-@netgroup, - * try searching regular groups with the same name. + * log an error if "files" or "compat" is specified in passwd_compat database */ -static inline int -verf(name) - const char *name; -{ - DBT key; - char bf[sizeof(_pw_keynum) + 1]; - int keynum = 0; +static int _bad_getpw __P((void *, void *, va_list)); -again: - ++keynum; - bf[0] = _PW_KEYYPBYNUM; - bcopy((char *)&keynum, bf + 1, sizeof(keynum)); - key.data = (u_char *)bf; - key.size = sizeof(keynum) + 1; - if (!__hashpw(&key)) { - /* Try again using old format */ - bf[0] = _PW_KEYBYNUM; - bcopy((char *)&keynum, bf + 1, sizeof(keynum)); - key.data = (u_char *)bf; - if (!__hashpw(&key)) - return(0); - } - if (_pw_passwd.pw_name[0] != '+' && (_pw_passwd.pw_name[0] != '-')) - goto again; - if (_pw_passwd.pw_name[0] == '+') { - if (strlen(_pw_passwd.pw_name) == 1) /* Wildcard */ - return(1); - if (_pw_passwd.pw_name[1] == '@') { - if ((innetgr(_pw_passwd.pw_name+2, NULL, name, - _pw_yp_domain) || - ingr(_pw_passwd.pw_name+2, name)) && !lookup(name)) - return(1); - else - goto again; - } else { - if (!strcmp(name, _pw_passwd.pw_name+1) && - !lookup(name)) - return(1); - else - goto again; - } - } - if (_pw_passwd.pw_name[0] == '-') { - /* Note that a minus wildcard is a no-op. */ - if (_pw_passwd.pw_name[1] == '@') { - if (innetgr(_pw_passwd.pw_name+2, NULL, name, - _pw_yp_domain) || - ingr(_pw_passwd.pw_name+2, name)) { - store(name); - return(0); - } else - goto again; - } else { - if (!strcmp(name, _pw_passwd.pw_name+1)) { - store(name); - return(0); - } else - goto again; - } - +/*ARGSUSED*/ +static int +_bad_getpw(rv, cb_data, ap) + void *rv; + void *cb_data; + va_list ap; +{ + static int warned; + if (!warned) { + syslog(LOG_ERR, + "nsswitch.conf passwd_compat database can't use '%s'", + (char *)cb_data); } - return(0); + warned = 1; + return NS_UNAVAIL; } -static char * -_get_adjunct_pw(name) - const char *name; -{ - static char adjunctbuf[YPMAXRECORD+2]; - int rval; - char *result; - int resultlen; - char *map = "passwd.adjunct.byname"; - char *s; - - if ((rval = yp_match(_pw_yp_domain, map, name, strlen(name), - &result, &resultlen))) - return(NULL); - - strncpy(adjunctbuf, result, resultlen); - adjunctbuf[resultlen] = '\0'; - free(result); - result = (char *)&adjunctbuf; - - /* Don't care about the name. */ - if ((s = strsep(&result, ":")) == NULL) - return (NULL); /* name */ - if ((s = strsep(&result, ":")) == NULL) - return (NULL); /* password */ +/* + * when a name lookup in compat mode is required (e.g., '+name', or a name in + * '+@netgroup'), look it up in the 'passwd_compat' nsswitch database. + * only Hesiod and NIS is supported - it doesn't make sense to lookup + * compat names from 'files' or 'compat'. + */ +static int __getpwcompat __P((int, uid_t, const char *)); - return(s); +static int +__getpwcompat(type, uid, name) + int type; + uid_t uid; + const char *name; +{ + static const ns_dtab dtab[] = { + NS_FILES_CB(_bad_getpw, "files") + NS_DNS_CB(_dns_getpw, NULL) + NS_NIS_CB(_nis_getpw, NULL) + NS_COMPAT_CB(_bad_getpw, "compat") + { 0 } + }; + static const ns_src defaultnis[] = { + { NSSRC_NIS, NS_SUCCESS }, + { 0 } + }; + + switch (type) { + case _PW_KEYBYNUM: + return nsdispatch(NULL, dtab, NSDB_PASSWD_COMPAT, "getpwcompat", + defaultnis, type); + case _PW_KEYBYNAME: + return nsdispatch(NULL, dtab, NSDB_PASSWD_COMPAT, "getpwcompat", + defaultnis, type, name); + case _PW_KEYBYUID: + return nsdispatch(NULL, dtab, NSDB_PASSWD_COMPAT, "getpwcompat", + defaultnis, type, uid); + default: + abort(); + /*NOTREACHED*/ + } } +#endif /* _PASSWD_COMPAT */ + +/* + * compat implementation of getpwent() + * varargs (ignored): + * type, [ uid (type == _PW_KEYBYUID) | name (type == _PW_KEYBYNAME) ] + */ +static int _compat_getpwent __P((void *, void *, va_list)); +/*ARGSUSED*/ static int -_pw_breakout_yp(struct passwd *pw, char *res, int resultlen, int master) +_compat_getpwent(rv, cb_data, ap) + void *rv; + void *cb_data; + va_list ap; { - char *s, *result; - static char resbuf[YPMAXRECORD+2]; + DBT key; + int rval; + char bf[sizeof(_pw_keynum) + 1]; +#ifdef _PASSWD_COMPAT + static char *name = NULL; + char *user, *host, *dom; + int has_compatpw; +#endif - /* - * Be triple, ultra super-duper paranoid: reject entries - * that start with a + or -. yp_mkdb and /var/yp/Makefile - * are _both_ supposed to strip these out, but you never - * know. - */ - if (*res == '+' || *res == '-') - return 0; + if (!_pw_db && !__initdb()) + return NS_UNAVAIL; - /* - * The NIS protocol definition limits the size of an NIS - * record to YPMAXRECORD bytes. We need to do a copy to - * a static buffer here since the memory pointed to by - * res will be free()ed when this function returns. - */ - strncpy((char *)&resbuf, res, resultlen); - resbuf[resultlen] = '\0'; - result = (char *)&resbuf; +#ifdef _PASSWD_COMPAT + has_compatpw = __has_compatpw(); - /* - * XXX Sanity check: make sure all fields are valid (no NULLs). - * If we find a badly formatted entry, we punt. - */ - if ((s = strsep(&result, ":")) == NULL) return 0; /* name */ - /* - * We don't care what pw_fields says: we _always_ want the - * username returned to us by NIS. - */ - pw->pw_name = s; - pw->pw_fields |= _PWF_NAME; - - if ((s = strsep(&result, ":")) == NULL) return 0; /* password */ - if(!(pw->pw_fields & _PWF_PASSWD)) { - /* SunOS passwd.adjunct hack */ - if (master == YP_HAVE_ADJUNCT && strstr(s, "##") != NULL) { - char *realpw; - realpw = _get_adjunct_pw(pw->pw_name); - if (realpw == NULL) - pw->pw_passwd = s; - else - pw->pw_passwd = realpw; - } else { - pw->pw_passwd = s; +again: + if (has_compatpw && (__pwmode != PWMODE_NONE)) { + int r; + + switch (__pwmode) { + case PWMODE_FULL: + r = __getpwcompat(_PW_KEYBYNUM, 0, NULL); + if (r == NS_SUCCESS) + return r; + __pwmode = PWMODE_NONE; + break; + + case PWMODE_NETGRP: + r = getnetgrent(&host, &user, &dom); + if (r == 0) { /* end of group */ + endnetgrent(); + __pwmode = PWMODE_NONE; + break; + } + if (!user || !*user) + break; + r = __getpwcompat(_PW_KEYBYNAME, 0, user); + if (r == NS_SUCCESS) + return r; + break; + + case PWMODE_USER: + if (name == NULL) { + __pwmode = PWMODE_NONE; + break; + } + r = __getpwcompat(_PW_KEYBYNAME, 0, name); + free(name); + name = NULL; + if (r == NS_SUCCESS) + return r; + break; + + case PWMODE_NONE: + abort(); } - pw->pw_fields |= _PWF_PASSWD; + goto again; } +#endif - if ((s = strsep(&result, ":")) == NULL) return 0; /* uid */ - if(!(pw->pw_fields & _PWF_UID)) { - pw->pw_uid = atoi(s); - pw->pw_fields |= _PWF_UID; - } + if (_pw_keynum == -1) + return NS_NOTFOUND; /* no more local records */ + ++_pw_keynum; + bf[0] = _PW_KEYBYNUM; + memmove(bf + 1, &_pw_keynum, sizeof(_pw_keynum)); + key.data = (u_char *)bf; + key.size = sizeof(_pw_keynum) + 1; + rval = __hashpw(&key); + if (rval == NS_NOTFOUND) + _pw_keynum = -1; /* flag `no more local records' */ + else if (rval == NS_SUCCESS) { +#ifdef _PASSWD_COMPAT + /* if we don't have YP at all, don't bother. */ + if (has_compatpw) { + if(_pw_passwd.pw_name[0] == '+') { + /* set the mode */ + switch(_pw_passwd.pw_name[1]) { + case '\0': + __pwmode = PWMODE_FULL; + break; + case '@': + __pwmode = PWMODE_NETGRP; + setnetgrent(_pw_passwd.pw_name + 2); + break; + default: + __pwmode = PWMODE_USER; + name = strdup(_pw_passwd.pw_name + 1); + break; + } - if ((s = strsep(&result, ":")) == NULL) return 0; /* gid */ - if(!(pw->pw_fields & _PWF_GID)) { - pw->pw_gid = atoi(s); - pw->pw_fields |= _PWF_GID; + /* save the prototype */ + __pwproto_set(); + goto again; + } else if(_pw_passwd.pw_name[0] == '-') { + /* an attempted exclusion */ + switch(_pw_passwd.pw_name[1]) { + case '\0': + break; + case '@': + setnetgrent(_pw_passwd.pw_name + 2); + while(getnetgrent(&host, &user, &dom)) { + if(user && *user) + __pwexclude_add(user); + } + endnetgrent(); + break; + default: + __pwexclude_add(_pw_passwd.pw_name + 1); + break; + } + goto again; + } + } +#endif } + return (rval); +} - if (master == YP_HAVE_MASTER) { - if ((s = strsep(&result, ":")) == NULL) return 0; /* class */ - if(!(pw->pw_fields & _PWF_CLASS)) { - pw->pw_class = s; - pw->pw_fields |= _PWF_CLASS; - } +/* + * compat implementation of getpwnam() and getpwuid() + * varargs: type, [ uid (type == _PW_KEYBYUID) | name (type == _PW_KEYBYNAME) ] + */ +static int _compat_getpw __P((void *, void *, va_list)); - if ((s = strsep(&result, ":")) == NULL) return 0; /* change */ - if(!(pw->pw_fields & _PWF_CHANGE)) { - pw->pw_change = atol(s); - pw->pw_fields |= _PWF_CHANGE; - } +static int +_compat_getpw(rv, cb_data, ap) + void *rv; + void *cb_data; + va_list ap; +{ +#ifdef _PASSWD_COMPAT + DBT key; + int search, rval, r, s, keynum; + uid_t uid; + char bf[sizeof(keynum) + 1]; + char *name, *host, *user, *dom; +#endif - if ((s = strsep(&result, ":")) == NULL) return 0; /* expire */ - if(!(pw->pw_fields & _PWF_EXPIRE)) { - pw->pw_expire = atol(s); - pw->pw_fields |= _PWF_EXPIRE; - } - } + if (!_pw_db && !__initdb()) + return NS_UNAVAIL; - if ((s = strsep(&result, ":")) == NULL) return 0; /* gecos */ - if(!(pw->pw_fields & _PWF_GECOS)) { - pw->pw_gecos = s; - pw->pw_fields |= _PWF_GECOS; + /* + * If there isn't a compat token in the database, use files. + */ +#ifdef _PASSWD_COMPAT + if (! __has_compatpw()) +#endif + return (_local_getpw(rv, cb_data, ap)); + +#ifdef _PASSWD_COMPAT + search = va_arg(ap, int); + uid = 0; + name = NULL; + rval = NS_NOTFOUND; + switch (search) { + case _PW_KEYBYNAME: + name = va_arg(ap, char *); + break; + case _PW_KEYBYUID: + uid = va_arg(ap, uid_t); + break; + default: + abort(); } - if ((s = strsep(&result, ":")) == NULL) return 0; /* dir */ - if(!(pw->pw_fields & _PWF_DIR)) { - pw->pw_dir = s; - pw->pw_fields |= _PWF_DIR; + for (s = -1, keynum = 1 ; ; keynum++) { + bf[0] = _PW_KEYBYNUM; + memmove(bf + 1, &keynum, sizeof(keynum)); + key.data = (u_char *)bf; + key.size = sizeof(keynum) + 1; + if(__hashpw(&key) != NS_SUCCESS) + break; + switch(_pw_passwd.pw_name[0]) { + case '+': + /* save the prototype */ + __pwproto_set(); + + switch(_pw_passwd.pw_name[1]) { + case '\0': + r = __getpwcompat(search, uid, name); + if (r != NS_SUCCESS) + continue; + break; + case '@': +pwnam_netgrp: +#if 0 /* XXX: is this a hangover from pre-nsswitch? */ + if(__ypcurrent) { + free(__ypcurrent); + __ypcurrent = NULL; + } +#endif + if (s == -1) /* first time */ + setnetgrent(_pw_passwd.pw_name + 2); + s = getnetgrent(&host, &user, &dom); + if (s == 0) { /* end of group */ + endnetgrent(); + s = -1; + continue; + } + if (!user || !*user) + goto pwnam_netgrp; + + r = __getpwcompat(_PW_KEYBYNAME, 0, user); + + if (r == NS_UNAVAIL) + return r; + if (r == NS_NOTFOUND) { + /* + * just because this user is bad + * it doesn't mean they all are. + */ + goto pwnam_netgrp; + } + break; + default: + user = _pw_passwd.pw_name + 1; + r = __getpwcompat(_PW_KEYBYNAME, 0, user); + + if (r == NS_UNAVAIL) + return r; + if (r == NS_NOTFOUND) + continue; + break; + } + if(__pwexclude_is(_pw_passwd.pw_name)) { + if(s == 1) /* inside netgroup */ + goto pwnam_netgrp; + continue; + } + break; + case '-': + /* attempted exclusion */ + switch(_pw_passwd.pw_name[1]) { + case '\0': + break; + case '@': + setnetgrent(_pw_passwd.pw_name + 2); + while(getnetgrent(&host, &user, &dom)) { + if(user && *user) + __pwexclude_add(user); + } + endnetgrent(); + break; + default: + __pwexclude_add(_pw_passwd.pw_name + 1); + break; + } + break; + } + if ((search == _PW_KEYBYNAME && + strcmp(_pw_passwd.pw_name, name) == 0) + || (search == _PW_KEYBYUID && _pw_passwd.pw_uid == uid)) { + rval = NS_SUCCESS; + break; + } + if(s == 1) /* inside netgroup */ + goto pwnam_netgrp; + continue; } + __pwproto = (struct passwd *)NULL; - if ((s = strsep(&result, ":")) == NULL) return 0; /* shell */ - if(!(pw->pw_fields & _PWF_SHELL)) { - pw->pw_shell = s; - pw->pw_fields |= _PWF_SHELL; + if (!_pw_stayopen) { + (void)(_pw_db->close)(_pw_db); + _pw_db = (DB *)NULL; } - - /* Be consistent. */ - if ((s = strchr(pw->pw_shell, '\n'))) *s = '\0'; - - return 1; + if(__pwexclude != (DB *)NULL) { + (void)(__pwexclude->close)(__pwexclude); + __pwexclude = (DB *)NULL; + } + return rval; +#endif /* _PASSWD_COMPAT */ } -static int -_havemaster(char *_yp_domain) +struct passwd * +getpwent() { - int order; - int rval; + int r; + static const ns_dtab dtab[] = { + NS_FILES_CB(_local_getpw, NULL) + NS_DNS_CB(_dns_getpw, NULL) + NS_NIS_CB(_nis_getpw, NULL) + NS_COMPAT_CB(_compat_getpwent, NULL) + { 0 } + }; + + r = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwent", compatsrc, + _PW_KEYBYNUM); + if (r != NS_SUCCESS) + return (struct passwd *)NULL; + return &_pw_passwd; +} - if (!(rval = yp_order(_yp_domain, "master.passwd.byname", &order))) - return(YP_HAVE_MASTER); +struct passwd * +getpwnam(name) + const char *name; +{ + int r; + static const ns_dtab dtab[] = { + NS_FILES_CB(_local_getpw, NULL) + NS_DNS_CB(_dns_getpw, NULL) + NS_NIS_CB(_nis_getpw, NULL) + NS_COMPAT_CB(_compat_getpw, NULL) + { 0 } + }; + + if (name == NULL || name[0] == '\0') + return (struct passwd *)NULL; + + r = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwnam", compatsrc, + _PW_KEYBYNAME, name); + return (r == NS_SUCCESS ? &_pw_passwd : (struct passwd *)NULL); +} - /* - * NIS+ in YP compat mode doesn't support - * YPPROC_ORDER -- no point in continuing. - */ - if (rval == YPERR_YPERR) - return(YP_HAVE_NONE); +struct passwd * +getpwuid(uid) + uid_t uid; +{ + int r; + static const ns_dtab dtab[] = { + NS_FILES_CB(_local_getpw, NULL) + NS_DNS_CB(_dns_getpw, NULL) + NS_NIS_CB(_nis_getpw, NULL) + NS_COMPAT_CB(_compat_getpw, NULL) + { 0 } + }; + + r = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwuid", compatsrc, + _PW_KEYBYUID, uid); + return (r == NS_SUCCESS ? &_pw_passwd : (struct passwd *)NULL); +} - /* master.passwd doesn't exist -- try passwd.adjunct */ - if (rval == YPERR_MAP) { - rval = yp_order(_yp_domain, "passwd.adjunct.byname", &order); - if (!rval) - return(YP_HAVE_ADJUNCT); +int +setpassent(stayopen) + int stayopen; +{ + _pw_keynum = 0; + _pw_stayopen = stayopen; +#ifdef YP + __pwmode = PWMODE_NONE; + if(__ypcurrent) + free(__ypcurrent); + __ypcurrent = NULL; + _pw_ypdone = 0; +#endif +#ifdef HESIOD + _pw_hesnum = 0; +#endif +#ifdef _PASSWD_COMPAT + if(__pwexclude != (DB *)NULL) { + (void)(__pwexclude->close)(__pwexclude); + __pwexclude = (DB *)NULL; } + __pwproto = (struct passwd *)NULL; +#endif + return 1; +} - return (YP_HAVE_NONE); +void +setpwent() +{ + (void) setpassent(0); } -static int -_getyppass(struct passwd *pw, const char *name, const char *map) +void +endpwent() { - char *result, *s; - int resultlen; - int rv; - char mastermap[YPMAXRECORD]; - - if(!_pw_yp_domain) { - if(yp_get_default_domain(&_pw_yp_domain)) - return 0; + _pw_keynum = 0; + if (_pw_db) { + (void)(_pw_db->close)(_pw_db); + _pw_db = (DB *)NULL; } - - if (_gotmaster == YP_HAVE_MASTER) - snprintf(mastermap, sizeof(mastermap), "master.%s", map); - else - snprintf(mastermap, sizeof(mastermap), "%s", map); - - if(yp_match(_pw_yp_domain, (char *)&mastermap, name, strlen(name), - &result, &resultlen)) { - if (_gotmaster != YP_HAVE_MASTER) - return 0; - snprintf(mastermap, sizeof(mastermap), "%s", map); - if (yp_match(_pw_yp_domain, (char *)&mastermap, - name, strlen(name), &result, &resultlen)) - return 0; - _gotmaster = YP_HAVE_NONE; +#ifdef _PASSWD_COMPAT + __pwmode = PWMODE_NONE; +#endif +#ifdef YP + if(__ypcurrent) + free(__ypcurrent); + __ypcurrent = NULL; + _pw_ypdone = 0; +#endif +#ifdef HESIOD + _pw_hesnum = 0; +#endif +#ifdef _PASSWD_COMPAT + if(__pwexclude != (DB *)NULL) { + (void)(__pwexclude->close)(__pwexclude); + __pwexclude = (DB *)NULL; } + __pwproto = (struct passwd *)NULL; +#endif +} - if (!_pw_stepping_yp) { - s = strchr(result, ':'); - if (s) { - *s = '\0'; - } else { - /* Must be a malformed entry if no colons. */ - free(result); - return(0); - } - - if (!verf(result)) { - *s = ':'; - free(result); - return(0); - } +static int +__initdb() +{ + static int warned; + char *p; - *s = ':'; /* Put back the colon we previously replaced with a NUL. */ +#ifdef _PASSWD_COMPAT + __pwmode = PWMODE_NONE; +#endif + if (geteuid() == 0) { + _pw_db = dbopen((p = _PATH_SMP_DB), O_RDONLY, 0, DB_HASH, NULL); + if (_pw_db) + return(1); } - - rv = _pw_breakout_yp(pw, result, resultlen, _gotmaster); - free(result); - return(rv); + _pw_db = dbopen((p = _PATH_MP_DB), O_RDONLY, 0, DB_HASH, NULL); + if (_pw_db) + return 1; + if (!warned) + syslog(LOG_ERR, "%s: %m", p); + warned = 1; + return 0; } static int -_nextyppass(struct passwd *pw) +__hashpw(key) + DBT *key; { - static char *key; - static int keylen; - char *lastkey, *result, *s; - int resultlen; - int rv; - char *map = "passwd.byname"; - - if(!_pw_yp_domain) { - if(yp_get_default_domain(&_pw_yp_domain)) - return 0; - } - - if (_gotmaster == YP_HAVE_MASTER) - map = "master.passwd.byname"; + char *p, *t; + static u_int max; + static char *buf; + DBT data; - if(!_pw_stepping_yp) { - if(key) free(key); - rv = yp_first(_pw_yp_domain, map, - &key, &keylen, &result, &resultlen); - if(rv) { - return 0; - } - _pw_stepping_yp = 1; - goto unpack; - } else { -tryagain: - lastkey = key; - rv = yp_next(_pw_yp_domain, map, key, keylen, - &key, &keylen, &result, &resultlen); - free(lastkey); -unpack: - if(rv) { - _pw_stepping_yp = 0; - return 0; - } + switch ((_pw_db->get)(_pw_db, key, &data, 0)) { + case 0: + break; /* found */ + case 1: + return NS_NOTFOUND; + case -1: + return NS_UNAVAIL; /* error in db routines */ + default: + abort(); + } - s = strchr(result, ':'); - if (s) { - *s = '\0'; - } else { - /* Must be a malformed entry if no colons. */ - free(result); - goto tryagain; - } + p = (char *)data.data; + if (data.size > max && !(buf = realloc(buf, (max += 1024)))) + return NS_UNAVAIL; - if (lookup(result)) { - *s = ':'; - free(result); - goto tryagain; - } + /* THIS CODE MUST MATCH THAT IN pwd_mkdb. */ + t = buf; +#define EXPAND(e) e = t; while ((*t++ = *p++)); +#define SCALAR(v) memmove(&(v), p, sizeof v); p += sizeof v + EXPAND(_pw_passwd.pw_name); + EXPAND(_pw_passwd.pw_passwd); + SCALAR(_pw_passwd.pw_uid); + SCALAR(_pw_passwd.pw_gid); + SCALAR(_pw_passwd.pw_change); + EXPAND(_pw_passwd.pw_class); + EXPAND(_pw_passwd.pw_gecos); + EXPAND(_pw_passwd.pw_dir); + EXPAND(_pw_passwd.pw_shell); + SCALAR(_pw_passwd.pw_expire); + SCALAR(_pw_passwd.pw_fields); - *s = ':'; /* Put back the colon we previously replaced with a NUL. */ - if (_pw_breakout_yp(pw, result, resultlen, _gotmaster)) { - free(result); - return(1); - } else { - free(result); - goto tryagain; - } - } + return NS_SUCCESS; } - -#endif /* YP */ diff --git a/lib/libc/gen/getusershell.3 b/lib/libc/gen/getusershell.3 index 068c5d9d96ec1..d4924fa987b04 100644 --- a/lib/libc/gen/getusershell.3 +++ b/lib/libc/gen/getusershell.3 @@ -1,3 +1,6 @@ +.\" $NetBSD: getusershell.3,v 1.6 1999/03/22 19:44:42 garbled Exp $ +.\" $FreeBSD$ +.\" .\" Copyright (c) 1985, 1991, 1993 .\" The Regents of the University of California. All rights reserved. .\" @@ -30,16 +33,15 @@ .\" SUCH DAMAGE. .\" .\" @(#)getusershell.3 8.1 (Berkeley) 6/4/93 -.\" $FreeBSD$ .\" -.Dd June 4, 1993 +.Dd January 16, 1999 .Dt GETUSERSHELL 3 -.Os BSD 4.3 +.Os .Sh NAME .Nm getusershell , .Nm setusershell , .Nm endusershell -.Nd get legal user shells +.Nd get valid user shells .Sh LIBRARY .Lb libc .Sh SYNOPSIS @@ -54,18 +56,16 @@ The .Fn getusershell function -returns a pointer to a legal user shell as defined by the -system manager in the file -.Pa /etc/shells . -If -.Pa /etc/shells -is unreadable or does not exist, +returns a pointer to a valid user shell as defined by the +system manager in the shells database as described in +.Xr shells 5 . +If the shells database is not available, .Fn getusershell behaves as if .Pa /bin/sh and .Pa /bin/csh -were listed in the file. +were listed. .Pp The .Fn getusershell @@ -86,6 +86,7 @@ The routine returns a null pointer (0) on .Dv EOF . .Sh SEE ALSO +.Xr nsswitch.conf 5 , .Xr shells 5 .Sh HISTORY The @@ -96,7 +97,6 @@ function appeared in The .Fn getusershell function leaves its result in an internal static object and returns -a pointer to that object. -Subsequent calls to +a pointer to that object. Subsequent calls to .Fn getusershell will modify the same object. diff --git a/lib/libc/gen/getusershell.c b/lib/libc/gen/getusershell.c index be1a77ab84ad7..a852421f3b6bb 100644 --- a/lib/libc/gen/getusershell.c +++ b/lib/libc/gen/getusershell.c @@ -1,3 +1,5 @@ +/* $NetBSD: getusershell.c,v 1.17 1999/01/25 01:09:34 lukem Exp $ */ + /* * Copyright (c) 1985, 1993 * The Regents of the University of California. All rights reserved. @@ -29,111 +31,248 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * - * $FreeBSD$ */ +#include <sys/cdefs.h> #if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)getusershell.c 8.1 (Berkeley) 6/4/93"; +static char rcsid[] = + "$FreeBSD$"; #endif /* LIBC_SCCS and not lint */ #include <sys/param.h> #include <sys/file.h> -#include <sys/stat.h> -#include <stdio.h> + #include <ctype.h> +#include <errno.h> +#include <nsswitch.h> +#include <paths.h> +#include <stdio.h> #include <stdlib.h> +#include <string.h> +#include <stringlist.h> #include <unistd.h> -#include <paths.h> + +#ifdef HESIOD +#include <hesiod.h> +#endif +#ifdef YP +#include <rpc/rpc.h> +#include <rpcsvc/ypclnt.h> +#include <rpcsvc/yp_prot.h> +#endif /* * Local shells should NOT be added here. They should be added in * /etc/shells. */ -static char *okshells[] = { _PATH_BSHELL, _PATH_CSHELL, NULL }; -static char **curshell, **shells, *strings; -static char **initshells __P((void)); +static const char *const okshells[] = { _PATH_BSHELL, _PATH_CSHELL, NULL }; +static const char *const *curshell; +static StringList *sl; + +static const char *const *initshells __P((void)); /* - * Get a list of shells from _PATH_SHELLS, if it exists. + * Get a list of shells from "shells" nsswitch database */ char * -getusershell() +getusershell(void) { char *ret; if (curshell == NULL) curshell = initshells(); - ret = *curshell; + /*LINTED*/ + ret = (char *)*curshell; if (ret != NULL) curshell++; return (ret); } void -endusershell() +endusershell(void) { - - if (shells != NULL) - free(shells); - shells = NULL; - if (strings != NULL) - free(strings); - strings = NULL; + if (sl) + sl_free(sl, 1); + sl = NULL; curshell = NULL; } void -setusershell() +setusershell(void) { curshell = initshells(); } -static char ** -initshells() + +static int _local_initshells __P((void *, void *, va_list)); + +/*ARGSUSED*/ +static int +_local_initshells(rv, cb_data, ap) + void *rv; + void *cb_data; + va_list ap; { - register char **sp, *cp; - register FILE *fp; - struct stat statb; - - if (shells != NULL) - free(shells); - shells = NULL; - if (strings != NULL) - free(strings); - strings = NULL; + char *sp, *cp; + FILE *fp; + char line[MAXPATHLEN + 2]; + + if (sl) + sl_free(sl, 1); + sl = sl_init(); + if ((fp = fopen(_PATH_SHELLS, "r")) == NULL) - return (okshells); - if (fstat(fileno(fp), &statb) == -1) { - (void)fclose(fp); - return (okshells); - } - if ((strings = malloc((u_int)statb.st_size)) == NULL) { - (void)fclose(fp); - return (okshells); - } - shells = calloc((unsigned)statb.st_size / 3, sizeof (char *)); - if (shells == NULL) { - (void)fclose(fp); - free(strings); - strings = NULL; - return (okshells); - } - sp = shells; - cp = strings; + return NS_UNAVAIL; + + sp = cp = line; while (fgets(cp, MAXPATHLEN + 1, fp) != NULL) { while (*cp != '#' && *cp != '/' && *cp != '\0') cp++; if (*cp == '#' || *cp == '\0') continue; - *sp++ = cp; - while (!isspace((unsigned char)*cp) && *cp != '#' && *cp != '\0') + sp = cp; + while (!isspace(*cp) && *cp != '#' && *cp != '\0') cp++; *cp++ = '\0'; + sl_add(sl, strdup(sp)); } - *sp = NULL; (void)fclose(fp); - return (shells); + return NS_SUCCESS; +} + +#ifdef HESIOD +static int _dns_initshells __P((void *, void *, va_list)); + +/*ARGSUSED*/ +static int +_dns_initshells(rv, cb_data, ap) + void *rv; + void *cb_data; + va_list ap; +{ + char shellname[] = "shells-XXXXX"; + int hsindex, hpi, r; + char **hp; + void *context; + + if (sl) + sl_free(sl, 1); + sl = sl_init(); + r = NS_UNAVAIL; + if (hesiod_init(&context) == -1) + return (r); + + for (hsindex = 0; ; hsindex++) { + snprintf(shellname, sizeof(shellname)-1, "shells-%d", hsindex); + hp = hesiod_resolve(context, shellname, "shells"); + if (hp == NULL) { + if (errno == ENOENT) { + if (hsindex == 0) + r = NS_NOTFOUND; + else + r = NS_SUCCESS; + } + break; + } else { + for (hpi = 0; hp[hpi]; hpi++) + sl_add(sl, hp[hpi]); + free(hp); + } + } + hesiod_end(context); + return (r); +} +#endif /* HESIOD */ + +#ifdef YP +static int _nis_initshells __P((void *, void *, va_list)); + +/*ARGSUSED*/ +static int +_nis_initshells(rv, cb_data, ap) + void *rv; + void *cb_data; + va_list ap; +{ + static char *ypdomain; + + if (sl) + sl_free(sl, 1); + sl = sl_init(); + + if (ypdomain == NULL) { + switch (yp_get_default_domain(&ypdomain)) { + case 0: + break; + case YPERR_RESRC: + return NS_TRYAGAIN; + default: + return NS_UNAVAIL; + } + } + + for (;;) { + char *ypcur = NULL; + int ypcurlen = 0; /* XXX: GCC */ + char *key, *data; + int keylen, datalen; + int r; + + key = data = NULL; + if (ypcur) { + r = yp_next(ypdomain, "shells", ypcur, ypcurlen, + &key, &keylen, &data, &datalen); + free(ypcur); + switch (r) { + case 0: + break; + case YPERR_NOMORE: + free(key); + free(data); + return NS_SUCCESS; + default: + free(key); + free(data); + return NS_UNAVAIL; + } + ypcur = key; + ypcurlen = keylen; + } else { + if (yp_first(ypdomain, "shells", &ypcur, + &ypcurlen, &data, &datalen)) { + free(data); + return NS_UNAVAIL; + } + } + data[datalen] = '\0'; /* clear trailing \n */ + sl_add(sl, data); + } +} +#endif /* YP */ + +static const char *const * +initshells() +{ + static const ns_dtab dtab[] = { + NS_FILES_CB(_local_initshells, NULL) + NS_DNS_CB(_dns_initshells, NULL) + NS_NIS_CB(_nis_initshells, NULL) + { 0 } + }; + if (sl) + sl_free(sl, 1); + sl = sl_init(); + + if (nsdispatch(NULL, dtab, NSDB_SHELLS, "initshells", __nsdefaultsrc) + != NS_SUCCESS) { + if (sl) + sl_free(sl, 1); + sl = NULL; + return (okshells); + } + sl_add(sl, NULL); + + return (const char *const *)(sl->sl_str); } diff --git a/lib/libc/gen/pw_scan.c b/lib/libc/gen/pw_scan.c index d0fb5f17d0351..3ecb9e0ac07a8 100644 --- a/lib/libc/gen/pw_scan.c +++ b/lib/libc/gen/pw_scan.c @@ -66,12 +66,10 @@ static const char rcsid[] = * it will be set based on the existance of PW_SCAN_BIG_IDS in the * environment. */ -int pw_big_ids_warning = -1; +static int pw_big_ids_warning = -1; int -pw_scan(bp, pw) - char *bp; - struct passwd *pw; +__pw_scan(char *bp, struct passwd *pw, int flags) { uid_t id; int root; @@ -97,20 +95,23 @@ pw_scan(bp, pw) pw->pw_fields |= _PWF_UID; else { if (pw->pw_name[0] != '+' && pw->pw_name[0] != '-') { - warnx("no uid for user %s", pw->pw_name); + if (flags & _PWSCAN_WARN) + warnx("no uid for user %s", pw->pw_name); return (0); } } id = strtoul(p, (char **)NULL, 10); if (errno == ERANGE) { - warnx("%s > max uid value (%u)", p, ULONG_MAX); + if (flags & _PWSCAN_WARN) + warnx("%s > max uid value (%u)", p, ULONG_MAX); return (0); } if (root && id) { - warnx("root uid should be 0"); + if (flags & _PWSCAN_WARN) + warnx("root uid should be 0"); return (0); } - if (pw_big_ids_warning && id > USHRT_MAX) { + if (flags & _PWSCAN_WARN && pw_big_ids_warning && id > USHRT_MAX) { warnx("%s > recommended max uid value (%u)", p, USHRT_MAX); /*return (0);*/ /* THIS SHOULD NOT BE FATAL! */ } @@ -121,28 +122,30 @@ pw_scan(bp, pw) if(p[0]) pw->pw_fields |= _PWF_GID; id = strtoul(p, (char **)NULL, 10); if (errno == ERANGE) { - warnx("%s > max gid value (%u)", p, ULONG_MAX); + if (flags & _PWSCAN_WARN) + warnx("%s > max gid value (%u)", p, ULONG_MAX); return (0); } - if (pw_big_ids_warning && id > USHRT_MAX) { + if (flags & _PWSCAN_WARN && pw_big_ids_warning && id > USHRT_MAX) { warnx("%s > recommended max gid value (%u)", p, USHRT_MAX); /* return (0); This should not be fatal! */ } pw->pw_gid = id; - pw->pw_class = strsep(&bp, ":"); /* class */ - if(pw->pw_class[0]) pw->pw_fields |= _PWF_CLASS; - - if (!(p = strsep(&bp, ":"))) /* change */ - goto fmt; - if(p[0]) pw->pw_fields |= _PWF_CHANGE; - pw->pw_change = atol(p); - - if (!(p = strsep(&bp, ":"))) /* expire */ - goto fmt; - if(p[0]) pw->pw_fields |= _PWF_EXPIRE; - pw->pw_expire = atol(p); - + if (flags & _PWSCAN_MASTER ) { + pw->pw_class = strsep(&bp, ":"); /* class */ + if(pw->pw_class[0]) pw->pw_fields |= _PWF_CLASS; + + if (!(p = strsep(&bp, ":"))) /* change */ + goto fmt; + if(p[0]) pw->pw_fields |= _PWF_CHANGE; + pw->pw_change = atol(p); + + if (!(p = strsep(&bp, ":"))) /* expire */ + goto fmt; + if(p[0]) pw->pw_fields |= _PWF_EXPIRE; + pw->pw_expire = atol(p); + } if (!(pw->pw_gecos = strsep(&bp, ":"))) /* gecos */ goto fmt; if(pw->pw_gecos[0]) pw->pw_fields |= _PWF_GECOS; @@ -158,7 +161,8 @@ pw_scan(bp, pw) if (root && *p) /* empty == /bin/sh */ for (setusershell();;) { if (!(sh = getusershell())) { - warnx("warning, unknown root shell"); + if (flags & _PWSCAN_WARN) + warnx("warning, unknown root shell"); break; } if (!strcmp(p, sh)) @@ -167,7 +171,9 @@ pw_scan(bp, pw) if(p[0]) pw->pw_fields |= _PWF_SHELL; if ((p = strsep(&bp, ":"))) { /* too many */ -fmt: warnx("corrupted entry"); +fmt: + if (flags & _PWSCAN_WARN) + warnx("corrupted entry"); return (0); } return (1); diff --git a/lib/libc/gen/pw_scan.h b/lib/libc/gen/pw_scan.h index 2519bd45db019..3bc62010a871a 100644 --- a/lib/libc/gen/pw_scan.h +++ b/lib/libc/gen/pw_scan.h @@ -35,6 +35,7 @@ * $FreeBSD$ */ -extern int pw_big_ids_warning; +#define _PWSCAN_MASTER 0x01 +#define _PWSCAN_WARN 0x02 -extern int pw_scan __P((char *, struct passwd *)); +extern int __pw_scan __P((char *, struct passwd *, int)); |