Home | History | Annotate | Line # | Download | only in pwd_mkdb
pwd_mkdb.c revision 1.37
      1 /*	$NetBSD: pwd_mkdb.c,v 1.37 2009/02/02 04:24:18 uebayasi Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2000, 2009 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     26  * POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 
     29 /*
     30  * Copyright (c) 1991, 1993, 1994
     31  *	The Regents of the University of California.  All rights reserved.
     32  *
     33  * Redistribution and use in source and binary forms, with or without
     34  * modification, are permitted provided that the following conditions
     35  * are met:
     36  * 1. Redistributions of source code must retain the above copyright
     37  *    notice, this list of conditions and the following disclaimer.
     38  * 2. Redistributions in binary form must reproduce the above copyright
     39  *    notice, this list of conditions and the following disclaimer in the
     40  *    documentation and/or other materials provided with the distribution.
     41  * 3. Neither the name of the University nor the names of its contributors
     42  *    may be used to endorse or promote products derived from this software
     43  *    without specific prior written permission.
     44  *
     45  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     46  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     47  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     48  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     49  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     50  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     51  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     52  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     53  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     54  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     55  * SUCH DAMAGE.
     56  */
     57 
     58 /*
     59  * Portions Copyright(C) 1994, Jason Downs.  All rights reserved.
     60  *
     61  * Redistribution and use in source and binary forms, with or without
     62  * modification, are permitted provided that the following conditions
     63  * are met:
     64  * 1. Redistributions of source code must retain the above copyright
     65  *    notice, this list of conditions and the following disclaimer.
     66  * 2. Redistributions in binary form must reproduce the above copyright
     67  *    notice, this list of conditions and the following disclaimer in the
     68  *    documentation and/or other materials provided with the distribution.
     69  *
     70  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS
     71  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     72  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     73  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT,
     74  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     75  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     76  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     77  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     78  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     79  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     80  * SUCH DAMAGE.
     81  */
     82 
     83 #if HAVE_NBTOOL_CONFIG_H
     84 #include "nbtool_config.h"
     85 #endif
     86 
     87 #include <sys/cdefs.h>
     88 #if !defined(lint)
     89 __COPYRIGHT("@(#) Copyright (c) 2000, 2009\
     90  The NetBSD Foundation, Inc.  All rights reserved.\
     91   Copyright (c) 1991, 1993, 1994\
     92  The Regents of the University of California.  All rights reserved.");
     93 __SCCSID("from: @(#)pwd_mkdb.c	8.5 (Berkeley) 4/20/94");
     94 __RCSID("$NetBSD: pwd_mkdb.c,v 1.37 2009/02/02 04:24:18 uebayasi Exp $");
     95 #endif /* not lint */
     96 
     97 #if HAVE_NBTOOL_CONFIG_H
     98 #include "compat_pwd.h"
     99 #else
    100 #include <pwd.h>
    101 #endif
    102 
    103 #include <sys/param.h>
    104 #include <sys/stat.h>
    105 
    106 #include <db.h>
    107 #include <err.h>
    108 #include <errno.h>
    109 #include <fcntl.h>
    110 #include <limits.h>
    111 #include <signal.h>
    112 #include <stdio.h>
    113 #include <stdlib.h>
    114 #include <string.h>
    115 #include <unistd.h>
    116 #include <util.h>
    117 
    118 #define	MAX_CACHESIZE	8*1024*1024
    119 #define	MIN_CACHESIZE	2*1024*1024
    120 
    121 #define	PERM_INSECURE	(S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
    122 #define	PERM_SECURE	(S_IRUSR | S_IWUSR)
    123 
    124 #if HAVE_NBTOOL_CONFIG_H
    125 static const char __yp_token[] = "__YP!";
    126 #else
    127 /* Pull this out of the C library. */
    128 extern const char __yp_token[];
    129 #endif
    130 
    131 HASHINFO openinfo = {
    132 	4096,		/* bsize */
    133 	32,		/* ffactor */
    134 	256,		/* nelem */
    135 	0,		/* cachesize */
    136 	NULL,		/* hash() */
    137 	0		/* lorder */
    138 };
    139 
    140 #define	FILE_INSECURE	0x01
    141 #define	FILE_SECURE	0x02
    142 #define	FILE_ORIG	0x04
    143 
    144 static char	*pname;				/* password file name */
    145 static char	prefix[MAXPATHLEN];
    146 static char	oldpwdfile[MAX(MAXPATHLEN, LINE_MAX * 2)];
    147 static char	pwd_db_tmp[MAX(MAXPATHLEN, LINE_MAX * 2)];
    148 static char	pwd_Sdb_tmp[MAX(MAXPATHLEN, LINE_MAX * 2)];
    149 static int 	lorder = BYTE_ORDER;
    150 static int	clean;
    151 
    152 void	bailout(void);
    153 void	cp(const char *, const char *, mode_t);
    154 int	deldbent(DB *, const char *, int, void *);
    155 void	error(const char *);
    156 int	getdbent(DB *, const char *, int, void *, struct passwd **);
    157 void	inconsistancy(void);
    158 void	install(const char *, const char *);
    159 int	main(int, char **);
    160 void	putdbents(DB *, struct passwd *, const char *, int, const char *, int,
    161 		  int, int);
    162 void	putyptoken(DB *, const char *);
    163 void	rm(const char *);
    164 int	scan(FILE *, struct passwd *, int *, int *);
    165 void	usage(void);
    166 void	wr_error(const char *);
    167 void	checkversion(DB *);
    168 uint32_t getversion(void);
    169 void	setversion(DB *);
    170 
    171 static __inline uint16_t swap16(uint16_t sw)
    172 {
    173 	return ((sw & 0x00ff) << 8) |
    174 	       ((sw & 0xff00) >> 8);
    175 }
    176 
    177 static __inline uint32_t swap32(uint32_t sw) {
    178 	return ((sw & 0x000000ff) << 24) |
    179 	       ((sw & 0x0000ff00) << 8) |
    180 	       ((sw & 0x00ff0000) >> 8) |
    181 	       ((sw & 0xff000000) >> 24);
    182 }
    183 
    184 static __inline uint64_t swap64(uint64_t sw) {
    185 	return ((sw & 0x00000000000000ffULL) << 56) |
    186 	       ((sw & 0x000000000000ff00ULL) << 40) |
    187 	       ((sw & 0x0000000000ff0000ULL) >> 24) |
    188 	       ((sw & 0x00000000ff000000ULL) << 8) |
    189 	       ((sw & 0x000000ff00000000ULL) >> 8) |
    190 	       ((sw & 0x0000ff0000000000ULL) >> 24) |
    191 	       ((sw & 0x00ff000000000000ULL) >> 40) |
    192 	       ((sw & 0xff00000000000000ULL) >> 56);
    193 }
    194 
    195 #define SWAP(sw) \
    196     ((sizeof(sw) == 2 ? (typeof(sw))swap16((uint16_t)sw) : \
    197     (sizeof(sw) == 4 ? (typeof(sw))swap32((uint32_t)sw) : \
    198     (sizeof(sw) == 8 ? (typeof(sw))swap64((uint64_t)sw) : abort(), 0))))
    199 
    200 int
    201 main(int argc, char *argv[])
    202 {
    203 	int ch, makeold, tfd, lineno, found, rv, hasyp, secureonly;
    204 	struct passwd pwd, *tpwd;
    205 	char *username;
    206 	DB *dp, *edp;
    207 	FILE *fp, *oldfp;
    208 	sigset_t set;
    209 	int dbflg, uid_dbflg, newuser, olduid, flags;
    210 	char buf[MAXPATHLEN];
    211 	struct stat st;
    212 	u_int cachesize;
    213 
    214 	prefix[0] = '\0';
    215 	makeold = 0;
    216 	oldfp = NULL;
    217 	username = NULL;
    218 	hasyp = 0;
    219 	secureonly = 0;
    220 	found = 0;
    221 	newuser = 0;
    222 	dp = NULL;
    223 	cachesize = 0;
    224 
    225 	while ((ch = getopt(argc, argv, "BLc:d:psu:v")) != -1)
    226 		switch (ch) {
    227 		case 'B':			/* big-endian output */
    228 			lorder = BIG_ENDIAN;
    229 			break;
    230 		case 'L':			/* little-endian output */
    231 			lorder = LITTLE_ENDIAN;
    232 			break;
    233 		case 'c':
    234 			cachesize = atoi(optarg) * 1024 * 1024;
    235 			break;
    236 		case 'd':			/* set prefix */
    237 			strlcpy(prefix, optarg, sizeof(prefix));
    238 			break;
    239 		case 'p':			/* create V7 "file.orig" */
    240 			makeold = 1;
    241 			break;
    242 		case 's':			/* modify secure db only */
    243 			secureonly = 1;
    244 			break;
    245 		case 'u':			/* modify one user only */
    246 			username = optarg;
    247 			break;
    248 		case 'v':			/* backward compatible */
    249 			break;
    250 		case '?':
    251 		default:
    252 			usage();
    253 		}
    254 	argc -= optind;
    255 	argv += optind;
    256 
    257 	if (argc != 1)
    258 		usage();
    259 	if (username != NULL)
    260 		if (username[0] == '+' || username[0] == '-')
    261 			usage();
    262 	if (secureonly)
    263 		makeold = 0;
    264 
    265 	/*
    266 	 * This could be changed to allow the user to interrupt.
    267 	 * Probably not worth the effort.
    268 	 */
    269 	sigemptyset(&set);
    270 	sigaddset(&set, SIGTSTP);
    271 	sigaddset(&set, SIGHUP);
    272 	sigaddset(&set, SIGINT);
    273 	sigaddset(&set, SIGQUIT);
    274 	sigaddset(&set, SIGTERM);
    275 	(void)sigprocmask(SIG_BLOCK, &set, (sigset_t *)NULL);
    276 
    277 	/* We don't care what the user wants. */
    278 	(void)umask(0);
    279 
    280 	if (username == NULL)
    281 		flags = O_RDWR | O_CREAT | O_EXCL;
    282 	else
    283 		flags = O_RDWR;
    284 
    285 	pname = *argv;
    286 	/* Open the original password file */
    287 	if ((fp = fopen(pname, "r")) == NULL)
    288 		error(pname);
    289 
    290 	openinfo.lorder = lorder;
    291 
    292 	if (fstat(fileno(fp), &st) == -1)
    293 		error(pname);
    294 
    295 	if (cachesize) {
    296 		openinfo.cachesize = cachesize;
    297 	} else {
    298 		/* Tweak openinfo values for large passwd files. */
    299 		cachesize = st.st_size * 20;
    300 		if (cachesize > MAX_CACHESIZE)
    301 			cachesize = MAX_CACHESIZE;
    302 		else if (cachesize < MIN_CACHESIZE)
    303 			cachesize = MIN_CACHESIZE;
    304 		openinfo.cachesize = cachesize;
    305 	}
    306 
    307 	/* Open the temporary insecure password database. */
    308 	if (!secureonly) {
    309 		(void)snprintf(pwd_db_tmp, sizeof(pwd_db_tmp), "%s%s.tmp",
    310 		    prefix, _PATH_MP_DB);
    311 		if (username != NULL) {
    312 			snprintf(buf, sizeof(buf), "%s" _PATH_MP_DB, prefix);
    313 			cp(buf, pwd_db_tmp, PERM_INSECURE);
    314 		}
    315 		dp = dbopen(pwd_db_tmp, flags, PERM_INSECURE, DB_HASH,
    316 		    &openinfo);
    317 		if (dp == NULL)
    318 			error(pwd_db_tmp);
    319 		clean |= FILE_INSECURE;
    320 		if (username != NULL)
    321 			checkversion(dp);
    322 		else
    323 			setversion(dp);
    324 	}
    325 
    326 	/* Open the temporary encrypted password database. */
    327 	(void)snprintf(pwd_Sdb_tmp, sizeof(pwd_Sdb_tmp), "%s%s.tmp", prefix,
    328 		_PATH_SMP_DB);
    329 	if (username != NULL) {
    330 		snprintf(buf, sizeof(buf), "%s" _PATH_SMP_DB, prefix);
    331 		cp(buf, pwd_Sdb_tmp, PERM_SECURE);
    332 	}
    333 	edp = dbopen(pwd_Sdb_tmp, flags, PERM_SECURE, DB_HASH, &openinfo);
    334 	if (!edp)
    335 		error(pwd_Sdb_tmp);
    336 	clean |= FILE_SECURE;
    337 	if (username != NULL)
    338 		checkversion(edp);
    339 	else
    340 		setversion(edp);
    341 
    342 	/*
    343 	 * Open file for old password file.  Minor trickiness -- don't want to
    344 	 * chance the file already existing, since someone (stupidly) might
    345 	 * still be using this for permission checking.  So, open it first and
    346 	 * fdopen the resulting fd.  The resulting file should be readable by
    347 	 * everyone.
    348 	 */
    349 	if (makeold) {
    350 		(void)snprintf(oldpwdfile, sizeof(oldpwdfile), "%s.orig",
    351 		    pname);
    352 		if ((tfd = open(oldpwdfile, O_WRONLY | O_CREAT | O_EXCL,
    353 		    PERM_INSECURE)) < 0)
    354 			error(oldpwdfile);
    355 		clean |= FILE_ORIG;
    356 		if ((oldfp = fdopen(tfd, "w")) == NULL)
    357 			error(oldpwdfile);
    358 	}
    359 
    360 	if (username != NULL) {
    361 		uid_dbflg = 0;
    362 		dbflg = 0;
    363 
    364 		/*
    365 		 * Determine if this is a new entry.
    366 		 */
    367 		if (getdbent(edp, pwd_Sdb_tmp, _PW_KEYBYNAME, username, &tpwd))
    368 			newuser = 1;
    369 		else {
    370 			newuser = 0;
    371 			olduid = tpwd->pw_uid;
    372 		}
    373 
    374 	} else {
    375 		uid_dbflg = R_NOOVERWRITE;
    376 		dbflg = R_NOOVERWRITE;
    377 	}
    378 
    379 	/*
    380 	 * If we see something go by that looks like YP, we save a special
    381 	 * pointer record, which if YP is enabled in the C lib, will speed
    382 	 * things up.
    383 	 */
    384 	for (lineno = 0; scan(fp, &pwd, &flags, &lineno);) {
    385 		/*
    386 		 * Create original format password file entry.
    387 		 */
    388 		if (makeold) {
    389 			(void)fprintf(oldfp, "%s:*:%d:%d:%s:%s:%s\n",
    390 			    pwd.pw_name, pwd.pw_uid, pwd.pw_gid, pwd.pw_gecos,
    391 			    pwd.pw_dir, pwd.pw_shell);
    392 			if (ferror(oldfp))
    393 				wr_error(oldpwdfile);
    394 		}
    395 
    396 		if (username == NULL) {
    397 			/* Look like YP? */
    398 			if (pwd.pw_name[0] == '+' || pwd.pw_name[0] == '-')
    399 				hasyp++;
    400 
    401 			/* Warn about potentially unsafe uid/gid overrides. */
    402 			if (pwd.pw_name[0] == '+') {
    403 				if ((flags & _PASSWORD_NOUID) == 0 &&
    404 				    pwd.pw_uid == 0)
    405 					warnx("line %d: superuser override "
    406 					    "in YP inclusion", lineno);
    407 				if ((flags & _PASSWORD_NOGID) == 0 &&
    408 				    pwd.pw_gid == 0)
    409 					warnx("line %d: wheel override "
    410 					    "in YP inclusion", lineno);
    411 			}
    412 
    413 			/* Write the database entry out. */
    414 			if (!secureonly)
    415 				putdbents(dp, &pwd, "*", flags, pwd_db_tmp,
    416 				    lineno, dbflg, uid_dbflg);
    417 			continue;
    418 		} else if (strcmp(username, pwd.pw_name) != 0)
    419 			continue;
    420 
    421 		if (found) {
    422 			warnx("user `%s' listed twice in password file",
    423 			    username);
    424 			bailout();
    425 		}
    426 
    427 		/*
    428 		 * Ensure that the text file and database agree on
    429 		 * which line the record is from.
    430 		 */
    431 		rv = getdbent(edp, pwd_Sdb_tmp, _PW_KEYBYNUM, &lineno, &tpwd);
    432 		if (newuser) {
    433 			if (rv == 0)
    434 				inconsistancy();
    435 		} else if (rv == -1 ||
    436 			strcmp(username, tpwd->pw_name) != 0)
    437 			inconsistancy();
    438 		else if (olduid != pwd.pw_uid) {
    439 			/*
    440 			 * If we're changing UID, remove the BYUID
    441 			 * record for the old UID only if it has the
    442 			 * same username.
    443 			 */
    444 			if (!getdbent(edp, pwd_Sdb_tmp, _PW_KEYBYUID, &olduid,
    445 			    &tpwd)) {
    446 				if (strcmp(username, tpwd->pw_name) == 0) {
    447 					if (!secureonly)
    448 						deldbent(dp, pwd_db_tmp,
    449 						    _PW_KEYBYUID, &olduid);
    450 					deldbent(edp, pwd_Sdb_tmp,
    451 					    _PW_KEYBYUID, &olduid);
    452 				}
    453 			} else
    454 				inconsistancy();
    455 		}
    456 
    457 		/*
    458 		 * If there's an existing BYUID record for the new UID and
    459 		 * the username doesn't match then be sure not to overwrite
    460 		 * it.
    461 		 */
    462 		if (!getdbent(edp, pwd_Sdb_tmp, _PW_KEYBYUID, &pwd.pw_uid,
    463 		    &tpwd))
    464 			if (strcmp(username, tpwd->pw_name) != 0)
    465 				uid_dbflg = R_NOOVERWRITE;
    466 
    467 		/* Write the database entries out */
    468 		if (!secureonly)
    469 			putdbents(dp, &pwd, "*", flags, pwd_db_tmp, lineno,
    470 			    dbflg, uid_dbflg);
    471 		putdbents(edp, &pwd, pwd.pw_passwd, flags, pwd_Sdb_tmp,
    472 		    lineno, dbflg, uid_dbflg);
    473 
    474 		found = 1;
    475 		if (!makeold)
    476 			break;
    477 	}
    478 
    479 	if (!secureonly) {
    480 		/* Store YP token if needed. */
    481 		if (hasyp)
    482 			putyptoken(dp, pwd_db_tmp);
    483 
    484 		/* Close the insecure database. */
    485 		if ((*dp->close)(dp) < 0)
    486 			wr_error(pwd_db_tmp);
    487 	}
    488 
    489 	/*
    490 	 * If rebuilding the databases, we re-parse the text file and write
    491 	 * the secure entries out in a separate pass.
    492 	 */
    493 	if (username == NULL) {
    494 		rewind(fp);
    495 		for (lineno = 0; scan(fp, &pwd, &flags, &lineno);)
    496 			putdbents(edp, &pwd, pwd.pw_passwd, flags, pwd_Sdb_tmp,
    497 			    lineno, dbflg, uid_dbflg);
    498 
    499 		/* Store YP token if needed. */
    500 		if (hasyp)
    501 			putyptoken(edp, pwd_Sdb_tmp);
    502 	} else if (!found) {
    503 		warnx("user `%s' not found in password file", username);
    504 		bailout();
    505 	}
    506 
    507 	/* Close the secure database. */
    508 	if ((*edp->close)(edp) < 0)
    509 		wr_error(pwd_Sdb_tmp);
    510 
    511 	/* Install as the real password files. */
    512 	if (!secureonly)
    513 		install(pwd_db_tmp, _PATH_MP_DB);
    514 	install(pwd_Sdb_tmp, _PATH_SMP_DB);
    515 
    516 	/* Install the V7 password file. */
    517 	if (makeold) {
    518 		if (fflush(oldfp) == EOF)
    519 			wr_error(oldpwdfile);
    520 		if (fclose(oldfp) == EOF)
    521 			wr_error(oldpwdfile);
    522 		install(oldpwdfile, _PATH_PASSWD);
    523 	}
    524 
    525 	/* Set master.passwd permissions, in case caller forgot. */
    526 	(void)fchmod(fileno(fp), S_IRUSR|S_IWUSR);
    527 	if (fclose(fp) == EOF)
    528 		wr_error(pname);
    529 
    530 	/*
    531 	 * Move the temporary master password file LAST -- chpass(1),
    532 	 * passwd(1), vipw(8) and friends all use its existence to block
    533 	 * other incarnations of themselves.  The rename means that
    534 	 * everything is unlocked, as the original file can no longer be
    535 	 * accessed.
    536 	 */
    537 	install(pname, _PATH_MASTERPASSWD);
    538 	exit(EXIT_SUCCESS);
    539 	/* NOTREACHED */
    540 }
    541 
    542 int
    543 scan(FILE *fp, struct passwd *pw, int *flags, int *lineno)
    544 {
    545 	static char line[LINE_MAX];
    546 	char *p;
    547 	int oflags;
    548 
    549 	if (fgets(line, sizeof(line), fp) == NULL)
    550 		return (0);
    551 	(*lineno)++;
    552 
    553 	/*
    554 	 * ``... if I swallow anything evil, put your fingers down my
    555 	 * throat...''
    556 	 *	-- The Who
    557 	 */
    558 	if ((p = strchr(line, '\n')) == NULL) {
    559 		warnx("line too long");
    560 		errno = EFTYPE;	/* XXX */
    561 		error(pname);
    562 	}
    563 	*p = '\0';
    564 	if (strcmp(line, "+") == 0)
    565 		strcpy(line, "+:::::::::");	/* pw_scan() can't handle "+" */
    566 	oflags = 0;
    567 	if (!pw_scan(line, pw, &oflags)) {
    568 		warnx("at line #%d", *lineno);
    569 		errno = EFTYPE;	/* XXX */
    570 		error(pname);
    571 	}
    572 	*flags = oflags;
    573 
    574 	return (1);
    575 }
    576 
    577 void
    578 install(const char *from, const char *to)
    579 {
    580 	char buf[MAXPATHLEN];
    581 	char errbuf[BUFSIZ];
    582 	int sverrno;
    583 
    584 	snprintf(buf, sizeof(buf), "%s%s", prefix, to);
    585 	if (rename(from, buf)) {
    586 		sverrno = errno;
    587 		(void)snprintf(errbuf, sizeof(errbuf), "%s to %s", from, buf);
    588 		errno = sverrno;
    589 		error(errbuf);
    590 	}
    591 }
    592 
    593 void
    594 rm(const char *victim)
    595 {
    596 
    597 	if (unlink(victim) < 0)
    598 		warn("unlink(%s)", victim);
    599 }
    600 
    601 void
    602 cp(const char *from, const char *to, mode_t mode)
    603 {
    604 	static char buf[MAXBSIZE];
    605 	int from_fd, rcount, to_fd, wcount, sverrno;
    606 
    607 	if ((from_fd = open(from, O_RDONLY, 0)) < 0)
    608 		error(from);
    609 	if ((to_fd = open(to, O_WRONLY | O_CREAT | O_EXCL, mode)) < 0)
    610 		error(to);
    611 	while ((rcount = read(from_fd, buf, MAXBSIZE)) > 0) {
    612 		wcount = write(to_fd, buf, rcount);
    613 		if (rcount != wcount || wcount == -1) {
    614 			sverrno = errno;
    615 			(void)snprintf(buf, sizeof(buf), "%s to %s", from, to);
    616 			errno = sverrno;
    617 			error(buf);
    618 		}
    619 	}
    620 
    621 	if (rcount < 0) {
    622 		sverrno = errno;
    623 		(void)snprintf(buf, sizeof(buf), "%s to %s", from, to);
    624 		errno = sverrno;
    625 		error(buf);
    626 	}
    627 }
    628 
    629 void
    630 wr_error(const char *str)
    631 {
    632 	char errbuf[BUFSIZ];
    633 	int sverrno;
    634 
    635 	sverrno = errno;
    636 
    637 	(void)snprintf(errbuf, sizeof(errbuf),
    638 		"attempt to write %s failed", str);
    639 
    640 	errno = sverrno;
    641 	error(errbuf);
    642 }
    643 
    644 void
    645 error(const char *str)
    646 {
    647 
    648 	warn("%s", str);
    649 	bailout();
    650 }
    651 
    652 void
    653 inconsistancy(void)
    654 {
    655 
    656 	warnx("text files and databases are inconsistent");
    657 	warnx("re-build the databases without -u");
    658 	bailout();
    659 }
    660 
    661 void
    662 bailout(void)
    663 {
    664 
    665 	if ((clean & FILE_ORIG) != 0)
    666 		rm(oldpwdfile);
    667 	if ((clean & FILE_SECURE) != 0)
    668 		rm(pwd_Sdb_tmp);
    669 	if ((clean & FILE_INSECURE) != 0)
    670 		rm(pwd_db_tmp);
    671 
    672 	exit(EXIT_FAILURE);
    673 }
    674 
    675 /*
    676  * Ensures that an existing database is up to date.
    677  *
    678  * Makes sure that the version number of an existing database matches the
    679  * version number setversion() writes.  If it does not, this function aborts
    680  * execution because updating the database without fully regenerating it will
    681  * leave it inconsistent.
    682  */
    683 void
    684 checkversion(DB *dp)
    685 {
    686 	DBT data, key;
    687 	int ret;
    688 
    689 	key.data = __UNCONST("VERSION");
    690 	key.size = strlen((const char *)key.data) + 1;
    691 
    692 	ret = (*dp->get)(dp, &key, &data, 0);
    693 	if (ret == -1) {
    694 		warnx("cannot get VERSION record from database");
    695 		bailout();
    696 	}
    697 
    698 	if (ret == 1 || *(int *)data.data != getversion()) {
    699 		warnx("databases are laid out according to an old version");
    700 		warnx("re-build the databases without -u");
    701 		bailout();
    702 	}
    703 }
    704 
    705 /*
    706  * Returns the version number we write to and expect from databases.
    707  */
    708 uint32_t
    709 getversion(void)
    710 {
    711 	uint32_t version = sizeof(((struct passwd *)NULL)->pw_change) != sizeof(int32_t);
    712 	if (lorder != BYTE_ORDER)
    713 		version = SWAP(version);
    714 	return version;
    715 }
    716 
    717 void
    718 setversion(DB *dp)
    719 {
    720 	DBT data, key;
    721 	uint32_t version = getversion();
    722 
    723 	key.data = __UNCONST("VERSION");
    724 	key.size = strlen((const char *)key.data) + 1;
    725 
    726 	data.data = &version;
    727 	data.size = sizeof(uint32_t);
    728 
    729 	if ((*dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1)
    730 		wr_error("setversion");
    731 }
    732 
    733 /*
    734  * Write entries to a database for a single user.
    735  *
    736  * The databases actually contain three copies of the original data.  Each
    737  * password file entry is converted into a rough approximation of a ``struct
    738  * passwd'', with the strings placed inline.  This object is then stored as
    739  * the data for three separate keys.  The first key * is the pw_name field
    740  * prepended by the _PW_KEYBYNAME character.  The second key is the pw_uid
    741  * field prepended by the _PW_KEYBYUID character.  The third key is the line
    742  * number in the original file prepended by the _PW_KEYBYNUM character.
    743  * (The special characters are prepended to ensure that the keys do not
    744  * collide.)
    745  */
    746 #define	COMPACT(e)	for (t = e; (*p++ = *t++) != '\0';)
    747 
    748 void
    749 putdbents(DB *dp, struct passwd *pw, const char *passwd, int flags,
    750 	  const char *fn, int lineno, int dbflg, int uid_dbflg)
    751 {
    752 	struct passwd pwd;
    753 	char buf[MAX(MAXPATHLEN, LINE_MAX * 2)], tbuf[1024], *p;
    754 	DBT data, key;
    755 	const char *t;
    756 	u_int32_t x;
    757 	int len;
    758 
    759 	memcpy(&pwd, pw, sizeof(pwd));
    760 	data.data = (u_char *)buf;
    761 	key.data = (u_char *)tbuf;
    762 
    763 	if (lorder != BYTE_ORDER) {
    764 		pwd.pw_uid = SWAP(pwd.pw_uid);
    765 		pwd.pw_gid = SWAP(pwd.pw_gid);
    766 		pwd.pw_change = SWAP(pwd.pw_change);
    767 		pwd.pw_expire = SWAP(pwd.pw_expire);
    768 	}
    769 
    770 	/* Create insecure data. */
    771 	p = buf;
    772 	COMPACT(pwd.pw_name);
    773 	COMPACT(passwd);
    774 	memmove(p, &pwd.pw_uid, sizeof(pwd.pw_uid));
    775 	p += sizeof(pwd.pw_uid);
    776 	memmove(p, &pwd.pw_gid, sizeof(pwd.pw_gid));
    777 	p += sizeof(pwd.pw_gid);
    778 	memmove(p, &pwd.pw_change, sizeof(pwd.pw_change));
    779 	p += sizeof(pwd.pw_change);
    780 	COMPACT(pwd.pw_class);
    781 	COMPACT(pwd.pw_gecos);
    782 	COMPACT(pwd.pw_dir);
    783 	COMPACT(pwd.pw_shell);
    784 	memmove(p, &pwd.pw_expire, sizeof(pwd.pw_expire));
    785 	p += sizeof(pwd.pw_expire);
    786 	x = flags;
    787 	if (lorder != BYTE_ORDER)
    788 		x = SWAP(x);
    789 	memmove(p, &x, sizeof(x));
    790 	p += sizeof(flags);
    791 	data.size = p - buf;
    792 
    793 	/* Store insecure by name. */
    794 	tbuf[0] = _PW_KEYBYNAME;
    795 	len = strlen(pwd.pw_name);
    796 	memmove(tbuf + 1, pwd.pw_name, len);
    797 	key.size = len + 1;
    798 	if ((*dp->put)(dp, &key, &data, dbflg) == -1)
    799 		wr_error(fn);
    800 
    801 	/* Store insecure by number. */
    802 	tbuf[0] = _PW_KEYBYNUM;
    803 	x = lineno;
    804 	if (lorder != BYTE_ORDER)
    805 		x = SWAP(x);
    806 	memmove(tbuf + 1, &x, sizeof(x));
    807 	key.size = sizeof(x) + 1;
    808 	if ((*dp->put)(dp, &key, &data, dbflg) == -1)
    809 		wr_error(fn);
    810 
    811 	/* Store insecure by uid. */
    812 	tbuf[0] = _PW_KEYBYUID;
    813 	memmove(tbuf + 1, &pwd.pw_uid, sizeof(pwd.pw_uid));
    814 	key.size = sizeof(pwd.pw_uid) + 1;
    815 	if ((*dp->put)(dp, &key, &data, uid_dbflg) == -1)
    816 		wr_error(fn);
    817 }
    818 
    819 int
    820 deldbent(DB *dp, const char *fn, int type, void *keyp)
    821 {
    822 	char tbuf[1024];
    823 	DBT key;
    824 	u_int32_t x;
    825 	int len, rv;
    826 
    827 	key.data = (u_char *)tbuf;
    828 
    829 	switch (tbuf[0] = type) {
    830 	case _PW_KEYBYNAME:
    831 		len = strlen((char *)keyp);
    832 		memcpy(tbuf + 1, keyp, len);
    833 		key.size = len + 1;
    834 		break;
    835 
    836 	case _PW_KEYBYNUM:
    837 	case _PW_KEYBYUID:
    838 		x = *(int *)keyp;
    839 		if (lorder != BYTE_ORDER)
    840 			x = SWAP(x);
    841 		memmove(tbuf + 1, &x, sizeof(x));
    842 		key.size = sizeof(x) + 1;
    843 		break;
    844 	}
    845 
    846 	if ((rv = (*dp->del)(dp, &key, 0)) == -1)
    847 		wr_error(fn);
    848 	return (rv);
    849 }
    850 
    851 int
    852 getdbent(DB *dp, const char *fn, int type, void *keyp, struct passwd **tpwd)
    853 {
    854 	static char buf[MAX(MAXPATHLEN, LINE_MAX * 2)];
    855 	static struct passwd pwd;
    856 	char tbuf[1024], *p;
    857 	DBT key, data;
    858 	u_int32_t x;
    859 	int len, rv;
    860 
    861 	data.data = (u_char *)buf;
    862 	data.size = sizeof(buf);
    863 	key.data = (u_char *)tbuf;
    864 
    865 	switch (tbuf[0] = type) {
    866 	case _PW_KEYBYNAME:
    867 		len = strlen((char *)keyp);
    868 		memcpy(tbuf + 1, keyp, len);
    869 		key.size = len + 1;
    870 		break;
    871 
    872 	case _PW_KEYBYNUM:
    873 	case _PW_KEYBYUID:
    874 		x = *(int *)keyp;
    875 		if (lorder != BYTE_ORDER)
    876 			x = SWAP(x);
    877 		memmove(tbuf + 1, &x, sizeof(x));
    878 		key.size = sizeof(x) + 1;
    879 		break;
    880 	}
    881 
    882 	if ((rv = (*dp->get)(dp, &key, &data, 0)) == 1)
    883 		return (rv);
    884 	if (rv == -1)
    885 		error(pwd_Sdb_tmp);
    886 
    887 	p = (char *)data.data;
    888 
    889 	pwd.pw_name = p;
    890 	while (*p++ != '\0')
    891 		;
    892 	pwd.pw_passwd = p;
    893 	while (*p++ != '\0')
    894 		;
    895 
    896 	memcpy(&pwd.pw_uid, p, sizeof(pwd.pw_uid));
    897 	p += sizeof(pwd.pw_uid);
    898 	memcpy(&pwd.pw_gid, p, sizeof(pwd.pw_gid));
    899 	p += sizeof(pwd.pw_gid);
    900 	memcpy(&pwd.pw_change, p, sizeof(pwd.pw_change));
    901 	p += sizeof(pwd.pw_change);
    902 
    903 	pwd.pw_class = p;
    904 	while (*p++ != '\0')
    905 		;
    906 	pwd.pw_gecos = p;
    907 	while (*p++ != '\0')
    908 		;
    909 	pwd.pw_dir = p;
    910 	while (*p++ != '\0')
    911 		;
    912 	pwd.pw_shell = p;
    913 	while (*p++ != '\0')
    914 		;
    915 
    916 	memcpy(&pwd.pw_expire, p, sizeof(pwd.pw_expire));
    917 	p += sizeof(pwd.pw_expire);
    918 
    919 	if (lorder != BYTE_ORDER) {
    920 		pwd.pw_uid = SWAP(pwd.pw_uid);
    921 		pwd.pw_gid = SWAP(pwd.pw_gid);
    922 		pwd.pw_change = SWAP(pwd.pw_change);
    923 		pwd.pw_expire = SWAP(pwd.pw_expire);
    924 	}
    925 
    926 	*tpwd = &pwd;
    927 	return (0);
    928 }
    929 
    930 void
    931 putyptoken(DB *dp, const char *fn)
    932 {
    933 	DBT data, key;
    934 
    935 	key.data = (u_char *)__yp_token;
    936 	key.size = strlen(__yp_token);
    937 	data.data = (u_char *)NULL;
    938 	data.size = 0;
    939 
    940 	if ((*dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1)
    941 		wr_error(fn);
    942 }
    943 
    944 void
    945 usage(void)
    946 {
    947 
    948 	(void)fprintf(stderr,
    949 	    "usage: pwd_mkdb [-BLps] [-c cachesize] [-d directory] [-u user] file\n");
    950 	exit(EXIT_FAILURE);
    951 }
    952