diff options
-rw-r--r-- | lib/libc/gen/Makefile.inc | 3 | ||||
-rw-r--r-- | lib/libc/gen/getpwent.3 | 34 | ||||
-rw-r--r-- | lib/libc/gen/getpwent.c | 872 | ||||
-rw-r--r-- | usr.bin/chpass/Makefile | 4 | ||||
-rw-r--r-- | usr.bin/passwd/Makefile | 4 |
5 files changed, 441 insertions, 476 deletions
diff --git a/lib/libc/gen/Makefile.inc b/lib/libc/gen/Makefile.inc index 8db506298ff..e60c1bd8f2f 100644 --- a/lib/libc/gen/Makefile.inc +++ b/lib/libc/gen/Makefile.inc @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile.inc,v 1.40 2008/03/22 19:18:42 otto Exp $ +# $OpenBSD: Makefile.inc,v 1.41 2008/06/24 14:27:24 deraadt Exp $ # gen sources .PATH: ${LIBCSRCDIR}/arch/${MACHINE_ARCH}/gen ${LIBCSRCDIR}/gen @@ -105,6 +105,7 @@ MLINKS+=getnetgrent.3 endnetgrent.3 getnetgrent.3 innetgr.3 \ getnetgrent.3 setnetgrent.3 MLINKS+=getpwent.3 endpwent.3 getpwent.3 setpassent.3 getpwent.3 getpwnam.3 \ getpwent.3 getpwuid.3 getpwent.3 setpwent.3 getpwent.3 setpwfile.3 +MLINKS+=getpwent.3 getpwnam_r.3 getpwent.3 getpwuid_r.3 MLINKS+=getttyent.3 endttyent.3 getttyent.3 getttynam.3 getttyent.3 setttyent.3 MLINKS+=getusershell.3 endusershell.3 getusershell.3 setusershell.3 MLINKS+=glob.3 globfree.3 diff --git a/lib/libc/gen/getpwent.3 b/lib/libc/gen/getpwent.3 index 86d2565607a..c2a1d733743 100644 --- a/lib/libc/gen/getpwent.3 +++ b/lib/libc/gen/getpwent.3 @@ -1,4 +1,4 @@ -.\" $OpenBSD: getpwent.3,v 1.21 2007/05/31 19:19:28 jmc Exp $ +.\" $OpenBSD: getpwent.3,v 1.22 2008/06/24 14:27:24 deraadt Exp $ .\" .\" Copyright (c) 1988, 1991, 1993 .\" The Regents of the University of California. All rights reserved. @@ -27,13 +27,15 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd $Mdocdate: May 31 2007 $ +.Dd $Mdocdate: June 24 2008 $ .Dt GETPWENT 3 .Os .Sh NAME .Nm getpwent , .Nm getpwnam , .Nm getpwuid , +.Nm getpwnam_r , +.Nm getpwuid_r , .Nm setpassent , .Nm setpwent , .Nm endpwent @@ -48,6 +50,10 @@ .Ft struct passwd * .Fn getpwuid "uid_t uid" .Ft int +.Fn getpwnam_r "const char *login" "struct passwd *pwstore" "char *buf" "size_t buflen" "struct passwd **result" +.Ft int +.Fn getpwuid_r "uid_t uid" "struct passwd *pwstore" "char *buf" "size_t buflen" "struct passwd **result" +.Ft int .Fn setpassent "int stayopen" .Ft void .Fn setpwent void @@ -82,6 +88,18 @@ and search the password database for the given login name or user ID, respectively, always returning the first one encountered. .Pp +The re-entrant functions +.Fn getpwnam_r +and +.Fn getpwuid_r +search the password database for the given login name or user ID, +respectively, always returning the first one encountered. +The various strings associated with the result are stored in +.Va buf , +and +.Va pwstore +is updated to point at those strings. +.Pp .Fn getpwent sequentially reads the password database and is intended for programs that wish to process the complete list of users. @@ -131,6 +149,17 @@ and .Fn getpwuid return a valid pointer to a passwd structure on success or a null pointer if end-of-file is reached or an error occurs. +.Pp +The functions +.Fn getpwnam_r +and +.Fn getpwuid_r +update +.Va result +to point to +.Va pwstore +and then return 0 on success. +.Pp The .Fn setpassent function returns 0 on failure or 1 on success. @@ -153,6 +182,7 @@ a Version 7 format password file .Sh SEE ALSO .Xr getlogin 2 , .Xr getgrent 3 , +.Xr getgrouplist 3 , .Xr pw_dup 3 , .Xr passwd 5 , .Xr pwd_mkdb 8 , diff --git a/lib/libc/gen/getpwent.c b/lib/libc/gen/getpwent.c index 5a2e9b1d8ed..38c0b9425f4 100644 --- a/lib/libc/gen/getpwent.c +++ b/lib/libc/gen/getpwent.c @@ -1,5 +1,6 @@ -/* $OpenBSD: getpwent.c,v 1.34 2005/08/08 08:05:34 espie Exp $ */ +/* $OpenBSD: getpwent.c,v 1.35 2008/06/24 14:27:24 deraadt Exp $ */ /* + * Copyright (c) 2008 Theo de Raadt * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * Portions Copyright (c) 1994, 1995, 1996, Jason Downs. All rights reserved. @@ -48,53 +49,69 @@ #include <rpcsvc/ypclnt.h> #include "ypinternal.h" #endif +#include "thread_private.h" + +_THREAD_PRIVATE_KEY(pw); -static struct passwd _pw_passwd; /* password structure */ static DB *_pw_db; /* password database */ + +/* Following are used only by setpwent(), getpwent(), and endpwent() */ +static struct passwd _pw_passwd; /* password structure */ +static char _pw_string[1024]; /* string pointed to by _pw_passwd */ static int _pw_keynum; /* key counter */ static int _pw_stayopen; /* keep fd's open */ static int _pw_flags; /* password flags */ -static int __hashpw(DBT *); -static int __initdb(void); + +static int __hashpw(DBT *, char *buf, size_t buflen, struct passwd *, int *); +static int __initdb(); +static struct passwd *_pwhashbyname(const char *name, char *buf, + size_t buflen, struct passwd *pw, int *); +static struct passwd *_pwhashbyuid(uid_t uid, char *buf, + size_t buflen, struct passwd *pw, int *); #ifdef YP -enum _ypmode { YPMODE_NONE, YPMODE_FULL, YPMODE_USER, YPMODE_NETGRP }; -static enum _ypmode __ypmode; +static char *__ypdomain; -static char *__ypcurrent, *__ypdomain; +struct _ypexclude { + const char *name; + struct _ypexclude *next; +}; + +/* Following are used only by setpwent(), getpwent(), and endpwent() */ +enum _ypmode { YPMODE_NONE, YPMODE_FULL, YPMODE_USER, YPMODE_NETGRP }; +static enum _ypmode __ypmode; +static char *__ypcurrent; static int __ypcurrentlen; -static struct passwd *__ypproto = (struct passwd *)NULL; -static int __ypflags; +static int __yp_pw_flags; +static struct passwd *__ypproto; static char __ypline[1024]; -static long __yppbuf[1024 / sizeof(long)]; -static int __yp_override_passwd = 0; +static int __getpwent_has_yppw = -1; +static struct _ypexclude *__ypexhead; -static int __has_yppw(void); +static int __has_yppw(); static int __has_ypmaster(void); +static int __ypexclude_add(struct _ypexclude **, const char *); +static int __ypexclude_is(struct _ypexclude **, const char *); +static void __ypexclude_free(struct _ypexclude **); +static void __ypproto_set(struct passwd *, long *, int, int *); +static int __ypparse(struct passwd *pw, char *s, int); -static int __ypexclude_add(const char *); -static int __ypexclude_is(const char *); -static void __ypexclude_free(void); -static void __ypproto_set(void); -static int __ypparse(struct passwd *pw, char *s); +#define LOOKUP_BYNAME 0 +#define LOOKUP_BYUID 1 +static struct passwd *__yppwlookup(int, char *, uid_t, struct passwd *, + char *, size_t, int *); /* macro for deciding which YP maps to use. */ #define PASSWD_BYNAME \ - __has_ypmaster() ? "master.passwd.byname" : "passwd.byname" + (__has_ypmaster() ? "master.passwd.byname" : "passwd.byname") #define PASSWD_BYUID \ - __has_ypmaster() ? "master.passwd.byuid" : "passwd.byuid" - -struct _ypexclude { - const char *name; - struct _ypexclude *next; -}; -static struct _ypexclude *__ypexclude = (struct _ypexclude *)NULL; + (__has_ypmaster() ? "master.passwd.byuid" : "passwd.byuid") /* * Using DB for this just wastes too damn much memory. */ static int -__ypexclude_add(const char *name) +__ypexclude_add(struct _ypexclude **headp, const char *name) { struct _ypexclude *new; @@ -105,24 +122,22 @@ __ypexclude_add(const char *name) if (new == NULL) return (1); new->name = strdup(name); - if (new->name == (char *)NULL) { + if (new->name == NULL) { free(new); return (1); } - new->next = __ypexclude; - __ypexclude = new; - + new->next = *headp; + *headp = new; return (0); } static int -__ypexclude_is(const char *name) +__ypexclude_is(struct _ypexclude **headp, const char *name) { struct _ypexclude *curr; - for (curr = __ypexclude; curr != (struct _ypexclude *)NULL; - curr = curr->next) { + for (curr = *headp; curr; curr = curr->next) { if (strcmp(curr->name, name) == 0) return (1); /* excluded */ } @@ -130,28 +145,25 @@ __ypexclude_is(const char *name) } static void -__ypexclude_free(void) +__ypexclude_free(struct _ypexclude **headp) { struct _ypexclude *curr, *next; - for (curr = __ypexclude; curr != (struct _ypexclude *)NULL; - curr = next) { + for (curr = *headp; curr; curr = next) { next = curr->next; - free((void *)curr->name); free(curr); } - __ypexclude = (struct _ypexclude *)NULL; + *headp = NULL; } static void -__ypproto_set(void) +__ypproto_set(struct passwd *pw, long *buf, int flags, int *yp_pw_flagsp) { char *ptr; - struct passwd *pw = &_pw_passwd; /* make this the new prototype */ - ptr = (char *)__yppbuf; + ptr = (char *)buf; /* first allocate the struct. */ __ypproto = (struct passwd *)ptr; @@ -164,7 +176,7 @@ __ypproto_set(void) __ypproto->pw_name = ptr; ptr += (strlen(pw->pw_name) + 1); } else - __ypproto->pw_name = (char *)NULL; + __ypproto->pw_name = NULL; /* password */ if (pw->pw_passwd && (pw->pw_passwd)[0]) { @@ -173,7 +185,7 @@ __ypproto_set(void) __ypproto->pw_passwd = ptr; ptr += (strlen(pw->pw_passwd) + 1); } else - __ypproto->pw_passwd = (char *)NULL; + __ypproto->pw_passwd = NULL; /* uid */ __ypproto->pw_uid = pw->pw_uid; @@ -194,7 +206,7 @@ __ypproto_set(void) __ypproto->pw_gecos = ptr; ptr += (strlen(pw->pw_gecos) + 1); } else - __ypproto->pw_gecos = (char *)NULL; + __ypproto->pw_gecos = NULL; /* dir */ if (pw->pw_dir && (pw->pw_dir)[0]) { @@ -203,7 +215,7 @@ __ypproto_set(void) __ypproto->pw_dir = ptr; ptr += (strlen(pw->pw_dir) + 1); } else - __ypproto->pw_dir = (char *)NULL; + __ypproto->pw_dir = NULL; /* shell */ if (pw->pw_shell && (pw->pw_shell)[0]) { @@ -212,17 +224,17 @@ __ypproto_set(void) __ypproto->pw_shell = ptr; ptr += (strlen(pw->pw_shell) + 1); } else - __ypproto->pw_shell = (char *)NULL; + __ypproto->pw_shell = NULL; /* expire (ignored anyway) */ __ypproto->pw_expire = pw->pw_expire; /* flags */ - __ypflags = _pw_flags; + *yp_pw_flagsp = flags; } static int -__ypparse(struct passwd *pw, char *s) +__ypparse(struct passwd *pw, char *s, int yp_pw_flags) { char *bp, *cp, *endp; u_long ul; @@ -240,16 +252,16 @@ __ypparse(struct passwd *pw, char *s) pw->pw_name = strsep(&bp, ":\n"); pw->pw_passwd = strsep(&bp, ":\n"); if (!(cp = strsep(&bp, ":\n"))) - return 1; + return (1); ul = strtoul(cp, &endp, 10); if (endp == cp || *endp != '\0' || ul >= UID_MAX) - return 1; + return (1); pw->pw_uid = (uid_t)ul; if (!(cp = strsep(&bp, ":\n"))) - return 1; + return (1); ul = strtoul(cp, &endp, 10); if (endp == cp || *endp != '\0' || ul >= GID_MAX) - return 1; + return (1); pw->pw_gid = (gid_t)ul; if (count == 9) { long l; @@ -257,16 +269,16 @@ __ypparse(struct passwd *pw, char *s) /* If the ypserv gave us all the fields, use them. */ pw->pw_class = strsep(&bp, ":\n"); if (!(cp = strsep(&bp, ":\n"))) - return 1; + return (1); l = strtol(cp, &endp, 10); if (endp == cp || *endp != '\0' || l >= INT_MAX || l <= INT_MIN) - return 1; + return (1); pw->pw_change = (time_t)l; if (!(cp = strsep(&bp, ":\n"))) - return 1; + return (1); l = strtol(cp, &endp, 10); if (endp == cp || *endp != '\0' || l >= INT_MAX || l <= INT_MIN) - return 1; + return (1); pw->pw_expire = (time_t)l; } else { /* ..else it is a normal ypserv. */ @@ -279,50 +291,48 @@ __ypparse(struct passwd *pw, char *s) pw->pw_shell = strsep(&bp, ":\n"); /* now let the prototype override, if set. */ - if (__ypproto != (struct passwd *)NULL) { - if (__yp_override_passwd && __ypproto->pw_passwd != (char *)NULL) - pw->pw_passwd = __ypproto->pw_passwd; - if (!(__ypflags & _PASSWORD_NOUID)) + if (__ypproto) { + if (!(yp_pw_flags & _PASSWORD_NOUID)) pw->pw_uid = __ypproto->pw_uid; - if (!(__ypflags & _PASSWORD_NOGID)) + if (!(yp_pw_flags & _PASSWORD_NOGID)) pw->pw_gid = __ypproto->pw_gid; - if (__ypproto->pw_gecos != (char *)NULL) + if (__ypproto->pw_gecos) pw->pw_gecos = __ypproto->pw_gecos; - if (__ypproto->pw_dir != (char *)NULL) + if (__ypproto->pw_dir) pw->pw_dir = __ypproto->pw_dir; - if (__ypproto->pw_shell != (char *)NULL) + if (__ypproto->pw_shell) pw->pw_shell = __ypproto->pw_shell; } - return 0; + return (0); } #endif -#ifdef YP -static int __getpwent_has_yppw = -1; -#endif - struct passwd * getpwent(void) { - DBT key; - char bf[sizeof(_pw_keynum) + 1]; #ifdef YP - static char *name = (char *)NULL; - const char *user, *host, *dom; + static char *name = NULL; + char *map; #endif + char bf[1 + sizeof(_pw_keynum)], pwbuf[1024]; + struct passwd *pw = NULL; + DBT key; + _THREAD_PRIVATE_MUTEX_LOCK(pw); if (!_pw_db && !__initdb()) - return ((struct passwd *)NULL); + goto done; #ifdef YP + map = PASSWD_BYNAME; + if (__getpwent_has_yppw == -1) __getpwent_has_yppw = __has_yppw(); again: if (__getpwent_has_yppw && (__ypmode != YPMODE_NONE)) { + const char *user, *host, *dom; + int keylen, datalen, r, s; char *key, *data; - int keylen, datalen; - int r, s; if (!__ypdomain) { if (_yp_check(&__ypdomain) == 0) { @@ -333,12 +343,12 @@ again: switch (__ypmode) { case YPMODE_FULL: if (__ypcurrent) { - r = yp_next(__ypdomain, (PASSWD_BYNAME), + r = yp_next(__ypdomain, map, __ypcurrent, __ypcurrentlen, &key, &keylen, &data, &datalen); free(__ypcurrent); + __ypcurrent = NULL; if (r != 0) { - __ypcurrent = NULL; __ypmode = YPMODE_NONE; if (data) free(data); @@ -347,23 +357,21 @@ again: } __ypcurrent = key; __ypcurrentlen = keylen; - bcopy(data, __ypline, datalen); - free(data); - data = NULL; } else { - r = yp_first(__ypdomain, (PASSWD_BYNAME), + r = yp_first(__ypdomain, map, &__ypcurrent, &__ypcurrentlen, &data, &datalen); - if (r != 0) { + if (r != 0 || + __ypcurrentlen > sizeof(__ypline)) { __ypmode = YPMODE_NONE; if (data) free(data); goto again; } - bcopy(data, __ypline, datalen); - free(data); - data = NULL; } + bcopy(data, __ypline, datalen); + free(data); + data = NULL; break; case YPMODE_NETGRP: s = getnetgrent(&host, &user, &dom); @@ -373,12 +381,12 @@ again: goto again; } if (user && *user) { - r = yp_match(__ypdomain, (PASSWD_BYNAME), - user, strlen(user), - &data, &datalen); + r = yp_match(__ypdomain, map, + user, strlen(user), &data, &datalen); } else goto again; - if (r != 0) { + if (r != 0 || + __ypcurrentlen > sizeof(__ypline)) { /* * if the netgroup is invalid, keep looking * as there may be valid users later on. @@ -389,24 +397,24 @@ again: } bcopy(data, __ypline, datalen); free(data); - data = (char *)NULL; + data = NULL; break; case YPMODE_USER: - if (name != (char *)NULL) { - r = yp_match(__ypdomain, (PASSWD_BYNAME), - name, strlen(name), - &data, &datalen); + if (name) { + r = yp_match(__ypdomain, map, + name, strlen(name), &data, &datalen); __ypmode = YPMODE_NONE; free(name); - name = (char *)NULL; - if (r != 0) { + name = NULL; + if (r != 0 || + __ypcurrentlen > sizeof(__ypline)) { if (data) free(data); goto again; } bcopy(data, __ypline, datalen); free(data); - data = (char *)NULL; + data = NULL; } else { /* XXX */ __ypmode = YPMODE_NONE; goto again; @@ -418,19 +426,23 @@ again: } __ypline[datalen] = '\0'; - if (__ypparse(&_pw_passwd, __ypline)) + if (__ypparse(&_pw_passwd, __ypline, __yp_pw_flags)) goto again; - return &_pw_passwd; + pw = &_pw_passwd; + goto done; } #endif ++_pw_keynum; bf[0] = _PW_KEYBYNUM; - bcopy((char *)&_pw_keynum, bf + 1, sizeof(_pw_keynum)); + bcopy((char *)&_pw_keynum, &bf[1], sizeof(_pw_keynum)); key.data = (u_char *)bf; - key.size = sizeof(_pw_keynum) + 1; - if (__hashpw(&key)) { + key.size = 1 + sizeof(_pw_keynum); + if (__hashpw(&key, pwbuf, sizeof pwbuf, &_pw_passwd, &_pw_flags)) { #ifdef YP + static long __yppbuf[1024 / sizeof(long)]; + const char *user, *host, *dom; + /* if we don't have YP at all, don't bother. */ if (__getpwent_has_yppw) { if (_pw_passwd.pw_name[0] == '+') { @@ -449,8 +461,8 @@ again: break; } - /* save the prototype */ - __ypproto_set(); + __ypproto_set(&_pw_passwd, __yppbuf, + _pw_flags, &__yp_pw_flags); goto again; } else if (_pw_passwd.pw_name[0] == '-') { /* an attempted exclusion */ @@ -461,25 +473,30 @@ again: setnetgrent(_pw_passwd.pw_name + 2); while (getnetgrent(&host, &user, &dom)) { if (user && *user) - __ypexclude_add(user); + __ypexclude_add(&__ypexhead, + user); } endnetgrent(); break; default: - __ypexclude_add(_pw_passwd.pw_name + 1); + __ypexclude_add(&__ypexhead, + _pw_passwd.pw_name + 1); break; } goto again; } } #endif - return &_pw_passwd; + pw = &_pw_passwd; + goto done; } - return (struct passwd *)NULL; + +done: + _THREAD_PRIVATE_MUTEX_UNLOCK(pw); + return (pw); } #ifdef YP - /* * See if the YP token is in the database. Only works if pwd_mkdb knows * about the token. @@ -487,10 +504,9 @@ again: static int __has_yppw(void) { - DBT key, data; - DBT pkey, pdata; + DBT key, data, pkey, pdata; + char bf[1 + _PW_NAME_LEN]; int len; - char bf[_PW_NAME_LEN + 1]; key.data = (u_char *)_PW_YPTOKEN; key.size = strlen(_PW_YPTOKEN); @@ -498,9 +514,9 @@ __has_yppw(void) /* Pre-token database support. */ bf[0] = _PW_KEYBYNAME; len = strlen("+"); - bcopy("+", bf + 1, MIN(len, _PW_NAME_LEN)); + bcopy("+", &bf[1], MIN(len, _PW_NAME_LEN)); pkey.data = (u_char *)bf; - pkey.size = MIN(len, _PW_NAME_LEN) + 1; + pkey.size = 1 + MIN(len, _PW_NAME_LEN); if ((_pw_db->get)(_pw_db, &key, &data, 0) && (_pw_db->get)(_pw_db, &pkey, &pdata, 0)) @@ -509,8 +525,7 @@ __has_yppw(void) } /* - * See if there's a FreeBSD-style master.passwd map set. From the FreeBSD - * libc code. + * See if there's a master.passwd map. */ static int __has_ypmaster(void) @@ -551,370 +566,300 @@ __has_ypmaster(void) checked = 0; return (checked); } - free (result); + free(result); + if (key) + free(key); saved_uid = uid; saved_euid = euid; checked = 1; return (checked); } -#endif -struct passwd * -getpwnam(const char *name) +static struct passwd * +__yppwlookup(int lookup, char *name, uid_t uid, struct passwd *pw, + char *buf, size_t buflen, int *flagsp) { + char bf[1 + _PW_NAME_LEN], *ypcurrent = NULL, *map; + int yp_pw_flags = 0, ypcurrentlen, r, s = -1, pw_keynum; + static long yppbuf[1024 / sizeof(long)]; + struct _ypexclude *ypexhead = NULL; + const char *host, *user, *dom; DBT key; - int len, rval; - char bf[_PW_NAME_LEN + 1]; - if (!_pw_db && !__initdb()) - return ((struct passwd *)NULL); + if (lookup == LOOKUP_BYNAME) { + map = PASSWD_BYNAME; + name = strdup(name); + } else { + map = PASSWD_BYUID; + asprintf(&name, "%u", uid); + } -#ifdef YP - /* - * If YP is active, we must sequence through the passwd file - * in sequence. - */ - if (__has_yppw()) { - int r; - int s = -1; - const char *host, *user, *dom; - - for (_pw_keynum=1; _pw_keynum; _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; - if (__hashpw(&key) == 0) - break; - switch (_pw_passwd.pw_name[0]) { - case '+': - if (!__ypdomain) { - if (_yp_check(&__ypdomain) == 0) { - continue; - } - } - /* save the prototype */ - __ypproto_set(); + for (pw_keynum = 1; pw_keynum; pw_keynum++) { + bf[0] = _PW_KEYBYNUM; + bcopy((char *)&pw_keynum, &bf[1], sizeof(pw_keynum)); + key.data = (u_char *)bf; + key.size = 1 + sizeof(pw_keynum); + if (__hashpw(&key, buf, buflen, pw, flagsp) == 0) + break; + switch (pw->pw_name[0]) { + case '+': + if (!__ypdomain) { + if (_yp_check(&__ypdomain) == 0) + continue; + } + __ypproto_set(pw, yppbuf, *flagsp, &yp_pw_flags); - switch (_pw_passwd.pw_name[1]) { - case '\0': - if (__ypcurrent) { - free(__ypcurrent); - __ypcurrent = NULL; - } - r = yp_match(__ypdomain, - (PASSWD_BYNAME), - name, strlen(name), - &__ypcurrent, &__ypcurrentlen); - if (r != 0) { - if (__ypcurrent) - free(__ypcurrent); - __ypcurrent = NULL; - continue; - } - break; - case '@': -pwnam_netgrp: - if (__ypcurrent) { - free(__ypcurrent); - __ypcurrent = NULL; - } - 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; - } else { - if (user && *user) { - r = yp_match(__ypdomain, - (PASSWD_BYNAME), - user, strlen(user), - &__ypcurrent, - &__ypcurrentlen); - } else - goto pwnam_netgrp; - if (r != 0) { - if (__ypcurrent) - free(__ypcurrent); - __ypcurrent = NULL; - /* - * just because this - * user is bad, doesn't - * mean they all are. - */ - goto pwnam_netgrp; - } - } - break; - default: - if (__ypcurrent) { - free(__ypcurrent); - __ypcurrent = NULL; - } - user = _pw_passwd.pw_name + 1; - r = yp_match(__ypdomain, - (PASSWD_BYNAME), - user, strlen(user), - &__ypcurrent, - &__ypcurrentlen); - if (r != 0) { - if (__ypcurrent) - free(__ypcurrent); - __ypcurrent = NULL; - continue; - } - break; + switch (pw->pw_name[1]) { + case '\0': + if (ypcurrent) { + free(ypcurrent); + ypcurrent = NULL; } - bcopy(__ypcurrent, __ypline, __ypcurrentlen); - __ypline[__ypcurrentlen] = '\0'; - if (__ypparse(&_pw_passwd, __ypline) - || __ypexclude_is(_pw_passwd.pw_name)) { - if (s == 1) /* inside netgrp */ - goto pwnam_netgrp; + r = yp_match(__ypdomain, map, + name, strlen(name), + &ypcurrent, &ypcurrentlen); + if (r != 0 || ypcurrentlen > buflen) { + if (ypcurrent) + free(ypcurrent); + ypcurrent = NULL; 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) - __ypexclude_add(user); - } + case '@': +pwnam_netgrp: + if (ypcurrent) { + free(ypcurrent); + ypcurrent = NULL; + } + if (s == -1) /* first time */ + setnetgrent(pw->pw_name + 2); + s = getnetgrent(&host, &user, &dom); + if (s == 0) { /* end of group */ endnetgrent(); - break; - default: - __ypexclude_add(_pw_passwd.pw_name + 1); - break; + s = -1; + continue; + } else { + if (user && *user) { + r = yp_match(__ypdomain, map, + user, strlen(user), + &ypcurrent, &ypcurrentlen); + } else + goto pwnam_netgrp; + if (r != 0 || ypcurrentlen > buflen) { + if (ypcurrent) + free(ypcurrent); + ypcurrent = NULL; + /* + * just because this + * user is bad, doesn't + * mean they all are. + */ + goto pwnam_netgrp; + } } break; + default: + if (ypcurrent) { + free(ypcurrent); + ypcurrent = NULL; + } + user = pw->pw_name + 1; + r = yp_match(__ypdomain, map, + user, strlen(user), + &ypcurrent, &ypcurrentlen); + if (r != 0 || ypcurrentlen > buflen) { + if (ypcurrent) + free(ypcurrent); + ypcurrent = NULL; + continue; + } + break; + } + bcopy(ypcurrent, buf, ypcurrentlen); + buf[ypcurrentlen] = '\0'; + if (__ypparse(pw, buf, yp_pw_flags) || + __ypexclude_is(&ypexhead, pw->pw_name)) { + if (s == 1) /* inside netgrp */ + goto pwnam_netgrp; + continue; } - if (strcmp(_pw_passwd.pw_name, name) == 0) { - if (!_pw_stayopen) { - (void)(_pw_db->close)(_pw_db); - _pw_db = (DB *)NULL; + break; + case '-': + /* attempted exclusion */ + switch (pw->pw_name[1]) { + case '\0': + break; + case '@': + setnetgrent(pw->pw_name + 2); + while (getnetgrent(&host, &user, &dom)) { + if (user && *user) + __ypexclude_add(&ypexhead, user); } - __ypexclude_free(); - __ypproto = (struct passwd *)NULL; - return &_pw_passwd; + endnetgrent(); + break; + default: + __ypexclude_add(&ypexhead, pw->pw_name + 1); + break; } - if (s == 1) /* inside netgrp */ - goto pwnam_netgrp; - continue; - } - if (!_pw_stayopen) { - (void)(_pw_db->close)(_pw_db); - _pw_db = (DB *)NULL; + break; } - __ypexclude_free(); - __ypproto = (struct passwd *)NULL; - return (struct passwd *)NULL; + if ((lookup == LOOKUP_BYUID && pw->pw_uid == uid) || + (lookup == LOOKUP_BYNAME && strcmp(pw->pw_name, name) == 0)) + goto done; + if (s == 1) /* inside netgrp */ + goto pwnam_netgrp; + continue; } + pw = NULL; +done: + __ypexclude_free(&ypexhead); + __ypproto = NULL; + if (ypcurrent) + free(ypcurrent); + ypcurrent = NULL; + free(name); + return (pw); +} #endif /* YP */ - bf[0] = _PW_KEYBYNAME; +static struct passwd * +_pwhashbyname(const char *name, char *buf, size_t buflen, struct passwd *pw, + int *flagsp) +{ + char bf[1 + _PW_NAME_LEN]; + int len, r; + DBT key; + len = strlen(name); if (len > _PW_NAME_LEN) - rval = 0; - else { - bcopy(name, bf + 1, MIN(len, _PW_NAME_LEN)); - key.data = (u_char *)bf; - key.size = MIN(len, _PW_NAME_LEN) + 1; - rval = __hashpw(&key); - } + return (NULL); + bf[0] = _PW_KEYBYNAME; + bcopy(name, &bf[1], MIN(len, _PW_NAME_LEN)); + key.data = (u_char *)bf; + key.size = 1 + MIN(len, _PW_NAME_LEN); + r = __hashpw(&key, buf, buflen, pw, flagsp); + if (r) + return (pw); + return (NULL); +} + +static struct passwd * +_pwhashbyuid(uid_t uid, char *buf, size_t buflen, struct passwd *pw, + int *flagsp) +{ + char bf[1 + sizeof(int)]; + DBT key; + int r; + + bf[0] = _PW_KEYBYUID; + bcopy(&uid, &bf[1], sizeof(uid)); + key.data = (u_char *)bf; + key.size = 1 + sizeof(uid); + r = __hashpw(&key, buf, buflen, pw, flagsp); + if (r) + return (pw); + return (NULL); +} + +int +getpwnam_r(const char *name, struct passwd *pw, char *buf, size_t buflen, + struct passwd **pwretp) +{ + struct passwd *pwret = NULL; + int flags = 0, *flagsp; + DB *savedb; + + _THREAD_PRIVATE_MUTEX_LOCK(pw); + savedb = _pw_db; + if (!_pw_db && !__initdb()) + goto fail; + + if (pw == &_pw_passwd) + flagsp = &_pw_flags; + else + flagsp = &flags; - if (!_pw_stayopen) { +#ifdef YP + if (__has_yppw()) + pwret = __yppwlookup(LOOKUP_BYNAME, (char *)name, 0, pw, + buf, buflen, flagsp); +#endif /* YP */ + if (!pwret) + pwret = _pwhashbyname(name, buf, buflen, pw, flagsp); + + if (savedb != _pw_db || !_pw_stayopen) { (void)(_pw_db->close)(_pw_db); - _pw_db = (DB *)NULL; + _pw_db = NULL; } - return (rval ? &_pw_passwd : (struct passwd *)NULL); +fail: + if (pwretp) + *pwretp = pwret; + _THREAD_PRIVATE_MUTEX_UNLOCK(pw); + return (pwret ? 0 : 1); } struct passwd * -getpwuid(uid_t uid) +getpwnam(const char *name) { - DBT key; - char bf[sizeof(_pw_keynum) + 1]; - uid_t keyuid; - int rval; + struct passwd *pw = NULL; + if (getpwnam_r(name, &_pw_passwd, _pw_string, sizeof _pw_string, &pw)) + pw = NULL; + return (pw); +} + +int +getpwuid_r(uid_t uid, struct passwd *pw, char *buf, size_t buflen, + struct passwd **pwretp) +{ + struct passwd *pwret = NULL; + int flags = 0, *flagsp; + DB *savedb; + + _THREAD_PRIVATE_MUTEX_LOCK(pw); + savedb = _pw_db; if (!_pw_db && !__initdb()) - return ((struct passwd *)NULL); + goto fail; -#ifdef YP - /* - * If YP is active, we must sequence through the passwd file - * in sequence. - */ - if (__has_yppw()) { - char uidbuf[20]; - int r; - int s = -1; - const char *host, *user, *dom; - - snprintf(uidbuf, sizeof uidbuf, "%u", uid); - for (_pw_keynum=1; _pw_keynum; _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; - if (__hashpw(&key) == 0) - break; - switch (_pw_passwd.pw_name[0]) { - case '+': - if (!__ypdomain) { - if (_yp_check(&__ypdomain) == 0) { - continue; - } - } - /* save the prototype */ - __ypproto_set(); + if (pw == &_pw_passwd) + flagsp = &_pw_flags; + else + flagsp = &flags; - switch (_pw_passwd.pw_name[1]) { - case '\0': - if (__ypcurrent) { - free(__ypcurrent); - __ypcurrent = NULL; - } - r = yp_match(__ypdomain, (PASSWD_BYUID), - uidbuf, strlen(uidbuf), - &__ypcurrent, &__ypcurrentlen); - if (r != 0) { - if (__ypcurrent) - free(__ypcurrent); - __ypcurrent = NULL; - continue; - } - break; - case '@': -pwuid_netgrp: - if (__ypcurrent) { - free(__ypcurrent); - __ypcurrent = NULL; - } - 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; - } else { - if (user && *user) { - r = yp_match(__ypdomain, - (PASSWD_BYNAME), - user, strlen(user), - &__ypcurrent, - &__ypcurrentlen); - } else - goto pwuid_netgrp; - if (r != 0) { - if (__ypcurrent) - free(__ypcurrent); - __ypcurrent = NULL; - /* - * just because this - * user is bad, doesn't - * mean they all are. - */ - goto pwuid_netgrp; - } - } - break; - default: - if (__ypcurrent) { - free(__ypcurrent); - __ypcurrent = NULL; - } - user = _pw_passwd.pw_name + 1; - r = yp_match(__ypdomain, - (PASSWD_BYNAME), - user, strlen(user), - &__ypcurrent, - &__ypcurrentlen); - if (r != 0) { - if (__ypcurrent) - free(__ypcurrent); - __ypcurrent = NULL; - continue; - } - break; - } - bcopy(__ypcurrent, __ypline, __ypcurrentlen); - __ypline[__ypcurrentlen] = '\0'; - if (__ypparse(&_pw_passwd, __ypline) - || __ypexclude_is(_pw_passwd.pw_name)) { - if (s == 1) /* inside netgroup */ - goto pwuid_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) - __ypexclude_add(user); - } - endnetgrent(); - break; - default: - __ypexclude_add(_pw_passwd.pw_name + 1); - break; - } - break; - } - if (_pw_passwd.pw_uid == uid) { - if (!_pw_stayopen) { - (void)(_pw_db->close)(_pw_db); - _pw_db = (DB *)NULL; - } - __ypexclude_free(); - __ypproto = NULL; - return &_pw_passwd; - } - if (s == 1) /* inside netgroup */ - goto pwuid_netgrp; - continue; - } - if (!_pw_stayopen) { - (void)(_pw_db->close)(_pw_db); - _pw_db = (DB *)NULL; - } - __ypexclude_free(); - __ypproto = (struct passwd *)NULL; - return (struct passwd *)NULL; - } +#ifdef YP + if (__has_yppw()) + pwret = __yppwlookup(LOOKUP_BYUID, NULL, uid, pw, + buf, buflen, flagsp); #endif /* YP */ + if (!pwret) + pwret = _pwhashbyuid(uid, buf, buflen, pw, flagsp); - 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 (!_pw_stayopen) { + if (savedb != _pw_db || !_pw_stayopen) { (void)(_pw_db->close)(_pw_db); - _pw_db = (DB *)NULL; + _pw_db = NULL; } - return (rval ? &_pw_passwd : (struct passwd *)NULL); +fail: + if (pwretp) + *pwretp = pwret; + _THREAD_PRIVATE_MUTEX_UNLOCK(pw); + return (pwret ? 0 : 1); +} + +struct passwd * +getpwuid(uid_t uid) +{ + struct passwd *pw = NULL; + + if (getpwuid_r(uid, &_pw_passwd, _pw_string, sizeof _pw_string, &pw)) + pw = NULL; + return (pw); } int setpassent(int stayopen) { + _THREAD_PRIVATE_MUTEX_LOCK(pw); _pw_keynum = 0; _pw_stayopen = stayopen; #ifdef YP @@ -922,9 +867,10 @@ setpassent(int stayopen) if (__ypcurrent) free(__ypcurrent); __ypcurrent = NULL; - __ypexclude_free(); - __ypproto = (struct passwd *)NULL; + __ypexclude_free(&__ypexhead); + __ypproto = NULL; #endif + _THREAD_PRIVATE_MUTEX_UNLOCK(pw); return (1); } @@ -937,19 +883,21 @@ setpwent(void) void endpwent(void) { + _THREAD_PRIVATE_MUTEX_LOCK(pw); _pw_keynum = 0; if (_pw_db) { (void)(_pw_db->close)(_pw_db); - _pw_db = (DB *)NULL; + _pw_db = NULL; } #ifdef YP __ypmode = YPMODE_NONE; if (__ypcurrent) free(__ypcurrent); __ypcurrent = NULL; - __ypexclude_free(); - __ypproto = (struct passwd *)NULL; + __ypexclude_free(&__ypexhead); + __ypproto = NULL; #endif + _THREAD_PRIVATE_MUTEX_UNLOCK(pw); } static int @@ -971,54 +919,40 @@ __initdb(void) } static int -__hashpw(DBT *key) +__hashpw(DBT *key, char *buf, size_t buflen, struct passwd *pw, + int *flagsp) { char *p, *t; - static u_int max; - static char *line; DBT data; if ((_pw_db->get)(_pw_db, key, &data, 0)) return (0); p = (char *)data.data; - if (data.size > max) { - char *nline; - - max = data.size + 256; - nline = realloc(line, max); - if (nline == NULL) { - if (line) - free(line); - line = NULL; - max = 0; - return 0; - } - line = nline; - } + if (data.size > buflen) + return (0); - t = line; + t = buf; #define EXPAND(e) e = t; while ((*t++ = *p++)); - EXPAND(_pw_passwd.pw_name); - EXPAND(_pw_passwd.pw_passwd); - bcopy(p, (char *)&_pw_passwd.pw_uid, sizeof(int)); + EXPAND(pw->pw_name); + EXPAND(pw->pw_passwd); + bcopy(p, (char *)&pw->pw_uid, sizeof(int)); p += sizeof(int); - bcopy(p, (char *)&_pw_passwd.pw_gid, sizeof(int)); + bcopy(p, (char *)&pw->pw_gid, sizeof(int)); p += sizeof(int); - bcopy(p, (char *)&_pw_passwd.pw_change, sizeof(time_t)); + bcopy(p, (char *)&pw->pw_change, sizeof(time_t)); p += sizeof(time_t); - EXPAND(_pw_passwd.pw_class); - EXPAND(_pw_passwd.pw_gecos); - EXPAND(_pw_passwd.pw_dir); - EXPAND(_pw_passwd.pw_shell); - bcopy(p, (char *)&_pw_passwd.pw_expire, sizeof(time_t)); + EXPAND(pw->pw_class); + EXPAND(pw->pw_gecos); + EXPAND(pw->pw_dir); + EXPAND(pw->pw_shell); + bcopy(p, (char *)&pw->pw_expire, sizeof(time_t)); p += sizeof(time_t); /* See if there's any data left. If so, read in flags. */ if (data.size > (p - (char *)data.data)) { - bcopy(p, (char *)&_pw_flags, sizeof(int)); + bcopy(p, (char *)flagsp, sizeof(int)); p += sizeof(int); } else - _pw_flags = _PASSWORD_NOUID|_PASSWORD_NOGID; /* default */ - + *flagsp = _PASSWORD_NOUID|_PASSWORD_NOGID; /* default */ return (1); } diff --git a/usr.bin/chpass/Makefile b/usr.bin/chpass/Makefile index 16348dee558..41dcc64e329 100644 --- a/usr.bin/chpass/Makefile +++ b/usr.bin/chpass/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.10 2001/11/23 15:32:05 espie Exp $ +# $OpenBSD: Makefile,v 1.11 2008/06/24 14:27:26 deraadt Exp $ .include <bsd.own.mk> @@ -10,7 +10,7 @@ BINMODE=4555 LINKS= ${BINDIR}/chpass ${BINDIR}/chfn ${BINDIR}/chpass ${BINDIR}/chsh MLINKS= chpass.1 chfn.1 chpass.1 chsh.1 .if (${YP:L} == "yes") -CFLAGS+=-DYP -I${.CURDIR}/../../lib/libc/yp +CFLAGS+=-DYP -I${.CURDIR}/../../lib/libc/yp -I${.CURDIR}/../../lib/libc/include .endif DPADD+= ${LIBRPCSVC} ${LIBUTIL} LDADD+= -lrpcsvc -lutil diff --git a/usr.bin/passwd/Makefile b/usr.bin/passwd/Makefile index b140bd524de..4b35f3a5e51 100644 --- a/usr.bin/passwd/Makefile +++ b/usr.bin/passwd/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.29 2003/08/04 07:29:22 hin Exp $ +# $OpenBSD: Makefile,v 1.30 2008/06/24 14:27:26 deraadt Exp $ .include <bsd.own.mk> @@ -11,7 +11,7 @@ LDADD+= -lrpcsvc -lutil CFLAGS+= -I${.CURDIR} .if (${YP:L} == "yes") -CFLAGS+=-DYP -I${.CURDIR}/../../lib/libc/yp +CFLAGS+=-DYP -I${.CURDIR}/../../lib/libc/yp -I${.CURDIR}/../../lib/libc/include .endif .include <bsd.own.mk> # For Kerberos |