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