1aa66460f8
NIS map which is present on SunOS NIS servers with the SunOS C2 security hack^Woption installed. I'm convinced that the C2 security option restricts access to the passwd.adjunct.byname map in the same way that I restrict access to the master.passwd.{byname,buid} maps (checking for reserved ports), which means that we should be able to handle passwd.adjunct.byname map correctly. If _havemaster() doesn't find a master.passwd.byname map, it will now test for a passwd.adjunct.byname map before defaulting back to the standard non-shadowed passwd.{byname,byuid} maps. If _pw_breakout_yp() sees that the adjunct map was found and the password from the standard maps starts with ##, it will try to grab the correct password field from the adjunct map. As with the master.passwd maps, this only happens if the caller is root, so the shadowing feature is preserved; non-root users just get back ##username as the encrypted password. Note that all we do is grab the second field from the passwd.adjunct.byname entry, which is designated to be the real encrypted password. There are other auditing fields in the entry but they aren't of much use to us. Also switched back to using yp_order() to probe for the maps (instead of yp_first()). The original problem with yp_order() was that it barfed with NIS+ servers in YP compat mode since they don't support the YPPROC_ORDER procedure. This condition is handled a bit more gracefully in yplib now: we can detect the error and just punt on the probing.
830 lines
19 KiB
C
830 lines
19 KiB
C
/*
|
|
* Copyright (c) 1988, 1993
|
|
* The Regents of the University of California. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
* must display the following acknowledgement:
|
|
* This product includes software developed by the University of
|
|
* California, Berkeley and its contributors.
|
|
* 4. Neither the name of the University nor the names of its contributors
|
|
* may be used to endorse or promote products derived from this software
|
|
* without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* 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.
|
|
*/
|
|
|
|
#if defined(LIBC_SCCS) && !defined(lint)
|
|
static char sccsid[] = "@(#)getpwent.c 8.1 (Berkeley) 6/4/93";
|
|
#endif /* LIBC_SCCS and not lint */
|
|
|
|
#include <stdio.h>
|
|
#include <sys/param.h>
|
|
#include <fcntl.h>
|
|
#include <db.h>
|
|
#include <syslog.h>
|
|
#include <pwd.h>
|
|
#include <utmp.h>
|
|
#include <errno.h>
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <limits.h>
|
|
#include <grp.h>
|
|
|
|
extern void setnetgrent __P(( char * ));
|
|
extern int getnetgrent __P(( char **, char **, char ** ));
|
|
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_stayopen; /* keep fd's open */
|
|
#ifdef YP
|
|
#include <rpc/rpc.h>
|
|
#include <rpcsvc/yp_prot.h>
|
|
#include <rpcsvc/ypclnt.h>
|
|
|
|
static struct passwd _pw_copy;
|
|
static DBT empty = { NULL, 0 };
|
|
static DB *_ypcache = (DB *)NULL;
|
|
static int _yp_exclusions = 0;
|
|
static int _yp_enabled; /* set true when yp enabled */
|
|
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 inline 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 *));
|
|
#endif
|
|
static int __hashpw(), __initdb();
|
|
|
|
struct passwd *
|
|
getpwent()
|
|
{
|
|
DBT key;
|
|
char bf[sizeof(_pw_keynum) + 1];
|
|
int rv;
|
|
|
|
if (!_pw_db && !__initdb())
|
|
return((struct passwd *)NULL);
|
|
|
|
#ifdef YP
|
|
if(_pw_stepping_yp) {
|
|
_pw_passwd = _pw_copy;
|
|
if (unwind((char *)&_ypnam))
|
|
return(&_pw_passwd);
|
|
}
|
|
#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] == '-') {
|
|
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;
|
|
}
|
|
#endif
|
|
return(&_pw_passwd);
|
|
}
|
|
|
|
struct passwd *
|
|
getpwnam(name)
|
|
const char *name;
|
|
{
|
|
DBT key;
|
|
int len, rval;
|
|
char bf[UT_NAMESIZE + 2];
|
|
|
|
if (!_pw_db && !__initdb())
|
|
return((struct passwd *)NULL);
|
|
|
|
bf[0] = _PW_KEYBYNAME;
|
|
len = strlen(name);
|
|
bcopy(name, bf + 1, MIN(len, UT_NAMESIZE));
|
|
key.data = (u_char *)bf;
|
|
key.size = len + 1;
|
|
rval = __hashpw(&key);
|
|
|
|
#ifdef YP
|
|
if (!rval && _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;
|
|
|
|
endpwent();
|
|
return(rval ? &_pw_passwd : (struct passwd *)NULL);
|
|
}
|
|
|
|
struct passwd *
|
|
#ifdef __STDC__
|
|
getpwuid(uid_t uid)
|
|
#else
|
|
getpwuid(uid)
|
|
int uid;
|
|
#endif
|
|
{
|
|
DBT key;
|
|
int keyuid, rval;
|
|
char bf[sizeof(keyuid) + 1];
|
|
|
|
if (!_pw_db && !__initdb())
|
|
return((struct passwd *)NULL);
|
|
|
|
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);
|
|
|
|
#ifdef YP
|
|
if (!rval && _yp_enabled) {
|
|
char ypbuf[16]; /* big enough for 32-bit uids and then some */
|
|
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;
|
|
|
|
endpwent();
|
|
return(rval ? &_pw_passwd : (struct passwd *)NULL);
|
|
}
|
|
|
|
int
|
|
setpassent(stayopen)
|
|
int stayopen;
|
|
{
|
|
_pw_keynum = 0;
|
|
#ifdef YP
|
|
_pw_stepping_yp = 0;
|
|
#endif
|
|
_pw_stayopen = stayopen;
|
|
return(1);
|
|
}
|
|
|
|
int
|
|
setpwent()
|
|
{
|
|
_pw_keynum = 0;
|
|
#ifdef YP
|
|
_pw_stepping_yp = 0;
|
|
#endif
|
|
_pw_stayopen = 0;
|
|
return(1);
|
|
}
|
|
|
|
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;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static int
|
|
__initdb()
|
|
{
|
|
static int warned;
|
|
char *p;
|
|
|
|
p = (geteuid()) ? _PATH_MP_DB : _PATH_SMP_DB;
|
|
_pw_db = dbopen(p, O_RDONLY, 0, DB_HASH, NULL);
|
|
if (_pw_db) {
|
|
#ifdef YP
|
|
DBT key, data;
|
|
char buf[] = { _PW_KEYYPENABLED };
|
|
key.data = buf;
|
|
key.size = 1;
|
|
if ((_pw_db->get)(_pw_db, &key, &data, 0)) {
|
|
_yp_enabled = 0;
|
|
} else {
|
|
_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(1);
|
|
_gotmaster = _havemaster(_pw_yp_domain);
|
|
} else _gotmaster = YP_HAVE_NONE;
|
|
if (!_ypcache)
|
|
_ypinitdb();
|
|
}
|
|
#endif
|
|
return(1);
|
|
}
|
|
if (!warned++)
|
|
syslog(LOG_ERR, "%s: %m", p);
|
|
return(0);
|
|
}
|
|
|
|
static int
|
|
__hashpw(key)
|
|
DBT *key;
|
|
{
|
|
register 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 && !(line = realloc(line, max += 1024)))
|
|
return(0);
|
|
|
|
t = line;
|
|
#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));
|
|
p += sizeof(int);
|
|
bcopy(p, (char *)&_pw_passwd.pw_gid, sizeof(int));
|
|
p += sizeof(int);
|
|
bcopy(p, (char *)&_pw_passwd.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));
|
|
p += sizeof(time_t);
|
|
bcopy(p, (char *)&_pw_passwd.pw_fields, sizeof _pw_passwd.pw_fields);
|
|
p += sizeof _pw_passwd.pw_fields;
|
|
return(1);
|
|
}
|
|
|
|
#ifdef YP
|
|
|
|
/*
|
|
* Create a DB hash database in memory. Bet you didn't know you
|
|
* could do a dbopen() will a NULL filename, did you.
|
|
*/
|
|
static inline void _ypinitdb()
|
|
{
|
|
if (_ypcache == (DB *)NULL)
|
|
_ypcache = dbopen(NULL, O_RDWR, 600, DB_HASH, NULL);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* See if a user is in the blackballed list.
|
|
*/
|
|
static inline int lookup(name)
|
|
char *name;
|
|
{
|
|
DBT key;
|
|
|
|
if (!_yp_exclusions)
|
|
return(0);
|
|
|
|
key.data = name;
|
|
key.size = strlen(name);
|
|
|
|
if ((_ypcache->get)(_ypcache, &key, &empty, 0)) {
|
|
return(0);
|
|
}
|
|
|
|
return(1);
|
|
}
|
|
|
|
/*
|
|
* Store a blackballed user in an in-core hash database.
|
|
*/
|
|
static inline void store(key)
|
|
char *key;
|
|
{
|
|
DBT lkey;
|
|
/*
|
|
if (lookup(key))
|
|
return;
|
|
*/
|
|
|
|
_yp_exclusions = 1;
|
|
|
|
lkey.data = key;
|
|
lkey.size = strlen(key);
|
|
|
|
(void)(_ypcache->put)(_ypcache, &lkey, &empty, R_NOOVERWRITE);
|
|
}
|
|
|
|
/*
|
|
* 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.
|
|
*/
|
|
static inline int unwind(grp)
|
|
char *grp;
|
|
{
|
|
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));
|
|
}
|
|
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 {
|
|
endgrent();
|
|
latch = 0;
|
|
gr = NULL;
|
|
return(0);
|
|
}
|
|
}
|
|
if (!latch) {
|
|
setnetgrent(grp+2);
|
|
latch++;
|
|
}
|
|
again:
|
|
if (getnetgrent(&host, &user, &domain) == NULL) {
|
|
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;
|
|
}
|
|
} else {
|
|
if (lookup(grp+1))
|
|
return(0);
|
|
return(_getyppass(&_pw_passwd, grp+1, "passwd.byname"));
|
|
}
|
|
} else {
|
|
if (grp[1] == '@') {
|
|
setnetgrent(grp+2);
|
|
rv = 0;
|
|
while(getnetgrent(&host, &user, &domain) != NULL) {
|
|
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);
|
|
}
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
/*
|
|
* See if a user is a member of a particular group.
|
|
*/
|
|
static inline int ingr(grp, name)
|
|
char *grp;
|
|
char *name;
|
|
{
|
|
register struct group *gr;
|
|
|
|
if ((gr = getgrnam(grp)) == NULL)
|
|
return(0);
|
|
|
|
while(*gr->gr_mem) {
|
|
if (!strcmp(*gr->gr_mem, name)) {
|
|
endgrent();
|
|
return(1);
|
|
}
|
|
gr->gr_mem++;
|
|
}
|
|
|
|
endgrent();
|
|
return(0);
|
|
}
|
|
|
|
/*
|
|
* 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.
|
|
*/
|
|
static inline int verf(name)
|
|
char *name;
|
|
{
|
|
DBT key;
|
|
char bf[sizeof(_pw_keynum) + 1];
|
|
int keynum = 0;
|
|
|
|
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;
|
|
}
|
|
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
static char * _get_adjunct_pw(name)
|
|
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((char *)&adjunctbuf, result, YPMAXRECORD);
|
|
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 */
|
|
|
|
return(s);
|
|
}
|
|
|
|
static int
|
|
_pw_breakout_yp(struct passwd *pw, char *res, int master)
|
|
{
|
|
char *s, *result;
|
|
static char resbuf[YPMAXRECORD+2];
|
|
|
|
/*
|
|
* 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;
|
|
|
|
/*
|
|
* 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, YPMAXRECORD);
|
|
result = (char *)&resbuf;
|
|
|
|
/*
|
|
* 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, "##")) {
|
|
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;
|
|
}
|
|
pw->pw_fields |= _PWF_PASSWD;
|
|
}
|
|
|
|
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 ((s = strsep(&result, ":")) == NULL) return 0; /* gid */
|
|
if(!(pw->pw_fields & _PWF_GID)) {
|
|
pw->pw_gid = atoi(s);
|
|
pw->pw_fields |= _PWF_GID;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
if ((s = strsep(&result, ":")) == NULL) return 0; /* change */
|
|
if(!(pw->pw_fields & _PWF_CHANGE)) {
|
|
pw->pw_change = atol(s);
|
|
pw->pw_fields |= _PWF_CHANGE;
|
|
}
|
|
|
|
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 ((s = strsep(&result, ":")) == NULL) return 0; /* gecos */
|
|
if(!(pw->pw_fields & _PWF_GECOS)) {
|
|
pw->pw_gecos = s;
|
|
pw->pw_fields |= _PWF_GECOS;
|
|
}
|
|
|
|
if ((s = strsep(&result, ":")) == NULL) return 0; /* dir */
|
|
if(!(pw->pw_fields & _PWF_DIR)) {
|
|
pw->pw_dir = s;
|
|
pw->pw_fields |= _PWF_DIR;
|
|
}
|
|
|
|
if ((s = strsep(&result, ":")) == NULL) return 0; /* shell */
|
|
if(!(pw->pw_fields & _PWF_SHELL)) {
|
|
pw->pw_shell = s;
|
|
pw->pw_fields |= _PWF_SHELL;
|
|
}
|
|
|
|
/* Be consistent. */
|
|
if ((s = strchr(pw->pw_shell, '\n'))) *s = '\0';
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
_havemaster(char *_pw_yp_domain)
|
|
{
|
|
int order;
|
|
int rval;
|
|
|
|
if (!(rval = yp_order(_pw_yp_domain, "master.passwd.byname", &order)))
|
|
return(YP_HAVE_MASTER);
|
|
|
|
/*
|
|
* NIS+ in YP compat mode doesn't support
|
|
* YPPROC_ORDER -- no point in continuing.
|
|
*/
|
|
if (rval == YPERR_YPERR)
|
|
return(YP_HAVE_NONE);
|
|
|
|
/* master.passwd doesn't exist -- try passwd.adjunct */
|
|
if (rval == YPERR_MAP) {
|
|
rval = yp_order(_pw_yp_domain, "passwd.adjunct.byname", &order);
|
|
if (!rval)
|
|
return(YP_HAVE_ADJUNCT);
|
|
}
|
|
|
|
return (YP_HAVE_NONE);
|
|
}
|
|
|
|
static int
|
|
_getyppass(struct passwd *pw, const char *name, const char *map)
|
|
{
|
|
char *result, *s;
|
|
int resultlen;
|
|
int rv;
|
|
char mastermap[YPMAXRECORD];
|
|
|
|
if(!_pw_yp_domain) {
|
|
if(yp_get_default_domain(&_pw_yp_domain))
|
|
return 0;
|
|
}
|
|
|
|
sprintf(mastermap,"%s",map);
|
|
|
|
if (_gotmaster == YP_HAVE_MASTER)
|
|
sprintf(mastermap,"master.%s", map);
|
|
|
|
if(yp_match(_pw_yp_domain, (char *)&mastermap, name, strlen(name),
|
|
&result, &resultlen))
|
|
return 0;
|
|
|
|
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);
|
|
}
|
|
|
|
*s = ':'; /* Put back the colon we previously replaced with a NUL. */
|
|
}
|
|
|
|
rv = _pw_breakout_yp(pw, result, _gotmaster);
|
|
free(result);
|
|
return(rv);
|
|
}
|
|
|
|
static int
|
|
_nextyppass(struct passwd *pw)
|
|
{
|
|
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";
|
|
|
|
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;
|
|
}
|
|
|
|
s = strchr(result, ':');
|
|
if (s) {
|
|
*s = '\0';
|
|
} else {
|
|
/* Must be a malformed entry if no colons. */
|
|
free(result);
|
|
goto tryagain;
|
|
}
|
|
|
|
if (lookup(result)) {
|
|
*s = ':';
|
|
free(result);
|
|
goto tryagain;
|
|
}
|
|
|
|
*s = ':'; /* Put back the colon we previously replaced with a NUL. */
|
|
if (_pw_breakout_yp(pw, result, _gotmaster)) {
|
|
free(result);
|
|
return(1);
|
|
} else {
|
|
free(result);
|
|
goto tryagain;
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif /* YP */
|