summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--usr.bin/chpass/Makefile37
-rw-r--r--usr.bin/chpass/chpass.1113
-rw-r--r--usr.bin/chpass/chpass.c81
-rw-r--r--usr.bin/chpass/edit.c10
-rw-r--r--usr.bin/chpass/pw_yp.c328
-rw-r--r--usr.bin/chpass/pw_yp.h79
-rw-r--r--usr.bin/passwd/Makefile42
-rw-r--r--usr.bin/passwd/passwd.155
-rw-r--r--usr.bin/passwd/passwd.c49
-rw-r--r--usr.bin/passwd/yp_passwd.c256
10 files changed, 755 insertions, 295 deletions
diff --git a/usr.bin/chpass/Makefile b/usr.bin/chpass/Makefile
index a1e2947..0f582b9 100644
--- a/usr.bin/chpass/Makefile
+++ b/usr.bin/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/usr.bin/chpass/chpass.1 b/usr.bin/chpass/chpass.1
index 83cddb8..2ba9be0 100644
--- a/usr.bin/chpass/chpass.1
+++ b/usr.bin/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/usr.bin/chpass/chpass.c b/usr.bin/chpass/chpass.c
index 2bfdd10..17d742a 100644
--- a/usr.bin/chpass/chpass.c
+++ b/usr.bin/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/usr.bin/chpass/edit.c b/usr.bin/chpass/edit.c
index c0f61e0..2968c84 100644
--- a/usr.bin/chpass/edit.c
+++ b/usr.bin/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/usr.bin/chpass/pw_yp.c b/usr.bin/chpass/pw_yp.c
index 2c1c138..9493db8 100644
--- a/usr.bin/chpass/pw_yp.c
+++ b/usr.bin/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/usr.bin/chpass/pw_yp.h b/usr.bin/chpass/pw_yp.h
index 9d98a43..7d37560 100644
--- a/usr.bin/chpass/pw_yp.h
+++ b/usr.bin/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 */
diff --git a/usr.bin/passwd/Makefile b/usr.bin/passwd/Makefile
index b7866de..b5d7a3c 100644
--- a/usr.bin/passwd/Makefile
+++ b/usr.bin/passwd/Makefile
@@ -1,15 +1,47 @@
# From: @(#)Makefile 8.3 (Berkeley) 4/2/94
-# $Id: Makefile,v 1.17 1995/09/03 11:40:37 markm Exp $
+# $Id: Makefile,v 1.18 1995/09/14 21:02:16 gibbs Exp $
PROG= passwd
-SRCS= local_passwd.c yp_passwd.c passwd.c pw_copy.c pw_util.c pw_yp.c
+SRCS= local_passwd.c yppasswd_private_xdr.c yppasswd_comm.c yp_passwd.c \
+ passwd.c pw_copy.c pw_util.c pw_yp.c
+
DPADD= ${LIBCRYPT} ${LIBRPCSVC}
LDADD= -lcrypt -lrpcsvc
.PATH: ${.CURDIR}/../../usr.bin/chpass ${.CURDIR}/../../usr.sbin/vipw \
- ${.CURDIR}/../rlogin
+ ${.CURDIR}/../rlogin ${.CURDIR}/../../libexec/ypxfr \
+ ${.CURDIR}/../../usr.sbin/rpc.yppasswdd
+
+CFLAGS+= -DCRYPT -DYP -I. -I${.CURDIR} -I${.CURDIR}/../../usr.sbin/vipw \
+ -I${.CURDIR}/../../usr.bin/chpass -I${.CURDIR}/../../libexec/ypxfr \
+ -I${.CURDIR}/../../usr.sbin/rpc.yppasswdd -Dyp_error=warnx
+
+SRCS+= ypxfr_misc.c yp_clnt.c yppasswd_clnt.c
+
+CLEANFILES= yp.h yp_clnt.c yppasswd.h yppasswd_clnt.c \
+ yppasswd_private.h yppasswd_private_xdr.c
+
+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}
-CFLAGS+=-DCRYPT -DYP -I${.CURDIR} -I${.CURDIR}/../../usr.sbin/vipw \
- -I${.CURDIR}/../../usr.bin/chpass
+yppasswd_private_xdr.c: ${RPCSRC_PRIV} yppasswd_private.h
+ ${RPCGEN} -c -o ${.TARGET} ${RPCSRC_PRIV}
BINOWN= root
BINMODE=4555
diff --git a/usr.bin/passwd/passwd.1 b/usr.bin/passwd/passwd.1
index 47a337a..533cd5e 100644
--- a/usr.bin/passwd/passwd.1
+++ b/usr.bin/passwd/passwd.1
@@ -87,6 +87,19 @@ user does not exist in either the local password database of the
NIS password maps,
.Nm passwd
returns an error.
+.Pp
+When changing an NIS password, unprivileged users are required to provide
+their old password for authentication (the
+.Xr rpc.yppasswdd 8
+daemon requires the original password before
+it will allow any changes to the NIS password maps).
+This restriction applies even to the
+super-user, with one important exception: the password authentication is
+bypassed for the super-user on the NIS master server. This means that
+the super-user on the NIS master server can make unrestricted changes to
+anyone's NIS password. The super-user on NIS client systems and NIS slave
+servers still needs to provide a password before the update will be processed.
+.Pp
The following additional options are supported for use with NIS:
.Bl -tag -width flag
.It Fl y
@@ -114,17 +127,39 @@ default,
will try to change the NIS password. The
.Fl l
flag can be used to change the local password instead.
-.El
+.It Fl d Ar domain
+Specify what domain to use when changing an NIS password. By default,
+.Nm passwd
+assumes that the system default domain should be used. This flag is
+primarily for use by the superuser on the NIS master server: a single
+NIS server can support multiple domains. It is also possible that the
+domainname on the NIS master may not be set (it is not necessary for
+an NIS server to also be a client) in which case the
+.Nm passwd
+command needs to be told what domain to operate on.
+.It Fl s Ar host
+Specify the name of an NIS server. This option, in conjunction
+with the
+.Fl d
+option, can be used to change an NIS password on a non-local NIS
+server. When a domain is specified with the
+.Fl d
+option and
+.Nm passwd
+is unable to determine the name of the NIS master server (possibly because
+the local domainname isn't set), the name of the NIS master is assumed to
+be ``localhost''. This can be overriden with the
+.Fl s
+flag. The specified hostname need not be the name of an NIS master: the
+name of the NIS master for a given map can be determined by querying any
+NIS server (master or slave) in a domain, so specifying the name of a
+slave server will work equally well.
.Pp
-When changing an NIS password, the user is required to provide
-the old password for authentication (the
-.Xr yppasswdd 8
-daemon requires the original password before
-it will allow any changes to the NIS password maps).
-This restriction applies even to the
-super-user: the only way for an administrator to override a
-user's NIS password is by modifying the NIS password maps on
-the master NIS server.
+.It Fl o
+Do not automatically override the password authentication checks for the
+super-user on the NIS master server; assume 'old' mode instead. This
+flag is of limited practical use but is useful for testing.
+.El
.Sh FILES
.Bl -tag -width /etc/master.passwd -compact
.It Pa /etc/master.passwd
diff --git a/usr.bin/passwd/passwd.c b/usr.bin/passwd/passwd.c
index 92dd895..a7e2623 100644
--- a/usr.bin/passwd/passwd.c
+++ b/usr.bin/passwd/passwd.c
@@ -43,7 +43,7 @@ static const char copyright[] =
#ifndef lint
static const char sccsid[] = "From: @(#)passwd.c 8.3 (Berkeley) 4/2/94";
static const char rcsid[] =
- "$Id$";
+ "$Id: passwd.c,v 1.7 1995/12/16 09:45:15 markm Exp $";
#endif /* not lint */
#include <err.h>
@@ -56,9 +56,10 @@ static const char rcsid[] =
#ifdef YP
#include <pwd.h>
#include <pw_yp.h>
-char *prog_name;
+#include <rpcsvc/yp.h>
int __use_yp = 0;
-int yp_passwd(char *user);
+int yp_errno = YP_TRUE;
+extern int yp_passwd __P(( char * ));
#endif
#ifdef KERBEROS
@@ -83,9 +84,9 @@ main(argc, argv)
#ifdef YP
#ifdef KERBEROS
char realm[REALM_SZ];
-#define OPTIONS "lysfi:r:u:"
+#define OPTIONS "d:h:lysfoi:r:u:"
#else
-#define OPTIONS "lysf"
+#define OPTIONS "d:h:lysfo"
#endif
#else
#ifdef KERBEROS
@@ -99,7 +100,7 @@ main(argc, argv)
#ifdef YP
int res = 0;
- if (strstr(argv[0], (prog_name = "yppasswd"))) __use_yp = 1;
+ if (strstr(argv[0], "yppasswd")) __use_yp = 1;
#endif
while ((ch = getopt(argc, argv, OPTIONS)) != EOF) {
@@ -122,6 +123,33 @@ main(argc, argv)
case 'y': /* Change NIS password */
__use_yp = 1;
break;
+ case 'd': /* Specify NIS domain. */
+#ifdef PARANOID
+ if (!getuid()) {
+#endif
+ yp_domain = optarg;
+ if (yp_server == NULL)
+ yp_server = "localhost";
+#ifdef PARANOID
+ } else {
+ warnx("Only the super-user may use the -d flag.");
+ }
+#endif
+ break;
+ case 'h': /* Specify NIS server. */
+#ifdef PARANOID
+ if (!getuid()) {
+#endif
+ yp_server = optarg;
+#ifdef PARANOID
+ } else {
+ warnx("Only the super-user may use the -h flag.");
+ }
+#endif
+ break;
+ case 'o':
+ force_old++;
+ break;
#endif
default:
case '?':
@@ -152,8 +180,8 @@ main(argc, argv)
#ifdef KERBEROS
if (__use_yp || (iflag == NULL && rflag == NULL && uflag == NULL)) {
#endif
- res = use_yp(uname);
- if (res == USER_YP_ONLY) {
+ res = use_yp(uname, 0, 0);
+ if (res == USER_YP_ONLY || __use_yp) {
if (!use_local_passwd) {
exit(yp_passwd(uname));
} else {
@@ -198,9 +226,10 @@ usage()
fprintf(stderr,
"usage: passwd [-l] [-i instance] [-r realm] [-u fullname]\n");
fprintf(stderr,
- " [-l] [-y] [user]\n");
+ " [-l] [-y] [-o] [-d domain [-h host]] [user]\n");
#else
- (void)fprintf(stderr, "usage: passwd [-l] [-y] [user] \n");
+ (void)fprintf(stderr, "usage: passwd [-l] [-y] [-o] [-d domain \
+[-h host]] [user] \n");
#endif
#else
#ifdef KERBEROS
diff --git a/usr.bin/passwd/yp_passwd.c b/usr.bin/passwd/yp_passwd.c
index fc6b0e4..b83e9f1 100644
--- a/usr.bin/passwd/yp_passwd.c
+++ b/usr.bin/passwd/yp_passwd.c
@@ -45,137 +45,141 @@
#include <rpcsvc/ypclnt.h>
#include <rpcsvc/yppasswd.h>
#include <pw_yp.h>
-
-extern char *prog_name;
-uid_t uid;
+#include "yppasswd_comm.h"
extern char *getnewpasswd __P(( struct passwd * , int ));
-char *
-getserver( void )
-{
- char *domainname, *master;
- int port, err;
- int getrpcport();
-
- if ((err = yp_get_default_domain(&domainname)) != 0) {
- fprintf(stderr, "%s: can't get local yp domain: %s\n",
- prog_name, yperr_string(err));
- return NULL;
- }
-
- if ((err = yp_master(domainname, "passwd.byname", &master)) != 0) {
- fprintf(stderr, "%s: can't find the master ypserver: %s\n",
- prog_name, yperr_string(err));
- return NULL;
- }
- port = getrpcport(master, YPPASSWDPROG, YPPASSWDPROC_UPDATE, IPPROTO_UDP);
- if (port==0) {
- fprintf (stderr, "%s: yppasswdd not running on NIS master host\n",
- prog_name);
- return NULL;
- }
- if (port >= IPPORT_RESERVED) {
- fprintf (stderr, "%s: yppasswd daemon running on illegal port.\n",
- prog_name);
- return NULL;
- }
- return master;
-}
-
int
yp_passwd(char *user)
{
- struct timeval timeout;
- struct yppasswd yppasswd;
- struct passwd *pw;
- CLIENT *clnt;
- char *master;
- int err, status;
- char *s;
-
- if ((master = getserver()) == NULL) {
- exit(1);
- }
-
- /* Obtain the passwd struct for the user whose password is to be changed.
- */
- uid = getuid();
- if (user == NULL) {
- if ((pw = getpwuid(uid)) == NULL) {
- fprintf ( stderr, "%s: unknown user (uid=%d).\n",
- prog_name, (int)uid );
- exit(1);
- }
- } else {
- if ((pw = getpwnam(user)) == NULL) {
- fprintf ( stderr, "%s: unknown user: %s.\n", prog_name, user );
- exit(1);
- }
- if (pw->pw_uid != uid && uid != 0) {
- fprintf ( stderr, "%s: Only root may change account information "
- "for others\n", prog_name );
- exit(1);
- }
- }
-
- /* Use the correct password */
- pw = (struct passwd *)&yp_password;
-
- /* Initialize password information */
- yppasswd.newpw.pw_passwd = pw->pw_passwd;
- yppasswd.newpw.pw_name = pw->pw_name;
- yppasswd.newpw.pw_uid = pw->pw_uid;
- yppasswd.newpw.pw_gid = pw->pw_gid;
- yppasswd.newpw.pw_gecos = pw->pw_gecos;
- yppasswd.newpw.pw_dir = pw->pw_dir;
- yppasswd.newpw.pw_shell = pw->pw_shell;
- yppasswd.oldpass = NULL;
-
- printf("Changing NIS password for %s on %s.\n", pw->pw_name, master);
-
- /* Get old password */
- if(pw->pw_passwd[0]) {
-
- s = getpass ("Old password: ");
- if( strcmp(crypt(s, pw->pw_passwd), pw->pw_passwd)) {
- fprintf(stderr, "Sorry.\n");
- exit (1);
- }
- yppasswd.oldpass = strdup(s);
- } else
- yppasswd.oldpass = "";
-
- if ((s = getnewpasswd(pw, 1)) == NULL)
- exit (1);
- yppasswd.newpw.pw_passwd = s;
-
- /* The yppasswd.x file said `unix authentication required',
- * so I added it. This is the only reason it is in here.
- * My yppasswdd doesn't use it, but maybe some others out there
- * do. --okir
- */
- clnt = clnt_create( master, YPPASSWDPROG, YPPASSWDVERS, "udp" );
- clnt->cl_auth = authunix_create_default();
- bzero( (char*)&status, sizeof(status) );
- timeout.tv_sec = 25; timeout.tv_usec = 0;
- err = clnt_call( clnt, YPPASSWDPROC_UPDATE,
- xdr_yppasswd, (char*)&yppasswd,
- xdr_int, (char*)&status,
- &timeout );
-
- if (err) {
- clnt_perrno(err);
- fprintf( stderr, "\n" );
- } else if (status) {
- fprintf( stderr, "Error while changing NIS password.\n");
- }
-
- printf("\nNIS password has%s been changed on %s.\n",
- (err || status)? " not" : "", master);
-
- auth_destroy( clnt->cl_auth );
- clnt_destroy( clnt );
- exit ((err || status) != 0);
+ struct timeval timeout;
+ struct yppasswd yppasswd;
+ struct master_yppasswd master_yppasswd;
+ struct passwd *pw;
+ CLIENT *clnt;
+ struct rpc_err err;
+ char *master;
+ int *status = NULL;
+ uid_t uid;
+
+ _use_yp = 1;
+
+ uid = getuid();
+
+ if ((master = get_yp_master(1)) == NULL) {
+ warnx("failed to find NIS master server");
+ return(1);
+ }
+
+ /*
+ * It is presumed that by the time we get here, use_yp()
+ * has been called and that we have verified that the user
+ * actually exists. This being the case, the yp_password
+ * stucture has already been filled in for us.
+ */
+
+ /* Use the correct password */
+ pw = (struct passwd *)&yp_password;
+
+ if (pw->pw_uid != uid && uid != 0) {
+ warnx("Only the super-user may change account information \
+for other users");
+ return(1);
+ }
+
+ /* Initialize password information */
+ 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 = "";
+ 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 = "";
+ }
+
+ if (suser_override)
+ printf("Changing NIS password for %s on %s in domain %s.\n",
+ pw->pw_name, master, yp_domain);
+ else
+ printf("Changing NIS password for %s on %s.\n",
+ pw->pw_name, master);
+
+ /* Get old password */
+
+ if(pw->pw_passwd[0] && !suser_override) {
+ yppasswd.oldpass = strdup(getpass("Old Password: "));
+ if (strcmp(crypt(yppasswd.oldpass, pw->pw_passwd),
+ pw->pw_passwd)) {
+ errx(1, "Sorry.");
+ }
+
+ }
+
+ if (suser_override) {
+ if ((master_yppasswd.newpw.pw_passwd = getnewpasswd(pw, 1)) == NULL)
+ return(1);
+ } else {
+ if ((yppasswd.newpw.pw_passwd = getnewpasswd(pw, 1)) == NULL)
+ return(1);
+ }
+
+ if (suser_override) {
+ if (senddat(&master_yppasswd)) {
+ warnx("failed to send request to rpc.yppasswdd");
+ return(1);
+ }
+ status = getresp();
+ } else {
+ if ((clnt = clnt_create(master, YPPASSWDPROG,
+ YPPASSWDVERS, "udp")) == NULL) {
+ warnx("failed to contact rpc.yppasswdd on host %s: %s",
+ master, clnt_spcreateerror(""));
+ return(1);
+ }
+ /*
+ * The yppasswd.x file said `unix authentication required',
+ * so I added it. This is the only reason it is in here.
+ * My yppasswdd doesn't use it, but maybe some others out there
+ * do. --okir
+ */
+ clnt->cl_auth = authunix_create_default();
+
+ status = yppasswdproc_update_1(&yppasswd, clnt);
+ clnt_geterr(clnt, &err);
+
+ auth_destroy(clnt->cl_auth);
+ clnt_destroy(clnt);
+ }
+
+ if ((!suser_override && err.re_status != RPC_SUCCESS) ||
+ status == NULL || *status) {
+ errx(1, "Failed to change NIS password: %s",
+ (err.re_status != RPC_SUCCESS && !suser_override) ?
+ clnt_sperrno(err.re_status) :
+ "rpc.yppasswdd returned error status");
+ }
+
+ printf("\nNIS password has%s been changed on %s.\n",
+ ((err.re_status != RPC_SUCCESS && !suser_override)
+ || status == NULL || *status) ?
+ " not" : "", master);
+
+ return ((err.re_status || status == NULL || *status));
}
#endif /* YP */
OpenPOWER on IntegriCloud