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);
 }

Reply via email to