diff options
author | wpaul <wpaul@FreeBSD.org> | 1996-02-12 15:09:01 +0000 |
---|---|---|
committer | wpaul <wpaul@FreeBSD.org> | 1996-02-12 15:09:01 +0000 |
commit | cddbdd03cad8377326f29999f7873a6dd0b3a0ff (patch) | |
tree | b703880bdbddd91df70e1980b86153e851a2dfc8 /usr.sbin/rpc.yppasswdd | |
parent | 31da7a08764484c0b96352dc6ef009fd4fcee60c (diff) | |
parent | 12f2e571f2f4854fee5b4fcefe9b6dadcc2f834f (diff) | |
download | FreeBSD-src-cddbdd03cad8377326f29999f7873a6dd0b3a0ff.zip FreeBSD-src-cddbdd03cad8377326f29999f7873a6dd0b3a0ff.tar.gz |
This commit was generated by cvs2svn to compensate for changes in r14062,
which included commits to RCS files with non-trunk default branches.
Diffstat (limited to 'usr.sbin/rpc.yppasswdd')
-rw-r--r-- | usr.sbin/rpc.yppasswdd/Makefile | 55 | ||||
-rw-r--r-- | usr.sbin/rpc.yppasswdd/pw_copy.c | 122 | ||||
-rw-r--r-- | usr.sbin/rpc.yppasswdd/pw_util.c | 174 | ||||
-rw-r--r-- | usr.sbin/rpc.yppasswdd/rpc.yppasswdd.8 | 276 | ||||
-rw-r--r-- | usr.sbin/rpc.yppasswdd/yppasswd_comm.c | 300 | ||||
-rw-r--r-- | usr.sbin/rpc.yppasswdd/yppasswd_comm.h | 46 | ||||
-rw-r--r-- | usr.sbin/rpc.yppasswdd/yppasswd_private.x | 67 | ||||
-rw-r--r-- | usr.sbin/rpc.yppasswdd/yppasswdd_extern.h | 71 | ||||
-rw-r--r-- | usr.sbin/rpc.yppasswdd/yppasswdd_main.c | 362 | ||||
-rw-r--r-- | usr.sbin/rpc.yppasswdd/yppasswdd_server.c | 649 | ||||
-rw-r--r-- | usr.sbin/rpc.yppasswdd/yppwupdate | 33 |
11 files changed, 2155 insertions, 0 deletions
diff --git a/usr.sbin/rpc.yppasswdd/Makefile b/usr.sbin/rpc.yppasswdd/Makefile new file mode 100644 index 0000000..8632fd8 --- /dev/null +++ b/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/usr.sbin/rpc.yppasswdd/pw_copy.c b/usr.sbin/rpc.yppasswdd/pw_copy.c new file mode 100644 index 0000000..54ab746 --- /dev/null +++ b/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/usr.sbin/rpc.yppasswdd/pw_util.c b/usr.sbin/rpc.yppasswdd/pw_util.c new file mode 100644 index 0000000..bfd5c5b --- /dev/null +++ b/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/usr.sbin/rpc.yppasswdd/rpc.yppasswdd.8 b/usr.sbin/rpc.yppasswdd/rpc.yppasswdd.8 new file mode 100644 index 0000000..fd51b96 --- /dev/null +++ b/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/usr.sbin/rpc.yppasswdd/yppasswd_comm.c b/usr.sbin/rpc.yppasswdd/yppasswd_comm.c new file mode 100644 index 0000000..d43d961 --- /dev/null +++ b/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/usr.sbin/rpc.yppasswdd/yppasswd_comm.h b/usr.sbin/rpc.yppasswdd/yppasswd_comm.h new file mode 100644 index 0000000..36d0b45 --- /dev/null +++ b/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/usr.sbin/rpc.yppasswdd/yppasswd_private.x b/usr.sbin/rpc.yppasswdd/yppasswd_private.x new file mode 100644 index 0000000..2f5e1b5 --- /dev/null +++ b/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/usr.sbin/rpc.yppasswdd/yppasswdd_extern.h b/usr.sbin/rpc.yppasswdd/yppasswdd_extern.h new file mode 100644 index 0000000..84e7eed --- /dev/null +++ b/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/usr.sbin/rpc.yppasswdd/yppasswdd_main.c b/usr.sbin/rpc.yppasswdd/yppasswdd_main.c new file mode 100644 index 0000000..358345f --- /dev/null +++ b/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/usr.sbin/rpc.yppasswdd/yppasswdd_server.c b/usr.sbin/rpc.yppasswdd/yppasswdd_server.c new file mode 100644 index 0000000..fa2551a --- /dev/null +++ b/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/usr.sbin/rpc.yppasswdd/yppwupdate b/usr.sbin/rpc.yppasswdd/yppwupdate new file mode 100644 index 0000000..7a76880 --- /dev/null +++ b/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 |