summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chpass/Makefile37
-rw-r--r--chpass/chpass.1113
-rw-r--r--chpass/chpass.c81
-rw-r--r--chpass/edit.c10
-rw-r--r--chpass/pw_yp.c328
-rw-r--r--chpass/pw_yp.h79
6 files changed, 504 insertions, 144 deletions
diff --git a/chpass/Makefile b/chpass/Makefile
index a1e2947..0f582b9 100644
--- a/chpass/Makefile
+++ b/chpass/Makefile
@@ -4,7 +4,9 @@ PROG= chpass
SRCS= chpass.c edit.c field.c pw_copy.c pw_scan.c pw_util.c table.c util.c
BINOWN= root
BINMODE=4555
-.PATH: ${.CURDIR}/../../usr.sbin/pwd_mkdb ${.CURDIR}/../../usr.sbin/vipw
+.PATH: ${.CURDIR}/../../usr.sbin/pwd_mkdb ${.CURDIR}/../../usr.sbin/vipw \
+ ${.CURDIR}/../../libexec/ypxfr \
+ ${.CURDIR}/../../usr.sbin/rpc.yppasswdd
CFLAGS+=-I${.CURDIR}/../../usr.sbin/pwd_mkdb -I${.CURDIR}/../../usr.sbin/vipw
LINKS= ${BINDIR}/chpass ${BINDIR}/chfn
LINKS+= ${BINDIR}/chpass ${BINDIR}/chsh
@@ -12,11 +14,40 @@ LINKS+= ${BINDIR}/chpass ${BINDIR}/ypchpass
LINKS+= ${BINDIR}/chpass ${BINDIR}/ypchfn
LINKS+= ${BINDIR}/chpass ${BINDIR}/ypchsh
MLINKS= chpass.1 chfn.1 chpass.1 chsh.1
-COPTS+= -DYP
-SRCS+= pw_yp.c
+COPTS+= -DYP -I. -I${.CURDIR}/../../libexec/ypxfr \
+ -I${.CURDIR}/../../usr.sbin/rpc.yppasswdd -Dyp_error=warnx
+
+SRCS+= yppasswd_private_xdr.c yppasswd_comm.c yp_clnt.c \
+ yppasswd_clnt.c pw_yp.c ypxfr_misc.c
+CLEANFILES= yp_clnt.c yp.h yppasswd_clnt.c yppasswd.h \
+ yppasswd_private_xdr.c yppasswd_private.h
+
DPADD= ${LIBRPCSVC} ${LIBCRYPT}
LDADD+= -lrpcsvc -lcrypt
+RPCGEN= rpcgen -C
+RPCSRC= ${DESTDIR}/usr/include/rpcsvc/yp.x
+RPCSRC_PW= ${DESTDIR}/usr/include/rpcsvc/yppasswd.x
+RPCSRC_PRIV= ${.CURDIR}/../../usr.sbin/rpc.yppasswdd/yppasswd_private.x
+
+yp.h: ${RPCSRC}
+ ${RPCGEN} -h -o ${.TARGET} ${RPCSRC}
+
+yp_clnt.c: ${RPCSRC} yp.h
+ ${RPCGEN} -l -o ${.TARGET} ${RPCSRC}
+
+yppasswd.h: ${RPCSRC_PW}
+ ${RPCGEN} -h -o ${.TARGET} ${RPCSRC_PW}
+
+yppasswd_clnt.c: ${RPCSRC_PW} yppasswd.h
+ ${RPCGEN} -l -o ${.TARGET} ${RPCSRC_PW}
+
+yppasswd_private.h: ${RPCSRC_PRIV}
+ ${RPCGEN} -h -o ${.TARGET} ${RPCSRC_PRIV}
+
+yppasswd_private_xdr.c: ${RPCSRC_PRIV} yppasswd_private.h
+ ${RPCGEN} -c -o ${.TARGET} ${RPCSRC_PRIV}
+
beforeinstall:
[ ! -e ${DESTDIR}${BINDIR}/chpass ] || \
chflags noschg ${DESTDIR}${BINDIR}/chpass
diff --git a/chpass/chpass.1 b/chpass/chpass.1
index 83cddb8..2ba9be0 100644
--- a/chpass/chpass.1
+++ b/chpass/chpass.1
@@ -212,39 +212,64 @@ apply.
Currently,
.Nm chpass
can only make changes to the NIS passwd maps through
-.Xr yppasswdd 8 ,
-which only permits changes to a user's password, shell and gecos
-fields. It can not be used to change other user information or to
-add new records to the NIS passwd maps. (Doing that would require
-something such as ypupdated, which is not yet supported.)
+.Xr rpc.yppasswdd 8 ,
+which normally only permits changes to a user's password, shell and GECOS
+fields. Except when invoked by the super-user on the NIS master server,
+.Nm chpass
+(and, similarly,
+.Xr passwd 1 )
+can not use the
+.Xr rpc.yppasswdd 8
+server to change other user information or
+add new records to the NIS passwd maps.
Furthermore,
-.Xr yppasswdd 8
+.Xr rpc.yppasswdd 8
requires password authentication before it will make any
-changes, even if it receives a request from the super-user.
+changes. The only user allowed to submit changes without supplying
+a password is the super-user on the NIS master server; all other users,
+including those with root privileges on NIS clients (and NIS slave
+servers) must enter a password.
+(The super-user on the NIS master is allowed to bypass these restrictions
+largely for convenience: a user with root access
+to the NIS master server already has the privileges required to make
+updates to the NIS maps, but editing the map source files by hand can
+be cumbersome.
+.Pp
+Note: these exceptions only apply when the NIS master server is a
+FreeBSD system.)
.Pp
-As a result, the following restrictions apply when
+Consequently, except where noted, the following restrictions apply when
.Nm chpass
is used with NIS:
.Bl -enum -offset indent
.It
-.Pa Only the shell and gecos information may be changed.
+.Pa Only the shell and GECOS information may be changed.
All other
fields are restricted, even when
.Nm chpass
-is invoked by the super-user, because the
-.Xr yppasswdd 8
-daemon has no support for updating them. While support for
+is invoked by the super-user.
+While support for
changing other fields could be added, this would lead to
compatibility problems with other NIS-capable systems.
Even though the super-user may supply data for other fields
while editing an entry, the extra information (other than the
password -- see below) will be silently discarded.
+.Pp
+Exception: the super-user on the NIS master server is permitted to
+change any field.
+.Pp
.It
.Pa Password authentication is required.
.Nm Chpass
will prompt for the user's NIS password before effecting
any changes. If the password is invalid, all changes will be
discarded.
+.Pp
+Exception: the super-user on the NIS master server is allowed to
+submit changes without supplying a password. (The super-user may
+choose to turn off this feature using the
+.Fl o
+flag, described below.)
.It
.Pa Adding new records to the local
.Pa password database is discouraged.
@@ -257,6 +282,18 @@ The administrator should use
.Xr vipw 8
to modify the local password
file when NIS is running.
+.Pp
+The super-user on the NIS master server is permitted to add new records
+to the NIS password maps, provided the
+.Xr rpc.yppasswdd 8
+server has been started with the
+.Fl a
+flag to permitted additions (it refuses them by default).
+.Nm Chpass
+tries to update the local password database by default; to update the
+NIS maps instead, invoke chpass with the
+.Fl y
+flag.
.It
.Pa Password changes are not permitted.
Users should use
@@ -268,11 +305,15 @@ a new password (even though the ``Password:'' field does not show
up in the editor template, the super-user may add it back by hand),
but even the super-user must supply the user's original password
otherwise
-.Xr yppasswdd 8
+.Xr rpc.yppasswdd 8
will refuse to update the NIS maps.
+.Pp
+Exception: the super-user on the NIS master server is permitted to
+change a user's NIS password with
+.Nm chpass .
.El
.Pp
-There are also two extra option flags that are available when
+There are also a few extra option flags that are available when
.Nm chpass
is compiled with NIS support:
.Bl -tag -width flag
@@ -290,6 +331,50 @@ This flag has the opposite effect of
This flag is largely redundant since
.Nm chpass
operates on NIS entries by default if NIS is enabled.
+.It Fl d Ar domain
+Specify a particular NIS domain.
+.Nm Chpass
+uses the system domain name by default, as set by the
+.Xr domainname 1
+command. The
+.Fl d
+option can be used to override a default, or to specify a domain
+when the system domain name is not set.
+.It Fl h Ar host
+Specify the name or address of an NIS server to query. Normally,
+.Nm chpass
+will communicate with the NIS master host specified in the
+.Pa master.passwd
+or
+.Pa passwd
+maps. On hosts that have not been configured as NIS clients, there is
+no way for the program to determine this information unless the user
+provides the hostname of a server. Note that the specified hostname need
+not be that of the NIS master server; the name of any server, master or
+slave, in a given NIS domain will do.
+.Pp
+When using the
+.Fl d
+option, the hostname defaults to ``localhost.'' The
+.Fl h
+option can be used in conjunction with the
+.Fl d
+option, in which case the user-specified hostname will override
+the default.
+.Pp
+.It Fl o
+Force the use of RPC-based updates when communicating with
+.Xr rpc.yppasswdd 8
+(``old-mode'').
+When invoked by the super-user on the NIS master server,
+.Nm chpass
+allows unrestricted changes to the NIS passwd maps using dedicated,
+non-RPC-based mechanism (in this case, a UNIX domain socket). The
+.Fl o
+flag can be used to force
+.Nm chpass
+to use the standard update mechanism instead. This option is provided
+mainly for testing purposes.
.El
.Pp
.Sh FILES
diff --git a/chpass/chpass.c b/chpass/chpass.c
index 2bfdd10..17d742a 100644
--- a/chpass/chpass.c
+++ b/chpass/chpass.c
@@ -40,7 +40,7 @@ static char copyright[] =
#ifndef lint
static char sccsid[] = "From: @(#)chpass.c 8.4 (Berkeley) 4/2/94";
static char rcsid[] =
- "$Id: chpass.c,v 1.5 1995/09/02 03:56:17 wpaul Exp $";
+ "$Id: chpass.c,v 1.5 1996/02/23 14:33:05 wpaul Exp $";
#endif /* not lint */
#include <sys/param.h>
@@ -63,13 +63,14 @@ static char rcsid[] =
#include <pw_util.h>
#include "pw_copy.h"
#ifdef YP
+#include <rpcsvc/yp.h>
+int yp_errno = YP_TRUE;
#include "pw_yp.h"
#endif
#include "chpass.h"
#include "pathnames.h"
-char *progname = "chpass";
char *tempname;
uid_t uid;
@@ -92,7 +93,7 @@ main(argc, argv)
op = EDITENTRY;
#ifdef YP
- while ((ch = getopt(argc, argv, "a:p:s:ly")) != EOF)
+ while ((ch = getopt(argc, argv, "a:p:s:d:h:oly")) != EOF)
#else
while ((ch = getopt(argc, argv, "a:p:s:")) != EOF)
#endif
@@ -110,11 +111,42 @@ main(argc, argv)
arg = optarg;
break;
#ifdef YP
+ case 'h':
+#ifdef PARAMOID
+ if (getuid()) {
+ warnx("Only the superuser can use the -d flag");
+ } else {
+#endif
+ yp_server = optarg;
+#ifdef PARANOID
+ }
+#endif
+ break;
+ case 'd':
+#ifdef PARANOID
+ if (getuid()) {
+ warnx("Only the superuser can use the -d flag");
+ } else {
+#endif
+ yp_domain = optarg;
+ if (yp_server == NULL)
+ yp_server = "localhost";
+#ifdef PARANOID
+ }
+#endif
+ break;
case 'l':
- force_local = 1;
+ if (getuid()) {
+ warnx("Only the superuser can use the -h flag");
+ } else {
+ force_local = 1;
+ }
break;
case 'y':
- force_yp = 1;
+ _use_yp = force_yp = 1;
+ break;
+ case 'o':
+ force_old++;
break;
#endif
case '?':
@@ -128,6 +160,15 @@ main(argc, argv)
if (op == EDITENTRY || op == NEWSH || op == NEWPW)
switch(argc) {
+#ifdef YP
+ case 0:
+ GETPWUID(uid)
+ get_yp_master(1); /* XXX just to set the suser flag */
+ break;
+ case 1:
+ GETPWNAM(*argv)
+ get_yp_master(1); /* XXX just to set the suser flag */
+#else
case 0:
if (!(pw = getpwuid(uid)))
errx(1, "unknown user: uid %u", uid);
@@ -135,39 +176,13 @@ main(argc, argv)
case 1:
if (!(pw = getpwnam(*argv)))
errx(1, "unknown user: %s", *argv);
+#endif
if (uid && uid != pw->pw_uid)
baduser();
break;
default:
usage();
}
-
-#ifdef YP
- pw->pw_name = strdup(pw->pw_name);
- _use_yp = use_yp(pw->pw_name);
- if (_use_yp == USER_YP_ONLY) {
- if (!force_local) {
- _use_yp = 1;
- pw = (struct passwd *)&yp_password;
- } else
- errx(1, "unknown local user: %s.", pw->pw_name);
- } else if (_use_yp == USER_LOCAL_ONLY) {
- if (!force_yp) {
- _use_yp = 0;
- pw = (struct passwd *)&local_password;
- } else
- errx(1, "unknown NIS user: %s.", pw->pw_name);
- } else if (_use_yp == USER_YP_AND_LOCAL) {
- if (!force_local) {
- _use_yp = 1;
- pw = (struct passwd *)&yp_password;
- } else {
- _use_yp = 0;
- pw = (struct passwd *)&local_password;
- }
- }
-#endif /* YP */
-
if (op == NEWSH) {
/* protect p_shell -- it thinks NULL is /bin/sh */
if (!arg[0])
@@ -258,7 +273,7 @@ usage()
(void)fprintf(stderr,
#ifdef YP
- "usage: chpass [-l] [-y] [-a list] [-p encpass] [-s shell] [user]\n");
+ "usage: chpass [-l] [-y] [-d domain [-h host]] [-a list] [-p encpass] [-s shell] [user]\n");
#else
"usage: chpass [-a list] [-p encpass] [-s shell] [user]\n");
#endif
diff --git a/chpass/edit.c b/chpass/edit.c
index c0f61e0..2968c84 100644
--- a/chpass/edit.c
+++ b/chpass/edit.c
@@ -99,7 +99,7 @@ display(fd, pw)
(void)fprintf(fp,
#ifdef YP
"#Changing %s information for %s.\n", _use_yp ? "NIS" : "user database", pw->pw_name);
- if (!uid && !_use_yp) {
+ if (!uid && (!_use_yp || suser_override)) {
#else
"#Changing user database information for %s.\n", pw->pw_name)
if (!uid) {
@@ -118,11 +118,19 @@ display(fd, pw)
*pw->pw_shell ? pw->pw_shell : _PATH_BSHELL);
}
/* Only admin can change "restricted" shells. */
+#ifdef 0
else if (ok_shell(pw->pw_shell))
/*
* Make shell a restricted field. Ugly with a
* necklace, but there's not much else to do.
*/
+#else
+ else if ((!list[E_SHELL].restricted && ok_shell(pw->pw_shell)) || !uid)
+ /*
+ * If change not restrict (table.c) and standard shell
+ * OR if root, then allow editing of shell.
+ */
+#endif
(void)fprintf(fp, "Shell: %s\n",
*pw->pw_shell ? pw->pw_shell : _PATH_BSHELL);
else
diff --git a/chpass/pw_yp.c b/chpass/pw_yp.c
index 2c1c138..9493db8 100644
--- a/chpass/pw_yp.c
+++ b/chpass/pw_yp.c
@@ -20,7 +20,7 @@
* THIS SOFTWARE IS PROVIDED BY Bill Paul 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
+ * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul 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)
@@ -35,7 +35,7 @@
* Center for Telecommunications Research
* Columbia University, New York City
*
- * $Id: pw_yp.c,v 1.1 1995/08/13 16:12:27 wpaul Exp $
+ * $Id: pw_yp.c,v 1.9 1996/02/23 04:20:19 wpaul Exp $
*/
#ifdef YP
@@ -45,6 +45,7 @@
#include <netdb.h>
#include <time.h>
#include <sys/types.h>
+#include <sys/stat.h>
#include <pwd.h>
#include <errno.h>
#include <err.h>
@@ -57,14 +58,18 @@
#include <sys/param.h>
#include <limits.h>
#include <rpc/rpc.h>
-#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/yp.h>
+struct dom_binding {};
#include <rpcsvc/ypclnt.h>
#include <rpcsvc/yppasswd.h>
#include <pw_util.h>
#include "pw_yp.h"
+#include "ypxfr_extern.h"
+#include "yppasswd_comm.h"
+#include "yppasswd_private.h"
#define PERM_SECURE (S_IRUSR|S_IWUSR)
-HASHINFO openinfo = {
+static HASHINFO openinfo = {
4096, /* bsize */
32, /* ffactor */
256, /* nelem */
@@ -73,22 +78,29 @@ HASHINFO openinfo = {
0, /* lorder */
};
+int force_old = 0;
int _use_yp = 0;
+int suser_override = 0;
+char *yp_domain = NULL;
+char *yp_server = NULL;
+
+extern char *tempname;
/* Save the local and NIS password information */
struct passwd local_password;
struct passwd yp_password;
-
void copy_yp_pass(p, x, m)
char *p;
int x, m;
{
register char *t, *s = p;
+ static char *buf;
yp_password.pw_fields = 0;
- t = (char *)malloc(m + 10);
+ buf = (char *)realloc(buf, m + 10);
+ bzero(buf, m + 10);
/* Turn all colons into NULLs */
while (strchr(s, ':')) {
@@ -96,7 +108,8 @@ int x, m;
*(s - 1)= '\0';
}
-#define EXPAND(e) e = t; while (*t++ = *p++);
+ t = buf;
+#define EXPAND(e) e = t; while ((*t++ = *p++));
EXPAND(yp_password.pw_name);
yp_password.pw_fields |= _PWF_NAME;
EXPAND(yp_password.pw_passwd);
@@ -115,7 +128,7 @@ int x, m;
yp_password.pw_fields |= _PWF_CHANGE;
yp_password.pw_expire = atol(p);
p += (strlen(p) + 1);
- yp_password.pw_expire |= _PWF_EXPIRE;
+ yp_password.pw_fields |= _PWF_EXPIRE;
}
EXPAND(yp_password.pw_gecos);
yp_password.pw_fields |= _PWF_GECOS;
@@ -132,9 +145,12 @@ char *p;
int m;
{
register char *t;
+ static char *buf;
- t = (char *)malloc(m + 10);
+ buf = (char *)realloc(buf, m + 10);
+ bzero(buf, m + 10);
+ t = buf;
EXPAND(local_password.pw_name);
EXPAND(local_password.pw_passwd);
bcopy(p, (char *)&local_password.pw_uid, sizeof(int));
@@ -156,60 +172,141 @@ int m;
}
/*
+ * It is not mandatory that an NIS master server also be a client.
+ * However, if the NIS master is not configured as a client, then the
+ * domain name will not be set and ypbind will not be running, so we
+ * will be unable to use the ypclnt routines inside libc. We therefore
+ * need our own magic version of yp_match() which we can use in any
+ * environment.
+ */
+static int my_yp_match(server, domain, map, key, keylen, result, resultlen)
+ char *server;
+ char *domain;
+ char *map;
+ char *key;
+ unsigned long keylen;
+ char **result;
+ unsigned long *resultlen;
+{
+ ypreq_key ypkey;
+ ypresp_val *ypval;
+ CLIENT *clnt;
+ static char buf[YPMAXRECORD + 2];
+
+ bzero((char *)buf, sizeof(buf));
+
+ if ((clnt = clnt_create(server, YPPROG,YPVERS,"udp")) == NULL) {
+ warnx("%s", clnt_spcreateerror("failed to create handle"));
+ pw_error(tempname, 0, 1);
+ }
+
+ ypkey.domain = domain;
+ ypkey.map = map;
+ ypkey.key.keydat_len = keylen;
+ ypkey.key.keydat_val = key;
+
+ if ((ypval = ypproc_match_2(&ypkey, clnt)) == NULL) {
+ clnt_destroy(clnt);
+ warnx("%s",clnt_sperror(clnt,"YPPROC_MATCH failed"));
+ pw_error(tempname, 0, 1);
+ }
+
+ clnt_destroy(clnt);
+
+ if (ypval->stat != YP_TRUE) {
+ int stat = ypval->stat;
+ xdr_free(xdr_ypresp_val, (char *)ypval);
+ if (stat == YP_NOMAP && strstr(map, "master.passwd"))
+ return(1);
+ if (stat == YP_NOKEY)
+ return(1);
+ warnx("ypmatch failed: %s", yperr_string(ypprot_err(stat)));
+ pw_error(tempname, 0, 1);
+ }
+
+
+ strncpy((char *)&buf, ypval->val.valdat_val, ypval->val.valdat_len);
+
+ *result = (char *)&buf;
+ *resultlen = ypval->val.valdat_len;
+
+ xdr_free(xdr_ypresp_val, (char *)ypval);
+
+ return(0);
+}
+
+/*
* Check if the user we're working with is local or in NIS.
*/
-int use_yp (user)
-char *user;
+int use_yp (user, uid, which)
+ char *user;
+ uid_t uid;
+ int which; /* 0 = use username, 1 = use uid */
{
int user_local = 0, user_yp = 0, user_exists = 0;
DB *dbp;
DBT key,data;
char bf[UT_NAMESIZE + 2];
- char *domain;
char *result;
- int resultlen, rval;
+ char *server;
+ int resultlen;
+ char ubuf[UT_NAMESIZE + 2];
+ if (which) {
+ snprintf(ubuf, sizeof(ubuf), "%lu", uid);
+ user = (char *)&ubuf;
+ }
- /* Is the user anywhere */
- if (getpwnam(user) != NULL)
- user_exists = 1;
+ /* Grope around for the user in the usual way */
+ if (which) {
+ if (getpwuid(uid) != NULL)
+ user_exists = 1;
+ } else {
+ if (getpwnam(user) != NULL)
+ user_exists = 1;
+ }
+ /* Now grope directly through the user database */
if ((dbp = dbopen(_PATH_SMP_DB, O_RDONLY, PERM_SECURE,
- DB_HASH, &openinfo)) == NULL)
- errx(1, "error opening database: %s.", _PATH_MP_DB);
+ DB_HASH, &openinfo)) == NULL) {
+ warn("error opening database: %s.", _PATH_MP_DB);
+ pw_error(tempname, 0, 1);
+ }
/* Is NIS turned on */
bf[0] = _PW_KEYYPENABLED;
key.data = (u_char *)bf;
key.size = 1;
- if (!(dbp->get)(dbp,&key,&data,0)) {
- if ((rval = yp_get_default_domain(&domain))) {
- warnx("can't get local NIS domain name: %s",yperr_string(rval));
- pw_error(NULL, 0, 1);
- }
+ if (!(dbp->get)(dbp,&key,&data,0) || (yp_domain && yp_server)) {
+ server = get_yp_master(0);
/* Is the user in the NIS passwd map */
- if (!yp_match(domain, "passwd.byname", user, strlen(user),
+ if (!my_yp_match(server, yp_domain, which ? "passwd.byuid" :
+ "passwd.byname", user, strlen(user),
&result, &resultlen)) {
- user_yp = 1;
+ user_yp = user_exists = 1;
+ *(char *)(result + resultlen) = '\0';
copy_yp_pass(result, 0, resultlen);
- free(result);
}
- /* Is the user in the NIS passwd map */
- if (user_yp && !yp_match(domain, "master.passwd.byname",
+ /* Is the user in the NIS master.passwd map */
+ if (user_yp && !my_yp_match(server, yp_domain, which ?
+ "master.passwd.byuid" : "master.passwd.byname",
user, strlen(user),
&result, &resultlen)) {
+ *(char *)(result + resultlen) = '\0';
copy_yp_pass(result, 1, resultlen);
}
- free(result);
}
/* Is the user in the local password database */
- bf[0] = _PW_KEYBYNAME;
- bcopy((char *)user, bf + 1, MIN(strlen(user), UT_NAMESIZE));
+ bf[0] = which ? _PW_KEYBYUID : _PW_KEYBYNAME;
+ if (which)
+ bcopy((char *)&uid, bf + 1, sizeof(uid));
+ else
+ bcopy((char *)user, bf + 1, MIN(strlen(user), UT_NAMESIZE));
key.data = (u_char *)bf;
- key.size = strlen(user) + 1;
+ key.size = which ? sizeof(uid) + 1 : strlen(user) + 1;
if (!(dbp->get)(dbp,&key,&data,0)) {
user_local = 1;
copy_local_pass(data.data, data.size);
@@ -232,31 +329,37 @@ char *user;
* Find the name of the NIS master server for this domain
* and make sure it's running yppasswdd.
*/
-static char *get_yp_master(void)
+char *get_yp_master(getserver)
+ int getserver;
{
- char *domain, *mastername;
- int rval;
+ char *mastername;
+ int rval, localport;
+ struct stat st;
/* Get default NIS domain. */
- if ((rval = yp_get_default_domain(&domain))) {
+ if (yp_domain == NULL && (rval = yp_get_default_domain(&yp_domain))) {
warnx("can't get local NIS domain name: %s",yperr_string(rval));
- pw_error(NULL, 0, 1);
+ pw_error(tempname, 0, 1);
}
/* Get master server of passwd map. */
- if ((rval = yp_master(domain, "passwd.byname", &mastername))) {
- warnx("can't get master NIS server: %s", yperr_string(rval));
- pw_error(NULL, 0, 1);
+ if ((mastername = ypxfr_get_master(yp_domain, "passwd.byname",
+ yp_server, yp_server ? 0 : 1)) == NULL) {
+ warnx("can't get name of master NIS server");
+ pw_error(tempname, 0, 1);
}
+ if (!getserver)
+ return(mastername);
+
/* Check if yppasswdd is out there. */
if ((rval = getrpcport(mastername, YPPASSWDPROG, YPPASSWDPROC_UPDATE,
IPPROTO_UDP)) == 0) {
- warnx("yppasswdd not running on NIS master server");
- pw_error(NULL, 0, 1);
+ warnx("rpc.yppasswdd is not running on the NIS master server");
+ pw_error(tempname, 0, 1);
}
/*
@@ -265,91 +368,136 @@ static char *get_yp_master(void)
*/
if (rval >= IPPORT_RESERVED) {
- warnx("yppasswdd server not running on reserved port");
- pw_error(NULL, 0, 1);
+ warnx("rpc.yppasswdd server not running on reserved port");
+ pw_error(tempname, 0, 1);
+ }
+
+ /* See if _we_ are the master server. */
+ if (!force_old && !getuid() && (localport = getrpcport("localhost",
+ YPPASSWDPROG, YPPASSWDPROC_UPDATE, IPPROTO_UDP)) != 0) {
+ if (localport == rval && stat(sockname, &st) != -1) {
+ suser_override = 1;
+ mastername = "localhost";
+ }
}
/* Everything checks out: return the name of the server. */
return (mastername);
}
+
/*
* Ask the user for his NIS password and submit the new information
- * to yppasswdd. Note that yppasswdd requires password authentication
+ * to yppasswdd. Note that rpc.yppasswdd requires password authentication
* and only allows changes to existing records rather than the addition
* of new records. (To do actual updates we would need something like
- * secure RPC and ypupdated, which FreeBSD doesn't have yet.) This means
- * that the superuser cannot use chpass(1) to add new users records to
- * the NIS password database.
+ * secure RPC and ypupdated, which FreeBSD doesn't have yet.) The FreeBSD
+ * rpc.yppasswdd has some special hooks to allow the superuser update
+ * information without specifying a password, however this only works
+ * for the superuser on the NIS master server.
*/
void yp_submit(pw)
-struct passwd *pw;
+ struct passwd *pw;
{
struct yppasswd yppasswd;
+ struct master_yppasswd master_yppasswd;
CLIENT *clnt;
- char *master, *password, *encpass;
- int rval, status = 0;
- struct timeval tv;
+ char *master, *password;
+ int *status = NULL;
+ struct rpc_err err;
- /* Populate the yppasswd structure that gets handed to yppasswdd. */
- /*
- * XXX This is done first to work around what looks like a very
- * strange memory corruption bug: the text fields pointed to
- * by the members of the 'pw' structure appear to be clobbered
- * after get_yp_master() returns (in particular, it happens
- * during getrpcport()). I don't know exactly where the problem
- * lies: I traced it all the way to gethostbyname(), then gave
- * up.
- */
- yppasswd.newpw.pw_passwd = strdup(pw->pw_passwd);
- yppasswd.newpw.pw_name = strdup(pw->pw_name);
- yppasswd.newpw.pw_uid = pw->pw_uid;
- yppasswd.newpw.pw_gid = pw->pw_gid;
- yppasswd.newpw.pw_gecos = strdup(pw->pw_gecos);
- yppasswd.newpw.pw_dir = strdup(pw->pw_dir);
- yppasswd.newpw.pw_shell = strdup(pw->pw_shell);
+ _use_yp = 1;
/* Get NIS master server name */
- master = get_yp_master();
+ master = get_yp_master(1);
+
+ /* Populate the yppasswd structure that gets handed to yppasswdd. */
+
+ if (suser_override) {
+ master_yppasswd.newpw.pw_passwd = strdup(pw->pw_passwd);
+ master_yppasswd.newpw.pw_name = strdup(pw->pw_name);
+ master_yppasswd.newpw.pw_uid = pw->pw_uid;
+ master_yppasswd.newpw.pw_gid = pw->pw_gid;
+ master_yppasswd.newpw.pw_expire = pw->pw_expire;
+ master_yppasswd.newpw.pw_change = pw->pw_change;
+ master_yppasswd.newpw.pw_fields = pw->pw_fields;
+ master_yppasswd.newpw.pw_gecos = strdup(pw->pw_gecos);
+ master_yppasswd.newpw.pw_dir = strdup(pw->pw_dir);
+ master_yppasswd.newpw.pw_shell = strdup(pw->pw_shell);
+ master_yppasswd.newpw.pw_class = strdup(pw->pw_class);
+ master_yppasswd.oldpass = ""; /* not really needed */
+ master_yppasswd.domain = yp_domain;
+ } else {
+ yppasswd.newpw.pw_passwd = strdup(pw->pw_passwd);
+ yppasswd.newpw.pw_name = strdup(pw->pw_name);
+ yppasswd.newpw.pw_uid = pw->pw_uid;
+ yppasswd.newpw.pw_gid = pw->pw_gid;
+ yppasswd.newpw.pw_gecos = strdup(pw->pw_gecos);
+ yppasswd.newpw.pw_dir = strdup(pw->pw_dir);
+ yppasswd.newpw.pw_shell = strdup(pw->pw_shell);
+ yppasswd.oldpass = "";
+ }
/* Get the user's password for authentication purposes. */
printf ("Changing NIS information for %s on %s\n",
- yppasswd.newpw.pw_name, master);
- encpass = (getpwnam(yppasswd.newpw.pw_name))->pw_passwd;
- password = getpass("Please enter password: ");
- if (strncmp(crypt(password, encpass), encpass, strlen(encpass))) {
- warnx("Password incorrect.");
- pw_error(NULL, 0, 1);
+ pw->pw_name, master);
+
+ if (pw->pw_passwd[0] && !suser_override) {
+ password = getpass("Please enter password: ");
+ if (strncmp(crypt(password,pw->pw_passwd),
+ pw->pw_passwd,strlen(pw->pw_passwd))) {
+ warnx("Password incorrect.");
+ pw_error(tempname, 0, 1);
+ }
+ yppasswd.oldpass = password; /* XXX */
}
- yppasswd.oldpass = password; /* XXX */
+ if (suser_override) {
+ /* Talk to server via AF_UNIX socket. */
+ if (senddat(&master_yppasswd)) {
+ warnx("failed to contact local rpc.yppasswdd");
+ pw_error(tempname, 0, 1);
+ }
+ /* Get return code. */
+ status = getresp();
+ } else {
+ /* Create a handle to yppasswdd. */
+
+ if ((clnt = clnt_create(master, YPPASSWDPROG,
+ YPPASSWDVERS, "udp")) == NULL) {
+ warnx("failed to contact rpc.yppasswdd on %s: %s",
+ master, clnt_spcreateerror(""));
+ pw_error(tempname, 0, 1);
+ }
- /* Create a handle to yppasswdd. */
+ clnt->cl_auth = authunix_create_default();
- clnt = clnt_create(master, YPPASSWDPROG, YPPASSWDVERS, "udp");
- clnt->cl_auth = authunix_create_default();
+ status = yppasswdproc_update_1(&yppasswd, clnt);
- /* Set a timeout and make the RPC call. */
+ clnt_geterr(clnt, &err);
- tv.tv_sec = 20;
- tv.tv_usec = 0;
- rval = clnt_call(clnt, YPPASSWDPROC_UPDATE, xdr_yppasswd,
- (char *)&yppasswd, xdr_int, (char *)&status, &tv);
+ auth_destroy(clnt->cl_auth);
+ clnt_destroy(clnt);
+ }
/* Call failed: signal the error. */
- if (rval) {
- warnx("NIS update failed: %s", clnt_sperrno(rval));
+ if ((!suser_override && err.re_status) != RPC_SUCCESS || status == NULL || *status) {
+ warnx("NIS update failed: %s", (err.re_status != RPC_SUCCESS &&
+ !suser_override) ? clnt_sperrno(err.re_status) :
+ "rpc.yppasswdd returned error status");
pw_error(NULL, 0, 1);
}
/* Success. */
- auth_destroy(clnt->cl_auth);
- clnt_destroy(clnt);
- warnx("NIS information changed on host %s", master);
+ if (suser_override)
+ warnx("NIS information changed on host %s, domain %s",
+ master, yp_domain);
+ else
+ warnx("NIS information changed on host %s", master);
return;
}
diff --git a/chpass/pw_yp.h b/chpass/pw_yp.h
index 9d98a43..7d37560 100644
--- a/chpass/pw_yp.h
+++ b/chpass/pw_yp.h
@@ -35,18 +35,91 @@
* Center for Telecommunications Research
* Columbia University, New York City
*
- * $Id: pw_yp.h,v 1.1 1995/08/13 16:12:28 wpaul Exp $
+ * $Id: pw_yp.h,v 1.8 1996/02/17 18:14:23 wpaul Exp $
*/
#ifdef YP
+#include <sys/types.h>
+#include <rpc/rpc.h>
+#include <rpc/auth.h>
+#include <rpc/auth_unix.h>
/* Four possible return codes from use_yp() */
#define USER_UNKNOWN 0
#define USER_YP_ONLY 1
#define USER_LOCAL_ONLY 2
#define USER_YP_AND_LOCAL 3
+
+extern int force_old;
extern int _use_yp;
+extern int suser_override;
extern struct passwd local_password;
extern struct passwd yp_password;
-void yp_submit __P(( struct passwd * ));
-int use_yp __P(( char * ));
+extern void copy_yp_pass __P(( char *, int, int ));
+extern char *yp_domain;
+extern char *yp_server;
+extern void yp_submit __P(( struct passwd * ));
+extern int use_yp __P(( char * , uid_t , int ));
+extern char *get_yp_master __P(( int ));
+
+/*
+ * Yucky.
+ */
+#define GETPWUID(X) \
+ _use_yp = use_yp(NULL, X, 1); \
+ \
+ if (_use_yp == USER_UNKNOWN) { \
+ errx(1, "unknown user: uid %u", X); \
+ } \
+ \
+ if (_use_yp == USER_YP_ONLY) { \
+ if (!force_local) { \
+ _use_yp = 1; \
+ pw = (struct passwd *)&yp_password; \
+ } else \
+ errx(1, "unknown local user: uid %u", X); \
+ } else if (_use_yp == USER_LOCAL_ONLY) { \
+ if (!force_yp) { \
+ _use_yp = 0; \
+ pw = (struct passwd *)&local_password; \
+ } else \
+ errx(1, "unknown NIS user: uid %u", X); \
+ } else if (_use_yp == USER_YP_AND_LOCAL) { \
+ if (!force_local) { \
+ _use_yp = 1; \
+ pw = (struct passwd *)&yp_password; \
+ } else { \
+ _use_yp = 0; \
+ pw = (struct passwd *)&local_password; \
+ } \
+ }
+
+#define GETPWNAM(X) \
+ _use_yp = use_yp(X, 0, 0); \
+ \
+ if (_use_yp == USER_UNKNOWN) { \
+ errx(1, "unknown user: %s", X); \
+ } \
+ \
+ if (_use_yp == USER_YP_ONLY) { \
+ if (!force_local) { \
+ _use_yp = 1; \
+ pw = (struct passwd *)&yp_password; \
+ } else \
+ errx(1, "unknown local user: %s.", X); \
+ } else if (_use_yp == USER_LOCAL_ONLY) { \
+ if (!force_yp) { \
+ _use_yp = 0; \
+ pw = (struct passwd *)&local_password; \
+ } else \
+ errx(1, "unknown NIS user: %s.", X); \
+ } else if (_use_yp == USER_YP_AND_LOCAL) { \
+ if (!force_local) { \
+ _use_yp = 1; \
+ pw = (struct passwd *)&yp_password; \
+ } else { \
+ _use_yp = 0; \
+ pw = (struct passwd *)&local_password; \
+ } \
+ }
+
#endif /* YP */