summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwpaul <wpaul@FreeBSD.org>1996-02-12 15:09:01 +0000
committerwpaul <wpaul@FreeBSD.org>1996-02-12 15:09:01 +0000
commit12f2e571f2f4854fee5b4fcefe9b6dadcc2f834f (patch)
tree6d384b289c217872a5ffe32b83a5d73cdee478e5
parentee368fa2d33a61b8664ae6f6ebdae90f863db1e2 (diff)
downloadFreeBSD-src-12f2e571f2f4854fee5b4fcefe9b6dadcc2f834f.zip
FreeBSD-src-12f2e571f2f4854fee5b4fcefe9b6dadcc2f834f.tar.gz
Import new rpc.yppasswdd. (Note: accompanying changes to passwd(1) and
chpass(1) are on the way too.) This version supports all the features of the old one and adds several new ones: - Supports real multi-domain operation (optional, can be turned on with a command-line flag). This means you can actually have several different domains all served from one NIS server and allow users in any of the supported domains to change their passwords. The old yppasswdd only allowed changing passwords in the domain that was set as the system default domain name on the NIS master server. The new one can change passwords in any domain by trying to match the user information passed to it against all the passwd maps it can find. This is something of a hack, but the yppasswd.x protocol definiton does not allow for a domain to be passwd as an argument to rpc.yppasswdd, so the server has no choice but to grope around for a likely match. Since this method can fail if the same user exists in two domains, this feature is off by default. If the feature is turned on and the server becomes confused by duplicate entries, it will abort the update. - Does not require NIS client services to be available. NIS servers do _NOT_ necessarily have to be configured as NIS clients in order to function: the ypserv, ypxfr and yppush programs I've written recently will operate fine even if the system domain name isn't set, ypbind isn't running and there are no magic '+' entries in any of the /etc files. Now rpc.yppasswdd is the same way. The old yppasswdd would not work like this because it depended on getpwent(3) and friends to look up users: this will obviously only work if the system where yppasswdd is running is configured as an NIS client. The new rpc.yppasswdd doesn't use getpwent(3) at all: instead it searches through the master.passwd map databases directly. This also makes it easier for it to handle multiple domains. - Allows the superuser on the NIS master server to change any user's password without requiring password authentication. rpc.yppasswdd creates a UNIX domain socket (/var/run/ypsock) which it monitors using the same svc_run() loop used to handle incoming RPC requests. It also clears all the permission bits for /var/run/ypsock; since this socket is owned by root, this prevents anyone except root from successfully connect()ing to it. (Using a UNIX domain socket also prevents IP spoofing attacks.) By building code into passwd(1) and chpass(1) to take advantage of this 'trusted' channel, the superuser can use them to send private requests to rpc.yppasswdd. - Allows the superuser on the NIS master to use chpass(1) to update _all_ of a user's master.passwd information. The UNIX domain access point accepts a full master.passwd style structure (along with a domain name and other information), which allows the superuser to update all of a user's master.passwd information in the NIS master.passwd maps. Normal users on NIS clients are still only allowed to change their full name and shell information with chpass. - Allows the superuser on the NIS master to _add_ records to the NIS master.passwd maps using chpass(1). This feature is also switchable with a command-line flag and is off by default.
-rw-r--r--dist/usr.sbin/rpc.yppasswdd/Makefile55
-rw-r--r--dist/usr.sbin/rpc.yppasswdd/pw_copy.c122
-rw-r--r--dist/usr.sbin/rpc.yppasswdd/pw_util.c174
-rw-r--r--dist/usr.sbin/rpc.yppasswdd/rpc.yppasswdd.8276
-rw-r--r--dist/usr.sbin/rpc.yppasswdd/yppasswd_comm.c300
-rw-r--r--dist/usr.sbin/rpc.yppasswdd/yppasswd_comm.h46
-rw-r--r--dist/usr.sbin/rpc.yppasswdd/yppasswd_private.x67
-rw-r--r--dist/usr.sbin/rpc.yppasswdd/yppasswdd_extern.h71
-rw-r--r--dist/usr.sbin/rpc.yppasswdd/yppasswdd_main.c362
-rw-r--r--dist/usr.sbin/rpc.yppasswdd/yppasswdd_server.c649
-rw-r--r--dist/usr.sbin/rpc.yppasswdd/yppwupdate33
11 files changed, 2155 insertions, 0 deletions
diff --git a/dist/usr.sbin/rpc.yppasswdd/Makefile b/dist/usr.sbin/rpc.yppasswdd/Makefile
new file mode 100644
index 0000000..8632fd8
--- /dev/null
+++ b/dist/usr.sbin/rpc.yppasswdd/Makefile
@@ -0,0 +1,55 @@
+# $Id: Makefile,v 1.3 1996/02/11 02:46:48 wpaul Exp $
+
+PROG= rpc.yppasswdd
+SRCS= pw_copy.c pw_util.c yppasswd_svc.c yp_error.c ypxfr_misc.c \
+ yp_clnt.c yp_dblookup.c yppasswd_private_xdr.c \
+ util.c yppasswdd_server.c yppasswd_comm.c yppasswdd_main.c
+
+.PATH: ${.CURDIR}/../../usr.sbin/ypserv ${.CURDIR}/../../usr.bin/chpass \
+ ${.CURDIR}/../../libexec/ypxfr
+
+MAN8= rpc.yppasswdd.8
+
+CFLAGS+= -I. -I${.CURDIR}/../../usr.sbin/vipw \
+ -I${.CURDIR}/../../libexec/ypxfr -I${.CURDIR}/../../usr.bin/chpass \
+ -I${.CURDIR}
+
+LDADD+=-lrpcsvc -lcrypt
+
+CLEANFILES= yppasswd_svc.c yppasswd.h \
+ yppasswd_private_xdr.c yppasswd_private.h \
+ yp.h yp_clnt.c
+
+RPCSRC= ${.DESTDIR}/usr/include/rpcsvc/yppasswd.x
+YP_RPCSRC= ${.DESTDIR}/usr/include/rpcsvc/yp.x
+PRIV_RPCSRC= ${.CURDIR}/yppasswd_private.x
+RPCGEN= rpcgen -I -C
+
+# We need to remove the 'static' keyword from _rpcsvcstate so that
+# yppasswdd_main.c can see it.
+yppasswd_svc.c: ${RPCSRC} yppasswd.h
+ rm -f ${.TARGET}
+ ${RPCGEN} -m ${RPCSRC} | \
+ sed s/"static int _rpcsvcstate"/"int _rpcsvcstate"/g > ${.TARGET}
+
+yppasswd.h: ${RPCSRC}
+ ${RPCGEN} -h -o ${.TARGET} ${RPCSRC}
+
+yp.h: ${YP_RPCSRC}
+ ${RPCGEN} -h -o ${.TARGET} ${YP_RPCSRC}
+
+yp_clnt.c: ${YP_RPCSRC} yp.h
+ ${RPCGEN} -DYPSERV_ONLY -l -o ${.TARGET} ${YP_RPCSRC}
+
+yppasswd_private.h: ${PRIV_RPCSRC}
+ ${RPCGEN} -h -o ${.TARGET} ${PRIV_RPCSRC}
+
+yppasswd_private_xdr.c: ${PRIV_RPCSRC} yppasswd_private.h
+ ${RPCGEN} -c -o ${.TARGET} ${PRIV_RPCSRC}
+
+afterinstall:
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+ ${.CURDIR}/yppwupdate \
+ ${DESTDIR}/usr/libexec/yppwupdate
+
+.include <bsd.prog.mk>
diff --git a/dist/usr.sbin/rpc.yppasswdd/pw_copy.c b/dist/usr.sbin/rpc.yppasswdd/pw_copy.c
new file mode 100644
index 0000000..54ab746
--- /dev/null
+++ b/dist/usr.sbin/rpc.yppasswdd/pw_copy.c
@@ -0,0 +1,122 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)pw_copy.c 8.4 (Berkeley) 4/2/94";
+#endif /* not lint */
+
+/*
+ * This module is used to copy the master password file, replacing a single
+ * record, by chpass(1) and passwd(1).
+ */
+
+#include <err.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <pw_util.h>
+#include "yppasswdd_extern.h"
+
+int
+pw_copy(ffd, tfd, pw)
+ int ffd, tfd;
+ struct passwd *pw;
+{
+ FILE *from, *to;
+ int done;
+ char *p, buf[8192];
+
+ if (!(from = fdopen(ffd, "r"))) {
+ pw_error(passfile, 1, 1);
+ return(-1);
+ }
+ if (!(to = fdopen(tfd, "w"))) {
+ pw_error(tempname, 1, 1);
+ return(-1);
+ }
+ for (done = 0; fgets(buf, sizeof(buf), from);) {
+ if (!strchr(buf, '\n')) {
+ yp_error("%s: line too long", passfile);
+ pw_error(NULL, 0, 1);
+ goto err;
+ }
+ if (done) {
+ (void)fprintf(to, "%s", buf);
+ if (ferror(to))
+ goto err;
+ continue;
+ }
+ if (!(p = strchr(buf, ':'))) {
+ yp_error("%s: corrupted entry", passfile);
+ pw_error(NULL, 0, 1);
+ goto err;
+ }
+ *p = '\0';
+ if (strcmp(buf, pw->pw_name)) {
+ *p = ':';
+ (void)fprintf(to, "%s", buf);
+ if (ferror(to))
+ goto err;
+ continue;
+ }
+ (void)fprintf(to, "%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s\n",
+ pw->pw_name, pw->pw_passwd, pw->pw_uid, pw->pw_gid,
+ pw->pw_class, pw->pw_change, pw->pw_expire, pw->pw_gecos,
+ pw->pw_dir, pw->pw_shell);
+ done = 1;
+ if (ferror(to))
+ goto err;
+ }
+ if (!done) {
+ if (allow_additions) {
+ (void)fprintf(to, "%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s\n",
+ pw->pw_name, pw->pw_passwd, pw->pw_uid, pw->pw_gid,
+ pw->pw_class, pw->pw_change, pw->pw_expire,
+ pw->pw_gecos, pw->pw_dir, pw->pw_shell);
+ } else {
+ yp_error("user \"%s\" not found in %s -- \
+NIS maps and password file possibly out of sync", pw->pw_name, passfile);
+ goto err;
+ }
+ }
+ if (ferror(to)) {
+err: pw_error(NULL, 1, 1);
+ (void)fclose(to);
+ (void)fclose(from);
+ return(-1);
+ }
+ (void)fclose(to);
+ (void)fclose(from);
+ return(0);
+}
diff --git a/dist/usr.sbin/rpc.yppasswdd/pw_util.c b/dist/usr.sbin/rpc.yppasswdd/pw_util.c
new file mode 100644
index 0000000..bfd5c5b
--- /dev/null
+++ b/dist/usr.sbin/rpc.yppasswdd/pw_util.c
@@ -0,0 +1,174 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)pw_util.c 8.3 (Berkeley) 4/2/94";
+#endif /* not lint */
+
+/*
+ * This file is used by all the "password" programs; vipw(8), chpass(1),
+ * and passwd(1).
+ */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <pw_util.h>
+#include "yppasswdd_extern.h"
+
+int pstat;
+pid_t pid;
+
+void
+pw_init()
+{
+ struct rlimit rlim;
+
+ /* Unlimited resource limits. */
+ rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY;
+ (void)setrlimit(RLIMIT_CPU, &rlim);
+ (void)setrlimit(RLIMIT_FSIZE, &rlim);
+ (void)setrlimit(RLIMIT_STACK, &rlim);
+ (void)setrlimit(RLIMIT_DATA, &rlim);
+ (void)setrlimit(RLIMIT_RSS, &rlim);
+
+ /* Don't drop core (not really necessary, but GP's). */
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ (void)setrlimit(RLIMIT_CORE, &rlim);
+
+ /* Turn off signals. */
+ /* (void)signal(SIGALRM, SIG_IGN); */
+ (void)signal(SIGHUP, SIG_IGN);
+ (void)signal(SIGINT, SIG_IGN);
+ (void)signal(SIGPIPE, SIG_IGN);
+ (void)signal(SIGQUIT, SIG_IGN);
+ (void)signal(SIGTSTP, SIG_IGN);
+ (void)signal(SIGTTOU, SIG_IGN);
+
+ /* Create with exact permissions. */
+ (void)umask(0);
+}
+
+static int lockfd;
+
+int
+pw_lock()
+{
+ /*
+ * If the master password file doesn't exist, the system is hosed.
+ * Might as well try to build one. Set the close-on-exec bit so
+ * that users can't get at the encrypted passwords while editing.
+ * Open should allow flock'ing the file; see 4.4BSD. XXX
+ */
+ lockfd = open(passfile, O_RDONLY, 0);
+ if (lockfd < 0 || fcntl(lockfd, F_SETFD, 1) == -1) {
+ yp_error("%s: %s", passfile, strerror(errno));
+ return (-1);
+ }
+ if (flock(lockfd, LOCK_EX|LOCK_NB)) {
+ yp_error("%s: the password db file is busy", passfile);
+ return(-1);
+ }
+ return (lockfd);
+}
+
+int
+pw_tmp()
+{
+ static char path[MAXPATHLEN];
+ int fd;
+ char *p;
+
+ sprintf(path,"%s",passfile);
+ if ((p = strrchr(path, '/')))
+ ++p;
+ else
+ p = path;
+ strcpy(p, "pw.XXXXXX");
+ if ((fd = mkstemp(path)) == -1) {
+ yp_error("%s: %s", path, strerror(errno));
+ return(-1);
+ }
+ tempname = path;
+ return (fd);
+}
+
+int
+pw_mkdb()
+{
+
+ yp_error("rebuilding the database...");
+ (void)fflush(stderr);
+ /* Temporarily turn off SIGCHLD catching */
+ install_reaper(0);
+ if (!(pid = vfork())) {
+ execl(_PATH_PWD_MKDB, "pwd_mkdb", "-p", tempname, NULL);
+ pw_error(_PATH_PWD_MKDB, 1, 1);
+ return(-1);
+ }
+ /* Handle this ourselves. */
+ reaper(-1);
+ /* Put the handler back. Foo. */
+ install_reaper(1);
+ if (pid == -1 || !WIFEXITED(pstat) || WEXITSTATUS(pstat) != 0) {
+ return (-1);
+ }
+ yp_error("done");
+ return (0);
+}
+
+void
+pw_error(name, err, eval)
+ char *name;
+ int err, eval;
+{
+ if (err && name != NULL)
+ yp_error("%s", name);
+
+ yp_error("%s: unchanged", passfile);
+ (void)unlink(tempname);
+}
diff --git a/dist/usr.sbin/rpc.yppasswdd/rpc.yppasswdd.8 b/dist/usr.sbin/rpc.yppasswdd/rpc.yppasswdd.8
new file mode 100644
index 0000000..fd51b96
--- /dev/null
+++ b/dist/usr.sbin/rpc.yppasswdd/rpc.yppasswdd.8
@@ -0,0 +1,276 @@
+.\" Copyright (c) 1995, 1996
+.\" Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by Bill Paul.
+.\" 4. Neither the name of the author nor the names of contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" 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 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)
+.\" 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.
+.\"
+.\" $Id: rpc.yppasswdd.8,v 1.3 1996/02/12 14:44:15 wpaul Exp $
+.\"
+.Dd February 8, 1996
+.Dt RPC.YPPASSWDD 8
+.Os
+.Sh NAME
+.Nm rpc.yppasswdd
+.Nd "server for updating NIS passwords"
+.Sh SYNOPSIS
+.Nm rpc.yppasswdd
+.Op Fl t Ar master.passwd template file
+.Op Fl d Ar default domain
+.Op Fl p Ar path
+.Op Fl s
+.Op Fl f
+.Op Fl a
+.Op Fl m
+.Op Fl v
+.Op Fl h
+.Sh DESCRIPTION
+The
+.Nm rpc.yppasswdd
+daemon allows users to change their NIS passwords and certain
+other information using the
+.Xr yppasswd 1
+and
+.Xr ypchpass 1
+commands.
+.Nm Rpc.yppasswdd
+is an RPC-based server that accepts incoming password change requests,
+authenticates them, places the updated information in the
+.Pa /var/yp/master.passwd
+template file and then updates the NIS
+.Pa master.passwd
+and
+.Pa passwd
+maps.
+.Pp
+The
+.Nm rpc.yppasswdd
+server allows a normal NIS user to change
+his or her NIS password, full name (also
+known as 'GECOS' field) or shell. These updates are typically done using
+the
+.Xr yppasswd 1 ,
+.Xr ypchfn 1 ,
+.Xr ypchsh 1 ,
+or
+.Xr ypchpass 1
+commands. (Some administrators don't want users to be able to change their
+full name information or shells; the server can be invoked with option flags
+that disallow such changes.) When the server receives an update request,
+it checks the 'old' password supplied by the user to make sure it's
+valid, then performs some sanity checks on the updated information (these
+include checking for embedded control characters, colons or invalid shells).
+Once it is satisfied that the update request is valid, the server modifies
+the template password file (the default is
+.Pa /var/yp/master.passwd )
+and then runs the
+.Pa /usr/libexec/yppwupdate
+script to rebuild the NIS maps. (This script has two arguments passed
+to it: the absolute pathname of the password template that was modified
+and the name of the domain that is to be updated. These in turn are
+passed to
+.Pa /var/yp/Makefile.)
+.Pp
+The FreeBSD version of
+.Nm rpc.yppasswdd
+also allows the super-user on the NIS master server to perform more
+sophisticated updates on the NIS passwd maps. The super-user can modify
+any field in any user's master.passwd entry in any domain, and can
+do so without knowing the user's existing NIS password (when the server
+receives a request from the super-user, the password authentication
+check is bypassed). Furthermore, if the server is invoked with the
+.Fl a
+flag, the super-user can even add new entries to the maps using
+.Xr ypchpass 1 .
+Again, this only applies to the super-user on the NIS
+master server: none of these special functions can be peformed over
+the network.
+.Pp
+The
+.Nm rpc.yppasswdd
+daemon can only be run on a machine that is an NIS master server.
+.Sh OPTIONS
+The following options and flags are supported by
+.Nm rpc.yppasswdd :
+.Bl -tag -width flag
+.It Fl t Ar master.passwd template file
+By default,
+.Nm rpc.yppasswdd
+assumes that the template file used to generates the
+.Pa master.passwd
+and
+.Pa passwd
+maps for the default domain is called
+.Pa /var/yp/master.passwd .
+This default can be overridden by specifying an alternate file name
+with the
+.Fl t
+flag.
+.Pp
+Note: if the template file specified with this flag is
+.Pa /etc/master.passwd ,
+.Nm rpc.yppasswdd
+will also automatically invoke
+.Xr pwd_mkdb 8
+to rebuild the local password databases in addition to the NIS
+maps.
+.It Fl d Ar domain
+The
+.Nm rpc.yppasswdd
+server can support multiple domains, however it must
+choose one domain as a default.
+It will try to use the system default domain name as set by the
+.Xr domainname 1
+command for this default. However,
+if the system domain name is not
+set, a default domain must be specified on
+the command line. If the system default domain is set,
+then this option can be used to override it.
+.It Fl p Ar path
+This option can be used to override the default path to
+the location of the NIS
+map databases. The compiled-in default path is
+.Pa /var/yp .
+.It Fl s
+Disallow changing of shell information.
+.It Fl f
+Disallow changing of full name ('GECOS') information.
+.It Fl a
+Allow additions to be made to the NIS passwd databases. The super-user on the
+NIS master server is permitted to use the
+.Xr ypchpass 1
+command to perform unrestricted modifications to any field in a user's
+.Pa master.passwd
+map entry. When
+.Nm rpc.yppasswdd
+is started with this flag, it will also allow the super-user to add new
+records to the NIS passwd maps, just as is possible when using
+.Xr chpass 1
+to modify the local password database.
+.It Fl m
+Turn on multi-domain mode. Even though
+.Xr ypserv 8
+can handle several simultaneous domains, most implementations of
+.Nm rpc.yppasswdd
+can only operate on a single NIS domain, which is generally the same as
+the system default domain of the NIS master server. The FreeBSD
+.Nm rpc.yppasswdd
+attempts to overcome this problem in spite of the inherent limitations
+of the
+.Pa yppasswd
+protocol, which does not allow for a
+.Pa domain
+argument in client requests. In multi-domain mode,
+.Nm rpc.yppasswdd
+will search through all the passwd maps of all the domains it
+can find under
+.Pa /var/yp
+until it finds an entry that matches the user information specified in
+a given update request. (Matches are determined by checking the username,
+UID and GID fields.) The matched entry and corresponding domain are then
+used for the update.
+.Pp
+Note that in order for multi-domain mode to work, there have to be
+seperate template files for each domain. For example, if a server
+supports three domains,
+.Pa foo ,
+.Pa bar ,
+and
+.Pa baz ,
+there should be three seperate master.passwd template files called
+.Pa /var/yp/foo/master.passwd ,
+.Pa /var/yp/bar/master.passwd ,
+and
+.Pa /var/yp/baz/master.passwd .
+If
+.Pa foo
+happens to be the system default domain, then its template file can
+be either
+.Pa /var/yp/foo/master.passwd
+or
+.Pa /var/yp/master.passwd .
+The server will check for the latter file first and then use the former
+if it can't find it.
+.Pp
+Multi-domain mode is off by default since it can fail if there are
+duplicate or near-duplicate user entries in different domains. The server
+will abort an update request if it finds more than one user entry that
+matches its search criteria. Even so, paranoid administrators
+may wish to leave multi-domain mode disabled.
+.It Fl v
+Turn on verbose logging mode. The server normally only logs messages
+using the
+.Xr syslog 3
+facility when it encounters an error condition, or when processing
+updates for the super-user on the NIS master server. Running the server
+with the
+.Fl v
+flag will cause it to log informational messages for all updates.
+.It Fl h
+Displays the list of flags and options understood by
+.Nm rpc.yppasswdd .
+.El
+.Sh FILES
+.Bl -tag -width Pa -compact
+.It Pa /usr/libexec/yppwupdate
+The script invoked by
+.Nm rpc.yppasswdd
+to update and push the NIS maps after
+an update.
+.It Pa /var/yp/master.passwd
+The template password file for the default domain.
+.It Pa /var/yp/[domainname]/[maps]
+The NIS maps for a particular NIS domain.
+.It Pa /var/yp/[domainname]/master.passwd
+The template password file(s) for non-default domains
+(used only in multi-domain mode).
+.El
+.Sh SEE ALSO
+.Xr ypserv 8 ,
+.Xr yppush 8 ,
+.Xr ypxfr 8 ,
+.Xr yp 4
+.Sh BUGS
+As listed in the yppasswd.x protocol definition, the YPPASSWDPROC_UPDATE
+procedure takes two arguments: a V7-style passwd structure containing
+updated user information and the user's existing unencrypted (cleartext)
+password. Since
+.Nm rpc.yppasswdd
+is supposed to handle update requests from remote NIS client machines,
+this means that
+.Xr yppasswd 1
+and similar client programs will in fact be transmitting users' cleartext
+passwords over the network.
+.Pp
+This is not a problem for password updates since the plaintext password
+sent with the update will no longer be valid once the new encrypted password
+is put into place, but if the user is only updating his or her 'GECOS'
+information or shell, then the cleartext password sent with the update
+will still be valid once the update is completed. If the network is
+insecure, this cleartext password could be intercepted and used to
+gain unauthorized access to the user's account.
+.Sh AUTHOR
+Bill Paul <wpaul@ctr.columbia.edu>
diff --git a/dist/usr.sbin/rpc.yppasswdd/yppasswd_comm.c b/dist/usr.sbin/rpc.yppasswdd/yppasswd_comm.c
new file mode 100644
index 0000000..d43d961
--- /dev/null
+++ b/dist/usr.sbin/rpc.yppasswdd/yppasswd_comm.c
@@ -0,0 +1,300 @@
+/*
+ * Copyright (c) 1995, 1996
+ * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * 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 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)
+ * 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.
+ *
+ * $Id: yppasswd_comm.c,v 1.10 1996/02/03 04:41:59 wpaul Exp $
+ */
+
+/*
+ * This file contains a UNIX domain socket communications package
+ * that lets a client process send pseudo-RPCs to rpc.yppasswdd
+ * without using IP. This 'local-only' communications channel is
+ * only used when the superuser runs passwd(1) or chpass(1) on
+ * the NIS master server. The idea is that we want to grant the
+ * superuser permission to perfom certain special operations, but
+ * we need an iron-clad way to tell when we're receiving a request
+ * from the superuser and when we aren't. To connect to a UNIX
+ * domain socket, one needs to be able to access a file in the
+ * filesystem. The socket created by rpc.yppasswdd is owned by
+ * root and has all its permission bits cleared, so the only
+ * user who can sucessfully connect() to it is root.
+ *
+ * It is the server's responsibility to initialize the listening
+ * socket with the makeservsock() function and to add the socket to
+ * the set of file descriptors monitored by the svc_run() loop.
+ * Once this is done, calls made through the UNIX domain socket
+ * can be handled almost exactly like a normal RPC. We even use
+ * the XDR functions for serializing data between the client and
+ * server to simplify the passing of complex data structures.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <err.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/fcntl.h>
+#include <rpc/rpc.h>
+#include <rpcsvc/yp.h>
+#include "yppasswd_comm.h"
+#include "yppasswd_private.h"
+#include "ypxfr_extern.h"
+
+#ifndef lint
+static const char rcsid[] = "$Id: yppasswd_comm.c,v 1.10 1996/02/03 04:41:59 wpaul Exp $";
+#endif
+
+char *sockname = "/var/run/ypsock";
+FILE *serv_fp;
+FILE *clnt_fp;
+int serv_sock;
+int clnt_sock;
+
+/*
+ * serialize_data() and serialize_resp() are what really do most of
+ * the work. These functions (ab)use xdrstdio_create() as the interface
+ * to the XDR library. The RPC library uses xdrrec_create() and friends
+ * for TCP based connections. I suppose we could use that here, but
+ * the interface is a bit too complicated to justify using in an
+ * applicatuion such as this. With xdrstdio_create(), the only catch
+ * is that we need to provide a buffered file stream rather than
+ * a simple socket descriptor, but we can easily turn the latter into
+ * the former using fdopen(2).
+ *
+ * Doing things this way buys us the ability to change the form of
+ * the data being exchanged without having to modify any of the
+ * routines in this package.
+ */
+static int serialize_data(data, fp, op)
+ struct master_yppasswd *data;
+ FILE *fp;
+ int op;
+{
+ XDR xdrs;
+
+ xdrstdio_create(&xdrs, fp, op);
+
+ if (!xdr_master_yppasswd(&xdrs, data)) {
+ xdr_destroy(&xdrs);
+ return(1);
+ }
+ return(0);
+}
+
+static int serialize_resp(resp, fp, op)
+ int *resp;
+ FILE *fp;
+ int op;
+{
+ XDR xdrs;
+
+ xdrstdio_create(&xdrs, fp, op);
+
+ if (!xdr_int(&xdrs, resp)) {
+ xdr_destroy(&xdrs);
+ return(1);
+ }
+ return(0);
+}
+
+/*
+ * Build the server's listening socket. The descriptor generated
+ * here will be monitored for new connections by the svc_run() loop.
+ */
+int makeservsock()
+{
+ static int ypsock;
+ struct sockaddr_un us;
+ int len;
+
+ unlink(sockname);
+
+ if ((ypsock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
+ err(1, "failed to create UNIX domain socket");
+
+ bzero((char *)&us, sizeof(us));
+ us.sun_family = AF_UNIX;
+ strcpy((char *)&us.sun_path, sockname);
+ len = strlen(us.sun_path) + sizeof(us.sun_family) + 1;
+
+ if (bind(ypsock, (struct sockaddr *)&us, len) == -1)
+ err(1,"failed to bind UNIX domain socket");
+
+ listen (ypsock, 1);
+
+ return(ypsock);
+}
+
+/*
+ * Create a socket for a client and try to connect() it to the
+ * server.
+ */
+static int makeclntsock()
+{
+ static int ypsock;
+ struct sockaddr_un us;
+ int len;
+
+ if ((ypsock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
+ warn("failed to create UNIX domain socket");
+ return(-1);
+ }
+
+ bzero((char *)&us, sizeof(us));
+ us.sun_family = AF_UNIX;
+ strcpy((char *)&us.sun_path, sockname);
+ len = strlen(us.sun_path) + sizeof(us.sun_family) + 1;
+
+ if (connect(ypsock, (struct sockaddr *)&us, len) == -1) {
+ warn("failed to connect to server");
+ return(-1);
+ }
+
+ return(ypsock);
+}
+
+/*
+ * This function is used by the server to accept a new connection
+ * from a client and read its request data into a master_yppasswd
+ * stucture.
+ */
+struct master_yppasswd *getdat(sock)
+ int sock;
+{
+ int len;
+ struct sockaddr_un us;
+ static struct master_yppasswd pw;
+ struct timeval tv;
+ fd_set fds;
+
+ FD_ZERO(&fds);
+ FD_SET(sock, &fds);
+
+ tv.tv_sec = CONNECTION_TIMEOUT;
+ tv.tv_usec = 0;
+
+ switch(select(FD_SETSIZE, &fds, NULL, NULL, &tv)) {
+ case 0:
+ yp_error("select timed out");
+ return(NULL);
+ break;
+ case -1:
+ yp_error("select() failed: %s", strerror(errno));
+ return(NULL);
+ break;
+ default:
+ break;
+ }
+
+ if ((serv_sock = accept(sock, (struct sockaddr *)&us, &len)) == -1) {
+ yp_error("accept failed: %s", strerror(errno));
+ return(NULL);
+ }
+
+ if ((serv_fp = fdopen(serv_sock, "r+")) == NULL) {
+ yp_error("fdopen failed: %s",strerror(errno));
+ return(NULL);
+ }
+
+ if (serialize_data(&pw, serv_fp, XDR_DECODE)) {
+ yp_error("failed to receive data");
+ return(NULL);
+ }
+
+ return(&pw);
+}
+
+/*
+ * Client uses this to read back a response code (a single
+ * integer) from the server. Note that we don't need to implement
+ * any special XDR function for this since an int is a base data
+ * type which the XDR library can handle directly.
+ */
+int *getresp()
+{
+ static int resp;
+
+ if (serialize_resp(&resp, clnt_fp, XDR_DECODE)) {
+ warn("failed to receive response");
+ return(NULL);
+ }
+
+ fclose(clnt_fp);
+ close(clnt_sock);
+ return(&resp);
+}
+
+/*
+ * Create a connection to the server and send a reqest
+ * to be processed.
+ */
+int senddat(pw)
+ struct master_yppasswd *pw;
+{
+
+ if ((clnt_sock = makeclntsock()) == -1) {
+ warn("failed to create socket");
+ return(1);
+ }
+
+ if ((clnt_fp = fdopen(clnt_sock, "r+")) == NULL) {
+ warn("fdopen failed");
+ return(1);
+ }
+
+ if (serialize_data(pw, clnt_fp, XDR_ENCODE)) {
+ warn("failed to send data");
+ return(1);
+ }
+
+ return(0);
+}
+
+/*
+ * This sends a response code back to the client.
+ */
+int sendresp(resp)
+ int resp;
+{
+
+ if (serialize_resp(&resp, serv_fp, XDR_ENCODE)) {
+ yp_error("failed to send response");
+ return(-1);
+ }
+
+ fclose(serv_fp);
+ close(serv_sock);
+ return(0);
+}
diff --git a/dist/usr.sbin/rpc.yppasswdd/yppasswd_comm.h b/dist/usr.sbin/rpc.yppasswdd/yppasswd_comm.h
new file mode 100644
index 0000000..36d0b45
--- /dev/null
+++ b/dist/usr.sbin/rpc.yppasswdd/yppasswd_comm.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 1995, 1996
+ * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * 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 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)
+ * 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.
+ *
+ * $Id: yppasswd_comm.h,v 1.2 1996/01/27 20:42:38 wpaul Exp $
+ */
+
+#include "yppasswd_private.h"
+
+#define CONNECTION_TIMEOUT 5
+
+extern FILE *yp_fp;
+extern char *sockname;
+extern int yp_sock;
+extern struct master_yppasswd *getdat __P(( int ));
+extern int makeservsock __P(( void ));
+extern int senddat __P(( struct master_yppasswd *pw ));
+extern int *getresp __P(( void ));
+extern int sendresp __P(( int ));
diff --git a/dist/usr.sbin/rpc.yppasswdd/yppasswd_private.x b/dist/usr.sbin/rpc.yppasswdd/yppasswd_private.x
new file mode 100644
index 0000000..2f5e1b5
--- /dev/null
+++ b/dist/usr.sbin/rpc.yppasswdd/yppasswd_private.x
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 1995, 1996
+ * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * 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 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)
+ * 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.
+ *
+ * $Id: yppasswd_private.x,v 1.2 1996/01/25 16:14:48 wpaul Exp $
+ */
+
+#ifndef RPC_HDR
+%#ifndef lint
+%static const char rcsid[] = "$Id: yppasswd_private.x,v 1.2 1996/01/25 16:14:48 wpaul Exp $";
+%#endif /* not lint */
+#endif
+
+/*
+ * This protocol definition file is only used to
+ * generate some XDR functions. We don't actually
+ * define any RPC services here.
+ */
+
+struct x_master_passwd {
+ string pw_name<>; /* username */
+ string pw_passwd<>; /* encrypted password */
+ int pw_uid; /* user id */
+ int pw_gid; /* group id */
+ unsigned long pw_change;/* password change time */
+ string pw_class<>; /* user access class */
+ string pw_gecos<>; /* in real life name */
+ string pw_dir<>; /* home directory */
+ string pw_shell<>; /* default shell */
+ unsigned long pw_expire;/* account expiration */
+ unsigned long pw_fields;/* internal: fields filled in */
+};
+
+const _YPMAXDOMAIN = 64;
+
+struct master_yppasswd {
+ string oldpass<>; /* unencrypted old password */
+ string domain<_YPMAXDOMAIN>; /* domain we want to operate on */
+ x_master_passwd newpw; /* new passwd entry */
+};
diff --git a/dist/usr.sbin/rpc.yppasswdd/yppasswdd_extern.h b/dist/usr.sbin/rpc.yppasswdd/yppasswdd_extern.h
new file mode 100644
index 0000000..84e7eed
--- /dev/null
+++ b/dist/usr.sbin/rpc.yppasswdd/yppasswdd_extern.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 1995, 1996
+ * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * 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 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)
+ * 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.
+ *
+ * $Id: yppasswdd_extern.h,v 1.4 1996/02/01 04:38:39 wpaul Exp $
+ */
+
+#include <sys/types.h>
+#include <limits.h>
+#include <db.h>
+#include <rpc/rpc.h>
+#include <pwd.h>
+#include <err.h>
+
+#ifndef YPLIBDIR
+#define YPLIBDIR "/usr/libexec/"
+#endif
+#define MAP_UPDATE "yppwupdate"
+#define MAP_UPDATE_PATH YPLIBDIR "yppwupdate"
+
+extern char *yp_dir;
+extern char *progname;
+extern void do_master __P(( void ));
+extern void yppasswdprog_1 __P(( struct svc_req *, register SVCXPRT * ));
+extern void reaper __P(( int ));
+extern void install_reaper __P(( int ));
+extern int pw_copy __P(( int, int, struct passwd * ));
+extern int pw_lock __P(( void ));
+extern int pw_mkdb __P(( void ));
+extern int pw_tmp __P(( void ));
+extern void pw_init __P(( void ));
+extern char *ok_shell __P (( char * ));
+extern char *passfile;
+extern char *passfile_default;
+extern char *tempname;
+extern char *yppasswd_domain;
+extern int no_chsh;
+extern int no_chfn;
+extern int allow_additions;
+extern int multidomain;
+extern int verbose;
+extern int _rpc_dtablesize __P((void));
+extern void yp_error __P((const char *, ...));
+extern int yp_get_record __P(( const char *, const char *, const DBT *, DBT *, int));
diff --git a/dist/usr.sbin/rpc.yppasswdd/yppasswdd_main.c b/dist/usr.sbin/rpc.yppasswdd/yppasswdd_main.c
new file mode 100644
index 0000000..358345f
--- /dev/null
+++ b/dist/usr.sbin/rpc.yppasswdd/yppasswdd_main.c
@@ -0,0 +1,362 @@
+/*
+ * Copyright (c) 1995, 1996
+ * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * 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 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)
+ * 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.
+ *
+ * $Id: yppasswdd_main.c,v 1.8 1996/02/09 04:21:35 wpaul Exp $
+ */
+
+#include "yppasswd.h"
+#include <stdio.h>
+#include <sys/types.h>
+#include <stdlib.h> /* getenv, exit */
+#include <unistd.h>
+#include <string.h>
+#include <sys/param.h>
+#include <rpc/pmap_clnt.h> /* for pmap_unset */
+#include <string.h> /* strcmp */
+#include <signal.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/ttycom.h> /* TIOCNOTTY */
+#ifdef __cplusplus
+#include <sysent.h> /* getdtablesize, open */
+#endif /* __cplusplus */
+#include <memory.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <syslog.h>
+#include <err.h>
+#include <errno.h>
+#include <rpcsvc/yp.h>
+struct dom_binding {};
+#include <rpcsvc/ypclnt.h>
+#include "yppasswdd_extern.h"
+#include "yppasswd_comm.h"
+#include "ypxfr_extern.h"
+
+#ifndef SIG_PF
+#define SIG_PF void(*)(int)
+#endif
+
+#ifdef DEBUG
+#define RPC_SVC_FG
+#endif
+
+#define _RPCSVC_CLOSEDOWN 120
+#ifndef lint
+static const char rcsid[] = "$Id: yppasswdd_main.c,v 1.8 1996/02/09 04:21:35 wpaul Exp $";
+#endif /* not lint */
+int _rpcpmstart = 0; /* Started by a port monitor ? */
+static int _rpcfdtype;
+ /* Whether Stream or Datagram ? */
+ /* States a server can be in wrt request */
+
+#define _IDLE 0
+#define _SERVED 1
+#define _SERVING 2
+
+extern int _rpcsvcstate; /* Set when a request is serviced */
+char *progname = "rpc.yppasswdd";
+char *passfile_default = "/var/yp/master.passwd";
+char *passfile;
+char *yppasswd_domain = NULL;
+int no_chsh = 0;
+int no_chfn = 0;
+int allow_additions = 0;
+int multidomain = 0;
+int verbose = 0;
+char *yp_dir = "/var/yp/";
+int yp_sock;
+
+
+static void
+my_svc_run()
+{
+#ifdef FD_SETSIZE
+ fd_set readfds;
+#else
+ int readfds;
+#endif /* def FD_SETSIZE */
+ extern int errno;
+
+ for (;;) {
+
+
+#ifdef FD_SETSIZE
+ readfds = svc_fdset;
+#else
+ readfds = svc_fds;
+#endif /* def FD_SETSIZE */
+ FD_SET(yp_sock, &readfds);
+
+ switch (select(_rpc_dtablesize(), &readfds, (fd_set *)0, (fd_set *)0,
+ (struct timeval *)0)) {
+ case -1:
+ if (errno == EINTR) {
+ continue;
+ }
+ perror("svc_run: - select failed");
+ return;
+ case 0:
+ continue;
+ default:
+ if (FD_ISSET(yp_sock, &readfds)) {
+ do_master();
+ FD_CLR(yp_sock, &readfds);
+ }
+ svc_getreqset(&readfds);
+ }
+ }
+}
+
+static void terminate(sig)
+ int sig;
+{
+ svc_unregister(YPPASSWDPROG, YPPASSWDVERS);
+ close(yp_sock);
+ unlink(sockname);
+ exit(0);
+}
+
+static void
+closedown(int sig)
+{
+ if (_rpcsvcstate == _IDLE) {
+ extern fd_set svc_fdset;
+ static int size;
+ int i, openfd;
+
+ if (_rpcfdtype == SOCK_DGRAM) {
+ close(yp_sock);
+ unlink(sockname);
+ exit(0);
+ }
+ if (size == 0) {
+ size = getdtablesize();
+ }
+ for (i = 0, openfd = 0; i < size && openfd < 2; i++)
+ if (FD_ISSET(i, &svc_fdset))
+ openfd++;
+ if (openfd <= 1) {
+ close(yp_sock);
+ unlink(sockname);
+ exit(0);
+ }
+ }
+ if (_rpcsvcstate == _SERVED)
+ _rpcsvcstate = _IDLE;
+
+ (void) signal(SIGALRM, (SIG_PF) closedown);
+ (void) alarm(_RPCSVC_CLOSEDOWN/2);
+}
+
+static void usage()
+{
+ fprintf(stderr, "Usage: %s [-t master.passwd file] [-d domain] \
+[-p path] [-s] [-f] [-m] [-a] [-v] [-h]\n",
+ progname);
+ exit(1);
+}
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register SVCXPRT *transp = NULL;
+ int sock;
+ int proto = 0;
+ struct sockaddr_in saddr;
+ int asize = sizeof (saddr);
+ int ch;
+ int rval;
+ char *mastername;
+ char myname[MAXHOSTNAMELEN + 2];
+ extern int errno;
+ extern int debug;
+
+ debug = 1;
+
+ while ((ch = getopt(argc, argv, "t:d:p:sfamvh")) != EOF) {
+ switch(ch) {
+ case 't':
+ passfile_default = optarg;
+ break;
+ case 'd':
+ yppasswd_domain = optarg;
+ break;
+ case 's':
+ no_chsh++;
+ break;
+ case 'f':
+ no_chfn++;
+ break;
+ case 'p':
+ yp_dir = optarg;
+ break;
+ case 'a':
+ allow_additions++;
+ break;
+ case 'm':
+ multidomain++;
+ break;
+ case 'v':
+ verbose++;
+ break;
+ default:
+ case 'h':
+ usage();
+ break;
+ }
+ }
+
+ if (yppasswd_domain == NULL) {
+ if (yp_get_default_domain(&yppasswd_domain)) {
+ yp_error("no domain specified and system domain \
+name isn't set -- aborting");
+ usage();
+ }
+ }
+
+ if (getrpcport("localhost", YPPROG, YPVERS, IPPROTO_UDP) <= 0) {
+ yp_error("this host is not an NIS server -- aborting");
+ exit(1);
+ }
+
+ if ((mastername = ypxfr_get_master(yppasswd_domain, "passwd.byname",
+ "localhost",0)) == NULL) {
+ yp_error("can't get name of NIS master server");
+ exit(1);
+ }
+
+ if (gethostname((char *)&myname, sizeof(myname)) == -1) {
+ yp_error("can't get local hostname: %s", strerror(errno));
+ exit(1);
+ }
+
+ if (strncmp(mastername, (char *)&myname, sizeof(myname))) {
+ yp_error("this host is not an NIS master server -- aborting");
+ exit(1);
+ }
+
+ if (getsockname(0, (struct sockaddr *)&saddr, &asize) == 0) {
+ int ssize = sizeof (int);
+
+ if (saddr.sin_family != AF_INET)
+ exit(1);
+ if (getsockopt(0, SOL_SOCKET, SO_TYPE,
+ (char *)&_rpcfdtype, &ssize) == -1)
+ exit(1);
+ sock = 0;
+ _rpcpmstart = 1;
+ proto = 0;
+ openlog(progname, LOG_PID, LOG_DAEMON);
+ } else {
+#ifndef RPC_SVC_FG
+ int size;
+ int pid, i;
+
+ pid = fork();
+ if (pid < 0) {
+ perror("cannot fork");
+ exit(1);
+ }
+ if (pid)
+ exit(0);
+ size = getdtablesize();
+ for (i = 0; i < size; i++)
+ (void) close(i);
+ i = open("/dev/console", 2);
+ (void) dup2(i, 1);
+ (void) dup2(i, 2);
+ i = open("/dev/tty", 2);
+ if (i >= 0) {
+ (void) ioctl(i, TIOCNOTTY, (char *)NULL);
+ (void) close(i);
+ }
+ openlog(progname, LOG_PID, LOG_DAEMON);
+#endif
+ sock = RPC_ANYSOCK;
+ (void) pmap_unset(YPPASSWDPROG, YPPASSWDVERS);
+ }
+
+ if ((_rpcfdtype == 0) || (_rpcfdtype == SOCK_DGRAM)) {
+ transp = svcudp_create(sock);
+ if (transp == NULL) {
+ yp_error("cannot create udp service.");
+ exit(1);
+ }
+ if (!_rpcpmstart)
+ proto = IPPROTO_UDP;
+ if (!svc_register(transp, YPPASSWDPROG, YPPASSWDVERS, yppasswdprog_1, proto)) {
+ yp_error("unable to register (YPPASSWDPROG, YPPASSWDVERS, udp).");
+ exit(1);
+ }
+ }
+
+ if ((_rpcfdtype == 0) || (_rpcfdtype == SOCK_STREAM)) {
+ transp = svctcp_create(sock, 0, 0);
+ if (transp == NULL) {
+ yp_error("cannot create tcp service.");
+ exit(1);
+ }
+ if (!_rpcpmstart)
+ proto = IPPROTO_TCP;
+ if (!svc_register(transp, YPPASSWDPROG, YPPASSWDVERS, yppasswdprog_1, proto)) {
+ yp_error("unable to register (YPPASSWDPROG, YPPASSWDVERS, tcp).");
+ exit(1);
+ }
+ }
+
+ if (transp == (SVCXPRT *)NULL) {
+ yp_error("could not create a handle");
+ exit(1);
+ }
+ if (_rpcpmstart) {
+ (void) signal(SIGALRM, (SIG_PF) closedown);
+ (void) alarm(_RPCSVC_CLOSEDOWN/2);
+ }
+ /* set up resporce limits and block signals */
+ pw_init();
+
+ /* except SIGCHLD, which we need to catch */
+ install_reaper(1);
+ signal(SIGTERM, (SIG_PF) terminate);
+
+ unlink(sockname);
+ yp_sock = makeservsock();
+ if (chmod(sockname, 0))
+ err(1, "chmod of %s failed", sockname);
+
+ my_svc_run();
+ yp_error("svc_run returned");
+ exit(1);
+ /* NOTREACHED */
+}
diff --git a/dist/usr.sbin/rpc.yppasswdd/yppasswdd_server.c b/dist/usr.sbin/rpc.yppasswdd/yppasswdd_server.c
new file mode 100644
index 0000000..fa2551a
--- /dev/null
+++ b/dist/usr.sbin/rpc.yppasswdd/yppasswdd_server.c
@@ -0,0 +1,649 @@
+/*
+ * Copyright (c) 1995, 1996
+ * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * 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 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)
+ * 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.
+ *
+ * $Id: yppasswdd_server.c,v 1.8 1996/02/09 04:38:19 wpaul Exp $
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <limits.h>
+#include <db.h>
+#include <pwd.h>
+#include <errno.h>
+#include <signal.h>
+#include <rpc/rpc.h>
+#include <rpcsvc/yp.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/param.h>
+struct dom_binding {};
+#include <rpcsvc/ypclnt.h>
+#include "yppasswdd_extern.h"
+#include "yppasswd.h"
+#include "yppasswd_private.h"
+#include "yppasswd_comm.h"
+
+#ifndef lint
+static const char rcsid[] = "$Id: yppasswdd_server.c,v 1.8 1996/02/09 04:38:19 wpaul Exp $";
+#endif /* not lint */
+
+char *tempname;
+
+void reaper(sig)
+ int sig;
+{
+ extern pid_t pid;
+ extern int pstat;
+ int st;
+
+ if (sig > 0) {
+ if (sig == SIGCHLD)
+ while(wait3(&st, WNOHANG, NULL) > 0) ;
+ } else {
+ pid = waitpid(pid, &pstat, 0);
+ }
+ return;
+}
+
+void install_reaper(on)
+ int on;
+{
+ if (on) {
+ signal(SIGCHLD, reaper);
+ } else {
+ signal(SIGCHLD, SIG_DFL);
+ }
+ return;
+}
+
+static struct passwd yp_password;
+
+static 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;
+
+ buf = (char *)realloc(buf, m + 10);
+ bzero(buf, m + 10);
+
+ /* Turn all colons into NULLs */
+ while (strchr(s, ':')) {
+ s = (strchr(s, ':') + 1);
+ *(s - 1)= '\0';
+ }
+
+ 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);
+ yp_password.pw_fields |= _PWF_PASSWD;
+ yp_password.pw_uid = atoi(p);
+ p += (strlen(p) + 1);
+ yp_password.pw_fields |= _PWF_UID;
+ yp_password.pw_gid = atoi(p);
+ p += (strlen(p) + 1);
+ yp_password.pw_fields |= _PWF_GID;
+ if (x) {
+ EXPAND(yp_password.pw_class);
+ yp_password.pw_fields |= _PWF_CLASS;
+ yp_password.pw_change = atol(p);
+ p += (strlen(p) + 1);
+ yp_password.pw_fields |= _PWF_CHANGE;
+ yp_password.pw_expire = atol(p);
+ p += (strlen(p) + 1);
+ yp_password.pw_fields |= _PWF_EXPIRE;
+ }
+ EXPAND(yp_password.pw_gecos);
+ yp_password.pw_fields |= _PWF_GECOS;
+ EXPAND(yp_password.pw_dir);
+ yp_password.pw_fields |= _PWF_DIR;
+ EXPAND(yp_password.pw_shell);
+ yp_password.pw_fields |= _PWF_SHELL;
+
+ return;
+}
+
+static int validchars(arg)
+ char *arg;
+{
+ int i;
+
+ for (i = 0; i < strlen(arg); i++) {
+ if (iscntrl(arg[i])) {
+ yp_error("string contains a control character");
+ return(1);
+ }
+ if (arg[i] == ':') {
+ yp_error("string contains a colon");
+ return(1);
+ }
+ /* Be evil: truncate strings with \n in them silently. */
+ if (arg[i] == '\n') {
+ arg[i] = '\0';
+ return(0);
+ }
+ }
+ return(0);
+}
+
+static int validate_master(opw, npw)
+ struct passwd *opw;
+ struct x_master_passwd *npw;
+{
+
+ if (npw->pw_name[0] == '+' || npw->pw_name[0] == '-') {
+ yp_error("client tried to modify an NIS entry");
+ return(1);
+ }
+
+ if (validchars(npw->pw_shell)) {
+ yp_error("specified shell contains invalid characters");
+ return(1);
+ }
+
+ if (validchars(npw->pw_gecos)) {
+ yp_error("specified gecos field contains invalid characters");
+ return(1);
+ }
+
+ if (validchars(npw->pw_passwd)) {
+ yp_error("specified password contains invalid characters");
+ return(1);
+ }
+ return(0);
+}
+
+static int validate(opw, npw)
+ struct passwd *opw;
+ struct x_passwd *npw;
+{
+
+ if (npw->pw_name[0] == '+' || npw->pw_name[0] == '-') {
+ yp_error("client tried to modify an NIS entry");
+ return(1);
+ }
+
+ if (npw->pw_uid != opw->pw_uid) {
+ yp_error("UID mismatch: client says user %s has UID %d",
+ npw->pw_name, npw->pw_uid);
+ yp_error("database says user %s has UID %d", opw->pw_name,
+ opw->pw_uid);
+ return(1);
+ }
+
+ if (npw->pw_gid != opw->pw_gid) {
+ yp_error("GID mismatch: client says user %s has GID %d",
+ npw->pw_name, npw->pw_gid);
+ yp_error("database says user %s has GID %d", opw->pw_name,
+ opw->pw_gid);
+ return(1);
+ }
+
+ /*
+ * Don't allow the user to shoot himself in the foot,
+ * even on purpose.
+ */
+ if (!ok_shell(npw->pw_shell)) {
+ yp_error("%s is not a valid shell", npw->pw_shell);
+ return(1);
+ }
+
+ if (validchars(npw->pw_shell)) {
+ yp_error("specified shell contains invalid characters");
+ return(1);
+ }
+
+ if (validchars(npw->pw_gecos)) {
+ yp_error("specified gecos field contains invalid characters");
+ return(1);
+ }
+
+ if (validchars(npw->pw_passwd)) {
+ yp_error("specified password contains invalid characters");
+ return(1);
+ }
+ return(0);
+}
+
+/*
+ * Kludge alert:
+ * In order to have one rpc.yppasswdd support multiple domains,
+ * we have to cheat: we search each directory under /var/yp
+ * and try to match the user in each master.passwd.byname
+ * map that we find. If the user matches (username, uid and gid
+ * all agree), then we use that domain. If we match the user in
+ * more than one database, we must abort.
+ */
+static char *find_domain(pw)
+ struct x_passwd *pw;
+{
+ struct stat statbuf;
+ struct dirent *dirp;
+ DIR *dird;
+ char yp_mapdir[MAXPATHLEN + 2];
+ char *domain = NULL;
+ char *tmp = NULL;
+ DBT key, data;
+ int hit = 0;
+
+ yp_error("performing multidomain lookup");
+
+ if ((dird = opendir(yp_dir)) == NULL) {
+ yp_error("opendir(%s) failed: %s", yp_dir, strerror(errno));
+ return(NULL);
+ }
+
+ while ((dirp = readdir(dird)) != NULL) {
+ snprintf(yp_mapdir, sizeof(yp_mapdir), "%s/%s",
+ yp_dir, dirp->d_name);
+ if (stat(yp_mapdir, &statbuf) < 0) {
+ yp_error("stat(%s) failed: %s", yp_mapdir,
+ strerror(errno));
+ closedir(dird);
+ return(NULL);
+ }
+ if (S_ISDIR(statbuf.st_mode)) {
+ tmp = (char *)dirp->d_name;
+ key.data = pw->pw_name;
+ key.size = strlen(pw->pw_name);
+
+ if (yp_get_record(tmp,"master.passwd.byname",
+ &key, &data, 0) != YP_TRUE) {
+ continue;
+ }
+ *(char *)(data.data + data.size) = '\0';
+ copy_yp_pass(data.data, 1, data.size);
+ if (yp_password.pw_uid == pw->pw_uid &&
+ yp_password.pw_gid == pw->pw_gid) {
+ hit++;
+ domain = tmp;
+ }
+ }
+ }
+
+ closedir(dird);
+ if (hit > 1) {
+ yp_error("found same user in two different domains");
+ return(NULL);
+ } else
+ return(domain);
+}
+
+int *
+yppasswdproc_update_1_svc(yppasswd *argp, struct svc_req *rqstp)
+{
+ static int result;
+ struct sockaddr_in *rqhost;
+ DBT key, data;
+ int rval = 0;
+ int pfd, tfd;
+ int pid;
+ int passwd_changed = 0;
+ int shell_changed = 0;
+ int gecos_changed = 0;
+ char *oldshell = NULL;
+ char *oldgecos = NULL;
+ char *passfile_hold;
+ char passfile_buf[MAXPATHLEN + 2];
+ char template[] = "/etc/yppwtmp.XXXXX";
+ char *domain = yppasswd_domain;
+
+ /*
+ * Normal user updates always use the 'default' master.passwd file.
+ */
+
+ passfile = passfile_default;
+ result = 1;
+
+ rqhost = svc_getcaller(rqstp->rq_xprt);
+
+ /*
+ * Step one: find the user. (It's kinda pointless to
+ * proceed if the user doesn't exist.) We look for the
+ * user in the master.passwd.byname database, _NOT_ by
+ * using getpwent() and friends! We can't use getpwent()
+ * since the NIS master server is not guaranteed to be
+ * configured as an NIS client.
+ */
+
+ if (multidomain) {
+ if ((domain = find_domain(&argp->newpw)) == NULL) {
+ yp_error("multidomain lookup failed - aborting update");
+ return(&result);
+ } else
+ yp_error("updating user %s in domain %s",
+ argp->newpw.pw_name, domain);
+ }
+
+ key.data = argp->newpw.pw_name;
+ key.size = strlen(argp->newpw.pw_name);
+
+ if ((rval=yp_get_record(domain,"master.passwd.byname",
+ &key, &data, 0)) != YP_TRUE) {
+ if (rval == YP_NOKEY) {
+ yp_error("user %s not found in passwd database",
+ argp->newpw.pw_name);
+ } else {
+ yp_error("database access error: %s",
+ yperr_string(rval));
+ }
+ return(&result);
+ }
+
+ /* Nul terminate, please. */
+ *(char *)(data.data + data.size) = '\0';
+
+ copy_yp_pass(data.data, 1, data.size);
+
+ /* Step 2: check that the supplied oldpass is valid. */
+
+ if (strcmp(crypt(argp->oldpass, yp_password.pw_passwd),
+ yp_password.pw_passwd)) {
+ yp_error("rejected change attempt -- bad password");
+ yp_error("client address: %s username: %s",
+ inet_ntoa(rqhost->sin_addr),
+ argp->newpw.pw_name);
+ return(&result);
+ }
+
+ /* Step 3: validate the arguments passed to us by the client. */
+
+ if (validate(&yp_password, &argp->newpw)) {
+ yp_error("rejecting change attempt: bad arguments");
+ yp_error("client address: %s username: %s",
+ inet_ntoa(rqhost->sin_addr),
+ argp->newpw.pw_name);
+ svcerr_decode(rqstp->rq_xprt);
+ return(&result);
+ }
+
+ /* Step 4: update the user's passwd structure. */
+
+ if (!no_chsh && strcmp(argp->newpw.pw_shell, yp_password.pw_shell)) {
+ oldshell = yp_password.pw_shell;
+ yp_password.pw_shell = argp->newpw.pw_shell;
+ shell_changed++;
+ }
+
+
+ if (!no_chfn && strcmp(argp->newpw.pw_gecos, yp_password.pw_gecos)) {
+ oldgecos = yp_password.pw_gecos;
+ yp_password.pw_gecos = argp->newpw.pw_gecos;
+ gecos_changed++;
+ }
+
+ if (strcmp(argp->newpw.pw_passwd, yp_password.pw_passwd)) {
+ yp_password.pw_passwd = argp->newpw.pw_passwd;
+ passwd_changed++;
+ }
+
+ /*
+ * If the caller specified a domain other than our 'default'
+ * domain, change the path to master.passwd accordingly.
+ */
+
+ if (strcmp(domain, yppasswd_domain)) {
+ snprintf(passfile_buf, sizeof(passfile_buf),
+ "/var/yp/%s/master.passwd", domain);
+ passfile = (char *)&passfile_buf;
+ }
+
+ /* Step 5: make a new password file with the updated info. */
+
+ if ((pfd = pw_lock()) < 0) {
+ return (&result);
+ }
+ if ((tfd = pw_tmp()) < 0) {
+ return (&result);
+ }
+
+ if (pw_copy(pfd, tfd, &yp_password)) {
+ yp_error("failed to created updated password file -- \
+cleaning up and bailing out");
+ unlink(tempname);
+ return(&result);
+ }
+
+ passfile_hold = mktemp((char *)&template);
+ rename(passfile, passfile_hold);
+ if (strcmp(passfile, _PATH_MASTERPASSWD)) {
+ rename(tempname, passfile);
+ } else {
+ if (pw_mkdb() < 0) {
+ yp_error("pwd_mkdb failed");
+ return(&result);
+ }
+ }
+
+ switch((pid = fork())) {
+ case 0:
+ /* unlink(passfile_hold); */
+ execlp(MAP_UPDATE_PATH, MAP_UPDATE, passfile,
+ yppasswd_domain, NULL);
+ yp_error("couldn't exec map update process: %s",
+ strerror(errno));
+ unlink(passfile);
+ rename(passfile_hold, passfile);
+ exit(1);
+ break;
+ case -1:
+ yp_error("fork() failed: %s", strerror(errno));
+ return(&result);
+ unlink(passfile);
+ rename(passfile_hold, passfile);
+ break;
+ default:
+ break;
+ }
+
+ if (verbose) {
+ yp_error("update completed for user %s (uid %d):",
+ argp->newpw.pw_name,
+ argp->newpw.pw_uid);
+
+ if (passwd_changed)
+ yp_error("password changed");
+
+ if (gecos_changed)
+ yp_error("gecos changed ('%s' -> '%s')",
+ oldgecos, argp->newpw.pw_gecos);
+
+ if (shell_changed)
+ yp_error("shell changed ('%s' -> '%s')",
+ oldshell, argp->newpw.pw_shell);
+ }
+
+ result = 0;
+ return (&result);
+
+}
+
+/*
+ * Note that this function performs a little less sanity checking
+ * than the last one. Since only the superuser is allowed to use it,
+ * it is assumed that the caller knows what he's doing.
+ */
+static int update_master(master_yppasswd *argp)
+{
+ int result;
+ int pfd, tfd;
+ int pid;
+ int rval = 0;
+ DBT key, data;
+ char *passfile_hold;
+ char passfile_buf[MAXPATHLEN + 2];
+ char template[] = "/etc/yppwtmp.XXXXX";
+
+ result = 1;
+ passfile = passfile_default;
+
+ key.data = argp->newpw.pw_name;
+ key.size = strlen(argp->newpw.pw_name);
+
+ /*
+ * The superuser may add entries to the passwd maps if
+ * rpc.yppasswdd is started with the -a flag. Paranoia
+ * prevents me from allowing additions by default.
+ */
+ if ((rval = yp_get_record(argp->domain, "master.passwd.byname",
+ &key, &data, 0)) != YP_TRUE) {
+ if (rval == YP_NOKEY) {
+ yp_error("user %s not found in passwd database",
+ argp->newpw.pw_name);
+ if (allow_additions)
+ yp_error("notice: adding user %s to \
+master.passwd database for domain %s", argp->newpw.pw_name, argp->domain);
+ else
+ yp_error("restart %s with the -a flag to \
+allow additions to be made to the password database", progname);
+ } else {
+ yp_error("database access error: %s",
+ yperr_string(rval));
+ }
+ if (!allow_additions)
+ return(result);
+ } else {
+
+ /* Nul terminate, please. */
+ *(char *)(data.data + data.size) = '\0';
+
+ copy_yp_pass(data.data, 1, data.size);
+ }
+
+ /*
+ * Perform a small bit of sanity checking.
+ */
+ if (validate_master(rval == YP_TRUE ? &yp_password:NULL,&argp->newpw)){
+ yp_error("rejecting update attempt for %s: bad arguments",
+ argp->newpw.pw_name);
+ return(result);
+ }
+
+ /*
+ * If the caller specified a domain other than our 'default'
+ * domain, change the path to master.passwd accordingly.
+ */
+
+ if (strcmp(argp->domain, yppasswd_domain)) {
+ snprintf(passfile_buf, sizeof(passfile_buf),
+ "/var/yp/%s/master.passwd", argp->domain);
+ passfile = (char *)&passfile_buf;
+ }
+
+ if ((pfd = pw_lock()) < 0) {
+ return (result);
+ }
+ if ((tfd = pw_tmp()) < 0) {
+ return (result);
+ }
+
+ if (pw_copy(pfd, tfd, (struct passwd *)&argp->newpw)) {
+ yp_error("failed to created updated password file -- \
+cleaning up and bailing out");
+ unlink(tempname);
+ return(result);
+ }
+
+ passfile_hold = mktemp((char *)&template);
+ rename(passfile, passfile_hold);
+ if (strcmp(passfile, _PATH_MASTERPASSWD)) {
+ rename(tempname, passfile);
+ } else {
+ if (pw_mkdb() < 0) {
+ yp_error("pwd_mkdb failed");
+ return(result);
+ }
+ }
+
+ switch((pid = fork())) {
+ case 0:
+ close(yp_sock);
+ execlp(MAP_UPDATE_PATH, MAP_UPDATE, passfile,
+ argp->domain, NULL);
+ yp_error("couldn't exec map update process: %s",
+ strerror(errno));
+ unlink(passfile);
+ rename(passfile_hold, passfile);
+ exit(1);
+ break;
+ case -1:
+ yp_error("fork() failed: %s", strerror(errno));
+ unlink(passfile);
+ rename(passfile_hold, passfile);
+ return(result);
+ break;
+ default:
+ break;
+ }
+
+ yp_error("performed update of user %s (uid %d) domain %s",
+ argp->newpw.pw_name,
+ argp->newpw.pw_uid,
+ argp->domain);
+
+ result = 0;
+ return(result);
+}
+
+/*
+ * Pseudo-dispatcher for private 'superuser-only' update handler.
+ */
+void do_master()
+{
+ struct master_yppasswd *pw;
+ int resp;
+
+ if ((pw = getdat(yp_sock)) == NULL) {
+ return;
+ }
+
+ yp_error("received update request from superuser on localhost");
+ resp = update_master(pw);
+ sendresp(resp);
+
+ /* Remember to free args. */
+ xdr_free(xdr_master_yppasswd, (char *)pw);
+
+ return;
+}
diff --git a/dist/usr.sbin/rpc.yppasswdd/yppwupdate b/dist/usr.sbin/rpc.yppasswdd/yppwupdate
new file mode 100644
index 0000000..7a76880
--- /dev/null
+++ b/dist/usr.sbin/rpc.yppasswdd/yppwupdate
@@ -0,0 +1,33 @@
+#!/bin/sh
+#
+# This script is invoked by rpc.yppasswdd to update the password
+# maps after the master password file has been modified. It expects
+# to be passed two arguments: the name of the master.passwd template
+# file that was modified by the server, and the name of the domain to
+# update. These are passed to /var/yp/Makefile.
+#
+# Comment out the LOG=yes line to disable logging.
+#
+# $Id: yppwupdate,v 1.2 1996/02/09 04:21:10 wpaul Exp $
+#
+
+LOG=yes
+LOGFILE=/var/yp/ypupdate.log
+
+umask 077
+
+if [ ! -f $LOGFILE ];
+then
+ /usr/bin/touch $LOGFILE
+ echo "# Edit /usr/libexec/yppwupdate to disable" >> $LOGFILE
+ echo "# logging to this file from yppasswdd." >> $LOGFILE
+ echo -n "# Log started on: " >> $LOGFILE
+ /bin/date >> $LOGFILE
+fi
+
+if [ ! $LOG ];
+then
+ cd /var/yp; /usr/bin/make MASTER_PASSWD=$1 UPDATE_DOMAIN=$2
+else
+ cd /var/yp; /usr/bin/make MASTER_PASSWD=$1 UPDATE_DOMAIN=$2 >> $LOGFILE
+fi
OpenPOWER on IntegriCloud