Module Name: src Committed By: christos Date: Thu Jun 18 17:46:24 UTC 2009
Modified Files: src/usr.sbin/pwd_mkdb: pwd_mkdb.8 pwd_mkdb.c Log Message: support reading and writing both version 0 and version 1 databases using -V <version>. By default the databases stay in their current version when rebuilding/updating. To generate a diff of this commit: cvs rdiff -u -r1.23 -r1.24 src/usr.sbin/pwd_mkdb/pwd_mkdb.8 cvs rdiff -u -r1.40 -r1.41 src/usr.sbin/pwd_mkdb/pwd_mkdb.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/usr.sbin/pwd_mkdb/pwd_mkdb.8 diff -u src/usr.sbin/pwd_mkdb/pwd_mkdb.8:1.23 src/usr.sbin/pwd_mkdb/pwd_mkdb.8:1.24 --- src/usr.sbin/pwd_mkdb/pwd_mkdb.8:1.23 Sat Sep 23 16:09:41 2006 +++ src/usr.sbin/pwd_mkdb/pwd_mkdb.8 Thu Jun 18 13:46:24 2009 @@ -1,4 +1,4 @@ -.\" $NetBSD: pwd_mkdb.8,v 1.23 2006/09/23 20:09:41 wiz Exp $ +.\" $NetBSD: pwd_mkdb.8,v 1.24 2009/06/18 17:46:24 christos Exp $ .\" .\" Copyright (c) 1991, 1993 .\" The Regents of the University of California. All rights reserved. @@ -29,7 +29,7 @@ .\" .\" from: @(#)pwd_mkdb.8 8.2 (Berkeley) 4/27/95 .\" -.Dd September 23, 2006 +.Dd June 18, 2009 .Dt PWD_MKDB 8 .Os .Sh NAME @@ -37,10 +37,11 @@ .Nd generate the password databases .Sh SYNOPSIS .Nm -.Op Fl BLps +.Op Fl BLpsv .Op Fl c Ar cachesize .Op Fl d Ar directory .Op Fl u Ar username +.Op Fl V Ar version .Ar file .Sh DESCRIPTION .Nm @@ -98,6 +99,30 @@ This option may only be used when the line number and user name in the password file have not changed, or when adding a new user from the last line in the password file. +.It Fl V Ar version +Upgrade or downgrade databases to the numbered version. Version +.Dv 0 +is the old format (up to and including +.Nx 5.0 ) +with the 4 byte time fields and version +.Dv 1 +is the new format with the 8 byte time fields (greater than +.Nx 5.0 ). +.Nx 5.0 +cannot read version +.Dv 1 +databases. +All versions above +.Nx 5.0 +can read and write both version +.Dv 0 +and version +.Dv 1 +databases. +By default the databases stay in the version they were before the command +was run. +.It Fl v +Mention when a version change occurs. .El .Pp The two databases differ in that the secure version contains the user's Index: src/usr.sbin/pwd_mkdb/pwd_mkdb.c diff -u src/usr.sbin/pwd_mkdb/pwd_mkdb.c:1.40 src/usr.sbin/pwd_mkdb/pwd_mkdb.c:1.41 --- src/usr.sbin/pwd_mkdb/pwd_mkdb.c:1.40 Sat Apr 18 04:08:36 2009 +++ src/usr.sbin/pwd_mkdb/pwd_mkdb.c Thu Jun 18 13:46:24 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: pwd_mkdb.c,v 1.40 2009/04/18 08:08:36 lukem Exp $ */ +/* $NetBSD: pwd_mkdb.c,v 1.41 2009/06/18 17:46:24 christos Exp $ */ /* * Copyright (c) 2000, 2009 The NetBSD Foundation, Inc. @@ -91,7 +91,7 @@ Copyright (c) 1991, 1993, 1994\ The Regents of the University of California. All rights reserved."); __SCCSID("from: @(#)pwd_mkdb.c 8.5 (Berkeley) 4/20/94"); -__RCSID("$NetBSD: pwd_mkdb.c,v 1.40 2009/04/18 08:08:36 lukem Exp $"); +__RCSID("$NetBSD: pwd_mkdb.c,v 1.41 2009/06/18 17:46:24 christos Exp $"); #endif /* not lint */ #if HAVE_NBTOOL_CONFIG_H @@ -133,7 +133,7 @@ extern const char __yp_token[]; #endif -HASHINFO openinfo = { +static HASHINFO openinfo = { 4096, /* bsize */ 32, /* ffactor */ 256, /* nelem */ @@ -154,24 +154,24 @@ static int lorder = BYTE_ORDER; static int clean; -void bailout(void); +void bailout(void) __attribute__((__noreturn__)); void cp(const char *, const char *, mode_t); int deldbent(DB *, const char *, int, void *); void error(const char *); -int getdbent(DB *, const char *, int, void *, struct passwd **); +int getdbent(DB *, const char *, int, void *, struct passwd **, uint32_t); void inconsistancy(void); void install(const char *, const char *); int main(int, char **); void putdbents(DB *, struct passwd *, const char *, int, const char *, int, - int, int); + int, int, uint32_t); void putyptoken(DB *, const char *); void rm(const char *); int scan(FILE *, struct passwd *, int *, int *); -void usage(void); +void usage(void) __attribute__((__noreturn__)); void wr_error(const char *); -void checkversion(DB *); -uint32_t getversion(void); -void setversion(DB *); +void checkversion(uint32_t, uint32_t); +uint32_t getversion(const char *); +void setversion(DB *, uint32_t); #define SWAP(sw) \ ((sizeof(sw) == 2 ? (typeof(sw))bswap16((uint16_t)sw) : \ @@ -181,7 +181,7 @@ int main(int argc, char *argv[]) { - int ch, makeold, tfd, lineno, found, rv, hasyp, secureonly; + int ch, makeold, tfd, lineno, found, rv, hasyp, secureonly, verbose; struct passwd pwd, *tpwd; char *username; DB *dp, *edp; @@ -191,6 +191,8 @@ char buf[MAXPATHLEN]; struct stat st; u_int cachesize; + uint32_t version, req_version; + uint32_t sversion, req_sversion; prefix[0] = '\0'; makeold = 0; @@ -202,8 +204,10 @@ newuser = 0; dp = NULL; cachesize = 0; + verbose = 0; + req_version = req_sversion = ~0U; - while ((ch = getopt(argc, argv, "BLc:d:psu:v")) != -1) + while ((ch = getopt(argc, argv, "BLc:d:psu:V:v")) != -1) switch (ch) { case 'B': /* big-endian output */ lorder = BIG_ENDIAN; @@ -226,7 +230,13 @@ case 'u': /* modify one user only */ username = optarg; break; - case 'v': /* backward compatible */ + case 'V': + req_sversion = req_version = (uint32_t)atoi(optarg); + if (req_version > 1) + err(1, "Unknown version %u\n", req_version); + break; + case 'v': + verbose++; break; case '?': default: @@ -298,10 +308,22 @@ if (dp == NULL) error(pwd_db_tmp); clean |= FILE_INSECURE; - if (username != NULL) - checkversion(dp); - else - setversion(dp); + version = getversion(_PATH_MP_DB); + if (req_version == ~0U) + req_version = version; + if (verbose) + fprintf(stderr, "%s: " _PATH_MP_DB + " version %u requested %u\n", + getprogname(), version, req_version); + if (username != NULL && req_version != version) + checkversion(req_version, version); + else if (req_version != version) { + if (verbose) + fprintf(stderr, "%s: changing " _PATH_MP_DB + " from version %u to version %u\n", + getprogname(), version, req_version); + setversion(dp, req_version); + } } /* Open the temporary encrypted password database. */ @@ -315,10 +337,22 @@ if (!edp) error(pwd_Sdb_tmp); clean |= FILE_SECURE; + sversion = getversion(_PATH_SMP_DB); + if (verbose) + fprintf(stderr, "%s: " _PATH_SMP_DB + " version %u requested %u\n", + getprogname(), sversion, req_version); + if (req_sversion == ~0U) + req_sversion = sversion; if (username != NULL) - checkversion(edp); - else - setversion(edp); + checkversion(req_sversion, sversion); + else if (req_sversion != sversion) { + if (verbose) + fprintf(stderr, "%s: changing " _PATH_SMP_DB + " from version %u to version %u\n", + getprogname(), sversion, req_sversion); + setversion(edp, req_sversion); + } /* * Open file for old password file. Minor trickiness -- don't want to @@ -345,7 +379,8 @@ /* * Determine if this is a new entry. */ - if (getdbent(edp, pwd_Sdb_tmp, _PW_KEYBYNAME, username, &tpwd)) + if (getdbent(edp, pwd_Sdb_tmp, _PW_KEYBYNAME, username, &tpwd, + sversion)) newuser = 1; else { newuser = 0; @@ -394,7 +429,7 @@ /* Write the database entry out. */ if (!secureonly) putdbents(dp, &pwd, "*", flags, pwd_db_tmp, - lineno, dbflg, uid_dbflg); + lineno, dbflg, uid_dbflg, req_version); continue; } else if (strcmp(username, pwd.pw_name) != 0) continue; @@ -409,7 +444,8 @@ * Ensure that the text file and database agree on * which line the record is from. */ - rv = getdbent(edp, pwd_Sdb_tmp, _PW_KEYBYNUM, &lineno, &tpwd); + rv = getdbent(edp, pwd_Sdb_tmp, _PW_KEYBYNUM, &lineno, &tpwd, + sversion); if (newuser) { if (rv == 0) inconsistancy(); @@ -423,7 +459,7 @@ * same username. */ if (!getdbent(edp, pwd_Sdb_tmp, _PW_KEYBYUID, &olduid, - &tpwd)) { + &tpwd, sversion)) { if (strcmp(username, tpwd->pw_name) == 0) { if (!secureonly) deldbent(dp, pwd_db_tmp, @@ -441,16 +477,16 @@ * it. */ if (!getdbent(edp, pwd_Sdb_tmp, _PW_KEYBYUID, &pwd.pw_uid, - &tpwd)) + &tpwd, sversion)) if (strcmp(username, tpwd->pw_name) != 0) uid_dbflg = R_NOOVERWRITE; /* Write the database entries out */ if (!secureonly) putdbents(dp, &pwd, "*", flags, pwd_db_tmp, lineno, - dbflg, uid_dbflg); + dbflg, uid_dbflg, req_version); putdbents(edp, &pwd, pwd.pw_passwd, flags, pwd_Sdb_tmp, - lineno, dbflg, uid_dbflg); + lineno, dbflg, uid_dbflg, req_sversion); found = 1; if (!makeold) @@ -475,7 +511,7 @@ rewind(fp); for (lineno = 0; scan(fp, &pwd, &flags, &lineno);) putdbents(edp, &pwd, pwd.pw_passwd, flags, pwd_Sdb_tmp, - lineno, dbflg, uid_dbflg); + lineno, dbflg, uid_dbflg, req_sversion); /* Store YP token if needed. */ if (hasyp) @@ -653,54 +689,49 @@ exit(EXIT_FAILURE); } -/* - * Ensures that an existing database is up to date. - * - * Makes sure that the version number of an existing database matches the - * version number setversion() writes. If it does not, this function aborts - * execution because updating the database without fully regenerating it will - * leave it inconsistent. - */ -void -checkversion(DB *dp) +uint32_t +getversion(const char *fname) { DBT data, key; int ret; + uint32_t version = 0; + DB *dp; - key.data = __UNCONST("VERSION"); - key.size = strlen((const char *)key.data) + 1; - - ret = (*dp->get)(dp, &key, &data, 0); - if (ret == -1) { - warnx("cannot get VERSION record from database"); + dp = dbopen(fname, O_RDONLY, PERM_INSECURE, DB_HASH, NULL); + if (dp == NULL) { + warn("Cannot open database %s", fname); bailout(); } + key.data = __UNCONST("VERSION"); + key.size = strlen((const char *)key.data) + 1; - if (ret == 1 || (uint32_t)(*(int *)data.data) != getversion()) { - warnx("databases are laid out according to an old version"); - warnx("re-build the databases without -u"); - bailout(); + switch (ret = (*dp->get)(dp, &key, &data, 0)) { + case -1: /* Error */ + warn("Cannot get VERSION record from database"); + goto out; + case 0: + if (data.size != sizeof(version)) { + warnx("Bad VERSION record in database"); + goto out; + } + memcpy(&version, data.data, sizeof(version)); + /*FALLTHROUGH*/ + case 1: + (*dp->close)(dp); + return version; + default: + warnx("internal error db->get returns %d", ret); + goto out; } -} - -/* - * Returns the version number we write to and expect from databases. - */ -uint32_t -getversion(void) -{ - uint32_t version = sizeof(((struct passwd *)NULL)->pw_change) != sizeof(int32_t); - if (lorder != BYTE_ORDER) - version = SWAP(version); - return version; +out: + (*dp->close)(dp); + bailout(); } void -setversion(DB *dp) +setversion(DB *dp, uint32_t version) { DBT data, key; - uint32_t version = getversion(); - key.data = __UNCONST("VERSION"); key.size = strlen((const char *)key.data) + 1; @@ -711,6 +742,15 @@ wr_error("setversion"); } +void +checkversion(uint32_t req_version, uint32_t version) +{ + (void)fprintf(stderr, "%s: you cannot change a single " + "record from version %u to version %u\n", getprogname(), + version, req_version); + bailout(); +} + /* * Write entries to a database for a single user. * @@ -728,7 +768,7 @@ void putdbents(DB *dp, struct passwd *pw, const char *passwd, int flags, - const char *fn, int lineno, int dbflg, int uid_dbflg) + const char *fn, int lineno, int dbflg, int uid_dbflg, uint32_t version) { struct passwd pwd; char buf[MAX(MAXPATHLEN, LINE_MAX * 2)], tbuf[1024], *p; @@ -744,10 +784,32 @@ if (lorder != BYTE_ORDER) { pwd.pw_uid = SWAP(pwd.pw_uid); pwd.pw_gid = SWAP(pwd.pw_gid); - pwd.pw_change = SWAP(pwd.pw_change); - pwd.pw_expire = SWAP(pwd.pw_expire); } +#define WRITEPWTIMEVAR(pwvar) \ + do { \ + if (version == 0 && \ + sizeof(pwvar) == sizeof(uint64_t)) { \ + uint32_t tmp = (uint32_t)pwvar; \ + if (lorder != BYTE_ORDER) \ + tmp = SWAP(tmp); \ + memmove(p, &tmp, sizeof(tmp)); \ + p += sizeof(tmp); \ + } else if (version == 1 && \ + sizeof(pwvar) == sizeof(uint32_t)) { \ + uint64_t tmp = pwvar; \ + if (lorder != BYTE_ORDER) \ + tmp = SWAP(tmp); \ + memmove(p, &tmp, sizeof(tmp)); \ + p += sizeof(tmp); \ + } else { \ + if (lorder != BYTE_ORDER) \ + pwvar = SWAP(pwvar); \ + memmove(p, &pwvar, sizeof(pwvar)); \ + p += sizeof(pwvar); \ + } \ + } while (/*CONSTCOND*/0) + /* Create insecure data. */ p = buf; COMPACT(pwd.pw_name); @@ -756,14 +818,12 @@ p += sizeof(pwd.pw_uid); memmove(p, &pwd.pw_gid, sizeof(pwd.pw_gid)); p += sizeof(pwd.pw_gid); - memmove(p, &pwd.pw_change, sizeof(pwd.pw_change)); - p += sizeof(pwd.pw_change); + WRITEPWTIMEVAR(pwd.pw_change); COMPACT(pwd.pw_class); COMPACT(pwd.pw_gecos); COMPACT(pwd.pw_dir); COMPACT(pwd.pw_shell); - memmove(p, &pwd.pw_expire, sizeof(pwd.pw_expire)); - p += sizeof(pwd.pw_expire); + WRITEPWTIMEVAR(pwd.pw_expire); x = flags; if (lorder != BYTE_ORDER) x = SWAP(x); @@ -830,7 +890,8 @@ } int -getdbent(DB *dp, const char *fn, int type, void *keyp, struct passwd **tpwd) +getdbent(DB *dp, const char *fn, int type, void *keyp, struct passwd **tpwd, + uint32_t version) { static char buf[MAX(MAXPATHLEN, LINE_MAX * 2)]; static struct passwd pwd; @@ -869,39 +930,64 @@ pwd.pw_name = p; while (*p++ != '\0') - ; + continue; pwd.pw_passwd = p; while (*p++ != '\0') - ; + continue; memcpy(&pwd.pw_uid, p, sizeof(pwd.pw_uid)); p += sizeof(pwd.pw_uid); memcpy(&pwd.pw_gid, p, sizeof(pwd.pw_gid)); p += sizeof(pwd.pw_gid); - memcpy(&pwd.pw_change, p, sizeof(pwd.pw_change)); - p += sizeof(pwd.pw_change); + +#define READPWTIMEVAR(pwvar) \ + do { \ + if (version == 0 && \ + sizeof(pwvar) == sizeof(uint64_t)) { \ + uint32_t tmp; \ + memcpy(&tmp, p, sizeof(tmp)); \ + p += sizeof(tmp); \ + if (lorder != BYTE_ORDER) \ + pwvar = SWAP(tmp); \ + else \ + pwvar = tmp; \ + } else if (version == 1 && \ + sizeof(pwvar) == sizeof(uint32_t)) { \ + uint64_t tmp; \ + memcpy(&tmp, p, sizeof(tmp)); \ + p += sizeof(tmp); \ + if (lorder != BYTE_ORDER) \ + pwvar = (uint32_t)SWAP(tmp); \ + else \ + pwvar = (uint32_t)tmp; \ + } else { \ + memcpy(&pwvar, p, sizeof(pwvar)); \ + p += sizeof(pwvar); \ + if (lorder != BYTE_ORDER) \ + pwvar = SWAP(pwvar); \ + } \ + } while (/*CONSTCOND*/0) + + READPWTIMEVAR(pwd.pw_change); pwd.pw_class = p; while (*p++ != '\0') - ; + continue; pwd.pw_gecos = p; while (*p++ != '\0') - ; + continue; pwd.pw_dir = p; while (*p++ != '\0') - ; + continue; pwd.pw_shell = p; while (*p++ != '\0') - ; + continue; - memcpy(&pwd.pw_expire, p, sizeof(pwd.pw_expire)); - p += sizeof(pwd.pw_expire); + READPWTIMEVAR(pwd.pw_expire); if (lorder != BYTE_ORDER) { pwd.pw_uid = SWAP(pwd.pw_uid); pwd.pw_gid = SWAP(pwd.pw_gid); - pwd.pw_change = SWAP(pwd.pw_change); - pwd.pw_expire = SWAP(pwd.pw_expire); } *tpwd = &pwd; @@ -927,6 +1013,8 @@ { (void)fprintf(stderr, - "usage: pwd_mkdb [-BLps] [-c cachesize] [-d directory] [-u user] file\n"); + "Usage: %s [-BLpsv] [-c cachesize] [-d directory] [-u user] " + "[-V version] file\n", + getprogname()); exit(EXIT_FAILURE); }