2fe8fb192f
There is important information about booting non-ack images in docs/UPDATING. ack/aout-format images can't be built any more, and booting clang/ELF-format ones is a little different. Updating to the new boot monitor is recommended. Changes in this commit: . drop boot monitor -> allowing dropping ack support . facility to copy ELF boot files to /boot so that old boot monitor can still boot fairly easily, see UPDATING . no more ack-format libraries -> single-case libraries . some cleanup of OBJECT_FMT, COMPILER_TYPE, etc cases . drop several ack toolchain commands, but not all support commands (e.g. aal is gone but acksize is not yet). . a few libc files moved to netbsd libc dir . new /bin/date as minix date used code in libc/ . test compile fix . harmonize includes . /usr/lib is no longer special: without ack, /usr/lib plays no kind of special bootstrapping role any more and bootstrapping is done exclusively through packages, so releases depend even less on the state of the machine making them now. . rename nbsd_lib* to lib* . reduce mtree
2580 lines
59 KiB
C
2580 lines
59 KiB
C
/* $NetBSD: getpwent.c,v 1.77 2010/03/23 20:28:59 drochner Exp $ */
|
|
|
|
/*-
|
|
* Copyright (c) 1997-2000, 2004-2005 The NetBSD Foundation, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This code is derived from software contributed to The NetBSD Foundation
|
|
* by Luke Mewburn.
|
|
*
|
|
* 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.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
|
|
*/
|
|
|
|
/*
|
|
* 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. 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.
|
|
*/
|
|
|
|
/*
|
|
* 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
|
|
* 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.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``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 AUTHOR(S) 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.
|
|
*/
|
|
|
|
#include <sys/cdefs.h>
|
|
#if defined(LIBC_SCCS) && !defined(lint)
|
|
#if 0
|
|
static char sccsid[] = "@(#)getpwent.c 8.2 (Berkeley) 4/27/95";
|
|
#else
|
|
__RCSID("$NetBSD: getpwent.c,v 1.77 2010/03/23 20:28:59 drochner Exp $");
|
|
#endif
|
|
#endif /* LIBC_SCCS and not lint */
|
|
|
|
#include "namespace.h"
|
|
#include "reentrant.h"
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include <assert.h>
|
|
#include <db.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <limits.h>
|
|
#include <netgroup.h>
|
|
#include <nsswitch.h>
|
|
#include <pwd.h>
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <syslog.h>
|
|
#include <unistd.h>
|
|
|
|
#ifdef HESIOD
|
|
#include <hesiod.h>
|
|
#endif
|
|
|
|
#ifdef YP
|
|
#include <machine/param.h>
|
|
#include <rpc/rpc.h>
|
|
#include <rpcsvc/yp_prot.h>
|
|
#include <rpcsvc/ypclnt.h>
|
|
#endif
|
|
|
|
#include "pw_private.h"
|
|
|
|
#define _PASSWD_COMPAT /* "passwd" defaults to compat, so always provide it */
|
|
|
|
#ifdef __weak_alias
|
|
__weak_alias(endpwent,_endpwent)
|
|
__weak_alias(setpassent,_setpassent)
|
|
__weak_alias(setpwent,_setpwent)
|
|
#endif
|
|
|
|
#ifdef _REENTRANT
|
|
static mutex_t _pwmutex = MUTEX_INITIALIZER;
|
|
#endif
|
|
|
|
const char __yp_token[] = "__YP!"; /* Let pwd_mkdb pull this in. */
|
|
|
|
|
|
/*
|
|
* The pwd.db lookup techniques and data extraction code here must be kept
|
|
* in sync with that in `pwd_mkdb'.
|
|
*/
|
|
|
|
#if defined(YP) || defined(HESIOD)
|
|
/*
|
|
* _pw_parse
|
|
* Parses entry using pw_scan(3) (without the trailing \n)
|
|
* after copying to buf, and fills in pw with corresponding values.
|
|
* If old is non-zero, entry is in _PASSWORD_OLDFMT.
|
|
* Returns 1 if parsed successfully, 0 on parse failure.
|
|
*/
|
|
static int
|
|
_pw_parse(const char *entry, struct passwd *pw, char *buf, size_t buflen,
|
|
int old)
|
|
{
|
|
int flags;
|
|
|
|
_DIAGASSERT(entry != NULL);
|
|
_DIAGASSERT(pw != NULL);
|
|
_DIAGASSERT(buf != NULL);
|
|
|
|
if (strlcpy(buf, entry, buflen) >= buflen)
|
|
return 0;
|
|
flags = _PASSWORD_NOWARN;
|
|
if (old)
|
|
flags |= _PASSWORD_OLDFMT;
|
|
return __pw_scan(buf, pw, &flags);
|
|
}
|
|
#endif /* YP || HESIOD */
|
|
|
|
/*
|
|
* _pw_opendb
|
|
* if *db is NULL, dbopen(3) /etc/spwd.db or /etc/pwd.db (depending
|
|
* upon permissions, etc)
|
|
*/
|
|
static int
|
|
_pw_opendb(DB **db, int *version)
|
|
{
|
|
static int warned;
|
|
DBT key;
|
|
DBT value;
|
|
|
|
const char *dbfile = NULL;
|
|
|
|
_DIAGASSERT(db != NULL);
|
|
_DIAGASSERT(version != NULL);
|
|
if (*db != NULL) /* open *db */
|
|
return NS_SUCCESS;
|
|
|
|
if (geteuid() == 0) {
|
|
dbfile = _PATH_SMP_DB;
|
|
*db = dbopen(dbfile, O_RDONLY, 0, DB_HASH, NULL);
|
|
}
|
|
if (*db == NULL) {
|
|
dbfile = _PATH_MP_DB;
|
|
*db = dbopen(dbfile, O_RDONLY, 0, DB_HASH, NULL);
|
|
}
|
|
if (*db == NULL) {
|
|
if (!warned) {
|
|
int serrno = errno;
|
|
syslog(LOG_ERR, "%s: %m", dbfile);
|
|
errno = serrno;
|
|
}
|
|
warned = 1;
|
|
return NS_UNAVAIL;
|
|
}
|
|
key.data = __UNCONST("VERSION");
|
|
key.size = strlen((char *)key.data) + 1;
|
|
switch ((*(*db)->get)(*db, &key, &value, 0)) {
|
|
case 0:
|
|
if (sizeof(*version) != value.size)
|
|
return NS_UNAVAIL;
|
|
(void)memcpy(version, value.data, value.size);
|
|
break; /* found */
|
|
case 1:
|
|
*version = 0; /* not found */
|
|
break;
|
|
case -1:
|
|
return NS_UNAVAIL; /* error in db routines */
|
|
default:
|
|
abort();
|
|
}
|
|
return NS_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* _pw_getkey
|
|
* Lookup key in *db, filling in pw
|
|
* with the result, allocating memory from buffer (size buflen).
|
|
* (The caller may point key.data to buffer on entry; the contents
|
|
* of key.data will be invalid on exit.)
|
|
*/
|
|
static int
|
|
_pw_getkey(DB *db, DBT *key,
|
|
struct passwd *pw, char *buffer, size_t buflen, int *pwflags,
|
|
int version)
|
|
{
|
|
char *p, *t;
|
|
DBT data;
|
|
|
|
_DIAGASSERT(db != NULL);
|
|
_DIAGASSERT(key != NULL);
|
|
_DIAGASSERT(pw != NULL);
|
|
_DIAGASSERT(buffer != NULL);
|
|
/* pwflags may be NULL (if we don't care about them */
|
|
|
|
if (db == NULL) /* this shouldn't happen */
|
|
return NS_UNAVAIL;
|
|
|
|
switch ((db->get)(db, key, &data, 0)) {
|
|
case 0:
|
|
break; /* found */
|
|
case 1:
|
|
return NS_NOTFOUND; /* not found */
|
|
case -1:
|
|
return NS_UNAVAIL; /* error in db routines */
|
|
default:
|
|
abort();
|
|
}
|
|
|
|
p = (char *)data.data;
|
|
if (data.size > buflen) {
|
|
errno = ERANGE;
|
|
return NS_UNAVAIL;
|
|
}
|
|
|
|
/*
|
|
* THE DECODING BELOW MUST MATCH THAT IN pwd_mkdb.
|
|
*/
|
|
t = buffer;
|
|
#define MACRO(a) do { a } while (/*CONSTCOND*/0)
|
|
#define EXPAND(e) MACRO(e = t; while ((*t++ = *p++));)
|
|
#define SCALAR(v) MACRO(memmove(&(v), p, sizeof v); p += sizeof v;)
|
|
EXPAND(pw->pw_name);
|
|
EXPAND(pw->pw_passwd);
|
|
SCALAR(pw->pw_uid);
|
|
SCALAR(pw->pw_gid);
|
|
if (version == 0) {
|
|
int32_t tmp;
|
|
SCALAR(tmp);
|
|
pw->pw_change = tmp;
|
|
} else
|
|
SCALAR(pw->pw_change);
|
|
EXPAND(pw->pw_class);
|
|
EXPAND(pw->pw_gecos);
|
|
EXPAND(pw->pw_dir);
|
|
EXPAND(pw->pw_shell);
|
|
if (version == 0) {
|
|
int32_t tmp;
|
|
SCALAR(tmp);
|
|
pw->pw_expire = tmp;
|
|
} else
|
|
SCALAR(pw->pw_expire);
|
|
if (pwflags) {
|
|
/* See if there's any data left. If so, read in flags. */
|
|
if (data.size > (size_t) (p - (char *)data.data)) {
|
|
SCALAR(*pwflags);
|
|
} else { /* default */
|
|
*pwflags = _PASSWORD_NOUID|_PASSWORD_NOGID;
|
|
}
|
|
}
|
|
|
|
return NS_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* _pw_memfrombuf
|
|
* Obtain want bytes from buffer (of size buflen) and return a pointer
|
|
* to the available memory after adjusting buffer/buflen.
|
|
* Returns NULL if there is insufficient space.
|
|
*/
|
|
static char *
|
|
_pw_memfrombuf(size_t want, char **buffer, size_t *buflen)
|
|
{
|
|
char *rv;
|
|
|
|
if (want > *buflen) {
|
|
errno = ERANGE;
|
|
return NULL;
|
|
}
|
|
rv = *buffer;
|
|
*buffer += want;
|
|
*buflen -= want;
|
|
return rv;
|
|
}
|
|
|
|
/*
|
|
* _pw_copy
|
|
* Copy the contents of frompw to pw; memory for strings
|
|
* and arrays will be allocated from buf (of size buflen).
|
|
* If proto != NULL, use various fields in proto in preference to frompw.
|
|
* Returns 1 if copied successfully, 0 on copy failure.
|
|
* NOTE: frompw must not use buf for its own pointers.
|
|
*/
|
|
static int
|
|
_pw_copy(const struct passwd *frompw, struct passwd *pw,
|
|
char *buf, size_t buflen, const struct passwd *protopw, int protoflags)
|
|
{
|
|
size_t count;
|
|
int useproto;
|
|
|
|
_DIAGASSERT(frompw != NULL);
|
|
_DIAGASSERT(pw != NULL);
|
|
_DIAGASSERT(buf != NULL);
|
|
/* protopw may be NULL */
|
|
|
|
useproto = protopw && protopw->pw_name;
|
|
|
|
#define COPYSTR(to, from) \
|
|
do { \
|
|
count = strlen((from)); \
|
|
(to) = _pw_memfrombuf(count+1, &buf, &buflen); \
|
|
if ((to) == NULL) \
|
|
return 0; \
|
|
memmove((to), (from), count); \
|
|
to[count] = '\0'; \
|
|
} while (0) /* LINTED */
|
|
|
|
#define COPYFIELD(field) COPYSTR(pw->field, frompw->field)
|
|
|
|
#define COPYPROTOFIELD(field) COPYSTR(pw->field, \
|
|
(useproto && *protopw->field ? protopw->field : frompw->field))
|
|
|
|
COPYFIELD(pw_name);
|
|
|
|
#ifdef PW_OVERRIDE_PASSWD
|
|
COPYPROTOFIELD(pw_passwd);
|
|
#else
|
|
COPYFIELD(pw_passwd);
|
|
#endif
|
|
|
|
if (useproto && !(protoflags & _PASSWORD_NOUID))
|
|
pw->pw_uid = protopw->pw_uid;
|
|
else
|
|
pw->pw_uid = frompw->pw_uid;
|
|
|
|
if (useproto && !(protoflags & _PASSWORD_NOGID))
|
|
pw->pw_gid = protopw->pw_gid;
|
|
else
|
|
pw->pw_gid = frompw->pw_gid;
|
|
|
|
pw->pw_change = frompw->pw_change;
|
|
COPYFIELD(pw_class);
|
|
COPYPROTOFIELD(pw_gecos);
|
|
COPYPROTOFIELD(pw_dir);
|
|
COPYPROTOFIELD(pw_shell);
|
|
|
|
#undef COPYSTR
|
|
#undef COPYFIELD
|
|
#undef COPYPROTOFIELD
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
/*
|
|
* files methods
|
|
*/
|
|
|
|
/* state shared between files methods */
|
|
struct files_state {
|
|
int stayopen; /* see getpassent(3) */
|
|
DB *db; /* passwd file handle */
|
|
int keynum; /* key counter, -1 if no more */
|
|
int version;
|
|
};
|
|
|
|
static struct files_state _files_state;
|
|
/* storage for non _r functions */
|
|
static struct passwd _files_passwd;
|
|
static char _files_passwdbuf[_GETPW_R_SIZE_MAX];
|
|
|
|
static int
|
|
_files_start(struct files_state *state)
|
|
{
|
|
int rv;
|
|
|
|
_DIAGASSERT(state != NULL);
|
|
|
|
state->keynum = 0;
|
|
rv = _pw_opendb(&state->db, &state->version);
|
|
if (rv != NS_SUCCESS)
|
|
return rv;
|
|
return NS_SUCCESS;
|
|
}
|
|
|
|
static int
|
|
_files_end(struct files_state *state)
|
|
{
|
|
|
|
_DIAGASSERT(state != NULL);
|
|
|
|
state->keynum = 0;
|
|
if (state->db) {
|
|
(void)(state->db->close)(state->db);
|
|
state->db = NULL;
|
|
}
|
|
return NS_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* _files_pwscan
|
|
* Search state->db for the next desired entry.
|
|
* If search is _PW_KEYBYNUM, look for state->keynum.
|
|
* If search is _PW_KEYBYNAME, look for name.
|
|
* If search is _PW_KEYBYUID, look for uid.
|
|
* Sets *retval to the errno if the result is not NS_SUCCESS
|
|
* or NS_NOTFOUND.
|
|
*/
|
|
static int
|
|
_files_pwscan(int *retval, struct passwd *pw, char *buffer, size_t buflen,
|
|
struct files_state *state, int search, const char *name, uid_t uid)
|
|
{
|
|
const void *from;
|
|
size_t fromlen;
|
|
DBT key;
|
|
int rv;
|
|
|
|
_DIAGASSERT(retval != NULL);
|
|
_DIAGASSERT(pw != NULL);
|
|
_DIAGASSERT(buffer != NULL);
|
|
_DIAGASSERT(state != NULL);
|
|
/* name is NULL to indicate searching for uid */
|
|
|
|
*retval = 0;
|
|
|
|
if (state->db == NULL) { /* only start if file not open yet */
|
|
rv = _files_start(state);
|
|
if (rv != NS_SUCCESS)
|
|
goto filespwscan_out;
|
|
}
|
|
|
|
for (;;) { /* search for a match */
|
|
switch (search) {
|
|
case _PW_KEYBYNUM:
|
|
if (state->keynum == -1)
|
|
return NS_NOTFOUND; /* no more records */
|
|
state->keynum++;
|
|
from = &state->keynum;
|
|
fromlen = sizeof(state->keynum);
|
|
break;
|
|
case _PW_KEYBYNAME:
|
|
from = name;
|
|
fromlen = strlen(name);
|
|
break;
|
|
case _PW_KEYBYUID:
|
|
from = &uid;
|
|
fromlen = sizeof(uid);
|
|
break;
|
|
default:
|
|
abort();
|
|
}
|
|
|
|
if (buflen <= fromlen) { /* buffer too small */
|
|
*retval = ERANGE;
|
|
return NS_UNAVAIL;
|
|
}
|
|
buffer[0] = search; /* setup key */
|
|
memmove(buffer + 1, from, fromlen);
|
|
key.size = fromlen + 1;
|
|
key.data = (u_char *)buffer;
|
|
|
|
/* search for key */
|
|
rv = _pw_getkey(state->db, &key, pw, buffer, buflen, NULL,
|
|
state->version);
|
|
if (rv != NS_SUCCESS) /* no match */
|
|
break;
|
|
if (pw->pw_name[0] == '+' || pw->pw_name[0] == '-') {
|
|
/* if a compat line */
|
|
if (search == _PW_KEYBYNUM)
|
|
continue; /* read next if pwent */
|
|
rv = NS_NOTFOUND; /* don't match if pw{nam,uid} */
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (rv == NS_NOTFOUND && search == _PW_KEYBYNUM)
|
|
state->keynum = -1; /* flag `no more records' */
|
|
|
|
if (rv == NS_SUCCESS) {
|
|
if ((search == _PW_KEYBYUID && pw->pw_uid != uid) ||
|
|
(search == _PW_KEYBYNAME && strcmp(pw->pw_name, name) != 0))
|
|
rv = NS_NOTFOUND;
|
|
}
|
|
|
|
filespwscan_out:
|
|
if (rv != NS_SUCCESS && rv != NS_NOTFOUND)
|
|
*retval = errno;
|
|
return rv;
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
static int
|
|
_files_setpwent(void *nsrv, void *nscb, va_list ap)
|
|
{
|
|
|
|
_files_state.stayopen = 0;
|
|
return _files_start(&_files_state);
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
static int
|
|
_files_setpassent(void *nsrv, void *nscb, va_list ap)
|
|
{
|
|
int *retval = va_arg(ap, int *);
|
|
int stayopen = va_arg(ap, int);
|
|
|
|
int rv;
|
|
|
|
_files_state.stayopen = stayopen;
|
|
rv = _files_start(&_files_state);
|
|
*retval = (rv == NS_SUCCESS);
|
|
return rv;
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
static int
|
|
_files_endpwent(void *nsrv, void *nscb, va_list ap)
|
|
{
|
|
|
|
_files_state.stayopen = 0;
|
|
return _files_end(&_files_state);
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
static int
|
|
_files_getpwent(void *nsrv, void *nscb, va_list ap)
|
|
{
|
|
struct passwd **retval = va_arg(ap, struct passwd **);
|
|
|
|
int rv, rerror;
|
|
|
|
_DIAGASSERT(retval != NULL);
|
|
|
|
*retval = NULL;
|
|
rv = _files_pwscan(&rerror, &_files_passwd,
|
|
_files_passwdbuf, sizeof(_files_passwdbuf),
|
|
&_files_state, _PW_KEYBYNUM, NULL, 0);
|
|
if (rv == NS_SUCCESS)
|
|
*retval = &_files_passwd;
|
|
return rv;
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
static int
|
|
_files_getpwent_r(void *nsrv, void *nscb, va_list ap)
|
|
{
|
|
int *retval = va_arg(ap, int *);
|
|
struct passwd *pw = va_arg(ap, struct passwd *);
|
|
char *buffer = va_arg(ap, char *);
|
|
size_t buflen = va_arg(ap, size_t);
|
|
struct passwd **result = va_arg(ap, struct passwd **);
|
|
|
|
int rv;
|
|
|
|
_DIAGASSERT(retval != NULL);
|
|
_DIAGASSERT(pw != NULL);
|
|
_DIAGASSERT(buffer != NULL);
|
|
_DIAGASSERT(result != NULL);
|
|
|
|
rv = _files_pwscan(retval, pw, buffer, buflen, &_files_state,
|
|
_PW_KEYBYNUM, NULL, 0);
|
|
if (rv == NS_SUCCESS)
|
|
*result = pw;
|
|
else
|
|
*result = NULL;
|
|
return rv;
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
static int
|
|
_files_getpwnam(void *nsrv, void *nscb, va_list ap)
|
|
{
|
|
struct passwd **retval = va_arg(ap, struct passwd **);
|
|
const char *name = va_arg(ap, const char *);
|
|
|
|
int rv, rerror;
|
|
|
|
_DIAGASSERT(retval != NULL);
|
|
|
|
*retval = NULL;
|
|
rv = _files_start(&_files_state);
|
|
if (rv != NS_SUCCESS)
|
|
return rv;
|
|
rv = _files_pwscan(&rerror, &_files_passwd,
|
|
_files_passwdbuf, sizeof(_files_passwdbuf),
|
|
&_files_state, _PW_KEYBYNAME, name, 0);
|
|
if (!_files_state.stayopen)
|
|
_files_end(&_files_state);
|
|
if (rv == NS_SUCCESS)
|
|
*retval = &_files_passwd;
|
|
return rv;
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
static int
|
|
_files_getpwnam_r(void *nsrv, void *nscb, va_list ap)
|
|
{
|
|
int *retval = va_arg(ap, int *);
|
|
const char *name = va_arg(ap, const char *);
|
|
struct passwd *pw = va_arg(ap, struct passwd *);
|
|
char *buffer = va_arg(ap, char *);
|
|
size_t buflen = va_arg(ap, size_t);
|
|
struct passwd **result = va_arg(ap, struct passwd **);
|
|
|
|
struct files_state state;
|
|
int rv;
|
|
|
|
_DIAGASSERT(retval != NULL);
|
|
_DIAGASSERT(pw != NULL);
|
|
_DIAGASSERT(buffer != NULL);
|
|
_DIAGASSERT(result != NULL);
|
|
|
|
*result = NULL;
|
|
memset(&state, 0, sizeof(state));
|
|
rv = _files_pwscan(retval, pw, buffer, buflen, &state,
|
|
_PW_KEYBYNAME, name, 0);
|
|
_files_end(&state);
|
|
if (rv == NS_SUCCESS)
|
|
*result = pw;
|
|
return rv;
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
static int
|
|
_files_getpwuid(void *nsrv, void *nscb, va_list ap)
|
|
{
|
|
struct passwd **retval = va_arg(ap, struct passwd **);
|
|
uid_t uid = va_arg(ap, uid_t);
|
|
|
|
int rv, rerror;
|
|
|
|
_DIAGASSERT(retval != NULL);
|
|
|
|
*retval = NULL;
|
|
rv = _files_start(&_files_state);
|
|
if (rv != NS_SUCCESS)
|
|
return rv;
|
|
rv = _files_pwscan(&rerror, &_files_passwd,
|
|
_files_passwdbuf, sizeof(_files_passwdbuf),
|
|
&_files_state, _PW_KEYBYUID, NULL, uid);
|
|
if (!_files_state.stayopen)
|
|
_files_end(&_files_state);
|
|
if (rv == NS_SUCCESS)
|
|
*retval = &_files_passwd;
|
|
return rv;
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
static int
|
|
_files_getpwuid_r(void *nsrv, void *nscb, va_list ap)
|
|
{
|
|
int *retval = va_arg(ap, int *);
|
|
uid_t uid = va_arg(ap, uid_t);
|
|
struct passwd *pw = va_arg(ap, struct passwd *);
|
|
char *buffer = va_arg(ap, char *);
|
|
size_t buflen = va_arg(ap, size_t);
|
|
struct passwd **result = va_arg(ap, struct passwd **);
|
|
|
|
struct files_state state;
|
|
int rv;
|
|
|
|
_DIAGASSERT(retval != NULL);
|
|
_DIAGASSERT(pw != NULL);
|
|
_DIAGASSERT(buffer != NULL);
|
|
_DIAGASSERT(result != NULL);
|
|
|
|
*result = NULL;
|
|
memset(&state, 0, sizeof(state));
|
|
rv = _files_pwscan(retval, pw, buffer, buflen, &state,
|
|
_PW_KEYBYUID, NULL, uid);
|
|
_files_end(&state);
|
|
if (rv == NS_SUCCESS)
|
|
*result = pw;
|
|
return rv;
|
|
}
|
|
|
|
|
|
#ifdef HESIOD
|
|
/*
|
|
* dns methods
|
|
*/
|
|
|
|
/* state shared between dns methods */
|
|
struct dns_state {
|
|
int stayopen; /* see getpassent(3) */
|
|
void *context; /* Hesiod context */
|
|
int num; /* passwd index, -1 if no more */
|
|
};
|
|
|
|
static struct dns_state _dns_state;
|
|
/* storage for non _r functions */
|
|
static struct passwd _dns_passwd;
|
|
static char _dns_passwdbuf[_GETPW_R_SIZE_MAX];
|
|
|
|
static int
|
|
_dns_start(struct dns_state *state)
|
|
{
|
|
|
|
_DIAGASSERT(state != NULL);
|
|
|
|
state->num = 0;
|
|
if (state->context == NULL) { /* setup Hesiod */
|
|
if (hesiod_init(&state->context) == -1)
|
|
return NS_UNAVAIL;
|
|
}
|
|
|
|
return NS_SUCCESS;
|
|
}
|
|
|
|
static int
|
|
_dns_end(struct dns_state *state)
|
|
{
|
|
|
|
_DIAGASSERT(state != NULL);
|
|
|
|
state->num = 0;
|
|
if (state->context) {
|
|
hesiod_end(state->context);
|
|
state->context = NULL;
|
|
}
|
|
return NS_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* _dns_pwscan
|
|
* Look for the Hesiod name provided in buffer in the NULL-terminated
|
|
* list of zones,
|
|
* and decode into pw/buffer/buflen.
|
|
*/
|
|
static int
|
|
_dns_pwscan(int *retval, struct passwd *pw, char *buffer, size_t buflen,
|
|
struct dns_state *state, const char **zones)
|
|
{
|
|
const char **curzone;
|
|
char **hp, *ep;
|
|
int rv;
|
|
|
|
_DIAGASSERT(retval != NULL);
|
|
_DIAGASSERT(pw != NULL);
|
|
_DIAGASSERT(buffer != NULL);
|
|
_DIAGASSERT(state != NULL);
|
|
_DIAGASSERT(zones != NULL);
|
|
|
|
*retval = 0;
|
|
|
|
if (state->context == NULL) { /* only start if Hesiod not setup */
|
|
rv = _dns_start(state);
|
|
if (rv != NS_SUCCESS)
|
|
return rv;
|
|
}
|
|
|
|
hp = NULL;
|
|
rv = NS_NOTFOUND;
|
|
|
|
for (curzone = zones; *curzone; curzone++) { /* search zones */
|
|
hp = hesiod_resolve(state->context, buffer, *curzone);
|
|
if (hp != NULL)
|
|
break;
|
|
if (errno != ENOENT) {
|
|
rv = NS_UNAVAIL;
|
|
goto dnspwscan_out;
|
|
}
|
|
}
|
|
if (*curzone == NULL)
|
|
goto dnspwscan_out;
|
|
|
|
if ((ep = strchr(hp[0], '\n')) != NULL)
|
|
*ep = '\0'; /* clear trailing \n */
|
|
if (_pw_parse(hp[0], pw, buffer, buflen, 1)) /* validate line */
|
|
rv = NS_SUCCESS;
|
|
else
|
|
rv = NS_UNAVAIL;
|
|
|
|
dnspwscan_out:
|
|
if (rv != NS_SUCCESS && rv != NS_NOTFOUND)
|
|
*retval = errno;
|
|
if (hp)
|
|
hesiod_free_list(state->context, hp);
|
|
return rv;
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
static int
|
|
_dns_setpwent(void *nsrv, void *nscb, va_list ap)
|
|
{
|
|
|
|
_dns_state.stayopen = 0;
|
|
return _dns_start(&_dns_state);
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
static int
|
|
_dns_setpassent(void *nsrv, void *nscb, va_list ap)
|
|
{
|
|
int *retval = va_arg(ap, int *);
|
|
int stayopen = va_arg(ap, int);
|
|
|
|
int rv;
|
|
|
|
_dns_state.stayopen = stayopen;
|
|
rv = _dns_start(&_dns_state);
|
|
*retval = (rv == NS_SUCCESS);
|
|
return rv;
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
static int
|
|
_dns_endpwent(void *nsrv, void *nscb, va_list ap)
|
|
{
|
|
|
|
_dns_state.stayopen = 0;
|
|
return _dns_end(&_dns_state);
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
static int
|
|
_dns_getpwent(void *nsrv, void *nscb, va_list ap)
|
|
{
|
|
struct passwd **retval = va_arg(ap, struct passwd **);
|
|
|
|
char **hp, *ep;
|
|
int rv;
|
|
|
|
_DIAGASSERT(retval != NULL);
|
|
|
|
*retval = NULL;
|
|
|
|
if (_dns_state.num == -1) /* exhausted search */
|
|
return NS_NOTFOUND;
|
|
|
|
if (_dns_state.context == NULL) {
|
|
/* only start if Hesiod not setup */
|
|
rv = _dns_start(&_dns_state);
|
|
if (rv != NS_SUCCESS)
|
|
return rv;
|
|
}
|
|
|
|
next_dns_entry:
|
|
hp = NULL;
|
|
rv = NS_NOTFOUND;
|
|
|
|
/* find passwd-NNN */
|
|
snprintf(_dns_passwdbuf, sizeof(_dns_passwdbuf),
|
|
"passwd-%u", _dns_state.num);
|
|
_dns_state.num++;
|
|
|
|
hp = hesiod_resolve(_dns_state.context, _dns_passwdbuf, "passwd");
|
|
if (hp == NULL) {
|
|
if (errno == ENOENT)
|
|
_dns_state.num = -1;
|
|
else
|
|
rv = NS_UNAVAIL;
|
|
} else {
|
|
if ((ep = strchr(hp[0], '\n')) != NULL)
|
|
*ep = '\0'; /* clear trailing \n */
|
|
/* validate line */
|
|
if (_pw_parse(hp[0], &_dns_passwd,
|
|
_dns_passwdbuf, sizeof(_dns_passwdbuf), 1))
|
|
rv = NS_SUCCESS;
|
|
else { /* dodgy entry, try again */
|
|
hesiod_free_list(_dns_state.context, hp);
|
|
goto next_dns_entry;
|
|
}
|
|
}
|
|
|
|
if (hp)
|
|
hesiod_free_list(_dns_state.context, hp);
|
|
if (rv == NS_SUCCESS)
|
|
*retval = &_dns_passwd;
|
|
return rv;
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
static int
|
|
_dns_getpwent_r(void *nsrv, void *nscb, va_list ap)
|
|
{
|
|
int *retval = va_arg(ap, int *);
|
|
struct passwd *pw = va_arg(ap, struct passwd *);
|
|
char *buffer = va_arg(ap, char *);
|
|
size_t buflen = va_arg(ap, size_t);
|
|
struct passwd **result = va_arg(ap, struct passwd **);
|
|
|
|
char **hp, *ep;
|
|
int rv;
|
|
|
|
_DIAGASSERT(retval != NULL);
|
|
_DIAGASSERT(pw != NULL);
|
|
_DIAGASSERT(buffer != NULL);
|
|
_DIAGASSERT(result != NULL);
|
|
|
|
*retval = 0;
|
|
|
|
if (_dns_state.num == -1) /* exhausted search */
|
|
return NS_NOTFOUND;
|
|
|
|
if (_dns_state.context == NULL) {
|
|
/* only start if Hesiod not setup */
|
|
rv = _dns_start(&_dns_state);
|
|
if (rv != NS_SUCCESS)
|
|
return rv;
|
|
}
|
|
|
|
next_dns_entry:
|
|
hp = NULL;
|
|
rv = NS_NOTFOUND;
|
|
|
|
/* find passwd-NNN */
|
|
snprintf(buffer, buflen, "passwd-%u", _dns_state.num);
|
|
_dns_state.num++;
|
|
|
|
hp = hesiod_resolve(_dns_state.context, buffer, "passwd");
|
|
if (hp == NULL) {
|
|
if (errno == ENOENT)
|
|
_dns_state.num = -1;
|
|
else
|
|
rv = NS_UNAVAIL;
|
|
} else {
|
|
if ((ep = strchr(hp[0], '\n')) != NULL)
|
|
*ep = '\0'; /* clear trailing \n */
|
|
/* validate line */
|
|
if (_pw_parse(hp[0], pw, buffer, buflen, 1))
|
|
rv = NS_SUCCESS;
|
|
else { /* dodgy entry, try again */
|
|
hesiod_free_list(_dns_state.context, hp);
|
|
goto next_dns_entry;
|
|
}
|
|
}
|
|
|
|
if (hp)
|
|
hesiod_free_list(_dns_state.context, hp);
|
|
if (rv == NS_SUCCESS)
|
|
*result = pw;
|
|
else
|
|
*result = NULL;
|
|
return rv;
|
|
}
|
|
|
|
static const char *_dns_uid_zones[] = {
|
|
"uid",
|
|
"passwd",
|
|
NULL
|
|
};
|
|
|
|
/*ARGSUSED*/
|
|
static int
|
|
_dns_getpwuid(void *nsrv, void *nscb, va_list ap)
|
|
{
|
|
struct passwd **retval = va_arg(ap, struct passwd **);
|
|
uid_t uid = va_arg(ap, uid_t);
|
|
|
|
int rv, rerror;
|
|
|
|
_DIAGASSERT(retval != NULL);
|
|
|
|
*retval = NULL;
|
|
rv = _dns_start(&_dns_state);
|
|
if (rv != NS_SUCCESS)
|
|
return rv;
|
|
snprintf(_dns_passwdbuf, sizeof(_dns_passwdbuf),
|
|
"%u", (unsigned int)uid);
|
|
rv = _dns_pwscan(&rerror, &_dns_passwd,
|
|
_dns_passwdbuf, sizeof(_dns_passwdbuf),
|
|
&_dns_state, _dns_uid_zones);
|
|
if (!_dns_state.stayopen)
|
|
_dns_end(&_dns_state);
|
|
if (rv == NS_SUCCESS && uid == _dns_passwd.pw_uid)
|
|
*retval = &_dns_passwd;
|
|
return rv;
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
static int
|
|
_dns_getpwuid_r(void *nsrv, void *nscb, va_list ap)
|
|
{
|
|
int *retval = va_arg(ap, int *);
|
|
uid_t uid = va_arg(ap, uid_t);
|
|
struct passwd *pw = va_arg(ap, struct passwd *);
|
|
char *buffer = va_arg(ap, char *);
|
|
size_t buflen = va_arg(ap, size_t);
|
|
struct passwd **result = va_arg(ap, struct passwd **);
|
|
|
|
struct dns_state state;
|
|
int rv;
|
|
|
|
_DIAGASSERT(retval != NULL);
|
|
_DIAGASSERT(pw != NULL);
|
|
_DIAGASSERT(buffer != NULL);
|
|
_DIAGASSERT(result != NULL);
|
|
|
|
*result = NULL;
|
|
memset(&state, 0, sizeof(state));
|
|
snprintf(buffer, buflen, "%u", (unsigned int)uid);
|
|
rv = _dns_pwscan(retval, pw, buffer, buflen, &state, _dns_uid_zones);
|
|
_dns_end(&state);
|
|
if (rv != NS_SUCCESS)
|
|
return rv;
|
|
if (uid == pw->pw_uid) {
|
|
*result = pw;
|
|
return NS_SUCCESS;
|
|
} else
|
|
return NS_NOTFOUND;
|
|
}
|
|
|
|
static const char *_dns_nam_zones[] = {
|
|
"passwd",
|
|
NULL
|
|
};
|
|
|
|
/*ARGSUSED*/
|
|
static int
|
|
_dns_getpwnam(void *nsrv, void *nscb, va_list ap)
|
|
{
|
|
struct passwd **retval = va_arg(ap, struct passwd **);
|
|
const char *name = va_arg(ap, const char *);
|
|
|
|
int rv, rerror;
|
|
|
|
_DIAGASSERT(retval != NULL);
|
|
|
|
*retval = NULL;
|
|
rv = _dns_start(&_dns_state);
|
|
if (rv != NS_SUCCESS)
|
|
return rv;
|
|
snprintf(_dns_passwdbuf, sizeof(_dns_passwdbuf), "%s", name);
|
|
rv = _dns_pwscan(&rerror, &_dns_passwd,
|
|
_dns_passwdbuf, sizeof(_dns_passwdbuf),
|
|
&_dns_state, _dns_nam_zones);
|
|
if (!_dns_state.stayopen)
|
|
_dns_end(&_dns_state);
|
|
if (rv == NS_SUCCESS && strcmp(name, _dns_passwd.pw_name) == 0)
|
|
*retval = &_dns_passwd;
|
|
return rv;
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
static int
|
|
_dns_getpwnam_r(void *nsrv, void *nscb, va_list ap)
|
|
{
|
|
int *retval = va_arg(ap, int *);
|
|
const char *name = va_arg(ap, const char *);
|
|
struct passwd *pw = va_arg(ap, struct passwd *);
|
|
char *buffer = va_arg(ap, char *);
|
|
size_t buflen = va_arg(ap, size_t);
|
|
struct passwd **result = va_arg(ap, struct passwd **);
|
|
|
|
struct dns_state state;
|
|
int rv;
|
|
|
|
_DIAGASSERT(retval != NULL);
|
|
_DIAGASSERT(pw != NULL);
|
|
_DIAGASSERT(buffer != NULL);
|
|
_DIAGASSERT(result != NULL);
|
|
|
|
*result = NULL;
|
|
memset(&state, 0, sizeof(state));
|
|
snprintf(buffer, buflen, "%s", name);
|
|
rv = _dns_pwscan(retval, pw, buffer, buflen, &state, _dns_nam_zones);
|
|
_dns_end(&state);
|
|
if (rv != NS_SUCCESS)
|
|
return rv;
|
|
if (strcmp(name, pw->pw_name) == 0) {
|
|
*result = pw;
|
|
return NS_SUCCESS;
|
|
} else
|
|
return NS_NOTFOUND;
|
|
}
|
|
|
|
#endif /* HESIOD */
|
|
|
|
|
|
#ifdef YP
|
|
/*
|
|
* nis methods
|
|
*/
|
|
/* state shared between nis methods */
|
|
struct nis_state {
|
|
int stayopen; /* see getpassent(3) */
|
|
char *domain; /* NIS domain */
|
|
int done; /* non-zero if search exhausted */
|
|
char *current; /* current first/next match */
|
|
int currentlen; /* length of _nis_current */
|
|
enum { /* shadow map type */
|
|
NISMAP_UNKNOWN, /* unknown ... */
|
|
NISMAP_NONE, /* none: use "passwd.by*" */
|
|
NISMAP_ADJUNCT, /* pw_passwd from "passwd.adjunct.*" */
|
|
NISMAP_MASTER /* all from "master.passwd.by*" */
|
|
} maptype;
|
|
};
|
|
|
|
static struct nis_state _nis_state;
|
|
/* storage for non _r functions */
|
|
static struct passwd _nis_passwd;
|
|
static char _nis_passwdbuf[_GETPW_R_SIZE_MAX];
|
|
|
|
/* macros for deciding which NIS maps to use. */
|
|
#define PASSWD_BYNAME(x) ((x)->maptype == NISMAP_MASTER \
|
|
? "master.passwd.byname" : "passwd.byname")
|
|
#define PASSWD_BYUID(x) ((x)->maptype == NISMAP_MASTER \
|
|
? "master.passwd.byuid" : "passwd.byuid")
|
|
|
|
static int
|
|
_nis_start(struct nis_state *state)
|
|
{
|
|
|
|
_DIAGASSERT(state != NULL);
|
|
|
|
state->done = 0;
|
|
if (state->current) {
|
|
free(state->current);
|
|
state->current = NULL;
|
|
}
|
|
if (state->domain == NULL) { /* setup NIS */
|
|
switch (yp_get_default_domain(&state->domain)) {
|
|
case 0:
|
|
break;
|
|
case YPERR_RESRC:
|
|
return NS_TRYAGAIN;
|
|
default:
|
|
return NS_UNAVAIL;
|
|
}
|
|
}
|
|
|
|
/* determine where to get pw_passwd from */
|
|
if (state->maptype == NISMAP_UNKNOWN) {
|
|
int r, order;
|
|
|
|
state->maptype = NISMAP_NONE; /* default to no adjunct */
|
|
if (geteuid() != 0) /* non-root can't use adjunct */
|
|
return NS_SUCCESS;
|
|
|
|
/* look for "master.passwd.*" */
|
|
r = yp_order(state->domain, "master.passwd.byname", &order);
|
|
if (r == 0) {
|
|
state->maptype = NISMAP_MASTER;
|
|
return NS_SUCCESS;
|
|
}
|
|
|
|
/* master.passwd doesn't exist, try passwd.adjunct */
|
|
if (r == YPERR_MAP) {
|
|
r = yp_order(state->domain, "passwd.adjunct.byname",
|
|
&order);
|
|
if (r == 0)
|
|
state->maptype = NISMAP_ADJUNCT;
|
|
}
|
|
}
|
|
return NS_SUCCESS;
|
|
}
|
|
|
|
static int
|
|
_nis_end(struct nis_state *state)
|
|
{
|
|
|
|
_DIAGASSERT(state != NULL);
|
|
|
|
if (state->domain)
|
|
state->domain = NULL;
|
|
state->done = 0;
|
|
if (state->current)
|
|
free(state->current);
|
|
state->current = NULL;
|
|
state->maptype = NISMAP_UNKNOWN;
|
|
return NS_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* nis_parse
|
|
* wrapper to _pw_parse that obtains the real password from the
|
|
* "passwd.adjunct.byname" NIS map if the maptype is NISMAP_ADJUNCT.
|
|
*/
|
|
static int
|
|
_nis_parse(const char *entry, struct passwd *pw, char *buf, size_t buflen,
|
|
struct nis_state *state)
|
|
{
|
|
size_t elen;
|
|
|
|
_DIAGASSERT(entry != NULL);
|
|
_DIAGASSERT(pw != NULL);
|
|
_DIAGASSERT(buf != NULL);
|
|
_DIAGASSERT(state != NULL);
|
|
|
|
elen = strlen(entry);
|
|
if (elen >= buflen)
|
|
return 0;
|
|
if (! _pw_parse(entry, pw, buf, buflen,
|
|
!(state->maptype == NISMAP_MASTER)))
|
|
return 0;
|
|
|
|
if ((state->maptype == NISMAP_ADJUNCT) &&
|
|
(strstr(pw->pw_passwd, "##") != NULL)) {
|
|
char *data;
|
|
int datalen;
|
|
|
|
if (yp_match(state->domain, "passwd.adjunct.byname",
|
|
pw->pw_name, (int)strlen(pw->pw_name),
|
|
&data, &datalen) == 0) {
|
|
char *bp, *ep;
|
|
/* skip name to get password */
|
|
ep = data;
|
|
if ((bp = strsep(&ep, ":")) != NULL &&
|
|
(bp = strsep(&ep, ":")) != NULL) {
|
|
/* store new pw_passwd after entry */
|
|
strlcpy(buf + elen, bp, buflen - elen);
|
|
pw->pw_passwd = &buf[elen];
|
|
}
|
|
free(data);
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
/*
|
|
* _nis_pwscan
|
|
* Look for the yp key provided in buffer from map,
|
|
* and decode into pw/buffer/buflen.
|
|
*/
|
|
static int
|
|
_nis_pwscan(int *retval, struct passwd *pw, char *buffer, size_t buflen,
|
|
struct nis_state *state, const char *map)
|
|
{
|
|
char *data;
|
|
int nisr, rv, datalen;
|
|
|
|
_DIAGASSERT(retval != NULL);
|
|
_DIAGASSERT(pw != NULL);
|
|
_DIAGASSERT(buffer != NULL);
|
|
_DIAGASSERT(state != NULL);
|
|
_DIAGASSERT(map != NULL);
|
|
|
|
*retval = 0;
|
|
|
|
if (state->domain == NULL) { /* only start if NIS not setup */
|
|
rv = _nis_start(state);
|
|
if (rv != NS_SUCCESS)
|
|
return rv;
|
|
}
|
|
|
|
data = NULL;
|
|
rv = NS_NOTFOUND;
|
|
|
|
/* search map */
|
|
nisr = yp_match(state->domain, map, buffer, (int)strlen(buffer),
|
|
&data, &datalen);
|
|
switch (nisr) {
|
|
case 0:
|
|
data[datalen] = '\0'; /* clear trailing \n */
|
|
if (_nis_parse(data, pw, buffer, buflen, state))
|
|
rv = NS_SUCCESS; /* validate line */
|
|
else
|
|
rv = NS_UNAVAIL;
|
|
break;
|
|
case YPERR_KEY:
|
|
break;
|
|
default:
|
|
rv = NS_UNAVAIL;
|
|
break;
|
|
}
|
|
|
|
if (rv != NS_SUCCESS && rv != NS_NOTFOUND)
|
|
*retval = errno;
|
|
if (data)
|
|
free(data);
|
|
return rv;
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
static int
|
|
_nis_setpwent(void *nsrv, void *nscb, va_list ap)
|
|
{
|
|
|
|
_nis_state.stayopen = 0;
|
|
return _nis_start(&_nis_state);
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
static int
|
|
_nis_setpassent(void *nsrv, void *nscb, va_list ap)
|
|
{
|
|
int *retval = va_arg(ap, int *);
|
|
int stayopen = va_arg(ap, int);
|
|
|
|
int rv;
|
|
|
|
_nis_state.stayopen = stayopen;
|
|
rv = _nis_start(&_nis_state);
|
|
*retval = (rv == NS_SUCCESS);
|
|
return rv;
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
static int
|
|
_nis_endpwent(void *nsrv, void *nscb, va_list ap)
|
|
{
|
|
|
|
return _nis_end(&_nis_state);
|
|
}
|
|
|
|
|
|
/*ARGSUSED*/
|
|
static int
|
|
_nis_getpwent(void *nsrv, void *nscb, va_list ap)
|
|
{
|
|
struct passwd **retval = va_arg(ap, struct passwd **);
|
|
|
|
char *key, *data;
|
|
int keylen, datalen, rv, nisr;
|
|
|
|
_DIAGASSERT(retval != NULL);
|
|
|
|
*retval = NULL;
|
|
|
|
if (_nis_state.done) /* exhausted search */
|
|
return NS_NOTFOUND;
|
|
if (_nis_state.domain == NULL) {
|
|
/* only start if NIS not setup */
|
|
rv = _nis_start(&_nis_state);
|
|
if (rv != NS_SUCCESS)
|
|
return rv;
|
|
}
|
|
|
|
next_nis_entry:
|
|
key = NULL;
|
|
data = NULL;
|
|
rv = NS_NOTFOUND;
|
|
|
|
if (_nis_state.current) { /* already searching */
|
|
nisr = yp_next(_nis_state.domain, PASSWD_BYNAME(&_nis_state),
|
|
_nis_state.current, _nis_state.currentlen,
|
|
&key, &keylen, &data, &datalen);
|
|
free(_nis_state.current);
|
|
_nis_state.current = NULL;
|
|
switch (nisr) {
|
|
case 0:
|
|
_nis_state.current = key;
|
|
_nis_state.currentlen = keylen;
|
|
key = NULL;
|
|
break;
|
|
case YPERR_NOMORE:
|
|
_nis_state.done = 1;
|
|
goto nisent_out;
|
|
default:
|
|
rv = NS_UNAVAIL;
|
|
goto nisent_out;
|
|
}
|
|
} else { /* new search */
|
|
if (yp_first(_nis_state.domain, PASSWD_BYNAME(&_nis_state),
|
|
&_nis_state.current, &_nis_state.currentlen,
|
|
&data, &datalen)) {
|
|
rv = NS_UNAVAIL;
|
|
goto nisent_out;
|
|
}
|
|
}
|
|
|
|
data[datalen] = '\0'; /* clear trailing \n */
|
|
/* validate line */
|
|
if (_nis_parse(data, &_nis_passwd,
|
|
_nis_passwdbuf, sizeof(_nis_passwdbuf), &_nis_state))
|
|
rv = NS_SUCCESS;
|
|
else { /* dodgy entry, try again */
|
|
free(data);
|
|
goto next_nis_entry;
|
|
}
|
|
|
|
nisent_out:
|
|
if (key)
|
|
free(key);
|
|
if (data)
|
|
free(data);
|
|
if (rv == NS_SUCCESS)
|
|
*retval = &_nis_passwd;
|
|
return rv;
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
static int
|
|
_nis_getpwent_r(void *nsrv, void *nscb, va_list ap)
|
|
{
|
|
int *retval = va_arg(ap, int *);
|
|
struct passwd *pw = va_arg(ap, struct passwd *);
|
|
char *buffer = va_arg(ap, char *);
|
|
size_t buflen = va_arg(ap, size_t);
|
|
struct passwd **result = va_arg(ap, struct passwd **);
|
|
|
|
char *key, *data;
|
|
int keylen, datalen, rv, nisr;
|
|
|
|
_DIAGASSERT(retval != NULL);
|
|
_DIAGASSERT(pw != NULL);
|
|
_DIAGASSERT(buffer != NULL);
|
|
_DIAGASSERT(result != NULL);
|
|
|
|
*retval = 0;
|
|
|
|
if (_nis_state.done) /* exhausted search */
|
|
return NS_NOTFOUND;
|
|
if (_nis_state.domain == NULL) {
|
|
/* only start if NIS not setup */
|
|
rv = _nis_start(&_nis_state);
|
|
if (rv != NS_SUCCESS)
|
|
return rv;
|
|
}
|
|
|
|
next_nis_entry:
|
|
key = NULL;
|
|
data = NULL;
|
|
rv = NS_NOTFOUND;
|
|
|
|
if (_nis_state.current) { /* already searching */
|
|
nisr = yp_next(_nis_state.domain, PASSWD_BYNAME(&_nis_state),
|
|
_nis_state.current, _nis_state.currentlen,
|
|
&key, &keylen, &data, &datalen);
|
|
free(_nis_state.current);
|
|
_nis_state.current = NULL;
|
|
switch (nisr) {
|
|
case 0:
|
|
_nis_state.current = key;
|
|
_nis_state.currentlen = keylen;
|
|
key = NULL;
|
|
break;
|
|
case YPERR_NOMORE:
|
|
_nis_state.done = 1;
|
|
goto nisent_out;
|
|
default:
|
|
rv = NS_UNAVAIL;
|
|
goto nisent_out;
|
|
}
|
|
} else { /* new search */
|
|
if (yp_first(_nis_state.domain, PASSWD_BYNAME(&_nis_state),
|
|
&_nis_state.current, &_nis_state.currentlen,
|
|
&data, &datalen)) {
|
|
rv = NS_UNAVAIL;
|
|
goto nisent_out;
|
|
}
|
|
}
|
|
|
|
data[datalen] = '\0'; /* clear trailing \n */
|
|
/* validate line */
|
|
if (_nis_parse(data, pw, buffer, buflen, &_nis_state))
|
|
rv = NS_SUCCESS;
|
|
else { /* dodgy entry, try again */
|
|
if (key)
|
|
free(key);
|
|
free(data);
|
|
goto next_nis_entry;
|
|
}
|
|
|
|
nisent_out:
|
|
if (key)
|
|
free(key);
|
|
if (data)
|
|
free(data);
|
|
if (rv == NS_SUCCESS)
|
|
*result = pw;
|
|
else
|
|
*result = NULL;
|
|
return rv;
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
static int
|
|
_nis_getpwuid(void *nsrv, void *nscb, va_list ap)
|
|
{
|
|
struct passwd **retval = va_arg(ap, struct passwd **);
|
|
uid_t uid = va_arg(ap, uid_t);
|
|
|
|
int rv, rerror;
|
|
|
|
_DIAGASSERT(retval != NULL);
|
|
|
|
*retval = NULL;
|
|
rv = _nis_start(&_nis_state);
|
|
if (rv != NS_SUCCESS)
|
|
return rv;
|
|
snprintf(_nis_passwdbuf, sizeof(_nis_passwdbuf), "%u", (unsigned int)uid);
|
|
rv = _nis_pwscan(&rerror, &_nis_passwd,
|
|
_nis_passwdbuf, sizeof(_nis_passwdbuf),
|
|
&_nis_state, PASSWD_BYUID(&_nis_state));
|
|
if (!_nis_state.stayopen)
|
|
_nis_end(&_nis_state);
|
|
if (rv == NS_SUCCESS && uid == _nis_passwd.pw_uid)
|
|
*retval = &_nis_passwd;
|
|
return rv;
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
static int
|
|
_nis_getpwuid_r(void *nsrv, void *nscb, va_list ap)
|
|
{
|
|
int *retval = va_arg(ap, int *);
|
|
uid_t uid = va_arg(ap, uid_t);
|
|
struct passwd *pw = va_arg(ap, struct passwd *);
|
|
char *buffer = va_arg(ap, char *);
|
|
size_t buflen = va_arg(ap, size_t);
|
|
struct passwd **result = va_arg(ap, struct passwd **);
|
|
|
|
struct nis_state state;
|
|
int rv;
|
|
|
|
_DIAGASSERT(retval != NULL);
|
|
_DIAGASSERT(pw != NULL);
|
|
_DIAGASSERT(buffer != NULL);
|
|
_DIAGASSERT(result != NULL);
|
|
|
|
*result = NULL;
|
|
memset(&state, 0, sizeof(state));
|
|
rv = _nis_start(&state);
|
|
if (rv != NS_SUCCESS)
|
|
return rv;
|
|
snprintf(buffer, buflen, "%u", (unsigned int)uid);
|
|
rv = _nis_pwscan(retval, pw, buffer, buflen,
|
|
&state, PASSWD_BYUID(&state));
|
|
_nis_end(&state);
|
|
if (rv != NS_SUCCESS)
|
|
return rv;
|
|
if (uid == pw->pw_uid) {
|
|
*result = pw;
|
|
return NS_SUCCESS;
|
|
} else
|
|
return NS_NOTFOUND;
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
static int
|
|
_nis_getpwnam(void *nsrv, void *nscb, va_list ap)
|
|
{
|
|
struct passwd **retval = va_arg(ap, struct passwd **);
|
|
const char *name = va_arg(ap, const char *);
|
|
|
|
int rv, rerror;
|
|
|
|
_DIAGASSERT(retval != NULL);
|
|
|
|
*retval = NULL;
|
|
rv = _nis_start(&_nis_state);
|
|
if (rv != NS_SUCCESS)
|
|
return rv;
|
|
snprintf(_nis_passwdbuf, sizeof(_nis_passwdbuf), "%s", name);
|
|
rv = _nis_pwscan(&rerror, &_nis_passwd,
|
|
_nis_passwdbuf, sizeof(_nis_passwdbuf),
|
|
&_nis_state, PASSWD_BYNAME(&_nis_state));
|
|
if (!_nis_state.stayopen)
|
|
_nis_end(&_nis_state);
|
|
if (rv == NS_SUCCESS && strcmp(name, _nis_passwd.pw_name) == 0)
|
|
*retval = &_nis_passwd;
|
|
return rv;
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
static int
|
|
_nis_getpwnam_r(void *nsrv, void *nscb, va_list ap)
|
|
{
|
|
int *retval = va_arg(ap, int *);
|
|
const char *name = va_arg(ap, const char *);
|
|
struct passwd *pw = va_arg(ap, struct passwd *);
|
|
char *buffer = va_arg(ap, char *);
|
|
size_t buflen = va_arg(ap, size_t);
|
|
struct passwd **result = va_arg(ap, struct passwd **);
|
|
|
|
struct nis_state state;
|
|
int rv;
|
|
|
|
_DIAGASSERT(retval != NULL);
|
|
_DIAGASSERT(pw != NULL);
|
|
_DIAGASSERT(buffer != NULL);
|
|
_DIAGASSERT(result != NULL);
|
|
|
|
*result = NULL;
|
|
snprintf(buffer, buflen, "%s", name);
|
|
memset(&state, 0, sizeof(state));
|
|
rv = _nis_start(&state);
|
|
if (rv != NS_SUCCESS)
|
|
return rv;
|
|
rv = _nis_pwscan(retval, pw, buffer, buflen,
|
|
&state, PASSWD_BYNAME(&state));
|
|
_nis_end(&state);
|
|
if (rv != NS_SUCCESS)
|
|
return rv;
|
|
if (strcmp(name, pw->pw_name) == 0) {
|
|
*result = pw;
|
|
return NS_SUCCESS;
|
|
} else
|
|
return NS_NOTFOUND;
|
|
}
|
|
|
|
#endif /* YP */
|
|
|
|
|
|
#ifdef _PASSWD_COMPAT
|
|
/*
|
|
* compat methods
|
|
*/
|
|
|
|
/* state shared between compat methods */
|
|
|
|
struct compat_state {
|
|
int stayopen; /* see getpassent(3) */
|
|
DB *db; /* passwd DB */
|
|
int keynum; /* key counter, -1 if no more */
|
|
enum { /* current compat mode */
|
|
COMPAT_NOTOKEN = 0, /* no compat token present */
|
|
COMPAT_NONE, /* parsing normal pwd.db line */
|
|
COMPAT_FULL, /* parsing `+' entries */
|
|
COMPAT_USER, /* parsing `+name' entries */
|
|
COMPAT_NETGROUP /* parsing `+@netgroup' entries */
|
|
} mode;
|
|
char *user; /* COMPAT_USER "+name" */
|
|
DB *exclude; /* compat exclude DB */
|
|
struct passwd proto; /* proto passwd entry */
|
|
char protobuf[_GETPW_R_SIZE_MAX];
|
|
/* buffer for proto ptrs */
|
|
int protoflags; /* proto passwd flags */
|
|
int version;
|
|
};
|
|
|
|
static struct compat_state _compat_state;
|
|
/* storage for non _r functions */
|
|
static struct passwd _compat_passwd;
|
|
static char _compat_passwdbuf[_GETPW_R_SIZE_MAX];
|
|
|
|
static int
|
|
_compat_start(struct compat_state *state)
|
|
{
|
|
int rv;
|
|
|
|
_DIAGASSERT(state != NULL);
|
|
|
|
state->keynum = 0;
|
|
if (state->db == NULL) { /* not open yet */
|
|
DBT key, data;
|
|
DBT pkey, pdata;
|
|
char bf[MAXLOGNAME];
|
|
|
|
rv = _pw_opendb(&state->db, &state->version);
|
|
if (rv != NS_SUCCESS)
|
|
return rv;
|
|
|
|
state->mode = COMPAT_NOTOKEN;
|
|
|
|
/*
|
|
* Determine if the "compat" token is present in pwd.db;
|
|
* either "__YP!" or PW_KEYBYNAME+"+".
|
|
* Only works if pwd_mkdb installs the token.
|
|
*/
|
|
key.data = (u_char *)__UNCONST(__yp_token);
|
|
key.size = strlen(__yp_token);
|
|
|
|
bf[0] = _PW_KEYBYNAME; /* Pre-token database support. */
|
|
bf[1] = '+';
|
|
pkey.data = (u_char *)bf;
|
|
pkey.size = 2;
|
|
|
|
if ((state->db->get)(state->db, &key, &data, 0) == 0
|
|
|| (state->db->get)(state->db, &pkey, &pdata, 0) == 0)
|
|
state->mode = COMPAT_NONE;
|
|
}
|
|
return NS_SUCCESS;
|
|
}
|
|
|
|
static int
|
|
_compat_end(struct compat_state *state)
|
|
{
|
|
|
|
_DIAGASSERT(state != NULL);
|
|
|
|
state->keynum = 0;
|
|
if (state->db) {
|
|
(void)(state->db->close)(state->db);
|
|
state->db = NULL;
|
|
}
|
|
state->mode = COMPAT_NOTOKEN;
|
|
if (state->user)
|
|
free(state->user);
|
|
state->user = NULL;
|
|
if (state->exclude != NULL)
|
|
(void)(state->exclude->close)(state->exclude);
|
|
state->exclude = NULL;
|
|
state->proto.pw_name = NULL;
|
|
state->protoflags = 0;
|
|
return NS_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* _compat_add_exclude
|
|
* add the name to the exclude list in state->exclude.
|
|
*/
|
|
static int
|
|
_compat_add_exclude(struct compat_state *state, const char *name)
|
|
{
|
|
DBT key, data;
|
|
|
|
_DIAGASSERT(state != NULL);
|
|
_DIAGASSERT(name != NULL);
|
|
|
|
/* initialize the exclusion table if needed */
|
|
if (state->exclude == NULL) {
|
|
state->exclude = dbopen(NULL, O_RDWR, 600, DB_HASH, NULL);
|
|
if (state->exclude == NULL)
|
|
return 0;
|
|
}
|
|
|
|
key.size = strlen(name); /* set up the key */
|
|
key.data = (u_char *)__UNCONST(name);
|
|
|
|
data.data = NULL; /* data is nothing */
|
|
data.size = 0;
|
|
|
|
/* store it */
|
|
if ((state->exclude->put)(state->exclude, &key, &data, 0) == -1)
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* _compat_is_excluded
|
|
* test if a name is on the compat mode exclude list
|
|
*/
|
|
static int
|
|
_compat_is_excluded(struct compat_state *state, const char *name)
|
|
{
|
|
DBT key, data;
|
|
|
|
_DIAGASSERT(state != NULL);
|
|
_DIAGASSERT(name != NULL);
|
|
|
|
if (state->exclude == NULL)
|
|
return 0; /* nothing excluded */
|
|
|
|
key.size = strlen(name); /* set up the key */
|
|
key.data = (u_char *)__UNCONST(name);
|
|
|
|
if ((state->exclude->get)(state->exclude, &key, &data, 0) == 0)
|
|
return 1; /* is excluded */
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* _passwdcompat_bad
|
|
* log an error if "files" or "compat" is specified in
|
|
* passwd_compat database
|
|
*/
|
|
/*ARGSUSED*/
|
|
static int
|
|
_passwdcompat_bad(void *nsrv, void *nscb, va_list ap)
|
|
{
|
|
static int warned;
|
|
|
|
_DIAGASSERT(nsrv != NULL);
|
|
_DIAGASSERT(nscb != NULL);
|
|
|
|
if (!warned) {
|
|
syslog(LOG_ERR,
|
|
"nsswitch.conf passwd_compat database can't use '%s'",
|
|
(char *)nscb);
|
|
}
|
|
warned = 1;
|
|
return NS_UNAVAIL;
|
|
}
|
|
|
|
/*
|
|
* _passwdcompat_setpassent
|
|
* Call setpassent for all passwd_compat sources.
|
|
*/
|
|
static int
|
|
_passwdcompat_setpassent(int stayopen)
|
|
{
|
|
static const ns_dtab dtab[] = {
|
|
NS_FILES_CB(_passwdcompat_bad, "files")
|
|
NS_DNS_CB(_dns_setpassent, NULL)
|
|
NS_NIS_CB(_nis_setpassent, NULL)
|
|
NS_COMPAT_CB(_passwdcompat_bad, "compat")
|
|
NS_NULL_CB
|
|
};
|
|
|
|
int rv, result;
|
|
|
|
rv = nsdispatch(NULL, dtab, NSDB_PASSWD_COMPAT, "setpassent",
|
|
__nsdefaultnis_forceall, &result, stayopen);
|
|
return rv;
|
|
}
|
|
|
|
/*
|
|
* _passwdcompat_endpwent
|
|
* Call endpwent for all passwd_compat sources.
|
|
*/
|
|
static int
|
|
_passwdcompat_endpwent(void)
|
|
{
|
|
static const ns_dtab dtab[] = {
|
|
NS_FILES_CB(_passwdcompat_bad, "files")
|
|
NS_DNS_CB(_dns_endpwent, NULL)
|
|
NS_NIS_CB(_nis_endpwent, NULL)
|
|
NS_COMPAT_CB(_passwdcompat_bad, "compat")
|
|
NS_NULL_CB
|
|
};
|
|
|
|
return nsdispatch(NULL, dtab, NSDB_PASSWD_COMPAT, "endpwent",
|
|
__nsdefaultnis_forceall);
|
|
}
|
|
|
|
/*
|
|
* _passwdcompat_pwscan
|
|
* 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.
|
|
* Fail if passwd_compat contains files or compat.
|
|
*/
|
|
static int
|
|
_passwdcompat_pwscan(struct passwd *pw, char *buffer, size_t buflen,
|
|
int search, const char *name, uid_t uid)
|
|
{
|
|
static const ns_dtab compatentdtab[] = {
|
|
NS_FILES_CB(_passwdcompat_bad, "files")
|
|
NS_DNS_CB(_dns_getpwent_r, NULL)
|
|
NS_NIS_CB(_nis_getpwent_r, NULL)
|
|
NS_COMPAT_CB(_passwdcompat_bad, "compat")
|
|
NS_NULL_CB
|
|
};
|
|
static const ns_dtab compatuiddtab[] = {
|
|
NS_FILES_CB(_passwdcompat_bad, "files")
|
|
NS_DNS_CB(_dns_getpwuid_r, NULL)
|
|
NS_NIS_CB(_nis_getpwuid_r, NULL)
|
|
NS_COMPAT_CB(_passwdcompat_bad, "compat")
|
|
NS_NULL_CB
|
|
};
|
|
static const ns_dtab compatnamdtab[] = {
|
|
NS_FILES_CB(_passwdcompat_bad, "files")
|
|
NS_DNS_CB(_dns_getpwnam_r, NULL)
|
|
NS_NIS_CB(_nis_getpwnam_r, NULL)
|
|
NS_COMPAT_CB(_passwdcompat_bad, "compat")
|
|
NS_NULL_CB
|
|
};
|
|
|
|
int rv, crv;
|
|
struct passwd *cpw;
|
|
|
|
switch (search) {
|
|
case _PW_KEYBYNUM:
|
|
rv = nsdispatch(NULL, compatentdtab,
|
|
NSDB_PASSWD_COMPAT, "getpwent_r", __nsdefaultnis,
|
|
&crv, pw, buffer, buflen, &cpw);
|
|
break;
|
|
case _PW_KEYBYNAME:
|
|
_DIAGASSERT(name != NULL);
|
|
rv = nsdispatch(NULL, compatnamdtab,
|
|
NSDB_PASSWD_COMPAT, "getpwnam_r", __nsdefaultnis,
|
|
&crv, name, pw, buffer, buflen, &cpw);
|
|
break;
|
|
case _PW_KEYBYUID:
|
|
rv = nsdispatch(NULL, compatuiddtab,
|
|
NSDB_PASSWD_COMPAT, "getpwuid_r", __nsdefaultnis,
|
|
&crv, uid, pw, buffer, buflen, &cpw);
|
|
break;
|
|
default:
|
|
abort();
|
|
/*NOTREACHED*/
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
/*
|
|
* _compat_pwscan
|
|
* Search state->db for the next desired entry.
|
|
* If search is _PW_KEYBYNUM, look for state->keynum.
|
|
* If search is _PW_KEYBYNAME, look for name.
|
|
* If search is _PW_KEYBYUID, look for uid.
|
|
* Sets *retval to the errno if the result is not NS_SUCCESS
|
|
* or NS_NOTFOUND.
|
|
*/
|
|
static int
|
|
_compat_pwscan(int *retval, struct passwd *pw, char *buffer, size_t buflen,
|
|
struct compat_state *state, int search, const char *name, uid_t uid)
|
|
{
|
|
DBT key;
|
|
int rv, r, pwflags;
|
|
const char *user, *host, *dom;
|
|
const void *from;
|
|
size_t fromlen;
|
|
|
|
_DIAGASSERT(retval != NULL);
|
|
_DIAGASSERT(pw != NULL);
|
|
_DIAGASSERT(buffer != NULL);
|
|
_DIAGASSERT(state != NULL);
|
|
/* name may be NULL */
|
|
|
|
*retval = 0;
|
|
|
|
if (state->db == NULL) {
|
|
rv = _compat_start(state);
|
|
if (rv != NS_SUCCESS)
|
|
return rv;
|
|
}
|
|
if (buflen <= 1) { /* buffer too small */
|
|
*retval = ERANGE;
|
|
return NS_UNAVAIL;
|
|
}
|
|
|
|
for (;;) { /* loop over pwd.db */
|
|
rv = NS_NOTFOUND;
|
|
if (state->mode != COMPAT_NOTOKEN &&
|
|
state->mode != COMPAT_NONE) {
|
|
/* doing a compat lookup */
|
|
struct passwd cpw;
|
|
char cbuf[_GETPW_R_SIZE_MAX];
|
|
|
|
switch (state->mode) {
|
|
|
|
case COMPAT_FULL:
|
|
/* get next user or lookup by key */
|
|
rv = _passwdcompat_pwscan(&cpw,
|
|
cbuf, sizeof(cbuf), search, name, uid);
|
|
if (rv != NS_SUCCESS)
|
|
state->mode = COMPAT_NONE;
|
|
break;
|
|
|
|
case COMPAT_NETGROUP:
|
|
/* XXXREENTRANT: getnetgrent is not thread safe */
|
|
/* get next user from netgroup */
|
|
r = getnetgrent(&host, &user, &dom);
|
|
if (r == 0) { /* end of group */
|
|
endnetgrent();
|
|
state->mode = COMPAT_NONE;
|
|
break;
|
|
}
|
|
if (!user || !*user)
|
|
break;
|
|
rv = _passwdcompat_pwscan(&cpw,
|
|
cbuf, sizeof(cbuf),
|
|
_PW_KEYBYNAME, user, 0);
|
|
break;
|
|
|
|
case COMPAT_USER:
|
|
/* get specific user */
|
|
if (state->user == NULL) {
|
|
state->mode = COMPAT_NONE;
|
|
break;
|
|
}
|
|
rv = _passwdcompat_pwscan(&cpw,
|
|
cbuf, sizeof(cbuf),
|
|
_PW_KEYBYNAME, state->user, 0);
|
|
free(state->user);
|
|
state->user = NULL;
|
|
state->mode = COMPAT_NONE;
|
|
break;
|
|
|
|
case COMPAT_NOTOKEN:
|
|
case COMPAT_NONE:
|
|
abort();
|
|
|
|
}
|
|
if (rv != NS_SUCCESS) /* if not matched, next loop */
|
|
continue;
|
|
|
|
/* copy cpw to pw, applying prototype */
|
|
if (! _pw_copy(&cpw, pw, buffer, buflen,
|
|
&state->proto, state->protoflags)) {
|
|
rv = NS_UNAVAIL;
|
|
break;
|
|
}
|
|
|
|
if (_compat_is_excluded(state, pw->pw_name))
|
|
continue; /* excluded; next loop */
|
|
|
|
if ((search == _PW_KEYBYNAME
|
|
&& strcmp(pw->pw_name, name) != 0)
|
|
|| (search == _PW_KEYBYUID && pw->pw_uid != uid)) {
|
|
continue; /* not specific; next loop */
|
|
}
|
|
|
|
break; /* exit loop if found */
|
|
} else { /* not a compat line */
|
|
state->proto.pw_name = NULL;
|
|
/* clear prototype */
|
|
}
|
|
|
|
if (state->mode == COMPAT_NOTOKEN) {
|
|
/* no compat token; do direct lookup */
|
|
switch (search) {
|
|
case _PW_KEYBYNUM:
|
|
if (state->keynum == -1) /* no more records */
|
|
return NS_NOTFOUND;
|
|
state->keynum++;
|
|
from = &state->keynum;
|
|
fromlen = sizeof(state->keynum);
|
|
break;
|
|
case _PW_KEYBYNAME:
|
|
from = name;
|
|
fromlen = strlen(name);
|
|
break;
|
|
case _PW_KEYBYUID:
|
|
from = &uid;
|
|
fromlen = sizeof(uid);
|
|
break;
|
|
default:
|
|
abort();
|
|
}
|
|
buffer[0] = search;
|
|
} else {
|
|
/* compat token; do line by line */
|
|
if (state->keynum == -1) /* no more records */
|
|
return NS_NOTFOUND;
|
|
state->keynum++;
|
|
from = &state->keynum;
|
|
fromlen = sizeof(state->keynum);
|
|
buffer[0] = _PW_KEYBYNUM;
|
|
}
|
|
|
|
if (buflen <= fromlen) { /* buffer too small */
|
|
*retval = ERANGE;
|
|
return NS_UNAVAIL;
|
|
}
|
|
memmove(buffer + 1, from, fromlen); /* setup key */
|
|
key.size = fromlen + 1;
|
|
key.data = (u_char *)buffer;
|
|
|
|
rv = _pw_getkey(state->db, &key, pw, buffer, buflen, &pwflags,
|
|
state->version);
|
|
if (rv != NS_SUCCESS) /* stop on error */
|
|
break;
|
|
|
|
if (state->mode == COMPAT_NOTOKEN)
|
|
break; /* stop if no compat token */
|
|
|
|
if (pw->pw_name[0] == '+') {
|
|
/* compat inclusion */
|
|
switch(pw->pw_name[1]) {
|
|
case '\0': /* `+' */
|
|
state->mode = COMPAT_FULL;
|
|
/* reset passwd_compat search */
|
|
/* XXXREENTRANT: setpassent is not thread safe ? */
|
|
(void) _passwdcompat_setpassent(0);
|
|
break;
|
|
case '@': /* `+@netgroup' */
|
|
state->mode = COMPAT_NETGROUP;
|
|
/* reset netgroup search */
|
|
/* XXXREENTRANT: setnetgrent is not thread safe */
|
|
setnetgrent(pw->pw_name + 2);
|
|
break;
|
|
default: /* `+name' */
|
|
state->mode = COMPAT_USER;
|
|
if (state->user)
|
|
free(state->user);
|
|
state->user = strdup(pw->pw_name + 1);
|
|
break;
|
|
}
|
|
/* save the prototype */
|
|
state->protoflags = pwflags;
|
|
if (! _pw_copy(pw, &state->proto, state->protobuf,
|
|
sizeof(state->protobuf), NULL, 0)) {
|
|
rv = NS_UNAVAIL;
|
|
break;
|
|
}
|
|
continue; /* loop again after inclusion */
|
|
} else if (pw->pw_name[0] == '-') {
|
|
/* compat exclusion */
|
|
rv = NS_SUCCESS;
|
|
switch(pw->pw_name[1]) {
|
|
case '\0': /* `-' */
|
|
break;
|
|
case '@': /* `-@netgroup' */
|
|
/* XXXREENTRANT: {set,get,end}netgrent is not thread safe */
|
|
setnetgrent(pw->pw_name + 2);
|
|
while (getnetgrent(&host, &user, &dom)) {
|
|
if (!user || !*user)
|
|
continue;
|
|
if (! _compat_add_exclude(state,user)) {
|
|
rv = NS_UNAVAIL;
|
|
break;
|
|
}
|
|
}
|
|
endnetgrent();
|
|
break;
|
|
default: /* `-name' */
|
|
if (! _compat_add_exclude(state,
|
|
pw->pw_name + 1)) {
|
|
rv = NS_UNAVAIL;
|
|
}
|
|
break;
|
|
}
|
|
if (rv != NS_SUCCESS) /* exclusion failure */
|
|
break;
|
|
continue; /* loop again after exclusion */
|
|
}
|
|
if (search == _PW_KEYBYNUM ||
|
|
(search == _PW_KEYBYUID && pw->pw_uid == uid) ||
|
|
(search == _PW_KEYBYNAME && strcmp(pw->pw_name, name) == 0))
|
|
break; /* token mode match found */
|
|
}
|
|
|
|
if (rv == NS_NOTFOUND &&
|
|
(search == _PW_KEYBYNUM || state->mode != COMPAT_NOTOKEN))
|
|
state->keynum = -1; /* flag `no more records' */
|
|
|
|
if (rv == NS_SUCCESS) {
|
|
if ((search == _PW_KEYBYNAME && strcmp(pw->pw_name, name) != 0)
|
|
|| (search == _PW_KEYBYUID && pw->pw_uid != uid))
|
|
rv = NS_NOTFOUND;
|
|
}
|
|
|
|
if (rv != NS_SUCCESS && rv != NS_NOTFOUND)
|
|
*retval = errno;
|
|
return rv;
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
static int
|
|
_compat_setpwent(void *nsrv, void *nscb, va_list ap)
|
|
{
|
|
|
|
/* force passwd_compat setpwent() */
|
|
(void) _passwdcompat_setpassent(0);
|
|
|
|
/* reset state, keep db open */
|
|
_compat_state.stayopen = 0;
|
|
return _compat_start(&_compat_state);
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
static int
|
|
_compat_setpassent(void *nsrv, void *nscb, va_list ap)
|
|
{
|
|
int *retval = va_arg(ap, int *);
|
|
int stayopen = va_arg(ap, int);
|
|
|
|
int rv;
|
|
|
|
/* force passwd_compat setpassent() */
|
|
(void) _passwdcompat_setpassent(stayopen);
|
|
|
|
_compat_state.stayopen = stayopen;
|
|
rv = _compat_start(&_compat_state);
|
|
*retval = (rv == NS_SUCCESS);
|
|
return rv;
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
static int
|
|
_compat_endpwent(void *nsrv, void *nscb, va_list ap)
|
|
{
|
|
|
|
/* force passwd_compat endpwent() */
|
|
(void) _passwdcompat_endpwent();
|
|
|
|
/* reset state, close db */
|
|
_compat_state.stayopen = 0;
|
|
return _compat_end(&_compat_state);
|
|
}
|
|
|
|
|
|
/*ARGSUSED*/
|
|
static int
|
|
_compat_getpwent(void *nsrv, void *nscb, va_list ap)
|
|
{
|
|
struct passwd **retval = va_arg(ap, struct passwd **);
|
|
|
|
int rv, rerror;
|
|
|
|
_DIAGASSERT(retval != NULL);
|
|
|
|
*retval = NULL;
|
|
rv = _compat_pwscan(&rerror, &_compat_passwd,
|
|
_compat_passwdbuf, sizeof(_compat_passwdbuf),
|
|
&_compat_state, _PW_KEYBYNUM, NULL, 0);
|
|
if (rv == NS_SUCCESS)
|
|
*retval = &_compat_passwd;
|
|
return rv;
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
static int
|
|
_compat_getpwent_r(void *nsrv, void *nscb, va_list ap)
|
|
{
|
|
int *retval = va_arg(ap, int *);
|
|
struct passwd *pw = va_arg(ap, struct passwd *);
|
|
char *buffer = va_arg(ap, char *);
|
|
size_t buflen = va_arg(ap, size_t);
|
|
struct passwd **result = va_arg(ap, struct passwd **);
|
|
|
|
int rv;
|
|
|
|
_DIAGASSERT(retval != NULL);
|
|
_DIAGASSERT(pw != NULL);
|
|
_DIAGASSERT(buffer != NULL);
|
|
_DIAGASSERT(result != NULL);
|
|
|
|
rv = _compat_pwscan(retval, pw, buffer, buflen, &_compat_state,
|
|
_PW_KEYBYNUM, NULL, 0);
|
|
if (rv == NS_SUCCESS)
|
|
*result = pw;
|
|
else
|
|
*result = NULL;
|
|
return rv;
|
|
}
|
|
|
|
|
|
/*ARGSUSED*/
|
|
static int
|
|
_compat_getpwnam(void *nsrv, void *nscb, va_list ap)
|
|
{
|
|
struct passwd **retval = va_arg(ap, struct passwd **);
|
|
const char *name = va_arg(ap, const char *);
|
|
|
|
int rv, rerror;
|
|
|
|
_DIAGASSERT(retval != NULL);
|
|
|
|
*retval = NULL;
|
|
rv = _compat_start(&_compat_state);
|
|
if (rv != NS_SUCCESS)
|
|
return rv;
|
|
rv = _compat_pwscan(&rerror, &_compat_passwd,
|
|
_compat_passwdbuf, sizeof(_compat_passwdbuf),
|
|
&_compat_state, _PW_KEYBYNAME, name, 0);
|
|
if (!_compat_state.stayopen)
|
|
_compat_end(&_compat_state);
|
|
if (rv == NS_SUCCESS)
|
|
*retval = &_compat_passwd;
|
|
return rv;
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
static int
|
|
_compat_getpwnam_r(void *nsrv, void *nscb, va_list ap)
|
|
{
|
|
int *retval = va_arg(ap, int *);
|
|
const char *name = va_arg(ap, const char *);
|
|
struct passwd *pw = va_arg(ap, struct passwd *);
|
|
char *buffer = va_arg(ap, char *);
|
|
size_t buflen = va_arg(ap, size_t);
|
|
struct passwd **result = va_arg(ap, struct passwd **);
|
|
|
|
struct compat_state state;
|
|
int rv;
|
|
|
|
_DIAGASSERT(retval != NULL);
|
|
_DIAGASSERT(pw != NULL);
|
|
_DIAGASSERT(buffer != NULL);
|
|
_DIAGASSERT(result != NULL);
|
|
|
|
*result = NULL;
|
|
memset(&state, 0, sizeof(state));
|
|
rv = _compat_pwscan(retval, pw, buffer, buflen, &state,
|
|
_PW_KEYBYNAME, name, 0);
|
|
_compat_end(&state);
|
|
if (rv == NS_SUCCESS)
|
|
*result = pw;
|
|
return rv;
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
static int
|
|
_compat_getpwuid(void *nsrv, void *nscb, va_list ap)
|
|
{
|
|
struct passwd **retval = va_arg(ap, struct passwd **);
|
|
uid_t uid = va_arg(ap, uid_t);
|
|
|
|
int rv, rerror;
|
|
|
|
_DIAGASSERT(retval != NULL);
|
|
|
|
*retval = NULL;
|
|
rv = _compat_start(&_compat_state);
|
|
if (rv != NS_SUCCESS)
|
|
return rv;
|
|
rv = _compat_pwscan(&rerror, &_compat_passwd,
|
|
_compat_passwdbuf, sizeof(_compat_passwdbuf),
|
|
&_compat_state, _PW_KEYBYUID, NULL, uid);
|
|
if (!_compat_state.stayopen)
|
|
_compat_end(&_compat_state);
|
|
if (rv == NS_SUCCESS)
|
|
*retval = &_compat_passwd;
|
|
return rv;
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
static int
|
|
_compat_getpwuid_r(void *nsrv, void *nscb, va_list ap)
|
|
{
|
|
int *retval = va_arg(ap, int *);
|
|
uid_t uid = va_arg(ap, uid_t);
|
|
struct passwd *pw = va_arg(ap, struct passwd *);
|
|
char *buffer = va_arg(ap, char *);
|
|
size_t buflen = va_arg(ap, size_t);
|
|
struct passwd **result = va_arg(ap, struct passwd **);
|
|
|
|
struct compat_state state;
|
|
int rv;
|
|
|
|
_DIAGASSERT(retval != NULL);
|
|
_DIAGASSERT(pw != NULL);
|
|
_DIAGASSERT(buffer != NULL);
|
|
_DIAGASSERT(result != NULL);
|
|
|
|
*result = NULL;
|
|
memset(&state, 0, sizeof(state));
|
|
rv = _compat_pwscan(retval, pw, buffer, buflen, &state,
|
|
_PW_KEYBYUID, NULL, uid);
|
|
_compat_end(&state);
|
|
if (rv == NS_SUCCESS)
|
|
*result = pw;
|
|
return rv;
|
|
}
|
|
|
|
#endif /* _PASSWD_COMPAT */
|
|
|
|
|
|
/*
|
|
* public functions
|
|
*/
|
|
|
|
struct passwd *
|
|
getpwent(void)
|
|
{
|
|
int r;
|
|
struct passwd *retval;
|
|
|
|
static const ns_dtab dtab[] = {
|
|
NS_FILES_CB(_files_getpwent, NULL)
|
|
NS_DNS_CB(_dns_getpwent, NULL)
|
|
NS_NIS_CB(_nis_getpwent, NULL)
|
|
NS_COMPAT_CB(_compat_getpwent, NULL)
|
|
NS_NULL_CB
|
|
};
|
|
|
|
mutex_lock(&_pwmutex);
|
|
r = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwent", __nsdefaultcompat,
|
|
&retval);
|
|
mutex_unlock(&_pwmutex);
|
|
return (r == NS_SUCCESS) ? retval : NULL;
|
|
}
|
|
|
|
int
|
|
getpwent_r(struct passwd *pwd, char *buffer, size_t buflen,
|
|
struct passwd **result)
|
|
{
|
|
int r, retval;
|
|
|
|
static const ns_dtab dtab[] = {
|
|
NS_FILES_CB(_files_getpwent_r, NULL)
|
|
NS_DNS_CB(_dns_getpwent_r, NULL)
|
|
NS_NIS_CB(_nis_getpwent_r, NULL)
|
|
NS_COMPAT_CB(_compat_getpwent_r, NULL)
|
|
NS_NULL_CB
|
|
};
|
|
|
|
_DIAGASSERT(pwd != NULL);
|
|
_DIAGASSERT(buffer != NULL);
|
|
_DIAGASSERT(result != NULL);
|
|
|
|
*result = NULL;
|
|
retval = 0;
|
|
mutex_lock(&_pwmutex);
|
|
r = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwent_r", __nsdefaultcompat,
|
|
&retval, pwd, buffer, buflen, result);
|
|
mutex_unlock(&_pwmutex);
|
|
switch (r) {
|
|
case NS_SUCCESS:
|
|
case NS_NOTFOUND:
|
|
return 0;
|
|
default:
|
|
return retval;
|
|
}
|
|
}
|
|
|
|
|
|
struct passwd *
|
|
getpwnam(const char *name)
|
|
{
|
|
int rv;
|
|
struct passwd *retval;
|
|
|
|
static const ns_dtab dtab[] = {
|
|
NS_FILES_CB(_files_getpwnam, NULL)
|
|
NS_DNS_CB(_dns_getpwnam, NULL)
|
|
NS_NIS_CB(_nis_getpwnam, NULL)
|
|
NS_COMPAT_CB(_compat_getpwnam, NULL)
|
|
NS_NULL_CB
|
|
};
|
|
|
|
mutex_lock(&_pwmutex);
|
|
rv = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwnam", __nsdefaultcompat,
|
|
&retval, name);
|
|
mutex_unlock(&_pwmutex);
|
|
return (rv == NS_SUCCESS) ? retval : NULL;
|
|
}
|
|
|
|
int
|
|
getpwnam_r(const char *name, struct passwd *pwd, char *buffer, size_t buflen,
|
|
struct passwd **result)
|
|
{
|
|
int r, retval;
|
|
|
|
static const ns_dtab dtab[] = {
|
|
NS_FILES_CB(_files_getpwnam_r, NULL)
|
|
NS_DNS_CB(_dns_getpwnam_r, NULL)
|
|
NS_NIS_CB(_nis_getpwnam_r, NULL)
|
|
NS_COMPAT_CB(_compat_getpwnam_r, NULL)
|
|
NS_NULL_CB
|
|
};
|
|
|
|
_DIAGASSERT(name != NULL);
|
|
_DIAGASSERT(pwd != NULL);
|
|
_DIAGASSERT(buffer != NULL);
|
|
_DIAGASSERT(result != NULL);
|
|
|
|
*result = NULL;
|
|
retval = 0;
|
|
mutex_lock(&_pwmutex);
|
|
r = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwnam_r", __nsdefaultcompat,
|
|
&retval, name, pwd, buffer, buflen, result);
|
|
mutex_unlock(&_pwmutex);
|
|
switch (r) {
|
|
case NS_SUCCESS:
|
|
case NS_NOTFOUND:
|
|
return 0;
|
|
default:
|
|
return retval;
|
|
}
|
|
}
|
|
|
|
struct passwd *
|
|
getpwuid(uid_t uid)
|
|
{
|
|
int rv;
|
|
struct passwd *retval;
|
|
|
|
static const ns_dtab dtab[] = {
|
|
NS_FILES_CB(_files_getpwuid, NULL)
|
|
NS_DNS_CB(_dns_getpwuid, NULL)
|
|
NS_NIS_CB(_nis_getpwuid, NULL)
|
|
NS_COMPAT_CB(_compat_getpwuid, NULL)
|
|
NS_NULL_CB
|
|
};
|
|
|
|
mutex_lock(&_pwmutex);
|
|
rv = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwuid", __nsdefaultcompat,
|
|
&retval, uid);
|
|
mutex_unlock(&_pwmutex);
|
|
return (rv == NS_SUCCESS) ? retval : NULL;
|
|
}
|
|
|
|
int
|
|
getpwuid_r(uid_t uid, struct passwd *pwd, char *buffer, size_t buflen,
|
|
struct passwd **result)
|
|
{
|
|
int r, retval;
|
|
|
|
static const ns_dtab dtab[] = {
|
|
NS_FILES_CB(_files_getpwuid_r, NULL)
|
|
NS_DNS_CB(_dns_getpwuid_r, NULL)
|
|
NS_NIS_CB(_nis_getpwuid_r, NULL)
|
|
NS_COMPAT_CB(_compat_getpwuid_r, NULL)
|
|
NS_NULL_CB
|
|
};
|
|
|
|
_DIAGASSERT(pwd != NULL);
|
|
_DIAGASSERT(buffer != NULL);
|
|
_DIAGASSERT(result != NULL);
|
|
|
|
*result = NULL;
|
|
retval = 0;
|
|
mutex_lock(&_pwmutex);
|
|
r = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwuid_r", __nsdefaultcompat,
|
|
&retval, uid, pwd, buffer, buflen, result);
|
|
|
|
mutex_unlock(&_pwmutex);
|
|
switch (r) {
|
|
case NS_SUCCESS:
|
|
case NS_NOTFOUND:
|
|
return 0;
|
|
default:
|
|
return retval;
|
|
}
|
|
}
|
|
|
|
void
|
|
endpwent(void)
|
|
{
|
|
static const ns_dtab dtab[] = {
|
|
NS_FILES_CB(_files_endpwent, NULL)
|
|
NS_DNS_CB(_dns_endpwent, NULL)
|
|
NS_NIS_CB(_nis_endpwent, NULL)
|
|
NS_COMPAT_CB(_compat_endpwent, NULL)
|
|
NS_NULL_CB
|
|
};
|
|
|
|
mutex_lock(&_pwmutex);
|
|
/* force all endpwent() methods */
|
|
(void) nsdispatch(NULL, dtab, NSDB_PASSWD, "endpwent",
|
|
__nsdefaultcompat_forceall);
|
|
mutex_unlock(&_pwmutex);
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
int
|
|
setpassent(int stayopen)
|
|
{
|
|
static const ns_dtab dtab[] = {
|
|
NS_FILES_CB(_files_setpassent, NULL)
|
|
NS_DNS_CB(_dns_setpassent, NULL)
|
|
NS_NIS_CB(_nis_setpassent, NULL)
|
|
NS_COMPAT_CB(_compat_setpassent, NULL)
|
|
NS_NULL_CB
|
|
};
|
|
int rv, retval;
|
|
|
|
mutex_lock(&_pwmutex);
|
|
/* force all setpassent() methods */
|
|
rv = nsdispatch(NULL, dtab, NSDB_PASSWD, "setpassent",
|
|
__nsdefaultcompat_forceall, &retval, stayopen);
|
|
mutex_unlock(&_pwmutex);
|
|
return (rv == NS_SUCCESS) ? retval : 0;
|
|
}
|
|
|
|
void
|
|
setpwent(void)
|
|
{
|
|
static const ns_dtab dtab[] = {
|
|
NS_FILES_CB(_files_setpwent, NULL)
|
|
NS_DNS_CB(_dns_setpwent, NULL)
|
|
NS_NIS_CB(_nis_setpwent, NULL)
|
|
NS_COMPAT_CB(_compat_setpwent, NULL)
|
|
NS_NULL_CB
|
|
};
|
|
|
|
mutex_lock(&_pwmutex);
|
|
/* force all setpwent() methods */
|
|
(void) nsdispatch(NULL, dtab, NSDB_PASSWD, "setpwent",
|
|
__nsdefaultcompat_forceall);
|
|
mutex_unlock(&_pwmutex);
|
|
}
|