summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--usr.sbin/pwd_mkdb/pwd_mkdb.810
-rw-r--r--usr.sbin/pwd_mkdb/pwd_mkdb.c297
2 files changed, 210 insertions, 97 deletions
diff --git a/usr.sbin/pwd_mkdb/pwd_mkdb.8 b/usr.sbin/pwd_mkdb/pwd_mkdb.8
index ed4b0047bd5..22d5e88dc05 100644
--- a/usr.sbin/pwd_mkdb/pwd_mkdb.8
+++ b/usr.sbin/pwd_mkdb/pwd_mkdb.8
@@ -1,4 +1,4 @@
-.\" $OpenBSD: pwd_mkdb.8,v 1.10 2000/11/09 17:53:21 aaron Exp $
+.\" $OpenBSD: pwd_mkdb.8,v 1.11 2000/11/26 01:23:12 millert Exp $
.\"
.\" Copyright (c) 1991, 1993
.\" The Regents of the University of California. All rights reserved.
@@ -44,6 +44,7 @@
.Op Fl c
.Op Fl p
.Op Fl d Ar directory
+.Op Fl u Ar username
.Ar file
.Sh DESCRIPTION
.Nm
@@ -73,6 +74,13 @@ Create a Version 7 style password file and install it into
.It Fl d Ar directory
Operate in a base directory other than the default of
.Pa /etc .
++.It Fl u Ar username
+Only update the record for the specified user. Utilities that
+operate on a single user can use this option to avoid the
+overhead of rebuilding the entire database. This option must
+never be used if the line number of the user's record in
+.Pa /etc/master.passwd
+has changed.
.It Ar file
The absolute path to a file in
.Ar master.passwd
diff --git a/usr.sbin/pwd_mkdb/pwd_mkdb.c b/usr.sbin/pwd_mkdb/pwd_mkdb.c
index 96f17d86cd0..6dedcb3a8e2 100644
--- a/usr.sbin/pwd_mkdb/pwd_mkdb.c
+++ b/usr.sbin/pwd_mkdb/pwd_mkdb.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pwd_mkdb.c,v 1.21 2000/06/30 16:00:26 millert Exp $ */
+/* $OpenBSD: pwd_mkdb.c,v 1.22 2000/11/26 01:23:12 millert Exp $ */
/*-
* Copyright (c) 1991, 1993, 1994
@@ -45,7 +45,7 @@ static char copyright[] =
#if 0
static char sccsid[] = "from: @(#)pwd_mkdb.c 8.5 (Berkeley) 4/20/94";
#else
-static char *rcsid = "$OpenBSD: pwd_mkdb.c,v 1.21 2000/06/30 16:00:26 millert Exp $";
+static char *rcsid = "$OpenBSD: pwd_mkdb.c,v 1.22 2000/11/26 01:23:12 millert Exp $";
#endif
#endif /* not lint */
@@ -70,6 +70,10 @@ static char *rcsid = "$OpenBSD: pwd_mkdb.c,v 1.21 2000/06/30 16:00:26 millert Ex
#define PERM_INSECURE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
#define PERM_SECURE (S_IRUSR|S_IWUSR)
+#define FILE_SECURE 0x01
+#define FILE_INSECURE 0x02
+#define FILE_ORIG 0x04
+
HASHINFO openinfo = {
4096, /* bsize */
32, /* ffactor */
@@ -79,19 +83,20 @@ HASHINFO openinfo = {
0 /* lorder */
};
-static enum state { FILE_INSECURE, FILE_SECURE, FILE_ORIG } clean;
-static struct passwd pwd; /* password structure */
static char *pname; /* password file name */
static char *basedir; /* dir holding master.passwd */
+static int clean; /* what to remove on cleanup */
static int hasyp; /* are we running YP? */
void cleanup __P((void));
void error __P((char *));
+void errorx __P((char *));
+void cp __P((char *, char *, mode_t));
void mv __P((char *, char *));
int scan __P((FILE *, struct passwd *, int *));
void usage __P((void));
char *changedir __P((char *path, char *dir));
-void db_store __P((FILE *, FILE *, DB *, struct passwd *, int, int));
+void db_store __P((FILE *, FILE *, DB *, DB *,struct passwd *, int, char *, uid_t));
int
main(argc, argv)
@@ -99,29 +104,35 @@ main(argc, argv)
char *argv[];
{
DB *dp, *edp;
- DBT ypdata, ypkey;
+ DBT data, key;
FILE *fp, *oldfp = NULL;
struct stat st;
+ struct passwd pwd;
sigset_t set;
+ uid_t olduid;
int ch, tfd, makeold, flags = 0, checkonly = 0;
- char buf[MAXPATHLEN];
+ char *username, buf[MAX(MAXPATHLEN, LINE_MAX * 2)];
makeold = 0;
- while ((ch = getopt(argc, argv, "cpvd:")) != -1)
+ username = NULL;
+ while ((ch = getopt(argc, argv, "cd:pu:v")) != -1)
switch(ch) {
case 'c': /* verify only */
checkonly = 1;
break;
- case 'p': /* create V7 "file.orig" */
- makeold = 1;
- break;
- case 'v': /* backward compatible */
- break;
case 'd':
basedir = optarg;
if (strlen(basedir) > MAXPATHLEN - 40)
errx(1, "basedir too long");
break;
+ case 'p': /* create V7 "file.orig" */
+ makeold = 1;
+ break;
+ case 'u': /* only update this record */
+ username = optarg;
+ break;
+ case 'v': /* backward compatible */
+ break;
case '?':
default:
usage();
@@ -129,7 +140,7 @@ main(argc, argv)
argc -= optind;
argv += optind;
- if (argc != 1)
+ if (argc != 1 || (username && (*username == '+' || *username == '-')))
usage();
/*
@@ -167,22 +178,62 @@ main(argc, argv)
if (fstat(fileno(fp), &st) == -1)
error(pname);
- /*
- * Tweak openinfo values for large passwd files.
- */
+ /* Tweak openinfo values for large passwd files. */
if (st.st_size > (off_t)100*1024)
openinfo.cachesize = MIN(st.st_size * 20, (off_t)12*1024*1024);
if (st.st_size / 128 > openinfo.nelem)
openinfo.nelem = st.st_size / 128;
+ /* If only updating a single record, stash the old uid */
+ if (username) {
+ dp = dbopen(_PATH_MP_DB, O_RDONLY, 0, DB_HASH, NULL);
+ if (dp == NULL)
+ error(_PATH_MP_DB);
+ buf[0] = _PW_KEYBYNAME;
+ strlcpy(buf + 1, username, sizeof(buf) - 1);
+ key.data = (u_char *)buf;
+ key.size = strlen(buf + 1) + 1;
+ if ((dp->get)(dp, &key, &data, 0) == 0) {
+ char *p = (char *)data.data;
+ /* Skip to uid field */
+ while (*p++ != '\0')
+ while (*p++ != '\0')
+ ;
+ memcpy(&olduid, p, sizeof(olduid));
+ } else
+ olduid = UID_MAX;
+ (dp->close)(dp);
+ }
+
+ /* Open the temporary encrypted password database. */
+ (void)snprintf(buf, sizeof(buf), "%s.tmp",
+ changedir(_PATH_SMP_DB, basedir));
+ if (username) {
+ cp(changedir(_PATH_SMP_DB, basedir), buf, PERM_SECURE);
+ edp = dbopen(buf,
+ O_RDWR, PERM_SECURE, DB_HASH, &openinfo);
+ } else {
+ edp = dbopen(buf,
+ O_RDWR|O_CREAT|O_EXCL, PERM_SECURE, DB_HASH, &openinfo);
+ }
+ if (!edp)
+ error(buf);
+ clean |= FILE_SECURE;
+
/* Open the temporary insecure password database. */
(void)snprintf(buf, sizeof(buf), "%s.tmp",
changedir(_PATH_MP_DB, basedir));
- dp = dbopen(buf,
- O_RDWR|O_CREAT|O_EXCL, PERM_INSECURE, DB_HASH, &openinfo);
+ if (username) {
+ cp(changedir(_PATH_MP_DB, basedir), buf, PERM_INSECURE);
+ dp = dbopen(buf,
+ O_RDWR, PERM_INSECURE, DB_HASH, &openinfo);
+ } else {
+ dp = dbopen(buf,
+ O_RDWR|O_CREAT|O_EXCL, PERM_INSECURE, DB_HASH, &openinfo);
+ }
if (dp == NULL)
error(buf);
- clean = FILE_INSECURE;
+ clean |= FILE_INSECURE;
/*
* Open file for old password file. Minor trickiness -- don't want to
@@ -198,7 +249,7 @@ main(argc, argv)
error(buf);
if ((oldfp = fdopen(tfd, "w")) == NULL)
error(buf);
- clean = FILE_ORIG;
+ clean |= FILE_ORIG;
}
/*
@@ -218,26 +269,30 @@ main(argc, argv)
*/
/*
- * Write "insecure" (no passwd) version of the .db file.
+ * Write the .db files.
* We do this three times, one per key type (for getpw{name,uid,ent}).
* The first time through we also check for YP, issue warnings
* and save the V7 format passwd file if necessary.
*/
- db_store(fp, makeold ? oldfp : NULL, dp, &pwd, _PW_KEYBYNAME, 1);
- db_store(fp, makeold ? oldfp : NULL, dp, &pwd, _PW_KEYBYUID, 1);
- db_store(fp, makeold ? oldfp : NULL, dp, &pwd, _PW_KEYBYNUM, 1);
+ db_store(fp, oldfp, edp, dp, &pwd, _PW_KEYBYNAME, username, olduid);
+ db_store(fp, oldfp, edp, dp, &pwd, _PW_KEYBYUID, username, olduid);
+ db_store(fp, oldfp, edp, dp, &pwd, _PW_KEYBYNUM, username, olduid);
/* Store YP token, if needed. */
- if (hasyp) {
- ypkey.data = (u_char *)_PW_YPTOKEN;
- ypkey.size = strlen(_PW_YPTOKEN);
- ypdata.data = (u_char *)NULL;
- ypdata.size = 0;
+ if (hasyp && !username) {
+ key.data = (u_char *)_PW_YPTOKEN;
+ key.size = strlen(_PW_YPTOKEN);
+ data.data = (u_char *)NULL;
+ data.size = 0;
- if ((dp->put)(dp, &ypkey, &ypdata, R_NOOVERWRITE) == -1)
+ if ((dp->put)(edp, &key, &data, R_NOOVERWRITE) == -1)
+ error("put");
+ if ((dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1)
error("put");
}
+ if ((edp->close)(edp))
+ error("close edp");
if ((dp->close)(dp))
error("close dp");
if (makeold) {
@@ -246,37 +301,6 @@ main(argc, argv)
error("close old");
}
- /* Open the temporary encrypted password database. */
- (void)snprintf(buf, sizeof(buf), "%s.tmp",
- changedir(_PATH_SMP_DB, basedir));
- edp = dbopen(buf,
- O_RDWR|O_CREAT|O_EXCL, PERM_SECURE, DB_HASH, &openinfo);
- if (!edp)
- error(buf);
- clean = FILE_SECURE;
-
- /*
- * Write "secure" (including passwd) info to the .db file.
- * We do this three times, one per key type (for getpw{name,uid,ent}).
- */
- db_store(fp, makeold ? oldfp : NULL, edp, &pwd, _PW_KEYBYNAME, 0);
- db_store(fp, makeold ? oldfp : NULL, edp, &pwd, _PW_KEYBYUID, 0);
- db_store(fp, makeold ? oldfp : NULL, edp, &pwd, _PW_KEYBYNUM, 0);
-
- /* Store YP token, if needed. */
- if (hasyp) {
- ypkey.data = (u_char *)_PW_YPTOKEN;
- ypkey.size = strlen(_PW_YPTOKEN);
- ypdata.data = (u_char *)NULL;
- ypdata.size = 0;
-
- if ((edp->put)(edp, &ypkey, &ypdata, R_NOOVERWRITE) == -1)
- error("put");
- }
-
- if ((edp->close)(edp))
- error("close edp");
-
/* Set master.passwd permissions, in case caller forgot. */
(void)fchmod(fileno(fp), S_IRUSR|S_IWUSR);
if (fclose(fp) != 0)
@@ -338,14 +362,46 @@ fmt: errno = EFTYPE; /* XXX */
return (1);
}
+void
+cp(from, to, mode)
+ char *from, *to;
+ mode_t mode;
+{
+ static char buf[MAXBSIZE];
+ int from_fd, rcount, to_fd, wcount;
+
+ if ((from_fd = open(from, O_RDONLY, 0)) < 0)
+ error(from);
+ if ((to_fd = open(to, O_WRONLY|O_CREAT|O_EXCL, mode)) < 0)
+ error(to);
+ while ((rcount = read(from_fd, buf, MAXBSIZE)) > 0) {
+ wcount = write(to_fd, buf, rcount);
+ if (rcount != wcount || wcount == -1) {
+ int sverrno = errno;
+
+ (void)snprintf(buf, sizeof(buf), "%s to %s", from, to);
+ errno = sverrno;
+ error(buf);
+ }
+ }
+ if (rcount < 0) {
+ int sverrno = errno;
+
+ (void)snprintf(buf, sizeof(buf), "%s to %s", from, to);
+ errno = sverrno;
+ error(buf);
+ }
+}
+
void
mv(from, to)
char *from, *to;
{
- char buf[MAXPATHLEN];
+ char buf[MAXPATHLEN * 2];
if (rename(from, to)) {
int sverrno = errno;
+
(void)snprintf(buf, sizeof(buf), "%s to %s", from, to);
errno = sverrno;
error(buf);
@@ -363,21 +419,30 @@ error(name)
}
void
+errorx(name)
+ char *name;
+{
+
+ warnx("%s", name);
+ cleanup();
+ exit(1);
+}
+
+void
cleanup()
{
char buf[MAXPATHLEN];
- switch(clean) {
- case FILE_ORIG:
+ if (clean & FILE_ORIG) {
(void)snprintf(buf, sizeof(buf), "%s.orig", pname);
(void)unlink(buf);
- /* FALLTHROUGH */
- case FILE_SECURE:
+ }
+ if (clean & FILE_SECURE) {
(void)snprintf(buf, sizeof(buf), "%s.tmp",
changedir(_PATH_SMP_DB, basedir));
(void)unlink(buf);
- /* FALLTHROUGH */
- case FILE_INSECURE:
+ }
+ if (clean & FILE_INSECURE) {
(void)snprintf(buf, sizeof(buf), "%s.tmp",
changedir(_PATH_MP_DB, basedir));
(void)unlink(buf);
@@ -388,7 +453,8 @@ void
usage()
{
- (void)fprintf(stderr, "usage: pwd_mkdb [-cp] [-d basedir] file\n");
+ (void)fprintf(stderr,
+ "usage: pwd_mkdb [-cp] [-d basedir] [-u username] file\n");
exit(1);
}
@@ -412,21 +478,27 @@ changedir(path, dir)
}
void
-db_store(fp, oldfp, dp, pw, keytype, insecure)
+db_store(fp, oldfp, edp, dp, pw, keytype, username, olduid)
FILE *fp;
FILE *oldfp;
+ DB *edp;
DB *dp;
struct passwd *pw;
int keytype;
- int insecure;
+ char *username;
+ uid_t olduid;
{
int flags = 0;
+ int dbmode, found = 0;
u_int cnt;
char *p, *t, buf[LINE_MAX * 2], tbuf[1024];
DBT data, key;
size_t len;
static int firsttime = 1;
+ /* If given a username just add that record to the existing db. */
+ dbmode = username ? 0 : R_NOOVERWRITE;
+
rewind(fp);
data.data = (u_char *)buf;
key.data = (u_char *)tbuf;
@@ -456,28 +528,24 @@ db_store(fp, oldfp, dp, pw, keytype, insecure)
error("write old");
}
- /* Create data (a packed struct passwd). */
-#define COMPACT(e) t = e; while ((*p++ = *t++));
- p = buf;
- COMPACT(pw->pw_name);
- COMPACT(insecure ? "*" : pw->pw_passwd);
- memmove(p, &pw->pw_uid, sizeof(uid_t));
- p += sizeof(uid_t);
- memmove(p, &pw->pw_gid, sizeof(gid_t));
- p += sizeof(gid_t);
- memmove(p, &pw->pw_change, sizeof(time_t));
- p += sizeof(time_t);
- COMPACT(pw->pw_class);
- COMPACT(pw->pw_gecos);
- COMPACT(pw->pw_dir);
- COMPACT(pw->pw_shell);
- memmove(p, &pw->pw_expire, sizeof(time_t));
- p += sizeof(time_t);
- memmove(p, &flags, sizeof(int));
- p += sizeof(int);
- data.size = p - buf;
+ /* Are we updating a specific record? */
+ if (username) {
+ if (strcmp(username, pw->pw_name) != 0)
+ continue;
+ found = 1;
+ /* If the uid changed, remove the old record by uid. */
+ if (olduid != UID_MAX && olduid != pw->pw_uid) {
+ tbuf[0] = _PW_KEYBYUID;
+ memcpy(tbuf + 1, &olduid, sizeof(olduid));
+ key.size = sizeof(olduid) + 1;
+ (edp->del)(dp, &key, 0);
+ (dp->del)(dp, &key, 0);
+ }
+ /* XXX - should check to see if line number changed. */
+ }
/* Build the key. */
+ tbuf[0] = keytype;
switch (keytype) {
case _PW_KEYBYNUM:
memmove(tbuf + 1, &cnt, sizeof(cnt));
@@ -495,12 +563,49 @@ db_store(fp, oldfp, dp, pw, keytype, insecure)
key.size = sizeof(pw->pw_uid) + 1;
break;
}
- tbuf[0] = keytype;
- /* Write the record. */
- if ((dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1)
+#define COMPACT(e) t = e; while ((*p++ = *t++));
+ /* Create the secure record. */
+ p = buf;
+ COMPACT(pw->pw_name);
+ COMPACT(pw->pw_passwd);
+ memmove(p, &pw->pw_uid, sizeof(uid_t));
+ p += sizeof(uid_t);
+ memmove(p, &pw->pw_gid, sizeof(gid_t));
+ p += sizeof(gid_t);
+ memmove(p, &pw->pw_change, sizeof(time_t));
+ p += sizeof(time_t);
+ COMPACT(pw->pw_class);
+ COMPACT(pw->pw_gecos);
+ COMPACT(pw->pw_dir);
+ COMPACT(pw->pw_shell);
+ memmove(p, &pw->pw_expire, sizeof(time_t));
+ p += sizeof(time_t);
+ memmove(p, &flags, sizeof(int));
+ p += sizeof(int);
+ data.size = p - buf;
+
+ /* Write the secure record. */
+ if ((dp->put)(edp, &key, &data, dbmode) == -1)
+ error("put");
+
+ /* Star out password to make insecure record. */
+ p = buf + strlen(pw->pw_name) + 1; /* skip pw_name */
+ len = strlen(pw->pw_passwd);
+ memset(p, 0, len); /* zero pw_passwd */
+ t = p + len + 1; /* skip pw_passwd */
+ *p++ = '*';
+ *p++ = '\0';
+ memmove(p, t, data.size - (t - buf));
+ data.size -= len - 1;
+
+ /* Write the insecure record. */
+ if ((dp->put)(dp, &key, &data, dbmode) == -1)
error("put");
}
- if (firsttime)
+ if (firsttime) {
firsttime = 0;
+ if (username && !found)
+ errorx("can't find user in master.passwd");
+ }
}