Added support for in-place updates:
If rpc.yppasswdd is invoked with the -i flag, password changes will be made to the master.passwd template file and the hash map files in-place, which means it won't have to run a complete map update. Instead, it calls /var/yp/Makefile with the 'pushpw' target, which just pushes the maps to the slaves and runs yp_mkdb -c to tell the local ypserv to flush its database cache. The server will check the passwd.byname and passwd.byuid maps to see if they were built in 'insecure' or 'secure' mode (i.e. with real encrypted passwords in them or without) and update them accordingly. This combined with rpc.ypxfrd greatly reduces the amount of time it takes to complete an NIS password change, especially with very large passwd databases.
This commit is contained in:
parent
7de3854770
commit
8b6a78c2ec
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=16134
@ -1,18 +1,20 @@
|
||||
# $Id: Makefile,v 1.1.1.1 1996/02/12 15:09:01 wpaul Exp $
|
||||
# $Id: Makefile,v 1.4 1996/02/18 22:06:11 wpaul Exp wpaul $
|
||||
|
||||
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 yp_access.c yppasswd_private_xdr.c \
|
||||
util.c yppasswdd_server.c yppasswd_comm.c yppasswdd_main.c
|
||||
SRCS= pw_copy.c pw_util.c util.c yppasswd_svc.c yp_error.c ypxfr_misc.c \
|
||||
yp_dblookup.c yp_dbwrite yp_access.c yppasswd_private_xdr.c \
|
||||
yp_clnt.c yppasswdd_server.c yppasswd_comm.c yppasswdd_main.c
|
||||
|
||||
RPCDIR= ${.CURDIR}/../../include/rpcsvc
|
||||
|
||||
.PATH: ${.CURDIR}/../../usr.sbin/ypserv ${.CURDIR}/../../usr.bin/chpass \
|
||||
${.CURDIR}/../../libexec/ypxfr
|
||||
${.CURDIR}/../../libexec/ypxfr ${RPCDIR}
|
||||
|
||||
MAN8= rpc.yppasswdd.8
|
||||
|
||||
CFLAGS+= -I. -I${.CURDIR}/../../usr.sbin/vipw \
|
||||
CFLAGS+= -I${.CURDIR}/../../usr.sbin/vipw -I${.CURDIR}/../../usr.sbin/ypserv \
|
||||
-I${.CURDIR}/../../libexec/ypxfr -I${.CURDIR}/../../usr.bin/chpass \
|
||||
-I${.CURDIR}
|
||||
-I${.CURDIR} -I.
|
||||
|
||||
LDADD+=-lrpcsvc -lcrypt
|
||||
|
||||
@ -20,32 +22,34 @@ 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
|
||||
yppasswd_svc.c: yppasswd.x yppasswd.h
|
||||
rm -f ${.TARGET}
|
||||
${RPCGEN} -m ${RPCSRC} | \
|
||||
${RPCGEN} -m ${RPCDIR}/yppasswd.x | \
|
||||
sed s/"static int _rpcsvcstate"/"int _rpcsvcstate"/g > ${.TARGET}
|
||||
|
||||
yppasswd.h: ${RPCSRC}
|
||||
${RPCGEN} -h -o ${.TARGET} ${RPCSRC}
|
||||
yppasswd.h: yppasswd.x
|
||||
rm -f ${.TARGET}
|
||||
${RPCGEN} -h -o ${.TARGET} ${RPCDIR}/yppasswd.x
|
||||
|
||||
yp.h: ${YP_RPCSRC}
|
||||
${RPCGEN} -h -o ${.TARGET} ${YP_RPCSRC}
|
||||
yp.h: yp.x
|
||||
rm -f ${.TARGET}
|
||||
${RPCGEN} -h -o ${.TARGET} ${RPCDIR}/yp.x
|
||||
|
||||
yp_clnt.c: ${YP_RPCSRC} yp.h
|
||||
${RPCGEN} -DYPSERV_ONLY -l -o ${.TARGET} ${YP_RPCSRC}
|
||||
yp_clnt.c: yp.x yp.h
|
||||
rm -f ${.TARGET}
|
||||
${RPCGEN} -DYPSERV_ONLY -l -o ${.TARGET} ${RPCDIR}/yp.x
|
||||
|
||||
yppasswd_private.h: ${PRIV_RPCSRC}
|
||||
${RPCGEN} -h -o ${.TARGET} ${PRIV_RPCSRC}
|
||||
yppasswd_private.h: yppasswd_private.x
|
||||
rm -f ${.TARGET}
|
||||
${RPCGEN} -h -o ${.TARGET} ${.CURDIR}/yppasswd_private.x
|
||||
|
||||
yppasswd_private_xdr.c: ${PRIV_RPCSRC} yppasswd_private.h
|
||||
${RPCGEN} -c -o ${.TARGET} ${PRIV_RPCSRC}
|
||||
yppasswd_private_xdr.c: yppasswd_private.x yppasswd_private.h
|
||||
rm -f ${.TARGET}
|
||||
${RPCGEN} -c -o ${.TARGET} ${.CURDIR}/yppasswd_private.x
|
||||
|
||||
afterinstall:
|
||||
${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
|
||||
|
@ -28,7 +28,7 @@
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" $Id: rpc.yppasswdd.8,v 1.2 1996/02/24 22:10:38 wpaul Exp $
|
||||
.\" $Id: rpc.yppasswdd.8,v 1.6 1996/06/03 23:53:21 wpaul Exp $
|
||||
.\"
|
||||
.Dd February 8, 1996
|
||||
.Dt RPC.YPPASSWDD 8
|
||||
@ -45,6 +45,7 @@
|
||||
.Op Fl f
|
||||
.Op Fl a
|
||||
.Op Fl m
|
||||
.Op Fl i
|
||||
.Op Fl v
|
||||
.Op Fl u
|
||||
.Op Fl h
|
||||
@ -233,6 +234,16 @@ 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 i
|
||||
If
|
||||
.Nm rpc.yppasswdd
|
||||
is invoked with this flag, it will perform map updates in place. This
|
||||
means that instead of just modifying the password template file and
|
||||
starting a map update, the server will modify the map databases
|
||||
directly. This is useful when the password maps are large: if, for
|
||||
example, the password database has tens of thousands of entries, it
|
||||
can take several minutes for a map update to complete. Updating the
|
||||
maps in place reduces this time to a few seconds.
|
||||
.It Fl v
|
||||
Turn on verbose logging mode. The server normally only logs messages
|
||||
using the
|
||||
|
@ -29,7 +29,7 @@
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: yppasswdd_extern.h,v 1.5 1996/02/24 21:41:36 wpaul Exp $
|
||||
* $Id: yppasswdd_extern.h,v 1.6 1996/06/03 03:22:36 wpaul Exp $
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
@ -38,6 +38,9 @@
|
||||
#include <rpc/rpc.h>
|
||||
#include <pwd.h>
|
||||
#include <err.h>
|
||||
#include <rpcsvc/yp.h>
|
||||
#include "yp_extern.h"
|
||||
#include "ypxfr_extern.h"
|
||||
|
||||
#ifndef YPLIBDIR
|
||||
#define YPLIBDIR "/usr/libexec/"
|
||||
@ -66,9 +69,6 @@ extern int no_chfn;
|
||||
extern int allow_additions;
|
||||
extern int multidomain;
|
||||
extern int resvport;
|
||||
extern int inplace;
|
||||
extern int verbose;
|
||||
extern int _rpc_dtablesize __P((void));
|
||||
extern void yp_error __P((const char *, ...));
|
||||
extern void load_securenets __P(( void ));
|
||||
extern int yp_access __P((const char *, const struct svc_req * ));
|
||||
extern int yp_get_record __P(( const char *, const char *, const DBT *, DBT *, int));
|
||||
|
@ -29,7 +29,7 @@
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: yppasswdd_main.c,v 1.10 1996/02/24 21:41:15 wpaul Exp $
|
||||
* $Id: yppasswdd_main.c,v 1.11 1996/06/03 03:21:24 wpaul Exp $
|
||||
*/
|
||||
|
||||
#include "yppasswd.h"
|
||||
@ -72,7 +72,7 @@ struct dom_binding {};
|
||||
|
||||
#define _RPCSVC_CLOSEDOWN 120
|
||||
#ifndef lint
|
||||
static const char rcsid[] = "$Id: yppasswdd_main.c,v 1.10 1996/02/24 21:41:15 wpaul Exp $";
|
||||
static const char rcsid[] = "$Id: yppasswdd_main.c,v 1.11 1996/06/03 03:21:24 wpaul Exp $";
|
||||
#endif /* not lint */
|
||||
int _rpcpmstart = 0; /* Started by a port monitor ? */
|
||||
static int _rpcfdtype;
|
||||
@ -94,6 +94,7 @@ int allow_additions = 0;
|
||||
int multidomain = 0;
|
||||
int verbose = 0;
|
||||
int resvport = 1;
|
||||
int inplace = 0;
|
||||
char *yp_dir = "/var/yp/";
|
||||
int yp_sock;
|
||||
|
||||
@ -188,7 +189,7 @@ closedown(int sig)
|
||||
static void usage()
|
||||
{
|
||||
fprintf(stderr, "Usage: %s [-t master.passwd file] [-d domain] \
|
||||
[-p path] [-s] [-f] [-m] [-a] [-v] [-u] [-h]\n",
|
||||
[-p path] [-s] [-f] [-m] [-i] [-a] [-v] [-u] [-h]\n",
|
||||
progname);
|
||||
exit(1);
|
||||
}
|
||||
@ -211,7 +212,7 @@ main(argc, argv)
|
||||
|
||||
debug = 1;
|
||||
|
||||
while ((ch = getopt(argc, argv, "t:d:p:sfamvh")) != EOF) {
|
||||
while ((ch = getopt(argc, argv, "t:d:p:sfamivh")) != EOF) {
|
||||
switch(ch) {
|
||||
case 't':
|
||||
passfile_default = optarg;
|
||||
@ -234,6 +235,9 @@ main(argc, argv)
|
||||
case 'm':
|
||||
multidomain++;
|
||||
break;
|
||||
case 'i':
|
||||
inplace++;
|
||||
break;
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
|
@ -29,7 +29,7 @@
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: yppasswdd_server.c,v 1.2 1996/02/24 22:10:42 wpaul Exp $
|
||||
* $Id: yppasswdd_server.c,v 1.16 1996/06/04 00:00:19 wpaul Exp $
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
@ -52,6 +52,7 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/fcntl.h>
|
||||
struct dom_binding {};
|
||||
#include <rpcsvc/ypclnt.h>
|
||||
#include "yppasswdd_extern.h"
|
||||
@ -60,7 +61,7 @@ struct dom_binding {};
|
||||
#include "yppasswd_comm.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char rcsid[] = "$Id: yppasswdd_server.c,v 1.2 1996/02/24 22:10:42 wpaul Exp $";
|
||||
static const char rcsid[] = "$Id: yppasswdd_server.c,v 1.16 1996/06/04 00:00:19 wpaul Exp $";
|
||||
#endif /* not lint */
|
||||
|
||||
char *tempname;
|
||||
@ -307,9 +308,119 @@ static char *find_domain(pw)
|
||||
yp_error("found same user in two different domains");
|
||||
return(NULL);
|
||||
} else
|
||||
return(&domain);
|
||||
return((char *)&domain);
|
||||
}
|
||||
|
||||
static int update_inplace(pw, domain)
|
||||
struct passwd *pw;
|
||||
char *domain;
|
||||
{
|
||||
DB *dbp = NULL;
|
||||
DBT key = { NULL, 0 };
|
||||
DBT data = { NULL, 0 };
|
||||
char pwbuf[YPMAXRECORD];
|
||||
char keybuf[20];
|
||||
int rval, i;
|
||||
char *maps[] = { "master.passwd.byname", "master.passwd.byuid",
|
||||
"passwd.byname", "passwd.byuid" };
|
||||
|
||||
char *formats[] = { "%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s",
|
||||
"%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s",
|
||||
"%s:%s:%d:%d:%s:%s:%s", "%s:%s:%d:%d:%s:%s:%s" };
|
||||
char *ptr = NULL;
|
||||
char *yp_last = "YP_LAST_MODIFIED";
|
||||
char yplastbuf[YPMAXRECORD];
|
||||
|
||||
snprintf(yplastbuf, sizeof(yplastbuf), "%lu", time(NULL));
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
|
||||
if (i % 2) {
|
||||
snprintf(keybuf, sizeof(keybuf), "%ld", pw->pw_uid);
|
||||
key.data = (char *)&keybuf;
|
||||
key.size = strlen(keybuf);
|
||||
} else {
|
||||
key.data = pw->pw_name;
|
||||
key.size = strlen(pw->pw_name);
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX The passwd.byname and passwd.byuid maps come in
|
||||
* two flavors: secure and insecure. The secure version
|
||||
* has a '*' in the password field whereas the insecure one
|
||||
* has a real crypted password. The maps will be insecure
|
||||
* if they were built with 'unsecure = TRUE' enabled in
|
||||
* /var/yp/Makefile, but we'd have no way of knowing if
|
||||
* this has been done unless we were to try parsing the
|
||||
* Makefile, which is a disgusting thought. Instead, we
|
||||
* read the records from the maps, skip to the first ':'
|
||||
* in them, and then look at the character immediately
|
||||
* following it. If it's an '*' then the map is 'secure'
|
||||
* and we must not insert a real password into the pw_passwd
|
||||
* field. If it's not an '*', then we put the real crypted
|
||||
* password in.
|
||||
*/
|
||||
if (yp_get_record(domain,maps[i],&key,&data,1) != YP_TRUE) {
|
||||
yp_error("couldn't read %s/%s: %s", domain,
|
||||
maps[i], strerror(errno));
|
||||
return(1);
|
||||
}
|
||||
|
||||
if ((ptr = strchr(data.data, ':')) == NULL) {
|
||||
yp_error("no colon in passwd record?!");
|
||||
return(1);
|
||||
}
|
||||
|
||||
if (i < 2) {
|
||||
snprintf(pwbuf, sizeof(pwbuf), formats[i],
|
||||
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 {
|
||||
snprintf(pwbuf, sizeof(pwbuf), formats[i],
|
||||
pw->pw_name, *(ptr+1) == '*' ? "*" : pw->pw_passwd,
|
||||
pw->pw_uid, pw->pw_gid, pw->pw_gecos, pw->pw_dir,
|
||||
pw->pw_shell);
|
||||
}
|
||||
|
||||
#define FLAGS O_RDWR|O_CREAT
|
||||
|
||||
if ((dbp = yp_open_db_rw(domain, maps[i], FLAGS)) == NULL) {
|
||||
yp_error("couldn't open %s/%s r/w: %s",domain,
|
||||
maps[i],strerror(errno));
|
||||
return(1);
|
||||
}
|
||||
|
||||
data.data = pwbuf;
|
||||
data.size = strlen(pwbuf);
|
||||
|
||||
if (yp_put_record(dbp, &key, &data, 1) != YP_TRUE) {
|
||||
yp_error("failed to update record in %s/%s", domain,
|
||||
maps[i]);
|
||||
(void)(dbp->close)(dbp);
|
||||
return(1);
|
||||
}
|
||||
|
||||
key.data = yp_last;
|
||||
key.size = strlen(yp_last);
|
||||
data.data = (char *)&yplastbuf;
|
||||
data.size = strlen(yplastbuf);
|
||||
|
||||
if (yp_put_record(dbp, &key, &data, 1) != YP_TRUE) {
|
||||
yp_error("failed to update timestamp in %s/%s", domain,
|
||||
maps[i]);
|
||||
(void)(dbp->close)(dbp);
|
||||
return(1);
|
||||
}
|
||||
|
||||
(void)(dbp->close)(dbp);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
int *
|
||||
yppasswdproc_update_1_svc(yppasswd *argp, struct svc_req *rqstp)
|
||||
{
|
||||
@ -462,11 +573,22 @@ cleaning up and bailing out");
|
||||
}
|
||||
}
|
||||
|
||||
if (inplace) {
|
||||
if ((rval = update_inplace(&yp_password, domain))) {
|
||||
yp_error("inplace update failed -- rebuilding maps");
|
||||
}
|
||||
}
|
||||
|
||||
switch((pid = fork())) {
|
||||
case 0:
|
||||
/* unlink(passfile_hold); */
|
||||
execlp(MAP_UPDATE_PATH, MAP_UPDATE, passfile,
|
||||
yppasswd_domain, NULL);
|
||||
if (inplace && !rval) {
|
||||
execlp(MAP_UPDATE_PATH, MAP_UPDATE, passfile,
|
||||
yppasswd_domain, "pushpw", NULL);
|
||||
} else {
|
||||
execlp(MAP_UPDATE_PATH, MAP_UPDATE, passfile,
|
||||
yppasswd_domain, NULL);
|
||||
}
|
||||
yp_error("couldn't exec map update process: %s",
|
||||
strerror(errno));
|
||||
unlink(passfile);
|
||||
@ -602,11 +724,23 @@ cleaning up and bailing out");
|
||||
}
|
||||
}
|
||||
|
||||
if (inplace) {
|
||||
if ((rval = update_inplace((struct passwd *)&argp->newpw,
|
||||
argp->domain))) {
|
||||
yp_error("inplace update failed -- rebuilding maps");
|
||||
}
|
||||
}
|
||||
|
||||
switch((pid = fork())) {
|
||||
case 0:
|
||||
close(yp_sock);
|
||||
execlp(MAP_UPDATE_PATH, MAP_UPDATE, passfile,
|
||||
argp->domain, NULL);
|
||||
if (inplace && !rval) {
|
||||
execlp(MAP_UPDATE_PATH, MAP_UPDATE, passfile,
|
||||
argp->domain, "pushpw", NULL);
|
||||
} else {
|
||||
execlp(MAP_UPDATE_PATH, MAP_UPDATE, passfile,
|
||||
argp->domain, NULL);
|
||||
}
|
||||
yp_error("couldn't exec map update process: %s",
|
||||
strerror(errno));
|
||||
unlink(passfile);
|
||||
|
@ -8,7 +8,7 @@
|
||||
#
|
||||
# Comment out the LOG=yes line to disable logging.
|
||||
#
|
||||
# $Id: yppwupdate,v 1.1.1.1 1996/02/12 15:09:01 wpaul Exp $
|
||||
# $Id: yppwupdate,v 1.4 1996/06/03 16:17:21 wpaul Exp $
|
||||
#
|
||||
|
||||
LOG=yes
|
||||
@ -27,7 +27,7 @@ fi
|
||||
|
||||
if [ ! $LOG ];
|
||||
then
|
||||
cd /var/yp; /usr/bin/make MASTER_PASSWD=$1 UPDATE_DOMAIN=$2 2>&1
|
||||
cd /var/yp; /usr/bin/make MASTER_PASSWD=$1 UPDATE_DOMAIN=$2 $3 2>&1
|
||||
else
|
||||
cd /var/yp; /usr/bin/make MASTER_PASSWD=$1 UPDATE_DOMAIN=$2 >> $LOGFILE 2>&1
|
||||
cd /var/yp; /usr/bin/make MASTER_PASSWD=$1 UPDATE_DOMAIN=$2 $3 >> $LOGFILE 2>&1
|
||||
fi
|
||||
|
Loading…
Reference in New Issue
Block a user