Home | History | Annotate | Line # | Download | only in pwd_mkdb
      1  1.61  christos /*	$NetBSD: pwd_mkdb.c,v 1.61 2024/10/04 20:32:20 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.61  christos __RCSID("$NetBSD: pwd_mkdb.c,v 1.61 2024/10/04 20:32:20 christos Exp $");
     94   1.1       cgd #endif /* not lint */
     95   1.1       cgd 
     96  1.29       jmc #if HAVE_NBTOOL_CONFIG_H
     97  1.29       jmc #include "compat_pwd.h"
     98  1.29       jmc #else
     99  1.29       jmc #include <pwd.h>
    100  1.29       jmc #endif
    101  1.29       jmc 
    102   1.1       cgd #include <sys/param.h>
    103   1.1       cgd #include <sys/stat.h>
    104  1.39       apb #include <sys/types.h>
    105  1.39       apb 
    106  1.39       apb #ifndef HAVE_NBTOOL_CONFIG_H
    107  1.39       apb #include <machine/bswap.h>
    108  1.39       apb #endif
    109   1.5   mycroft 
    110   1.1       cgd #include <db.h>
    111  1.24        tv #include <err.h>
    112   1.1       cgd #include <errno.h>
    113   1.5   mycroft #include <fcntl.h>
    114  1.52  christos #include <syslog.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.52  christos #include <stdarg.h>
    120   1.1       cgd #include <string.h>
    121   1.5   mycroft #include <unistd.h>
    122  1.56     pooka 
    123  1.56     pooka #ifndef HAVE_NBTOOL_CONFIG_H
    124  1.24        tv #include <util.h>
    125  1.56     pooka #endif
    126  1.23        tv 
    127  1.22        ad #define	MAX_CACHESIZE	8*1024*1024
    128  1.22        ad #define	MIN_CACHESIZE	2*1024*1024
    129  1.22        ad 
    130  1.19        ad #define	PERM_INSECURE	(S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
    131  1.19        ad #define	PERM_SECURE	(S_IRUSR | S_IWUSR)
    132   1.1       cgd 
    133  1.60  christos // Defined in libc
    134  1.23        tv static const char __yp_token[] = "__YP!";
    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.42  christos 
    150  1.42  christos struct pwddb {
    151  1.42  christos 	DB *db;
    152  1.42  christos 	char dbname[MAX(MAXPATHLEN, LINE_MAX * 2)];
    153  1.42  christos 	const char *fname;
    154  1.42  christos 	uint32_t rversion;
    155  1.42  christos 	uint32_t wversion;
    156  1.42  christos };
    157  1.42  christos 
    158  1.22        ad static char	*pname;				/* password file name */
    159  1.22        ad static char	prefix[MAXPATHLEN];
    160  1.22        ad static char	oldpwdfile[MAX(MAXPATHLEN, LINE_MAX * 2)];
    161  1.22        ad static int 	lorder = BYTE_ORDER;
    162  1.52  christos static int	logsyslog;
    163  1.22        ad static int	clean;
    164  1.42  christos static int	verbose;
    165  1.42  christos static int	warning;
    166  1.42  christos static struct pwddb sdb, idb;
    167  1.42  christos 
    168  1.22        ad 
    169  1.61  christos static void	bailout(void) __dead;
    170  1.61  christos static void	cp(const char *, const char *, mode_t);
    171  1.61  christos static void	deldbent(struct pwddb *, int, void *);
    172  1.61  christos static void	mkpw_error(const char *, ...) __dead;
    173  1.61  christos static void	mkpw_warning(const char *, ...);
    174  1.61  christos static int	getdbent(struct pwddb *, int, void *, struct passwd **);
    175  1.61  christos static void	inconsistency(void) __dead;
    176  1.61  christos static void	install(const char *, const char *);
    177  1.61  christos static void	putdbents(struct pwddb *, struct passwd *, const char *, int,
    178  1.61  christos     int, u_int, u_int);
    179  1.61  christos static void	putyptoken(struct pwddb *);
    180  1.61  christos static void	rm(const char *);
    181  1.61  christos static int	scan(FILE *, struct passwd *, int *, int *);
    182  1.61  christos static void	usage(void) __dead;
    183  1.61  christos static void	wr_error(const char *) __dead;
    184  1.61  christos static uint32_t getversion(const char *);
    185  1.61  christos static void	setversion(struct pwddb *);
    186  1.35  christos 
    187  1.44  christos #ifndef __lint__
    188  1.35  christos #define SWAP(sw) \
    189  1.39       apb     ((sizeof(sw) == 2 ? (typeof(sw))bswap16((uint16_t)sw) : \
    190  1.39       apb     (sizeof(sw) == 4 ? (typeof(sw))bswap32((uint32_t)sw) : \
    191  1.39       apb     (sizeof(sw) == 8 ? (typeof(sw))bswap64((uint64_t)sw) : (abort(), 0)))))
    192  1.44  christos #else
    193  1.44  christos #define SWAP(sw) sw
    194  1.44  christos #endif
    195   1.5   mycroft 
    196  1.42  christos static void
    197  1.42  christos closedb(struct pwddb *db)
    198  1.42  christos {
    199  1.42  christos     if ((*db->db->close)(db->db) < 0)
    200  1.42  christos 	    wr_error(db->dbname);
    201  1.42  christos }
    202  1.42  christos 
    203  1.42  christos static void
    204  1.42  christos opendb(struct pwddb *db, const char *dbname, const char *username,
    205  1.44  christos     uint32_t req_version, int flags, mode_t perm)
    206  1.42  christos {
    207  1.42  christos 	char buf[MAXPATHLEN];
    208  1.42  christos 
    209  1.42  christos 	(void)snprintf(db->dbname, sizeof(db->dbname), "%s%s.tmp", prefix,
    210  1.42  christos 	    dbname);
    211  1.42  christos 
    212  1.42  christos 	if (username != NULL) {
    213  1.44  christos 		(void)snprintf(buf, sizeof(buf), "%s%s", prefix, dbname);
    214  1.42  christos 		cp(buf, db->dbname, perm);
    215  1.42  christos 	}
    216  1.42  christos 
    217  1.42  christos 	db->db = dbopen(db->dbname, flags, perm, DB_HASH, &openinfo);
    218  1.42  christos 	if (db->db == NULL)
    219  1.52  christos 		mkpw_error("Cannot open `%s'", db->dbname);
    220  1.42  christos 
    221  1.42  christos 	db->fname = dbname;
    222  1.42  christos 	db->rversion = getversion(dbname);
    223  1.42  christos 	if (req_version == ~0U)
    224  1.42  christos 		db->wversion = db->rversion;
    225  1.42  christos 	else
    226  1.42  christos 		db->wversion = req_version;
    227  1.42  christos 
    228  1.42  christos 	if (warning && db->rversion == 0 && db->wversion == 0) {
    229  1.52  christos 		mkpw_warning("Database %s is a version %u database.",
    230  1.42  christos 		    db->fname, db->rversion);
    231  1.52  christos 		mkpw_warning("Use %s -V 1 to upgrade once you've recompiled "
    232  1.42  christos 		    "all your binaries.", getprogname());
    233  1.42  christos 	}
    234  1.42  christos 	if (db->wversion != db->rversion) {
    235  1.44  christos 		if (username != NULL) {
    236  1.52  christos 			mkpw_warning("You cannot change a single "
    237  1.44  christos 			    "record from version %u to version %u\n",
    238  1.52  christos 			    db->rversion, db->wversion);
    239  1.44  christos 			bailout();
    240  1.44  christos 		} else if (verbose) {
    241  1.52  christos 		    mkpw_warning("Changing %s from version %u to version %u",
    242  1.52  christos 			db->fname, db->rversion, db->wversion);
    243  1.42  christos 		}
    244  1.44  christos 	} else {
    245  1.44  christos 		if (verbose)
    246  1.52  christos 			mkpw_warning("File `%s' version %u requested %u",
    247  1.52  christos 			    db->fname, db->rversion, db->wversion);
    248  1.42  christos 	}
    249  1.44  christos 
    250  1.42  christos 	setversion(db);
    251  1.42  christos }
    252  1.42  christos 
    253   1.5   mycroft int
    254  1.19        ad main(int argc, char *argv[])
    255   1.1       cgd {
    256  1.42  christos 	int ch, makeold, tfd, lineno, found, rv, hasyp, secureonly;
    257  1.22        ad 	struct passwd pwd, *tpwd;
    258  1.22        ad 	char *username;
    259   1.1       cgd 	FILE *fp, *oldfp;
    260   1.1       cgd 	sigset_t set;
    261  1.44  christos 	u_int dbflg, uid_dbflg;
    262  1.44  christos 	int newuser, olduid, flags;
    263  1.22        ad 	struct stat st;
    264  1.22        ad 	u_int cachesize;
    265  1.42  christos 	uint32_t req_version;
    266   1.1       cgd 
    267  1.21      tron 	prefix[0] = '\0';
    268   1.1       cgd 	makeold = 0;
    269  1.22        ad 	oldfp = NULL;
    270  1.22        ad 	username = NULL;
    271  1.22        ad 	hasyp = 0;
    272  1.22        ad 	secureonly = 0;
    273  1.30     lukem 	found = 0;
    274  1.30     lukem 	newuser = 0;
    275  1.31    sketch 	cachesize = 0;
    276  1.41  christos 	verbose = 0;
    277  1.42  christos 	warning = 0;
    278  1.52  christos 	logsyslog = 0;
    279  1.42  christos 	req_version = ~0U;
    280  1.22        ad 
    281  1.52  christos 	while ((ch = getopt(argc, argv, "BLc:d:lpsu:V:vw")) != -1)
    282  1.22        ad 		switch (ch) {
    283  1.22        ad 		case 'B':			/* big-endian output */
    284  1.22        ad 			lorder = BIG_ENDIAN;
    285  1.22        ad 			break;
    286  1.22        ad 		case 'L':			/* little-endian output */
    287  1.22        ad 			lorder = LITTLE_ENDIAN;
    288  1.22        ad 			break;
    289  1.31    sketch 		case 'c':
    290  1.31    sketch 			cachesize = atoi(optarg) * 1024 * 1024;
    291  1.31    sketch 			break;
    292  1.19        ad 		case 'd':			/* set prefix */
    293  1.44  christos 			(void)strlcpy(prefix, optarg, sizeof(prefix));
    294   1.8     lukem 			break;
    295  1.52  christos 		case 'l':
    296  1.52  christos 			openlog(getprogname(), LOG_PID, LOG_AUTH);
    297  1.52  christos 			logsyslog = 1;
    298  1.52  christos 			break;
    299   1.1       cgd 		case 'p':			/* create V7 "file.orig" */
    300   1.1       cgd 			makeold = 1;
    301   1.1       cgd 			break;
    302  1.22        ad 		case 's':			/* modify secure db only */
    303  1.22        ad 			secureonly = 1;
    304   1.1       cgd 			break;
    305  1.22        ad 		case 'u':			/* modify one user only */
    306  1.22        ad 			username = optarg;
    307  1.17   mycroft 			break;
    308  1.41  christos 		case 'V':
    309  1.42  christos 			req_version = (uint32_t)atoi(optarg);
    310  1.52  christos 			if (req_version > 1) {
    311  1.52  christos 				mkpw_warning("Unknown version %u", req_version);
    312  1.52  christos 				return EXIT_FAILURE;
    313  1.52  christos 			}
    314  1.41  christos 			break;
    315  1.41  christos 		case 'v':
    316  1.41  christos 			verbose++;
    317  1.17   mycroft 			break;
    318  1.42  christos 		case 'w':
    319  1.42  christos 			warning++;
    320  1.42  christos 			break;
    321   1.1       cgd 		case '?':
    322   1.1       cgd 		default:
    323   1.1       cgd 			usage();
    324   1.1       cgd 		}
    325   1.1       cgd 	argc -= optind;
    326   1.1       cgd 	argv += optind;
    327   1.1       cgd 
    328   1.1       cgd 	if (argc != 1)
    329   1.1       cgd 		usage();
    330  1.22        ad 	if (username != NULL)
    331  1.22        ad 		if (username[0] == '+' || username[0] == '-')
    332  1.22        ad 			usage();
    333  1.22        ad 	if (secureonly)
    334  1.22        ad 		makeold = 0;
    335   1.4       cgd 
    336   1.1       cgd 	/*
    337   1.5   mycroft 	 * This could be changed to allow the user to interrupt.
    338   1.5   mycroft 	 * Probably not worth the effort.
    339   1.1       cgd 	 */
    340  1.44  christos 	(void)sigemptyset(&set);
    341  1.44  christos 	(void)sigaddset(&set, SIGTSTP);
    342  1.44  christos 	(void)sigaddset(&set, SIGHUP);
    343  1.44  christos 	(void)sigaddset(&set, SIGINT);
    344  1.44  christos 	(void)sigaddset(&set, SIGQUIT);
    345  1.44  christos 	(void)sigaddset(&set, SIGTERM);
    346  1.55    plunky 	(void)sigprocmask(SIG_BLOCK, &set, NULL);
    347   1.1       cgd 
    348   1.5   mycroft 	/* We don't care what the user wants. */
    349   1.5   mycroft 	(void)umask(0);
    350   1.5   mycroft 
    351  1.22        ad 	if (username == NULL)
    352  1.22        ad 		flags = O_RDWR | O_CREAT | O_EXCL;
    353  1.22        ad 	else
    354  1.22        ad 		flags = O_RDWR;
    355  1.22        ad 
    356   1.1       cgd 	pname = *argv;
    357   1.1       cgd 	/* Open the original password file */
    358  1.19        ad 	if ((fp = fopen(pname, "r")) == NULL)
    359  1.52  christos 		mkpw_error("Cannot open `%s'", pname);
    360   1.1       cgd 
    361  1.17   mycroft 	openinfo.lorder = lorder;
    362  1.17   mycroft 
    363  1.22        ad 	if (fstat(fileno(fp), &st) == -1)
    364  1.52  christos 		mkpw_error("Cannot stat `%s'", pname);
    365  1.22        ad 
    366  1.31    sketch 	if (cachesize) {
    367  1.31    sketch 		openinfo.cachesize = cachesize;
    368  1.31    sketch 	} else {
    369  1.31    sketch 		/* Tweak openinfo values for large passwd files. */
    370  1.44  christos 		cachesize = (u_int)(st.st_size * 20);
    371  1.31    sketch 		if (cachesize > MAX_CACHESIZE)
    372  1.31    sketch 			cachesize = MAX_CACHESIZE;
    373  1.31    sketch 		else if (cachesize < MIN_CACHESIZE)
    374  1.31    sketch 			cachesize = MIN_CACHESIZE;
    375  1.31    sketch 		openinfo.cachesize = cachesize;
    376  1.31    sketch 	}
    377  1.22        ad 
    378   1.1       cgd 	/* Open the temporary insecure password database. */
    379  1.22        ad 	if (!secureonly) {
    380  1.42  christos 		opendb(&idb, _PATH_MP_DB, username, req_version,
    381  1.42  christos 		    flags, PERM_INSECURE);
    382  1.22        ad 		clean |= FILE_INSECURE;
    383  1.22        ad 	}
    384  1.61  christos 
    385  1.22        ad 
    386  1.22        ad 	/* Open the temporary encrypted password database. */
    387  1.42  christos 	opendb(&sdb, _PATH_SMP_DB, username, req_version, flags, PERM_SECURE);
    388  1.22        ad 	clean |= FILE_SECURE;
    389   1.1       cgd 
    390   1.1       cgd 	/*
    391   1.1       cgd 	 * Open file for old password file.  Minor trickiness -- don't want to
    392   1.1       cgd 	 * chance the file already existing, since someone (stupidly) might
    393   1.1       cgd 	 * still be using this for permission checking.  So, open it first and
    394   1.5   mycroft 	 * fdopen the resulting fd.  The resulting file should be readable by
    395   1.5   mycroft 	 * everyone.
    396   1.1       cgd 	 */
    397   1.1       cgd 	if (makeold) {
    398  1.11      fair 		(void)snprintf(oldpwdfile, sizeof(oldpwdfile), "%s.orig",
    399  1.19        ad 		    pname);
    400  1.19        ad 		if ((tfd = open(oldpwdfile, O_WRONLY | O_CREAT | O_EXCL,
    401  1.19        ad 		    PERM_INSECURE)) < 0)
    402  1.52  christos 			mkpw_error("Cannot create `%s'", oldpwdfile);
    403  1.22        ad 		clean |= FILE_ORIG;
    404   1.5   mycroft 		if ((oldfp = fdopen(tfd, "w")) == NULL)
    405  1.52  christos 			mkpw_error("Cannot fdopen `%s'", oldpwdfile);
    406  1.22        ad 	}
    407  1.22        ad 
    408  1.22        ad 	if (username != NULL) {
    409  1.22        ad 		uid_dbflg = 0;
    410  1.22        ad 		dbflg = 0;
    411  1.22        ad 
    412  1.22        ad 		/*
    413  1.22        ad 		 * Determine if this is a new entry.
    414  1.22        ad 		 */
    415  1.42  christos 		if (getdbent(&sdb, _PW_KEYBYNAME, username, &tpwd))
    416  1.22        ad 			newuser = 1;
    417  1.22        ad 		else {
    418  1.22        ad 			newuser = 0;
    419  1.22        ad 			olduid = tpwd->pw_uid;
    420  1.22        ad 		}
    421  1.22        ad 
    422  1.22        ad 	} else {
    423  1.22        ad 		uid_dbflg = R_NOOVERWRITE;
    424  1.22        ad 		dbflg = R_NOOVERWRITE;
    425   1.1       cgd 	}
    426   1.1       cgd 
    427   1.1       cgd 	/*
    428   1.6      phil 	 * If we see something go by that looks like YP, we save a special
    429   1.6      phil 	 * pointer record, which if YP is enabled in the C lib, will speed
    430   1.6      phil 	 * things up.
    431   1.1       cgd 	 */
    432  1.19        ad 	for (lineno = 0; scan(fp, &pwd, &flags, &lineno);) {
    433   1.9   thorpej 		/*
    434  1.22        ad 		 * Create original format password file entry.
    435   1.9   thorpej 		 */
    436  1.11      fair 		if (makeold) {
    437   1.5   mycroft 			(void)fprintf(oldfp, "%s:*:%d:%d:%s:%s:%s\n",
    438   1.5   mycroft 			    pwd.pw_name, pwd.pw_uid, pwd.pw_gid, pwd.pw_gecos,
    439   1.5   mycroft 			    pwd.pw_dir, pwd.pw_shell);
    440  1.19        ad 			if (ferror(oldfp))
    441  1.11      fair 				wr_error(oldpwdfile);
    442  1.11      fair 		}
    443  1.22        ad 
    444  1.22        ad 		if (username == NULL) {
    445  1.22        ad 			/* Look like YP? */
    446  1.22        ad 			if (pwd.pw_name[0] == '+' || pwd.pw_name[0] == '-')
    447  1.22        ad 				hasyp++;
    448  1.22        ad 
    449  1.22        ad 			/* Warn about potentially unsafe uid/gid overrides. */
    450  1.22        ad 			if (pwd.pw_name[0] == '+') {
    451  1.22        ad 				if ((flags & _PASSWORD_NOUID) == 0 &&
    452  1.22        ad 				    pwd.pw_uid == 0)
    453  1.52  christos 					mkpw_warning("line %d: superuser "
    454  1.52  christos 					    "override in YP inclusion", lineno);
    455  1.22        ad 				if ((flags & _PASSWORD_NOGID) == 0 &&
    456  1.22        ad 				    pwd.pw_gid == 0)
    457  1.52  christos 					mkpw_warning("line %d: wheel override "
    458  1.22        ad 					    "in YP inclusion", lineno);
    459  1.22        ad 			}
    460  1.22        ad 
    461  1.22        ad 			/* Write the database entry out. */
    462  1.22        ad 			if (!secureonly)
    463  1.42  christos 				putdbents(&idb, &pwd, "*", flags, lineno, dbflg,
    464  1.42  christos 				    uid_dbflg);
    465  1.22        ad 			continue;
    466  1.22        ad 		} else if (strcmp(username, pwd.pw_name) != 0)
    467  1.22        ad 			continue;
    468  1.22        ad 
    469  1.22        ad 		if (found) {
    470  1.52  christos 			mkpw_warning("user `%s' listed twice in password file",
    471  1.22        ad 			    username);
    472  1.22        ad 			bailout();
    473  1.22        ad 		}
    474  1.22        ad 
    475  1.22        ad 		/*
    476  1.22        ad 		 * Ensure that the text file and database agree on
    477  1.22        ad 		 * which line the record is from.
    478  1.22        ad 		 */
    479  1.42  christos 		rv = getdbent(&sdb, _PW_KEYBYNUM, &lineno, &tpwd);
    480  1.22        ad 		if (newuser) {
    481  1.22        ad 			if (rv == 0)
    482  1.44  christos 				inconsistency();
    483  1.48     enami 		} else if (rv == 1 || strcmp(username, tpwd->pw_name) != 0)
    484  1.44  christos 			inconsistency();
    485  1.40     lukem 		else if ((uid_t)olduid != pwd.pw_uid) {
    486  1.22        ad 			/*
    487  1.22        ad 			 * If we're changing UID, remove the BYUID
    488  1.22        ad 			 * record for the old UID only if it has the
    489  1.22        ad 			 * same username.
    490  1.22        ad 			 */
    491  1.42  christos 			if (!getdbent(&sdb, _PW_KEYBYUID, &olduid, &tpwd)) {
    492  1.22        ad 				if (strcmp(username, tpwd->pw_name) == 0) {
    493  1.22        ad 					if (!secureonly)
    494  1.42  christos 						deldbent(&idb, _PW_KEYBYUID,
    495  1.42  christos 						    &olduid);
    496  1.42  christos 					deldbent(&sdb, _PW_KEYBYUID, &olduid);
    497  1.22        ad 				}
    498  1.22        ad 			} else
    499  1.44  christos 				inconsistency();
    500  1.22        ad 		}
    501  1.22        ad 
    502  1.22        ad 		/*
    503  1.22        ad 		 * If there's an existing BYUID record for the new UID and
    504  1.22        ad 		 * the username doesn't match then be sure not to overwrite
    505  1.22        ad 		 * it.
    506  1.22        ad 		 */
    507  1.42  christos 		if (!getdbent(&sdb, _PW_KEYBYUID, &pwd.pw_uid, &tpwd))
    508  1.22        ad 			if (strcmp(username, tpwd->pw_name) != 0)
    509  1.22        ad 				uid_dbflg = R_NOOVERWRITE;
    510  1.22        ad 
    511  1.22        ad 		/* Write the database entries out */
    512  1.22        ad 		if (!secureonly)
    513  1.42  christos 			putdbents(&idb, &pwd, "*", flags, lineno, dbflg,
    514  1.42  christos 			    uid_dbflg);
    515  1.42  christos 		putdbents(&sdb, &pwd, pwd.pw_passwd, flags, lineno, dbflg,
    516  1.42  christos 		    uid_dbflg);
    517  1.22        ad 
    518  1.22        ad 		found = 1;
    519  1.22        ad 		if (!makeold)
    520  1.22        ad 			break;
    521  1.22        ad 	}
    522  1.22        ad 
    523  1.22        ad 	if (!secureonly) {
    524  1.22        ad 		/* Store YP token if needed. */
    525  1.22        ad 		if (hasyp)
    526  1.42  christos 			putyptoken(&idb);
    527  1.22        ad 
    528  1.22        ad 		/* Close the insecure database. */
    529  1.42  christos 		closedb(&idb);
    530  1.22        ad 	}
    531  1.22        ad 
    532  1.22        ad 	/*
    533  1.22        ad 	 * If rebuilding the databases, we re-parse the text file and write
    534  1.22        ad 	 * the secure entries out in a separate pass.
    535  1.22        ad 	 */
    536  1.22        ad 	if (username == NULL) {
    537  1.22        ad 		rewind(fp);
    538  1.22        ad 		for (lineno = 0; scan(fp, &pwd, &flags, &lineno);)
    539  1.42  christos 			putdbents(&sdb, &pwd, pwd.pw_passwd, flags,
    540  1.42  christos 			    lineno, dbflg, uid_dbflg);
    541  1.22        ad 
    542  1.22        ad 		/* Store YP token if needed. */
    543  1.22        ad 		if (hasyp)
    544  1.42  christos 			putyptoken(&sdb);
    545  1.22        ad 	} else if (!found) {
    546  1.52  christos 		mkpw_warning("user `%s' not found in password file", username);
    547  1.22        ad 		bailout();
    548   1.5   mycroft 	}
    549   1.6      phil 
    550  1.22        ad 	/* Close the secure database. */
    551  1.42  christos 	closedb(&sdb);
    552  1.22        ad 
    553  1.22        ad 	/* Install as the real password files. */
    554  1.22        ad 	if (!secureonly)
    555  1.42  christos 		install(idb.dbname, idb.fname);
    556  1.42  christos 	install(sdb.dbname, sdb.fname);
    557   1.6      phil 
    558  1.22        ad 	/* Install the V7 password file. */
    559   1.5   mycroft 	if (makeold) {
    560  1.19        ad 		if (fflush(oldfp) == EOF)
    561  1.11      fair 			wr_error(oldpwdfile);
    562  1.19        ad 		if (fclose(oldfp) == EOF)
    563  1.11      fair 			wr_error(oldpwdfile);
    564  1.22        ad 		install(oldpwdfile, _PATH_PASSWD);
    565   1.5   mycroft 	}
    566   1.5   mycroft 
    567   1.1       cgd 	/* Set master.passwd permissions, in case caller forgot. */
    568   1.1       cgd 	(void)fchmod(fileno(fp), S_IRUSR|S_IWUSR);
    569  1.19        ad 	if (fclose(fp) == EOF)
    570  1.11      fair 		wr_error(pname);
    571   1.1       cgd 
    572  1.19        ad 	/*
    573  1.22        ad 	 * Move the temporary master password file LAST -- chpass(1),
    574  1.33       wiz 	 * passwd(1), vipw(8) and friends all use its existence to block
    575  1.22        ad 	 * other incarnations of themselves.  The rename means that
    576  1.22        ad 	 * everything is unlocked, as the original file can no longer be
    577  1.22        ad 	 * accessed.
    578  1.19        ad 	 */
    579  1.19        ad 	install(pname, _PATH_MASTERPASSWD);
    580  1.19        ad 	exit(EXIT_SUCCESS);
    581  1.19        ad 	/* NOTREACHED */
    582   1.1       cgd }
    583   1.1       cgd 
    584  1.61  christos static int
    585  1.19        ad scan(FILE *fp, struct passwd *pw, int *flags, int *lineno)
    586   1.1       cgd {
    587   1.1       cgd 	static char line[LINE_MAX];
    588   1.1       cgd 	char *p;
    589  1.17   mycroft 	int oflags;
    590   1.1       cgd 
    591  1.44  christos 	if (fgets(line, (int)sizeof(line), fp) == NULL)
    592   1.5   mycroft 		return (0);
    593  1.19        ad 	(*lineno)++;
    594  1.19        ad 
    595   1.1       cgd 	/*
    596   1.1       cgd 	 * ``... if I swallow anything evil, put your fingers down my
    597   1.1       cgd 	 * throat...''
    598   1.1       cgd 	 *	-- The Who
    599   1.1       cgd 	 */
    600  1.19        ad 	if ((p = strchr(line, '\n')) == NULL) {
    601  1.19        ad 		errno = EFTYPE;	/* XXX */
    602  1.52  christos 		mkpw_error("%s, %d: line too long", pname, *lineno);
    603   1.1       cgd 	}
    604   1.1       cgd 	*p = '\0';
    605  1.44  christos 	if (strcmp(line, "+") == 0) {
    606  1.44  christos 		/* pw_scan() can't handle "+" */
    607  1.44  christos 		(void)strcpy(line, "+:::::::::");
    608  1.44  christos 	}
    609  1.17   mycroft 	oflags = 0;
    610  1.17   mycroft 	if (!pw_scan(line, pw, &oflags)) {
    611  1.19        ad 		errno = EFTYPE;	/* XXX */
    612  1.52  christos 		mkpw_error("%s, %d: Syntax mkpw_error", pname, *lineno);
    613   1.1       cgd 	}
    614  1.17   mycroft 	*flags = oflags;
    615   1.5   mycroft 
    616   1.5   mycroft 	return (1);
    617   1.1       cgd }
    618   1.1       cgd 
    619  1.61  christos static void
    620  1.19        ad install(const char *from, const char *to)
    621   1.1       cgd {
    622   1.1       cgd 	char buf[MAXPATHLEN];
    623   1.1       cgd 
    624  1.44  christos 	(void)snprintf(buf, sizeof(buf), "%s%s", prefix, to);
    625  1.52  christos 	if (rename(from, buf))
    626  1.52  christos 		mkpw_error("Cannot rename `%s' to `%s'", from, buf);
    627   1.1       cgd }
    628   1.1       cgd 
    629  1.61  christos static void
    630  1.22        ad rm(const char *victim)
    631  1.22        ad {
    632  1.22        ad 
    633  1.22        ad 	if (unlink(victim) < 0)
    634  1.22        ad 		warn("unlink(%s)", victim);
    635  1.22        ad }
    636  1.22        ad 
    637  1.61  christos static void
    638  1.61  christos cp(const char *from, const char *to, mode_t mode)
    639  1.61  christos {
    640  1.22        ad 	static char buf[MAXBSIZE];
    641  1.52  christos 	int from_fd, to_fd;
    642  1.44  christos 	ssize_t rcount, wcount;
    643  1.22        ad 
    644  1.22        ad 	if ((from_fd = open(from, O_RDONLY, 0)) < 0)
    645  1.52  christos 		mkpw_error("Cannot open `%s'", from);
    646  1.53       wiz 	if ((to_fd = open(to, O_WRONLY | O_CREAT | O_EXCL, mode)) < 0) {
    647  1.53       wiz 		(void)close(from_fd);
    648  1.52  christos 		mkpw_error("Cannot open `%s'", to);
    649  1.53       wiz 	}
    650  1.22        ad 	while ((rcount = read(from_fd, buf, MAXBSIZE)) > 0) {
    651  1.44  christos 		wcount = write(to_fd, buf, (size_t)rcount);
    652  1.53       wiz 		if (rcount != wcount || wcount == -1) {
    653  1.53       wiz 			(void)close(from_fd);
    654  1.53       wiz 			(void)close(to_fd);
    655  1.50     joerg 			goto on_error;
    656  1.53       wiz 		}
    657  1.22        ad 	}
    658  1.22        ad 
    659  1.50     joerg 	close(from_fd);
    660  1.50     joerg 	if (close(to_fd))
    661  1.51       snj 		goto on_error;
    662  1.53       wiz 	if (rcount < 0)
    663  1.53       wiz 		goto on_error;
    664  1.50     joerg 	return;
    665  1.50     joerg 
    666  1.50     joerg on_error:
    667  1.52  christos 	mkpw_error("Cannot copy `%s' to `%s'", from, to);
    668  1.22        ad }
    669  1.22        ad 
    670  1.61  christos static void
    671  1.19        ad wr_error(const char *str)
    672  1.11      fair {
    673  1.52  christos 	mkpw_error("Cannot write `%s'", str);
    674  1.52  christos }
    675  1.19        ad 
    676  1.61  christos static void
    677  1.52  christos mkpw_error(const char *fmt, ...)
    678  1.52  christos {
    679  1.52  christos 	va_list ap;
    680  1.52  christos 	va_start(ap, fmt);
    681  1.52  christos 	if (logsyslog) {
    682  1.52  christos 		int sverrno = errno;
    683  1.52  christos 		char efmt[BUFSIZ];
    684  1.52  christos 		snprintf(efmt, sizeof(efmt), "%s (%%m)", fmt);
    685  1.52  christos 		errno = sverrno;
    686  1.52  christos 		vsyslog(LOG_ERR, efmt, ap);
    687  1.52  christos 	} else
    688  1.52  christos 		vwarn(fmt, ap);
    689  1.52  christos 	va_end(ap);
    690  1.52  christos 	bailout();
    691  1.11      fair }
    692  1.11      fair 
    693  1.61  christos static void
    694  1.52  christos mkpw_warning(const char *fmt, ...)
    695   1.1       cgd {
    696  1.52  christos 	va_list ap;
    697  1.52  christos 	va_start(ap, fmt);
    698  1.52  christos 	if (logsyslog)
    699  1.52  christos 		vsyslog(LOG_WARNING, fmt, ap);
    700  1.52  christos 	else
    701  1.52  christos 		vwarnx(fmt, ap);
    702  1.52  christos 	va_end(ap);
    703   1.1       cgd }
    704   1.1       cgd 
    705  1.61  christos static void
    706  1.44  christos inconsistency(void)
    707  1.11      fair {
    708  1.19        ad 
    709  1.52  christos 	mkpw_warning("text files and databases are inconsistent");
    710  1.52  christos 	mkpw_warning("re-build the databases without -u");
    711  1.22        ad 	bailout();
    712  1.11      fair }
    713  1.11      fair 
    714  1.61  christos static void
    715  1.22        ad bailout(void)
    716   1.1       cgd {
    717  1.19        ad 
    718  1.22        ad 	if ((clean & FILE_ORIG) != 0)
    719  1.11      fair 		rm(oldpwdfile);
    720  1.22        ad 	if ((clean & FILE_SECURE) != 0)
    721  1.42  christos 		rm(sdb.dbname);
    722  1.22        ad 	if ((clean & FILE_INSECURE) != 0)
    723  1.42  christos 		rm(idb.dbname);
    724  1.22        ad 
    725  1.22        ad 	exit(EXIT_FAILURE);
    726   1.1       cgd }
    727   1.1       cgd 
    728  1.61  christos static uint32_t
    729  1.41  christos getversion(const char *fname)
    730  1.35  christos {
    731  1.35  christos 	DBT data, key;
    732  1.36      jmmv 	int ret;
    733  1.41  christos 	uint32_t version = 0;
    734  1.42  christos 	DB *db;
    735  1.35  christos 
    736  1.42  christos 	db = dbopen(fname, O_RDONLY, PERM_INSECURE, DB_HASH, NULL);
    737  1.42  christos 	if (db == NULL) {
    738  1.45  christos 		/* If we are building on a separate root, assume version 1 */
    739  1.57  christos 		if ((errno == EACCES && prefix[0]) || errno == ENOENT)
    740  1.45  christos 			return 1;
    741  1.52  christos 		mkpw_warning("Cannot open database `%s'", fname);
    742  1.41  christos 		bailout();
    743  1.41  christos 	}
    744  1.35  christos 	key.data = __UNCONST("VERSION");
    745  1.35  christos 	key.size = strlen((const char *)key.data) + 1;
    746  1.35  christos 
    747  1.42  christos 	switch (ret = (*db->get)(db, &key, &data, 0)) {
    748  1.41  christos 	case -1:	/* Error */
    749  1.52  christos 		mkpw_warning("Cannot get VERSION record from database `%s'",
    750  1.52  christos 		    fname);
    751  1.41  christos 		goto out;
    752  1.41  christos 	case 0:
    753  1.41  christos 		if (data.size != sizeof(version)) {
    754  1.52  christos 		    mkpw_warning("Bad VERSION record in database `%s'", fname);
    755  1.41  christos 		    goto out;
    756  1.41  christos 		}
    757  1.44  christos 		(void)memcpy(&version, data.data, sizeof(version));
    758  1.41  christos 		/*FALLTHROUGH*/
    759  1.41  christos 	case 1:
    760  1.42  christos 		if (ret == 1)
    761  1.52  christos 			mkpw_warning("Database `%s' has no version info",
    762  1.52  christos 			    fname);
    763  1.42  christos 		(*db->close)(db);
    764  1.41  christos 		return version;
    765  1.41  christos 	default:
    766  1.52  christos 		mkpw_warning("internal mkpw_error db->get returns %d", ret);
    767  1.41  christos 		goto out;
    768  1.36      jmmv 	}
    769  1.41  christos out:
    770  1.42  christos 	(*db->close)(db);
    771  1.41  christos 	bailout();
    772  1.44  christos 	/*NOTREACHED*/
    773  1.36      jmmv }
    774  1.36      jmmv 
    775  1.61  christos static void
    776  1.42  christos setversion(struct pwddb *db)
    777  1.36      jmmv {
    778  1.36      jmmv 	DBT data, key;
    779  1.36      jmmv 	key.data = __UNCONST("VERSION");
    780  1.36      jmmv 	key.size = strlen((const char *)key.data) + 1;
    781  1.36      jmmv 
    782  1.42  christos 	data.data = &db->wversion;
    783  1.35  christos 	data.size = sizeof(uint32_t);
    784  1.35  christos 
    785  1.43  christos 	if ((*db->db->put)(db->db, &key, &data, 0) != 0) {
    786  1.52  christos 		mkpw_warning("Can't write VERSION record to `%s'", db->dbname);
    787  1.42  christos 		bailout();
    788  1.42  christos 	}
    789  1.35  christos }
    790  1.35  christos 
    791  1.41  christos 
    792  1.19        ad /*
    793  1.61  christos  * Write entries to a database for a single user.
    794  1.19        ad  *
    795  1.19        ad  * The databases actually contain three copies of the original data.  Each
    796  1.19        ad  * password file entry is converted into a rough approximation of a ``struct
    797  1.19        ad  * passwd'', with the strings placed inline.  This object is then stored as
    798  1.19        ad  * the data for three separate keys.  The first key * is the pw_name field
    799  1.19        ad  * prepended by the _PW_KEYBYNAME character.  The second key is the pw_uid
    800  1.19        ad  * field prepended by the _PW_KEYBYUID character.  The third key is the line
    801  1.61  christos  * number in the original file prepended by the _PW_KEYBYNUM character.
    802  1.19        ad  * (The special characters are prepended to ensure that the keys do not
    803  1.19        ad  * collide.)
    804  1.19        ad  */
    805  1.19        ad #define	COMPACT(e)	for (t = e; (*p++ = *t++) != '\0';)
    806  1.19        ad 
    807  1.61  christos static void
    808  1.42  christos putdbents(struct pwddb *db, struct passwd *pw, const char *passwd, int flags,
    809  1.61  christos     int lineno, u_int dbflg, u_int uid_dbflg)
    810  1.19        ad {
    811  1.19        ad 	struct passwd pwd;
    812  1.19        ad 	char buf[MAX(MAXPATHLEN, LINE_MAX * 2)], tbuf[1024], *p;
    813  1.19        ad 	DBT data, key;
    814  1.19        ad 	const char *t;
    815  1.19        ad 	u_int32_t x;
    816  1.44  christos 	size_t len;
    817  1.19        ad 
    818  1.44  christos 	(void)memcpy(&pwd, pw, sizeof(pwd));
    819  1.19        ad 	data.data = (u_char *)buf;
    820  1.19        ad 	key.data = (u_char *)tbuf;
    821  1.19        ad 
    822  1.19        ad 	if (lorder != BYTE_ORDER) {
    823  1.35  christos 		pwd.pw_uid = SWAP(pwd.pw_uid);
    824  1.35  christos 		pwd.pw_gid = SWAP(pwd.pw_gid);
    825  1.19        ad 	}
    826  1.19        ad 
    827  1.41  christos #define WRITEPWTIMEVAR(pwvar) \
    828  1.41  christos 	do { \
    829  1.42  christos 		if (db->wversion == 0 && \
    830  1.44  christos 		    /*CONSTCOND*/sizeof(pwvar) == sizeof(uint64_t)) { \
    831  1.41  christos 			uint32_t tmp = (uint32_t)pwvar; \
    832  1.41  christos 			if (lorder != BYTE_ORDER) \
    833  1.41  christos 				tmp = SWAP(tmp); \
    834  1.44  christos 			(void)memmove(p, &tmp, sizeof(tmp)); \
    835  1.41  christos 			p += sizeof(tmp); \
    836  1.42  christos 		} else if (db->wversion == 1 && \
    837  1.44  christos 		    /*CONSTCOND*/sizeof(pwvar) == sizeof(uint32_t)) { \
    838  1.41  christos 			uint64_t tmp = pwvar; \
    839  1.41  christos 			if (lorder != BYTE_ORDER) \
    840  1.41  christos 				tmp = SWAP(tmp); \
    841  1.44  christos 			(void)memmove(p, &tmp, sizeof(tmp)); \
    842  1.41  christos 			p += sizeof(tmp); \
    843  1.41  christos 		} else { \
    844  1.41  christos 			if (lorder != BYTE_ORDER) \
    845  1.41  christos 				pwvar = SWAP(pwvar); \
    846  1.44  christos 			(void)memmove(p, &pwvar, sizeof(pwvar)); \
    847  1.41  christos 			p += sizeof(pwvar); \
    848  1.41  christos 		} \
    849  1.59    rillig 	} while (0)
    850  1.41  christos 
    851  1.19        ad 	/* Create insecure data. */
    852  1.19        ad 	p = buf;
    853  1.19        ad 	COMPACT(pwd.pw_name);
    854  1.19        ad 	COMPACT(passwd);
    855  1.44  christos 	(void)memmove(p, &pwd.pw_uid, sizeof(pwd.pw_uid));
    856  1.19        ad 	p += sizeof(pwd.pw_uid);
    857  1.44  christos 	(void)memmove(p, &pwd.pw_gid, sizeof(pwd.pw_gid));
    858  1.19        ad 	p += sizeof(pwd.pw_gid);
    859  1.41  christos 	WRITEPWTIMEVAR(pwd.pw_change);
    860  1.19        ad 	COMPACT(pwd.pw_class);
    861  1.19        ad 	COMPACT(pwd.pw_gecos);
    862  1.19        ad 	COMPACT(pwd.pw_dir);
    863  1.19        ad 	COMPACT(pwd.pw_shell);
    864  1.41  christos 	WRITEPWTIMEVAR(pwd.pw_expire);
    865  1.19        ad 	x = flags;
    866  1.19        ad 	if (lorder != BYTE_ORDER)
    867  1.35  christos 		x = SWAP(x);
    868  1.44  christos 	(void)memmove(p, &x, sizeof(x));
    869  1.48     enami 	p += sizeof(x);
    870  1.19        ad 	data.size = p - buf;
    871  1.19        ad 
    872  1.19        ad 	/* Store insecure by name. */
    873  1.19        ad 	tbuf[0] = _PW_KEYBYNAME;
    874  1.19        ad 	len = strlen(pwd.pw_name);
    875  1.44  christos 	(void)memmove(tbuf + 1, pwd.pw_name, len);
    876  1.19        ad 	key.size = len + 1;
    877  1.42  christos 	if ((*db->db->put)(db->db, &key, &data, dbflg) == -1)
    878  1.42  christos 		wr_error(db->dbname);
    879  1.22        ad 
    880  1.19        ad 	/* Store insecure by number. */
    881  1.19        ad 	tbuf[0] = _PW_KEYBYNUM;
    882  1.19        ad 	x = lineno;
    883  1.19        ad 	if (lorder != BYTE_ORDER)
    884  1.35  christos 		x = SWAP(x);
    885  1.44  christos 	(void)memmove(tbuf + 1, &x, sizeof(x));
    886  1.19        ad 	key.size = sizeof(x) + 1;
    887  1.42  christos 	if ((*db->db->put)(db->db, &key, &data, dbflg) == -1)
    888  1.42  christos 		wr_error(db->dbname);
    889  1.19        ad 
    890  1.19        ad 	/* Store insecure by uid. */
    891  1.19        ad 	tbuf[0] = _PW_KEYBYUID;
    892  1.44  christos 	(void)memmove(tbuf + 1, &pwd.pw_uid, sizeof(pwd.pw_uid));
    893  1.19        ad 	key.size = sizeof(pwd.pw_uid) + 1;
    894  1.42  christos 	if ((*db->db->put)(db->db, &key, &data, uid_dbflg) == -1)
    895  1.42  christos 		wr_error(db->dbname);
    896  1.22        ad }
    897  1.22        ad 
    898  1.61  christos static void
    899  1.42  christos deldbent(struct pwddb *db, int type, void *keyp)
    900  1.22        ad {
    901  1.22        ad 	char tbuf[1024];
    902  1.22        ad 	DBT key;
    903  1.22        ad 	u_int32_t x;
    904  1.44  christos 	size_t len;
    905  1.22        ad 
    906  1.22        ad 	key.data = (u_char *)tbuf;
    907  1.22        ad 
    908  1.22        ad 	switch (tbuf[0] = type) {
    909  1.22        ad 	case _PW_KEYBYNAME:
    910  1.22        ad 		len = strlen((char *)keyp);
    911  1.44  christos 		(void)memcpy(tbuf + 1, keyp, len);
    912  1.22        ad 		key.size = len + 1;
    913  1.22        ad 		break;
    914  1.22        ad 
    915  1.22        ad 	case _PW_KEYBYNUM:
    916  1.22        ad 	case _PW_KEYBYUID:
    917  1.22        ad 		x = *(int *)keyp;
    918  1.22        ad 		if (lorder != BYTE_ORDER)
    919  1.35  christos 			x = SWAP(x);
    920  1.44  christos 		(void)memmove(tbuf + 1, &x, sizeof(x));
    921  1.22        ad 		key.size = sizeof(x) + 1;
    922  1.22        ad 		break;
    923  1.22        ad 	}
    924  1.22        ad 
    925  1.44  christos 	if ((*db->db->del)(db->db, &key, 0) == -1)
    926  1.42  christos 		wr_error(db->dbname);
    927  1.22        ad }
    928  1.22        ad 
    929  1.61  christos static int
    930  1.42  christos getdbent(struct pwddb *db, int type, void *keyp, struct passwd **tpwd)
    931  1.22        ad {
    932  1.22        ad 	static char buf[MAX(MAXPATHLEN, LINE_MAX * 2)];
    933  1.22        ad 	static struct passwd pwd;
    934  1.22        ad 	char tbuf[1024], *p;
    935  1.22        ad 	DBT key, data;
    936  1.22        ad 	u_int32_t x;
    937  1.44  christos 	size_t len;
    938  1.44  christos 	int rv;
    939  1.22        ad 
    940  1.22        ad 	data.data = (u_char *)buf;
    941  1.22        ad 	data.size = sizeof(buf);
    942  1.22        ad 	key.data = (u_char *)tbuf;
    943  1.22        ad 
    944  1.22        ad 	switch (tbuf[0] = type) {
    945  1.22        ad 	case _PW_KEYBYNAME:
    946  1.22        ad 		len = strlen((char *)keyp);
    947  1.44  christos 		(void)memcpy(tbuf + 1, keyp, len);
    948  1.22        ad 		key.size = len + 1;
    949  1.22        ad 		break;
    950  1.22        ad 
    951  1.22        ad 	case _PW_KEYBYNUM:
    952  1.22        ad 	case _PW_KEYBYUID:
    953  1.22        ad 		x = *(int *)keyp;
    954  1.22        ad 		if (lorder != BYTE_ORDER)
    955  1.35  christos 			x = SWAP(x);
    956  1.44  christos 		(void)memmove(tbuf + 1, &x, sizeof(x));
    957  1.22        ad 		key.size = sizeof(x) + 1;
    958  1.22        ad 		break;
    959  1.22        ad 	}
    960  1.22        ad 
    961  1.42  christos 	if ((rv = (*db->db->get)(db->db, &key, &data, 0)) == 1)
    962  1.22        ad 		return (rv);
    963  1.22        ad 	if (rv == -1)
    964  1.52  christos 		mkpw_error("Error getting record from `%s'", db->dbname);
    965  1.22        ad 
    966  1.22        ad 	p = (char *)data.data;
    967  1.22        ad 
    968  1.22        ad 	pwd.pw_name = p;
    969  1.22        ad 	while (*p++ != '\0')
    970  1.41  christos 		continue;
    971  1.22        ad 	pwd.pw_passwd = p;
    972  1.22        ad 	while (*p++ != '\0')
    973  1.41  christos 		continue;
    974  1.22        ad 
    975  1.44  christos 	(void)memcpy(&pwd.pw_uid, p, sizeof(pwd.pw_uid));
    976  1.22        ad 	p += sizeof(pwd.pw_uid);
    977  1.44  christos 	(void)memcpy(&pwd.pw_gid, p, sizeof(pwd.pw_gid));
    978  1.22        ad 	p += sizeof(pwd.pw_gid);
    979  1.41  christos 
    980  1.41  christos #define READPWTIMEVAR(pwvar) \
    981  1.41  christos 	do { \
    982  1.42  christos 		if (db->rversion == 0 && \
    983  1.44  christos 		    /*CONSTCOND*/sizeof(pwvar) == sizeof(uint64_t)) { \
    984  1.41  christos 			uint32_t tmp; \
    985  1.44  christos 			(void)memcpy(&tmp, p, sizeof(tmp)); \
    986  1.41  christos 			p += sizeof(tmp); \
    987  1.41  christos 			if (lorder != BYTE_ORDER) \
    988  1.41  christos 				pwvar = SWAP(tmp); \
    989  1.41  christos 			else \
    990  1.41  christos 				pwvar = tmp; \
    991  1.42  christos 		} else if (db->rversion == 1 && \
    992  1.44  christos 		    /*CONSTCOND*/sizeof(pwvar) == sizeof(uint32_t)) { \
    993  1.41  christos 			uint64_t tmp; \
    994  1.44  christos 			(void)memcpy(&tmp, p, sizeof(tmp)); \
    995  1.41  christos 			p += sizeof(tmp); \
    996  1.41  christos 			if (lorder != BYTE_ORDER) \
    997  1.41  christos 				pwvar = (uint32_t)SWAP(tmp); \
    998  1.41  christos 			else \
    999  1.41  christos 				pwvar = (uint32_t)tmp; \
   1000  1.41  christos 		} else { \
   1001  1.44  christos 			(void)memcpy(&pwvar, p, sizeof(pwvar)); \
   1002  1.41  christos 			p += sizeof(pwvar); \
   1003  1.41  christos 			if (lorder != BYTE_ORDER) \
   1004  1.41  christos 				pwvar = SWAP(pwvar); \
   1005  1.41  christos 		} \
   1006  1.59    rillig 	} while (0)
   1007  1.61  christos 
   1008  1.41  christos 	READPWTIMEVAR(pwd.pw_change);
   1009  1.22        ad 
   1010  1.22        ad 	pwd.pw_class = p;
   1011  1.22        ad 	while (*p++ != '\0')
   1012  1.41  christos 		continue;
   1013  1.22        ad 	pwd.pw_gecos = p;
   1014  1.22        ad 	while (*p++ != '\0')
   1015  1.41  christos 		continue;
   1016  1.22        ad 	pwd.pw_dir = p;
   1017  1.22        ad 	while (*p++ != '\0')
   1018  1.41  christos 		continue;
   1019  1.22        ad 	pwd.pw_shell = p;
   1020  1.22        ad 	while (*p++ != '\0')
   1021  1.41  christos 		continue;
   1022  1.22        ad 
   1023  1.41  christos 	READPWTIMEVAR(pwd.pw_expire);
   1024  1.22        ad 
   1025  1.22        ad 	if (lorder != BYTE_ORDER) {
   1026  1.35  christos 		pwd.pw_uid = SWAP(pwd.pw_uid);
   1027  1.35  christos 		pwd.pw_gid = SWAP(pwd.pw_gid);
   1028  1.22        ad 	}
   1029  1.22        ad 
   1030  1.22        ad 	*tpwd = &pwd;
   1031  1.22        ad 	return (0);
   1032  1.19        ad }
   1033  1.19        ad 
   1034  1.61  christos static void
   1035  1.42  christos putyptoken(struct pwddb *db)
   1036  1.19        ad {
   1037  1.19        ad 	DBT data, key;
   1038  1.19        ad 
   1039  1.40     lukem 	key.data = __UNCONST(__yp_token);
   1040  1.19        ad 	key.size = strlen(__yp_token);
   1041  1.55    plunky 	data.data = NULL;
   1042  1.19        ad 	data.size = 0;
   1043  1.19        ad 
   1044  1.42  christos 	if ((*db->db->put)(db->db, &key, &data, R_NOOVERWRITE) == -1)
   1045  1.42  christos 		wr_error(db->dbname);
   1046  1.19        ad }
   1047  1.19        ad 
   1048  1.61  christos static void
   1049  1.19        ad usage(void)
   1050   1.1       cgd {
   1051   1.5   mycroft 
   1052  1.22        ad 	(void)fprintf(stderr,
   1053  1.52  christos 	    "Usage: %s [-BLlpsvw] [-c cachesize] [-d directory] [-u user] "
   1054  1.41  christos 	    "[-V version] file\n",
   1055  1.41  christos 	    getprogname());
   1056  1.19        ad 	exit(EXIT_FAILURE);
   1057   1.1       cgd }
   1058