diff options
-rw-r--r-- | usr.sbin/pwd_mkdb/pwd_mkdb.8 | 10 | ||||
-rw-r--r-- | usr.sbin/pwd_mkdb/pwd_mkdb.c | 297 |
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"); + } } |