xref: /minix3/usr.sbin/pwd_mkdb/pwd_mkdb.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc /*	$NetBSD: pwd_mkdb.c,v 1.57 2014/01/26 01:57:04 christos Exp $	*/
25c007436SBen Gras 
35c007436SBen Gras /*
45c007436SBen Gras  * Copyright (c) 2000, 2009 The NetBSD Foundation, Inc.
55c007436SBen Gras  * All rights reserved.
65c007436SBen Gras  *
75c007436SBen Gras  * Redistribution and use in source and binary forms, with or without
85c007436SBen Gras  * modification, are permitted provided that the following conditions
95c007436SBen Gras  * are met:
105c007436SBen Gras  * 1. Redistributions of source code must retain the above copyright
115c007436SBen Gras  *    notice, this list of conditions and the following disclaimer.
125c007436SBen Gras  * 2. Redistributions in binary form must reproduce the above copyright
135c007436SBen Gras  *    notice, this list of conditions and the following disclaimer in the
145c007436SBen Gras  *    documentation and/or other materials provided with the distribution.
155c007436SBen Gras  *
165c007436SBen Gras  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
175c007436SBen Gras  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
185c007436SBen Gras  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
195c007436SBen Gras  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
205c007436SBen Gras  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
215c007436SBen Gras  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
225c007436SBen Gras  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
235c007436SBen Gras  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
245c007436SBen Gras  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
255c007436SBen Gras  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
265c007436SBen Gras  * POSSIBILITY OF SUCH DAMAGE.
275c007436SBen Gras  */
285c007436SBen Gras 
295c007436SBen Gras /*
305c007436SBen Gras  * Copyright (c) 1991, 1993, 1994
315c007436SBen Gras  *	The Regents of the University of California.  All rights reserved.
325c007436SBen Gras  *
335c007436SBen Gras  * Redistribution and use in source and binary forms, with or without
345c007436SBen Gras  * modification, are permitted provided that the following conditions
355c007436SBen Gras  * are met:
365c007436SBen Gras  * 1. Redistributions of source code must retain the above copyright
375c007436SBen Gras  *    notice, this list of conditions and the following disclaimer.
385c007436SBen Gras  * 2. Redistributions in binary form must reproduce the above copyright
395c007436SBen Gras  *    notice, this list of conditions and the following disclaimer in the
405c007436SBen Gras  *    documentation and/or other materials provided with the distribution.
415c007436SBen Gras  * 3. Neither the name of the University nor the names of its contributors
425c007436SBen Gras  *    may be used to endorse or promote products derived from this software
435c007436SBen Gras  *    without specific prior written permission.
445c007436SBen Gras  *
455c007436SBen Gras  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
465c007436SBen Gras  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
475c007436SBen Gras  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
485c007436SBen Gras  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
495c007436SBen Gras  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
505c007436SBen Gras  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
515c007436SBen Gras  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
525c007436SBen Gras  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
535c007436SBen Gras  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
545c007436SBen Gras  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
555c007436SBen Gras  * SUCH DAMAGE.
565c007436SBen Gras  */
575c007436SBen Gras 
585c007436SBen Gras /*
595c007436SBen Gras  * Portions Copyright(C) 1994, Jason Downs.  All rights reserved.
605c007436SBen Gras  *
615c007436SBen Gras  * Redistribution and use in source and binary forms, with or without
625c007436SBen Gras  * modification, are permitted provided that the following conditions
635c007436SBen Gras  * are met:
645c007436SBen Gras  * 1. Redistributions of source code must retain the above copyright
655c007436SBen Gras  *    notice, this list of conditions and the following disclaimer.
665c007436SBen Gras  * 2. Redistributions in binary form must reproduce the above copyright
675c007436SBen Gras  *    notice, this list of conditions and the following disclaimer in the
685c007436SBen Gras  *    documentation and/or other materials provided with the distribution.
695c007436SBen Gras  *
705c007436SBen Gras  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS
715c007436SBen Gras  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
725c007436SBen Gras  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
735c007436SBen Gras  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT,
745c007436SBen Gras  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
755c007436SBen Gras  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
765c007436SBen Gras  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
775c007436SBen Gras  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
785c007436SBen Gras  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
795c007436SBen Gras  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
805c007436SBen Gras  * SUCH DAMAGE.
815c007436SBen Gras  */
825c007436SBen Gras 
835c007436SBen Gras #if HAVE_NBTOOL_CONFIG_H
845c007436SBen Gras #include "nbtool_config.h"
855c007436SBen Gras #endif
865c007436SBen Gras 
875c007436SBen Gras #include <sys/cdefs.h>
885c007436SBen Gras #if !defined(lint)
895c007436SBen Gras __COPYRIGHT("@(#) Copyright (c) 2000, 2009\
905c007436SBen Gras  The NetBSD Foundation, Inc.  All rights reserved.\
915c007436SBen Gras   Copyright (c) 1991, 1993, 1994\
925c007436SBen Gras  The Regents of the University of California.  All rights reserved.");
93*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: pwd_mkdb.c,v 1.57 2014/01/26 01:57:04 christos Exp $");
945c007436SBen Gras #endif /* not lint */
955c007436SBen Gras 
965c007436SBen Gras #if HAVE_NBTOOL_CONFIG_H
975c007436SBen Gras #include "compat_pwd.h"
985c007436SBen Gras #else
995c007436SBen Gras #include <pwd.h>
1005c007436SBen Gras #endif
1015c007436SBen Gras 
1025c007436SBen Gras #include <sys/param.h>
1035c007436SBen Gras #include <sys/stat.h>
1045c007436SBen Gras #include <sys/types.h>
1055c007436SBen Gras 
1065c007436SBen Gras #ifndef HAVE_NBTOOL_CONFIG_H
1075c007436SBen Gras #include <machine/bswap.h>
1085c007436SBen Gras #endif
1095c007436SBen Gras 
1105c007436SBen Gras #include <db.h>
1115c007436SBen Gras #include <err.h>
1125c007436SBen Gras #include <errno.h>
1135c007436SBen Gras #include <fcntl.h>
1145c007436SBen Gras #include <syslog.h>
1155c007436SBen Gras #include <limits.h>
1165c007436SBen Gras #include <signal.h>
1175c007436SBen Gras #include <stdio.h>
1185c007436SBen Gras #include <stdlib.h>
1195c007436SBen Gras #include <stdarg.h>
1205c007436SBen Gras #include <string.h>
1215c007436SBen Gras #include <unistd.h>
12284d9c625SLionel Sambuc 
12384d9c625SLionel Sambuc #ifndef HAVE_NBTOOL_CONFIG_H
1245c007436SBen Gras #include <util.h>
12584d9c625SLionel Sambuc #endif
1265c007436SBen Gras 
1275c007436SBen Gras #define	MAX_CACHESIZE	8*1024*1024
1285c007436SBen Gras #define	MIN_CACHESIZE	2*1024*1024
1295c007436SBen Gras 
1305c007436SBen Gras #define	PERM_INSECURE	(S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
1315c007436SBen Gras #define	PERM_SECURE	(S_IRUSR | S_IWUSR)
1325c007436SBen Gras 
1335c007436SBen Gras #if HAVE_NBTOOL_CONFIG_H
1345c007436SBen Gras static const char __yp_token[] = "__YP!";
1355c007436SBen Gras #else
1365c007436SBen Gras /* Pull this out of the C library. */
1375c007436SBen Gras extern const char __yp_token[];
1385c007436SBen Gras #endif
1395c007436SBen Gras 
1405c007436SBen Gras static HASHINFO openinfo = {
1415c007436SBen Gras 	4096,		/* bsize */
1425c007436SBen Gras 	32,		/* ffactor */
1435c007436SBen Gras 	256,		/* nelem */
1445c007436SBen Gras 	0,		/* cachesize */
1455c007436SBen Gras 	NULL,		/* hash() */
1465c007436SBen Gras 	0		/* lorder */
1475c007436SBen Gras };
1485c007436SBen Gras 
1495c007436SBen Gras #define	FILE_INSECURE	0x01
1505c007436SBen Gras #define	FILE_SECURE	0x02
1515c007436SBen Gras #define	FILE_ORIG	0x04
1525c007436SBen Gras 
1535c007436SBen Gras 
1545c007436SBen Gras struct pwddb {
1555c007436SBen Gras 	DB *db;
1565c007436SBen Gras 	char dbname[MAX(MAXPATHLEN, LINE_MAX * 2)];
1575c007436SBen Gras 	const char *fname;
1585c007436SBen Gras 	uint32_t rversion;
1595c007436SBen Gras 	uint32_t wversion;
1605c007436SBen Gras };
1615c007436SBen Gras 
1625c007436SBen Gras static char	*pname;				/* password file name */
1635c007436SBen Gras static char	prefix[MAXPATHLEN];
1645c007436SBen Gras static char	oldpwdfile[MAX(MAXPATHLEN, LINE_MAX * 2)];
1655c007436SBen Gras static int 	lorder = BYTE_ORDER;
1665c007436SBen Gras static int	logsyslog;
1675c007436SBen Gras static int	clean;
1685c007436SBen Gras static int	verbose;
1695c007436SBen Gras static int	warning;
1705c007436SBen Gras static struct pwddb sdb, idb;
1715c007436SBen Gras 
1725c007436SBen Gras 
17384d9c625SLionel Sambuc void	bailout(void) __dead;
1745c007436SBen Gras void	cp(const char *, const char *, mode_t);
1755c007436SBen Gras void	deldbent(struct pwddb *, int, void *);
17684d9c625SLionel Sambuc void	mkpw_error(const char *, ...) __dead;
1775c007436SBen Gras void	mkpw_warning(const char *, ...);
1785c007436SBen Gras int	getdbent(struct pwddb *, int, void *, struct passwd **);
17984d9c625SLionel Sambuc void	inconsistency(void) __dead;
1805c007436SBen Gras void	install(const char *, const char *);
1815c007436SBen Gras int	main(int, char **);
1825c007436SBen Gras void	putdbents(struct pwddb *, struct passwd *, const char *, int, int,
1835c007436SBen Gras     u_int, u_int);
1845c007436SBen Gras void	putyptoken(struct pwddb *);
1855c007436SBen Gras void	rm(const char *);
1865c007436SBen Gras int	scan(FILE *, struct passwd *, int *, int *);
18784d9c625SLionel Sambuc void	usage(void) __dead;
18884d9c625SLionel Sambuc void	wr_error(const char *) __dead;
1895c007436SBen Gras uint32_t getversion(const char *);
1905c007436SBen Gras void	setversion(struct pwddb *);
1915c007436SBen Gras 
1925c007436SBen Gras #ifndef __lint__
1935c007436SBen Gras #define SWAP(sw) \
1945c007436SBen Gras     ((sizeof(sw) == 2 ? (typeof(sw))bswap16((uint16_t)sw) : \
1955c007436SBen Gras     (sizeof(sw) == 4 ? (typeof(sw))bswap32((uint32_t)sw) : \
1965c007436SBen Gras     (sizeof(sw) == 8 ? (typeof(sw))bswap64((uint64_t)sw) : (abort(), 0)))))
1975c007436SBen Gras #else
1985c007436SBen Gras #define SWAP(sw) sw
1995c007436SBen Gras #endif
2005c007436SBen Gras 
2015c007436SBen Gras static void
closedb(struct pwddb * db)2025c007436SBen Gras closedb(struct pwddb *db)
2035c007436SBen Gras {
2045c007436SBen Gras     if ((*db->db->close)(db->db) < 0)
2055c007436SBen Gras 	    wr_error(db->dbname);
2065c007436SBen Gras }
2075c007436SBen Gras 
2085c007436SBen Gras static void
opendb(struct pwddb * db,const char * dbname,const char * username,uint32_t req_version,int flags,mode_t perm)2095c007436SBen Gras opendb(struct pwddb *db, const char *dbname, const char *username,
2105c007436SBen Gras     uint32_t req_version, int flags, mode_t perm)
2115c007436SBen Gras {
2125c007436SBen Gras 	char buf[MAXPATHLEN];
2135c007436SBen Gras 
2145c007436SBen Gras 	(void)snprintf(db->dbname, sizeof(db->dbname), "%s%s.tmp", prefix,
2155c007436SBen Gras 	    dbname);
2165c007436SBen Gras 
2175c007436SBen Gras 	if (username != NULL) {
2185c007436SBen Gras 		(void)snprintf(buf, sizeof(buf), "%s%s", prefix, dbname);
2195c007436SBen Gras 		cp(buf, db->dbname, perm);
2205c007436SBen Gras 	}
2215c007436SBen Gras 
2225c007436SBen Gras 	db->db = dbopen(db->dbname, flags, perm, DB_HASH, &openinfo);
2235c007436SBen Gras 	if (db->db == NULL)
2245c007436SBen Gras 		mkpw_error("Cannot open `%s'", db->dbname);
2255c007436SBen Gras 
2265c007436SBen Gras 	db->fname = dbname;
2275c007436SBen Gras 	db->rversion = getversion(dbname);
2285c007436SBen Gras 	if (req_version == ~0U)
2295c007436SBen Gras 		db->wversion = db->rversion;
2305c007436SBen Gras 	else
2315c007436SBen Gras 		db->wversion = req_version;
2325c007436SBen Gras 
2335c007436SBen Gras 	if (warning && db->rversion == 0 && db->wversion == 0) {
2345c007436SBen Gras 		mkpw_warning("Database %s is a version %u database.",
2355c007436SBen Gras 		    db->fname, db->rversion);
2365c007436SBen Gras 		mkpw_warning("Use %s -V 1 to upgrade once you've recompiled "
2375c007436SBen Gras 		    "all your binaries.", getprogname());
2385c007436SBen Gras 	}
2395c007436SBen Gras 	if (db->wversion != db->rversion) {
2405c007436SBen Gras 		if (username != NULL) {
2415c007436SBen Gras 			mkpw_warning("You cannot change a single "
2425c007436SBen Gras 			    "record from version %u to version %u\n",
2435c007436SBen Gras 			    db->rversion, db->wversion);
2445c007436SBen Gras 			bailout();
2455c007436SBen Gras 		} else if (verbose) {
2465c007436SBen Gras 		    mkpw_warning("Changing %s from version %u to version %u",
2475c007436SBen Gras 			db->fname, db->rversion, db->wversion);
2485c007436SBen Gras 		}
2495c007436SBen Gras 	} else {
2505c007436SBen Gras 		if (verbose)
2515c007436SBen Gras 			mkpw_warning("File `%s' version %u requested %u",
2525c007436SBen Gras 			    db->fname, db->rversion, db->wversion);
2535c007436SBen Gras 	}
2545c007436SBen Gras 
2555c007436SBen Gras 	setversion(db);
2565c007436SBen Gras }
2575c007436SBen Gras 
2585c007436SBen Gras int
main(int argc,char * argv[])2595c007436SBen Gras main(int argc, char *argv[])
2605c007436SBen Gras {
2615c007436SBen Gras 	int ch, makeold, tfd, lineno, found, rv, hasyp, secureonly;
2625c007436SBen Gras 	struct passwd pwd, *tpwd;
2635c007436SBen Gras 	char *username;
2645c007436SBen Gras 	FILE *fp, *oldfp;
2655c007436SBen Gras 	sigset_t set;
2665c007436SBen Gras 	u_int dbflg, uid_dbflg;
2675c007436SBen Gras 	int newuser, olduid, flags;
2685c007436SBen Gras 	struct stat st;
2695c007436SBen Gras 	u_int cachesize;
2705c007436SBen Gras 	uint32_t req_version;
2715c007436SBen Gras 
2725c007436SBen Gras 	prefix[0] = '\0';
2735c007436SBen Gras 	makeold = 0;
2745c007436SBen Gras 	oldfp = NULL;
2755c007436SBen Gras 	username = NULL;
2765c007436SBen Gras 	hasyp = 0;
2775c007436SBen Gras 	secureonly = 0;
2785c007436SBen Gras 	found = 0;
2795c007436SBen Gras 	newuser = 0;
2805c007436SBen Gras 	cachesize = 0;
2815c007436SBen Gras 	verbose = 0;
2825c007436SBen Gras 	warning = 0;
2835c007436SBen Gras 	logsyslog = 0;
2845c007436SBen Gras 	req_version = ~0U;
2855c007436SBen Gras 
2865c007436SBen Gras 	while ((ch = getopt(argc, argv, "BLc:d:lpsu:V:vw")) != -1)
2875c007436SBen Gras 		switch (ch) {
2885c007436SBen Gras 		case 'B':			/* big-endian output */
2895c007436SBen Gras 			lorder = BIG_ENDIAN;
2905c007436SBen Gras 			break;
2915c007436SBen Gras 		case 'L':			/* little-endian output */
2925c007436SBen Gras 			lorder = LITTLE_ENDIAN;
2935c007436SBen Gras 			break;
2945c007436SBen Gras 		case 'c':
2955c007436SBen Gras 			cachesize = atoi(optarg) * 1024 * 1024;
2965c007436SBen Gras 			break;
2975c007436SBen Gras 		case 'd':			/* set prefix */
2985c007436SBen Gras 			(void)strlcpy(prefix, optarg, sizeof(prefix));
2995c007436SBen Gras 			break;
3005c007436SBen Gras 		case 'l':
3015c007436SBen Gras 			openlog(getprogname(), LOG_PID, LOG_AUTH);
3025c007436SBen Gras 			logsyslog = 1;
3035c007436SBen Gras 			break;
3045c007436SBen Gras 		case 'p':			/* create V7 "file.orig" */
3055c007436SBen Gras 			makeold = 1;
3065c007436SBen Gras 			break;
3075c007436SBen Gras 		case 's':			/* modify secure db only */
3085c007436SBen Gras 			secureonly = 1;
3095c007436SBen Gras 			break;
3105c007436SBen Gras 		case 'u':			/* modify one user only */
3115c007436SBen Gras 			username = optarg;
3125c007436SBen Gras 			break;
3135c007436SBen Gras 		case 'V':
3145c007436SBen Gras 			req_version = (uint32_t)atoi(optarg);
3155c007436SBen Gras 			if (req_version > 1) {
3165c007436SBen Gras 				mkpw_warning("Unknown version %u", req_version);
3175c007436SBen Gras 				return EXIT_FAILURE;
3185c007436SBen Gras 			}
3195c007436SBen Gras 			break;
3205c007436SBen Gras 		case 'v':
3215c007436SBen Gras 			verbose++;
3225c007436SBen Gras 			break;
3235c007436SBen Gras 		case 'w':
3245c007436SBen Gras 			warning++;
3255c007436SBen Gras 			break;
3265c007436SBen Gras 		case '?':
3275c007436SBen Gras 		default:
3285c007436SBen Gras 			usage();
3295c007436SBen Gras 		}
3305c007436SBen Gras 	argc -= optind;
3315c007436SBen Gras 	argv += optind;
3325c007436SBen Gras 
3335c007436SBen Gras 	if (argc != 1)
3345c007436SBen Gras 		usage();
3355c007436SBen Gras 	if (username != NULL)
3365c007436SBen Gras 		if (username[0] == '+' || username[0] == '-')
3375c007436SBen Gras 			usage();
3385c007436SBen Gras 	if (secureonly)
3395c007436SBen Gras 		makeold = 0;
3405c007436SBen Gras 
3415c007436SBen Gras 	/*
3425c007436SBen Gras 	 * This could be changed to allow the user to interrupt.
3435c007436SBen Gras 	 * Probably not worth the effort.
3445c007436SBen Gras 	 */
3455c007436SBen Gras 	(void)sigemptyset(&set);
3465c007436SBen Gras 	(void)sigaddset(&set, SIGTSTP);
3475c007436SBen Gras 	(void)sigaddset(&set, SIGHUP);
3485c007436SBen Gras 	(void)sigaddset(&set, SIGINT);
3495c007436SBen Gras 	(void)sigaddset(&set, SIGQUIT);
3505c007436SBen Gras 	(void)sigaddset(&set, SIGTERM);
35184d9c625SLionel Sambuc 	(void)sigprocmask(SIG_BLOCK, &set, NULL);
3525c007436SBen Gras 
3535c007436SBen Gras 	/* We don't care what the user wants. */
3545c007436SBen Gras 	(void)umask(0);
3555c007436SBen Gras 
3565c007436SBen Gras 	if (username == NULL)
3575c007436SBen Gras 		flags = O_RDWR | O_CREAT | O_EXCL;
3585c007436SBen Gras 	else
3595c007436SBen Gras 		flags = O_RDWR;
3605c007436SBen Gras 
3615c007436SBen Gras 	pname = *argv;
3625c007436SBen Gras 	/* Open the original password file */
3635c007436SBen Gras 	if ((fp = fopen(pname, "r")) == NULL)
3645c007436SBen Gras 		mkpw_error("Cannot open `%s'", pname);
3655c007436SBen Gras 
3665c007436SBen Gras 	openinfo.lorder = lorder;
3675c007436SBen Gras 
3685c007436SBen Gras 	if (fstat(fileno(fp), &st) == -1)
3695c007436SBen Gras 		mkpw_error("Cannot stat `%s'", pname);
3705c007436SBen Gras 
3715c007436SBen Gras 	if (cachesize) {
3725c007436SBen Gras 		openinfo.cachesize = cachesize;
3735c007436SBen Gras 	} else {
3745c007436SBen Gras 		/* Tweak openinfo values for large passwd files. */
3755c007436SBen Gras 		cachesize = (u_int)(st.st_size * 20);
3765c007436SBen Gras 		if (cachesize > MAX_CACHESIZE)
3775c007436SBen Gras 			cachesize = MAX_CACHESIZE;
3785c007436SBen Gras 		else if (cachesize < MIN_CACHESIZE)
3795c007436SBen Gras 			cachesize = MIN_CACHESIZE;
3805c007436SBen Gras 		openinfo.cachesize = cachesize;
3815c007436SBen Gras 	}
3825c007436SBen Gras 
3835c007436SBen Gras 	/* Open the temporary insecure password database. */
3845c007436SBen Gras 	if (!secureonly) {
3855c007436SBen Gras 		opendb(&idb, _PATH_MP_DB, username, req_version,
3865c007436SBen Gras 		    flags, PERM_INSECURE);
3875c007436SBen Gras 		clean |= FILE_INSECURE;
3885c007436SBen Gras 	}
3895c007436SBen Gras 
3905c007436SBen Gras 
3915c007436SBen Gras 	/* Open the temporary encrypted password database. */
3925c007436SBen Gras 	opendb(&sdb, _PATH_SMP_DB, username, req_version, flags, PERM_SECURE);
3935c007436SBen Gras 	clean |= FILE_SECURE;
3945c007436SBen Gras 
3955c007436SBen Gras 	/*
3965c007436SBen Gras 	 * Open file for old password file.  Minor trickiness -- don't want to
3975c007436SBen Gras 	 * chance the file already existing, since someone (stupidly) might
3985c007436SBen Gras 	 * still be using this for permission checking.  So, open it first and
3995c007436SBen Gras 	 * fdopen the resulting fd.  The resulting file should be readable by
4005c007436SBen Gras 	 * everyone.
4015c007436SBen Gras 	 */
4025c007436SBen Gras 	if (makeold) {
4035c007436SBen Gras 		(void)snprintf(oldpwdfile, sizeof(oldpwdfile), "%s.orig",
4045c007436SBen Gras 		    pname);
4055c007436SBen Gras 		if ((tfd = open(oldpwdfile, O_WRONLY | O_CREAT | O_EXCL,
4065c007436SBen Gras 		    PERM_INSECURE)) < 0)
4075c007436SBen Gras 			mkpw_error("Cannot create `%s'", oldpwdfile);
4085c007436SBen Gras 		clean |= FILE_ORIG;
4095c007436SBen Gras 		if ((oldfp = fdopen(tfd, "w")) == NULL)
4105c007436SBen Gras 			mkpw_error("Cannot fdopen `%s'", oldpwdfile);
4115c007436SBen Gras 	}
4125c007436SBen Gras 
4135c007436SBen Gras 	if (username != NULL) {
4145c007436SBen Gras 		uid_dbflg = 0;
4155c007436SBen Gras 		dbflg = 0;
4165c007436SBen Gras 
4175c007436SBen Gras 		/*
4185c007436SBen Gras 		 * Determine if this is a new entry.
4195c007436SBen Gras 		 */
4205c007436SBen Gras 		if (getdbent(&sdb, _PW_KEYBYNAME, username, &tpwd))
4215c007436SBen Gras 			newuser = 1;
4225c007436SBen Gras 		else {
4235c007436SBen Gras 			newuser = 0;
4245c007436SBen Gras 			olduid = tpwd->pw_uid;
4255c007436SBen Gras 		}
4265c007436SBen Gras 
4275c007436SBen Gras 	} else {
4285c007436SBen Gras 		uid_dbflg = R_NOOVERWRITE;
4295c007436SBen Gras 		dbflg = R_NOOVERWRITE;
4305c007436SBen Gras 	}
4315c007436SBen Gras 
4325c007436SBen Gras 	/*
4335c007436SBen Gras 	 * If we see something go by that looks like YP, we save a special
4345c007436SBen Gras 	 * pointer record, which if YP is enabled in the C lib, will speed
4355c007436SBen Gras 	 * things up.
4365c007436SBen Gras 	 */
4375c007436SBen Gras 	for (lineno = 0; scan(fp, &pwd, &flags, &lineno);) {
4385c007436SBen Gras 		/*
4395c007436SBen Gras 		 * Create original format password file entry.
4405c007436SBen Gras 		 */
4415c007436SBen Gras 		if (makeold) {
4425c007436SBen Gras 			(void)fprintf(oldfp, "%s:*:%d:%d:%s:%s:%s\n",
4435c007436SBen Gras 			    pwd.pw_name, pwd.pw_uid, pwd.pw_gid, pwd.pw_gecos,
4445c007436SBen Gras 			    pwd.pw_dir, pwd.pw_shell);
4455c007436SBen Gras 			if (ferror(oldfp))
4465c007436SBen Gras 				wr_error(oldpwdfile);
4475c007436SBen Gras 		}
4485c007436SBen Gras 
4495c007436SBen Gras 		if (username == NULL) {
4505c007436SBen Gras 			/* Look like YP? */
4515c007436SBen Gras 			if (pwd.pw_name[0] == '+' || pwd.pw_name[0] == '-')
4525c007436SBen Gras 				hasyp++;
4535c007436SBen Gras 
4545c007436SBen Gras 			/* Warn about potentially unsafe uid/gid overrides. */
4555c007436SBen Gras 			if (pwd.pw_name[0] == '+') {
4565c007436SBen Gras 				if ((flags & _PASSWORD_NOUID) == 0 &&
4575c007436SBen Gras 				    pwd.pw_uid == 0)
4585c007436SBen Gras 					mkpw_warning("line %d: superuser "
4595c007436SBen Gras 					    "override in YP inclusion", lineno);
4605c007436SBen Gras 				if ((flags & _PASSWORD_NOGID) == 0 &&
4615c007436SBen Gras 				    pwd.pw_gid == 0)
4625c007436SBen Gras 					mkpw_warning("line %d: wheel override "
4635c007436SBen Gras 					    "in YP inclusion", lineno);
4645c007436SBen Gras 			}
4655c007436SBen Gras 
4665c007436SBen Gras 			/* Write the database entry out. */
4675c007436SBen Gras 			if (!secureonly)
4685c007436SBen Gras 				putdbents(&idb, &pwd, "*", flags, lineno, dbflg,
4695c007436SBen Gras 				    uid_dbflg);
4705c007436SBen Gras 			continue;
4715c007436SBen Gras 		} else if (strcmp(username, pwd.pw_name) != 0)
4725c007436SBen Gras 			continue;
4735c007436SBen Gras 
4745c007436SBen Gras 		if (found) {
4755c007436SBen Gras 			mkpw_warning("user `%s' listed twice in password file",
4765c007436SBen Gras 			    username);
4775c007436SBen Gras 			bailout();
4785c007436SBen Gras 		}
4795c007436SBen Gras 
4805c007436SBen Gras 		/*
4815c007436SBen Gras 		 * Ensure that the text file and database agree on
4825c007436SBen Gras 		 * which line the record is from.
4835c007436SBen Gras 		 */
4845c007436SBen Gras 		rv = getdbent(&sdb, _PW_KEYBYNUM, &lineno, &tpwd);
4855c007436SBen Gras 		if (newuser) {
4865c007436SBen Gras 			if (rv == 0)
4875c007436SBen Gras 				inconsistency();
4885c007436SBen Gras 		} else if (rv == 1 || strcmp(username, tpwd->pw_name) != 0)
4895c007436SBen Gras 			inconsistency();
4905c007436SBen Gras 		else if ((uid_t)olduid != pwd.pw_uid) {
4915c007436SBen Gras 			/*
4925c007436SBen Gras 			 * If we're changing UID, remove the BYUID
4935c007436SBen Gras 			 * record for the old UID only if it has the
4945c007436SBen Gras 			 * same username.
4955c007436SBen Gras 			 */
4965c007436SBen Gras 			if (!getdbent(&sdb, _PW_KEYBYUID, &olduid, &tpwd)) {
4975c007436SBen Gras 				if (strcmp(username, tpwd->pw_name) == 0) {
4985c007436SBen Gras 					if (!secureonly)
4995c007436SBen Gras 						deldbent(&idb, _PW_KEYBYUID,
5005c007436SBen Gras 						    &olduid);
5015c007436SBen Gras 					deldbent(&sdb, _PW_KEYBYUID, &olduid);
5025c007436SBen Gras 				}
5035c007436SBen Gras 			} else
5045c007436SBen Gras 				inconsistency();
5055c007436SBen Gras 		}
5065c007436SBen Gras 
5075c007436SBen Gras 		/*
5085c007436SBen Gras 		 * If there's an existing BYUID record for the new UID and
5095c007436SBen Gras 		 * the username doesn't match then be sure not to overwrite
5105c007436SBen Gras 		 * it.
5115c007436SBen Gras 		 */
5125c007436SBen Gras 		if (!getdbent(&sdb, _PW_KEYBYUID, &pwd.pw_uid, &tpwd))
5135c007436SBen Gras 			if (strcmp(username, tpwd->pw_name) != 0)
5145c007436SBen Gras 				uid_dbflg = R_NOOVERWRITE;
5155c007436SBen Gras 
5165c007436SBen Gras 		/* Write the database entries out */
5175c007436SBen Gras 		if (!secureonly)
5185c007436SBen Gras 			putdbents(&idb, &pwd, "*", flags, lineno, dbflg,
5195c007436SBen Gras 			    uid_dbflg);
5205c007436SBen Gras 		putdbents(&sdb, &pwd, pwd.pw_passwd, flags, lineno, dbflg,
5215c007436SBen Gras 		    uid_dbflg);
5225c007436SBen Gras 
5235c007436SBen Gras 		found = 1;
5245c007436SBen Gras 		if (!makeold)
5255c007436SBen Gras 			break;
5265c007436SBen Gras 	}
5275c007436SBen Gras 
5285c007436SBen Gras 	if (!secureonly) {
5295c007436SBen Gras 		/* Store YP token if needed. */
5305c007436SBen Gras 		if (hasyp)
5315c007436SBen Gras 			putyptoken(&idb);
5325c007436SBen Gras 
5335c007436SBen Gras 		/* Close the insecure database. */
5345c007436SBen Gras 		closedb(&idb);
5355c007436SBen Gras 	}
5365c007436SBen Gras 
5375c007436SBen Gras 	/*
5385c007436SBen Gras 	 * If rebuilding the databases, we re-parse the text file and write
5395c007436SBen Gras 	 * the secure entries out in a separate pass.
5405c007436SBen Gras 	 */
5415c007436SBen Gras 	if (username == NULL) {
5425c007436SBen Gras 		rewind(fp);
5435c007436SBen Gras 		for (lineno = 0; scan(fp, &pwd, &flags, &lineno);)
5445c007436SBen Gras 			putdbents(&sdb, &pwd, pwd.pw_passwd, flags,
5455c007436SBen Gras 			    lineno, dbflg, uid_dbflg);
5465c007436SBen Gras 
5475c007436SBen Gras 		/* Store YP token if needed. */
5485c007436SBen Gras 		if (hasyp)
5495c007436SBen Gras 			putyptoken(&sdb);
5505c007436SBen Gras 	} else if (!found) {
5515c007436SBen Gras 		mkpw_warning("user `%s' not found in password file", username);
5525c007436SBen Gras 		bailout();
5535c007436SBen Gras 	}
5545c007436SBen Gras 
5555c007436SBen Gras 	/* Close the secure database. */
5565c007436SBen Gras 	closedb(&sdb);
5575c007436SBen Gras 
5585c007436SBen Gras 	/* Install as the real password files. */
5595c007436SBen Gras 	if (!secureonly)
5605c007436SBen Gras 		install(idb.dbname, idb.fname);
5615c007436SBen Gras 	install(sdb.dbname, sdb.fname);
5625c007436SBen Gras 
5635c007436SBen Gras 	/* Install the V7 password file. */
5645c007436SBen Gras 	if (makeold) {
5655c007436SBen Gras 		if (fflush(oldfp) == EOF)
5665c007436SBen Gras 			wr_error(oldpwdfile);
5675c007436SBen Gras 		if (fclose(oldfp) == EOF)
5685c007436SBen Gras 			wr_error(oldpwdfile);
5695c007436SBen Gras 		install(oldpwdfile, _PATH_PASSWD);
5705c007436SBen Gras 	}
5715c007436SBen Gras 
5725c007436SBen Gras 	/* Set master.passwd permissions, in case caller forgot. */
5735c007436SBen Gras 	(void)fchmod(fileno(fp), S_IRUSR|S_IWUSR);
5745c007436SBen Gras 	if (fclose(fp) == EOF)
5755c007436SBen Gras 		wr_error(pname);
5765c007436SBen Gras 
5775c007436SBen Gras 	/*
5785c007436SBen Gras 	 * Move the temporary master password file LAST -- chpass(1),
5795c007436SBen Gras 	 * passwd(1), vipw(8) and friends all use its existence to block
5805c007436SBen Gras 	 * other incarnations of themselves.  The rename means that
5815c007436SBen Gras 	 * everything is unlocked, as the original file can no longer be
5825c007436SBen Gras 	 * accessed.
5835c007436SBen Gras 	 */
5845c007436SBen Gras 	install(pname, _PATH_MASTERPASSWD);
5855c007436SBen Gras 	exit(EXIT_SUCCESS);
5865c007436SBen Gras 	/* NOTREACHED */
5875c007436SBen Gras }
5885c007436SBen Gras 
5895c007436SBen Gras int
scan(FILE * fp,struct passwd * pw,int * flags,int * lineno)5905c007436SBen Gras scan(FILE *fp, struct passwd *pw, int *flags, int *lineno)
5915c007436SBen Gras {
5925c007436SBen Gras 	static char line[LINE_MAX];
5935c007436SBen Gras 	char *p;
5945c007436SBen Gras 	int oflags;
5955c007436SBen Gras 
5965c007436SBen Gras 	if (fgets(line, (int)sizeof(line), fp) == NULL)
5975c007436SBen Gras 		return (0);
5985c007436SBen Gras 	(*lineno)++;
5995c007436SBen Gras 
6005c007436SBen Gras 	/*
6015c007436SBen Gras 	 * ``... if I swallow anything evil, put your fingers down my
6025c007436SBen Gras 	 * throat...''
6035c007436SBen Gras 	 *	-- The Who
6045c007436SBen Gras 	 */
6055c007436SBen Gras 	if ((p = strchr(line, '\n')) == NULL) {
6065c007436SBen Gras 		errno = EFTYPE;	/* XXX */
6075c007436SBen Gras 		mkpw_error("%s, %d: line too long", pname, *lineno);
6085c007436SBen Gras 	}
6095c007436SBen Gras 	*p = '\0';
6105c007436SBen Gras 	if (strcmp(line, "+") == 0) {
6115c007436SBen Gras 		/* pw_scan() can't handle "+" */
6125c007436SBen Gras 		(void)strcpy(line, "+:::::::::");
6135c007436SBen Gras 	}
6145c007436SBen Gras 	oflags = 0;
6155c007436SBen Gras 	if (!pw_scan(line, pw, &oflags)) {
6165c007436SBen Gras 		errno = EFTYPE;	/* XXX */
6175c007436SBen Gras 		mkpw_error("%s, %d: Syntax mkpw_error", pname, *lineno);
6185c007436SBen Gras 	}
6195c007436SBen Gras 	*flags = oflags;
6205c007436SBen Gras 
6215c007436SBen Gras 	return (1);
6225c007436SBen Gras }
6235c007436SBen Gras 
6245c007436SBen Gras void
install(const char * from,const char * to)6255c007436SBen Gras install(const char *from, const char *to)
6265c007436SBen Gras {
6275c007436SBen Gras 	char buf[MAXPATHLEN];
6285c007436SBen Gras 
6295c007436SBen Gras 	(void)snprintf(buf, sizeof(buf), "%s%s", prefix, to);
6305c007436SBen Gras 	if (rename(from, buf))
6315c007436SBen Gras 		mkpw_error("Cannot rename `%s' to `%s'", from, buf);
6325c007436SBen Gras }
6335c007436SBen Gras 
6345c007436SBen Gras void
rm(const char * victim)6355c007436SBen Gras rm(const char *victim)
6365c007436SBen Gras {
6375c007436SBen Gras 
6385c007436SBen Gras 	if (unlink(victim) < 0)
6395c007436SBen Gras 		warn("unlink(%s)", victim);
6405c007436SBen Gras }
6415c007436SBen Gras 
6425c007436SBen Gras void
cp(const char * from,const char * to,mode_t mode)6435c007436SBen Gras cp(const char *from, const char *to, mode_t mode)
6445c007436SBen Gras {
6455c007436SBen Gras 	static char buf[MAXBSIZE];
6465c007436SBen Gras 	int from_fd, to_fd;
6475c007436SBen Gras 	ssize_t rcount, wcount;
6485c007436SBen Gras 
6495c007436SBen Gras 	if ((from_fd = open(from, O_RDONLY, 0)) < 0)
6505c007436SBen Gras 		mkpw_error("Cannot open `%s'", from);
6515c007436SBen Gras 	if ((to_fd = open(to, O_WRONLY | O_CREAT | O_EXCL, mode)) < 0) {
6525c007436SBen Gras 		(void)close(from_fd);
6535c007436SBen Gras 		mkpw_error("Cannot open `%s'", to);
6545c007436SBen Gras 	}
6555c007436SBen Gras 	while ((rcount = read(from_fd, buf, MAXBSIZE)) > 0) {
6565c007436SBen Gras 		wcount = write(to_fd, buf, (size_t)rcount);
6575c007436SBen Gras 		if (rcount != wcount || wcount == -1) {
6585c007436SBen Gras 			(void)close(from_fd);
6595c007436SBen Gras 			(void)close(to_fd);
6605c007436SBen Gras 			goto on_error;
6615c007436SBen Gras 		}
6625c007436SBen Gras 	}
6635c007436SBen Gras 
6645c007436SBen Gras 	close(from_fd);
6655c007436SBen Gras 	if (close(to_fd))
6665c007436SBen Gras 		goto on_error;
6675c007436SBen Gras 	if (rcount < 0)
6685c007436SBen Gras 		goto on_error;
6695c007436SBen Gras 	return;
6705c007436SBen Gras 
6715c007436SBen Gras on_error:
6725c007436SBen Gras 	mkpw_error("Cannot copy `%s' to `%s'", from, to);
6735c007436SBen Gras }
6745c007436SBen Gras 
6755c007436SBen Gras void
wr_error(const char * str)6765c007436SBen Gras wr_error(const char *str)
6775c007436SBen Gras {
6785c007436SBen Gras 	mkpw_error("Cannot write `%s'", str);
6795c007436SBen Gras }
6805c007436SBen Gras 
6815c007436SBen Gras void
mkpw_error(const char * fmt,...)6825c007436SBen Gras mkpw_error(const char *fmt, ...)
6835c007436SBen Gras {
6845c007436SBen Gras 	va_list ap;
6855c007436SBen Gras 	va_start(ap, fmt);
6865c007436SBen Gras 	if (logsyslog) {
6875c007436SBen Gras 		int sverrno = errno;
6885c007436SBen Gras 		char efmt[BUFSIZ];
6895c007436SBen Gras 		snprintf(efmt, sizeof(efmt), "%s (%%m)", fmt);
6905c007436SBen Gras 		errno = sverrno;
6915c007436SBen Gras 		vsyslog(LOG_ERR, efmt, ap);
6925c007436SBen Gras 	} else
6935c007436SBen Gras 		vwarn(fmt, ap);
6945c007436SBen Gras 	va_end(ap);
6955c007436SBen Gras 	bailout();
6965c007436SBen Gras }
6975c007436SBen Gras 
6985c007436SBen Gras void
mkpw_warning(const char * fmt,...)6995c007436SBen Gras mkpw_warning(const char *fmt, ...)
7005c007436SBen Gras {
7015c007436SBen Gras 	va_list ap;
7025c007436SBen Gras 	va_start(ap, fmt);
7035c007436SBen Gras 	if (logsyslog)
7045c007436SBen Gras 		vsyslog(LOG_WARNING, fmt, ap);
7055c007436SBen Gras 	else
7065c007436SBen Gras 		vwarnx(fmt, ap);
7075c007436SBen Gras 	va_end(ap);
7085c007436SBen Gras }
7095c007436SBen Gras 
7105c007436SBen Gras void
inconsistency(void)7115c007436SBen Gras inconsistency(void)
7125c007436SBen Gras {
7135c007436SBen Gras 
7145c007436SBen Gras 	mkpw_warning("text files and databases are inconsistent");
7155c007436SBen Gras 	mkpw_warning("re-build the databases without -u");
7165c007436SBen Gras 	bailout();
7175c007436SBen Gras }
7185c007436SBen Gras 
7195c007436SBen Gras void
bailout(void)7205c007436SBen Gras bailout(void)
7215c007436SBen Gras {
7225c007436SBen Gras 
7235c007436SBen Gras 	if ((clean & FILE_ORIG) != 0)
7245c007436SBen Gras 		rm(oldpwdfile);
7255c007436SBen Gras 	if ((clean & FILE_SECURE) != 0)
7265c007436SBen Gras 		rm(sdb.dbname);
7275c007436SBen Gras 	if ((clean & FILE_INSECURE) != 0)
7285c007436SBen Gras 		rm(idb.dbname);
7295c007436SBen Gras 
7305c007436SBen Gras 	exit(EXIT_FAILURE);
7315c007436SBen Gras }
7325c007436SBen Gras 
7335c007436SBen Gras uint32_t
getversion(const char * fname)7345c007436SBen Gras getversion(const char *fname)
7355c007436SBen Gras {
7365c007436SBen Gras 	DBT data, key;
7375c007436SBen Gras 	int ret;
7385c007436SBen Gras 	uint32_t version = 0;
7395c007436SBen Gras 	DB *db;
7405c007436SBen Gras 
7415c007436SBen Gras 	db = dbopen(fname, O_RDONLY, PERM_INSECURE, DB_HASH, NULL);
7425c007436SBen Gras 	if (db == NULL) {
7435c007436SBen Gras 		/* If we are building on a separate root, assume version 1 */
744*0a6a1f1dSLionel Sambuc 		if ((errno == EACCES && prefix[0]) || errno == ENOENT)
7455c007436SBen Gras 			return 1;
7465c007436SBen Gras 		mkpw_warning("Cannot open database `%s'", fname);
7475c007436SBen Gras 		bailout();
7485c007436SBen Gras 	}
7495c007436SBen Gras 	key.data = __UNCONST("VERSION");
7505c007436SBen Gras 	key.size = strlen((const char *)key.data) + 1;
7515c007436SBen Gras 
7525c007436SBen Gras 	switch (ret = (*db->get)(db, &key, &data, 0)) {
7535c007436SBen Gras 	case -1:	/* Error */
7545c007436SBen Gras 		mkpw_warning("Cannot get VERSION record from database `%s'",
7555c007436SBen Gras 		    fname);
7565c007436SBen Gras 		goto out;
7575c007436SBen Gras 	case 0:
7585c007436SBen Gras 		if (data.size != sizeof(version)) {
7595c007436SBen Gras 		    mkpw_warning("Bad VERSION record in database `%s'", fname);
7605c007436SBen Gras 		    goto out;
7615c007436SBen Gras 		}
7625c007436SBen Gras 		(void)memcpy(&version, data.data, sizeof(version));
7635c007436SBen Gras 		/*FALLTHROUGH*/
7645c007436SBen Gras 	case 1:
7655c007436SBen Gras 		if (ret == 1)
7665c007436SBen Gras 			mkpw_warning("Database `%s' has no version info",
7675c007436SBen Gras 			    fname);
7685c007436SBen Gras 		(*db->close)(db);
7695c007436SBen Gras 		return version;
7705c007436SBen Gras 	default:
7715c007436SBen Gras 		mkpw_warning("internal mkpw_error db->get returns %d", ret);
7725c007436SBen Gras 		goto out;
7735c007436SBen Gras 	}
7745c007436SBen Gras out:
7755c007436SBen Gras 	(*db->close)(db);
7765c007436SBen Gras 	bailout();
7775c007436SBen Gras 	/*NOTREACHED*/
7785c007436SBen Gras }
7795c007436SBen Gras 
7805c007436SBen Gras void
setversion(struct pwddb * db)7815c007436SBen Gras setversion(struct pwddb *db)
7825c007436SBen Gras {
7835c007436SBen Gras 	DBT data, key;
7845c007436SBen Gras 	key.data = __UNCONST("VERSION");
7855c007436SBen Gras 	key.size = strlen((const char *)key.data) + 1;
7865c007436SBen Gras 
7875c007436SBen Gras 	data.data = &db->wversion;
7885c007436SBen Gras 	data.size = sizeof(uint32_t);
7895c007436SBen Gras 
7905c007436SBen Gras 	if ((*db->db->put)(db->db, &key, &data, 0) != 0) {
7915c007436SBen Gras 		mkpw_warning("Can't write VERSION record to `%s'", db->dbname);
7925c007436SBen Gras 		bailout();
7935c007436SBen Gras 	}
7945c007436SBen Gras }
7955c007436SBen Gras 
7965c007436SBen Gras 
7975c007436SBen Gras /*
7985c007436SBen Gras  * Write entries to a database for a single user.
7995c007436SBen Gras  *
8005c007436SBen Gras  * The databases actually contain three copies of the original data.  Each
8015c007436SBen Gras  * password file entry is converted into a rough approximation of a ``struct
8025c007436SBen Gras  * passwd'', with the strings placed inline.  This object is then stored as
8035c007436SBen Gras  * the data for three separate keys.  The first key * is the pw_name field
8045c007436SBen Gras  * prepended by the _PW_KEYBYNAME character.  The second key is the pw_uid
8055c007436SBen Gras  * field prepended by the _PW_KEYBYUID character.  The third key is the line
8065c007436SBen Gras  * number in the original file prepended by the _PW_KEYBYNUM character.
8075c007436SBen Gras  * (The special characters are prepended to ensure that the keys do not
8085c007436SBen Gras  * collide.)
8095c007436SBen Gras  */
8105c007436SBen Gras #define	COMPACT(e)	for (t = e; (*p++ = *t++) != '\0';)
8115c007436SBen Gras 
8125c007436SBen Gras void
putdbents(struct pwddb * db,struct passwd * pw,const char * passwd,int flags,int lineno,u_int dbflg,u_int uid_dbflg)8135c007436SBen Gras putdbents(struct pwddb *db, struct passwd *pw, const char *passwd, int flags,
8145c007436SBen Gras       int lineno, u_int dbflg, u_int uid_dbflg)
8155c007436SBen Gras {
8165c007436SBen Gras 	struct passwd pwd;
8175c007436SBen Gras 	char buf[MAX(MAXPATHLEN, LINE_MAX * 2)], tbuf[1024], *p;
8185c007436SBen Gras 	DBT data, key;
8195c007436SBen Gras 	const char *t;
8205c007436SBen Gras 	u_int32_t x;
8215c007436SBen Gras 	size_t len;
8225c007436SBen Gras 
8235c007436SBen Gras 	(void)memcpy(&pwd, pw, sizeof(pwd));
8245c007436SBen Gras 	data.data = (u_char *)buf;
8255c007436SBen Gras 	key.data = (u_char *)tbuf;
8265c007436SBen Gras 
8275c007436SBen Gras 	if (lorder != BYTE_ORDER) {
8285c007436SBen Gras 		pwd.pw_uid = SWAP(pwd.pw_uid);
8295c007436SBen Gras 		pwd.pw_gid = SWAP(pwd.pw_gid);
8305c007436SBen Gras 	}
8315c007436SBen Gras 
8325c007436SBen Gras #define WRITEPWTIMEVAR(pwvar) \
8335c007436SBen Gras 	do { \
8345c007436SBen Gras 		if (db->wversion == 0 && \
8355c007436SBen Gras 		    /*CONSTCOND*/sizeof(pwvar) == sizeof(uint64_t)) { \
8365c007436SBen Gras 			uint32_t tmp = (uint32_t)pwvar; \
8375c007436SBen Gras 			if (lorder != BYTE_ORDER) \
8385c007436SBen Gras 				tmp = SWAP(tmp); \
8395c007436SBen Gras 			(void)memmove(p, &tmp, sizeof(tmp)); \
8405c007436SBen Gras 			p += sizeof(tmp); \
8415c007436SBen Gras 		} else if (db->wversion == 1 && \
8425c007436SBen Gras 		    /*CONSTCOND*/sizeof(pwvar) == sizeof(uint32_t)) { \
8435c007436SBen Gras 			uint64_t tmp = pwvar; \
8445c007436SBen Gras 			if (lorder != BYTE_ORDER) \
8455c007436SBen Gras 				tmp = SWAP(tmp); \
8465c007436SBen Gras 			(void)memmove(p, &tmp, sizeof(tmp)); \
8475c007436SBen Gras 			p += sizeof(tmp); \
8485c007436SBen Gras 		} else { \
8495c007436SBen Gras 			if (lorder != BYTE_ORDER) \
8505c007436SBen Gras 				pwvar = SWAP(pwvar); \
8515c007436SBen Gras 			(void)memmove(p, &pwvar, sizeof(pwvar)); \
8525c007436SBen Gras 			p += sizeof(pwvar); \
8535c007436SBen Gras 		} \
8545c007436SBen Gras 	} while (/*CONSTCOND*/0)
8555c007436SBen Gras 
8565c007436SBen Gras 	/* Create insecure data. */
8575c007436SBen Gras 	p = buf;
8585c007436SBen Gras 	COMPACT(pwd.pw_name);
8595c007436SBen Gras 	COMPACT(passwd);
8605c007436SBen Gras 	(void)memmove(p, &pwd.pw_uid, sizeof(pwd.pw_uid));
8615c007436SBen Gras 	p += sizeof(pwd.pw_uid);
8625c007436SBen Gras 	(void)memmove(p, &pwd.pw_gid, sizeof(pwd.pw_gid));
8635c007436SBen Gras 	p += sizeof(pwd.pw_gid);
8645c007436SBen Gras 	WRITEPWTIMEVAR(pwd.pw_change);
8655c007436SBen Gras 	COMPACT(pwd.pw_class);
8665c007436SBen Gras 	COMPACT(pwd.pw_gecos);
8675c007436SBen Gras 	COMPACT(pwd.pw_dir);
8685c007436SBen Gras 	COMPACT(pwd.pw_shell);
8695c007436SBen Gras 	WRITEPWTIMEVAR(pwd.pw_expire);
8705c007436SBen Gras 	x = flags;
8715c007436SBen Gras 	if (lorder != BYTE_ORDER)
8725c007436SBen Gras 		x = SWAP(x);
8735c007436SBen Gras 	(void)memmove(p, &x, sizeof(x));
8745c007436SBen Gras 	p += sizeof(x);
8755c007436SBen Gras 	data.size = p - buf;
8765c007436SBen Gras 
8775c007436SBen Gras 	/* Store insecure by name. */
8785c007436SBen Gras 	tbuf[0] = _PW_KEYBYNAME;
8795c007436SBen Gras 	len = strlen(pwd.pw_name);
8805c007436SBen Gras 	(void)memmove(tbuf + 1, pwd.pw_name, len);
8815c007436SBen Gras 	key.size = len + 1;
8825c007436SBen Gras 	if ((*db->db->put)(db->db, &key, &data, dbflg) == -1)
8835c007436SBen Gras 		wr_error(db->dbname);
8845c007436SBen Gras 
8855c007436SBen Gras 	/* Store insecure by number. */
8865c007436SBen Gras 	tbuf[0] = _PW_KEYBYNUM;
8875c007436SBen Gras 	x = lineno;
8885c007436SBen Gras 	if (lorder != BYTE_ORDER)
8895c007436SBen Gras 		x = SWAP(x);
8905c007436SBen Gras 	(void)memmove(tbuf + 1, &x, sizeof(x));
8915c007436SBen Gras 	key.size = sizeof(x) + 1;
8925c007436SBen Gras 	if ((*db->db->put)(db->db, &key, &data, dbflg) == -1)
8935c007436SBen Gras 		wr_error(db->dbname);
8945c007436SBen Gras 
8955c007436SBen Gras 	/* Store insecure by uid. */
8965c007436SBen Gras 	tbuf[0] = _PW_KEYBYUID;
8975c007436SBen Gras 	(void)memmove(tbuf + 1, &pwd.pw_uid, sizeof(pwd.pw_uid));
8985c007436SBen Gras 	key.size = sizeof(pwd.pw_uid) + 1;
8995c007436SBen Gras 	if ((*db->db->put)(db->db, &key, &data, uid_dbflg) == -1)
9005c007436SBen Gras 		wr_error(db->dbname);
9015c007436SBen Gras }
9025c007436SBen Gras 
9035c007436SBen Gras void
deldbent(struct pwddb * db,int type,void * keyp)9045c007436SBen Gras deldbent(struct pwddb *db, int type, void *keyp)
9055c007436SBen Gras {
9065c007436SBen Gras 	char tbuf[1024];
9075c007436SBen Gras 	DBT key;
9085c007436SBen Gras 	u_int32_t x;
9095c007436SBen Gras 	size_t len;
9105c007436SBen Gras 
9115c007436SBen Gras 	key.data = (u_char *)tbuf;
9125c007436SBen Gras 
9135c007436SBen Gras 	switch (tbuf[0] = type) {
9145c007436SBen Gras 	case _PW_KEYBYNAME:
9155c007436SBen Gras 		len = strlen((char *)keyp);
9165c007436SBen Gras 		(void)memcpy(tbuf + 1, keyp, len);
9175c007436SBen Gras 		key.size = len + 1;
9185c007436SBen Gras 		break;
9195c007436SBen Gras 
9205c007436SBen Gras 	case _PW_KEYBYNUM:
9215c007436SBen Gras 	case _PW_KEYBYUID:
9225c007436SBen Gras 		x = *(int *)keyp;
9235c007436SBen Gras 		if (lorder != BYTE_ORDER)
9245c007436SBen Gras 			x = SWAP(x);
9255c007436SBen Gras 		(void)memmove(tbuf + 1, &x, sizeof(x));
9265c007436SBen Gras 		key.size = sizeof(x) + 1;
9275c007436SBen Gras 		break;
9285c007436SBen Gras 	}
9295c007436SBen Gras 
9305c007436SBen Gras 	if ((*db->db->del)(db->db, &key, 0) == -1)
9315c007436SBen Gras 		wr_error(db->dbname);
9325c007436SBen Gras }
9335c007436SBen Gras 
9345c007436SBen Gras int
getdbent(struct pwddb * db,int type,void * keyp,struct passwd ** tpwd)9355c007436SBen Gras getdbent(struct pwddb *db, int type, void *keyp, struct passwd **tpwd)
9365c007436SBen Gras {
9375c007436SBen Gras 	static char buf[MAX(MAXPATHLEN, LINE_MAX * 2)];
9385c007436SBen Gras 	static struct passwd pwd;
9395c007436SBen Gras 	char tbuf[1024], *p;
9405c007436SBen Gras 	DBT key, data;
9415c007436SBen Gras 	u_int32_t x;
9425c007436SBen Gras 	size_t len;
9435c007436SBen Gras 	int rv;
9445c007436SBen Gras 
9455c007436SBen Gras 	data.data = (u_char *)buf;
9465c007436SBen Gras 	data.size = sizeof(buf);
9475c007436SBen Gras 	key.data = (u_char *)tbuf;
9485c007436SBen Gras 
9495c007436SBen Gras 	switch (tbuf[0] = type) {
9505c007436SBen Gras 	case _PW_KEYBYNAME:
9515c007436SBen Gras 		len = strlen((char *)keyp);
9525c007436SBen Gras 		(void)memcpy(tbuf + 1, keyp, len);
9535c007436SBen Gras 		key.size = len + 1;
9545c007436SBen Gras 		break;
9555c007436SBen Gras 
9565c007436SBen Gras 	case _PW_KEYBYNUM:
9575c007436SBen Gras 	case _PW_KEYBYUID:
9585c007436SBen Gras 		x = *(int *)keyp;
9595c007436SBen Gras 		if (lorder != BYTE_ORDER)
9605c007436SBen Gras 			x = SWAP(x);
9615c007436SBen Gras 		(void)memmove(tbuf + 1, &x, sizeof(x));
9625c007436SBen Gras 		key.size = sizeof(x) + 1;
9635c007436SBen Gras 		break;
9645c007436SBen Gras 	}
9655c007436SBen Gras 
9665c007436SBen Gras 	if ((rv = (*db->db->get)(db->db, &key, &data, 0)) == 1)
9675c007436SBen Gras 		return (rv);
9685c007436SBen Gras 	if (rv == -1)
9695c007436SBen Gras 		mkpw_error("Error getting record from `%s'", db->dbname);
9705c007436SBen Gras 
9715c007436SBen Gras 	p = (char *)data.data;
9725c007436SBen Gras 
9735c007436SBen Gras 	pwd.pw_name = p;
9745c007436SBen Gras 	while (*p++ != '\0')
9755c007436SBen Gras 		continue;
9765c007436SBen Gras 	pwd.pw_passwd = p;
9775c007436SBen Gras 	while (*p++ != '\0')
9785c007436SBen Gras 		continue;
9795c007436SBen Gras 
9805c007436SBen Gras 	(void)memcpy(&pwd.pw_uid, p, sizeof(pwd.pw_uid));
9815c007436SBen Gras 	p += sizeof(pwd.pw_uid);
9825c007436SBen Gras 	(void)memcpy(&pwd.pw_gid, p, sizeof(pwd.pw_gid));
9835c007436SBen Gras 	p += sizeof(pwd.pw_gid);
9845c007436SBen Gras 
9855c007436SBen Gras #define READPWTIMEVAR(pwvar) \
9865c007436SBen Gras 	do { \
9875c007436SBen Gras 		if (db->rversion == 0 && \
9885c007436SBen Gras 		    /*CONSTCOND*/sizeof(pwvar) == sizeof(uint64_t)) { \
9895c007436SBen Gras 			uint32_t tmp; \
9905c007436SBen Gras 			(void)memcpy(&tmp, p, sizeof(tmp)); \
9915c007436SBen Gras 			p += sizeof(tmp); \
9925c007436SBen Gras 			if (lorder != BYTE_ORDER) \
9935c007436SBen Gras 				pwvar = SWAP(tmp); \
9945c007436SBen Gras 			else \
9955c007436SBen Gras 				pwvar = tmp; \
9965c007436SBen Gras 		} else if (db->rversion == 1 && \
9975c007436SBen Gras 		    /*CONSTCOND*/sizeof(pwvar) == sizeof(uint32_t)) { \
9985c007436SBen Gras 			uint64_t tmp; \
9995c007436SBen Gras 			(void)memcpy(&tmp, p, sizeof(tmp)); \
10005c007436SBen Gras 			p += sizeof(tmp); \
10015c007436SBen Gras 			if (lorder != BYTE_ORDER) \
10025c007436SBen Gras 				pwvar = (uint32_t)SWAP(tmp); \
10035c007436SBen Gras 			else \
10045c007436SBen Gras 				pwvar = (uint32_t)tmp; \
10055c007436SBen Gras 		} else { \
10065c007436SBen Gras 			(void)memcpy(&pwvar, p, sizeof(pwvar)); \
10075c007436SBen Gras 			p += sizeof(pwvar); \
10085c007436SBen Gras 			if (lorder != BYTE_ORDER) \
10095c007436SBen Gras 				pwvar = SWAP(pwvar); \
10105c007436SBen Gras 		} \
10115c007436SBen Gras 	} while (/*CONSTCOND*/0)
10125c007436SBen Gras 
10135c007436SBen Gras 	READPWTIMEVAR(pwd.pw_change);
10145c007436SBen Gras 
10155c007436SBen Gras 	pwd.pw_class = p;
10165c007436SBen Gras 	while (*p++ != '\0')
10175c007436SBen Gras 		continue;
10185c007436SBen Gras 	pwd.pw_gecos = p;
10195c007436SBen Gras 	while (*p++ != '\0')
10205c007436SBen Gras 		continue;
10215c007436SBen Gras 	pwd.pw_dir = p;
10225c007436SBen Gras 	while (*p++ != '\0')
10235c007436SBen Gras 		continue;
10245c007436SBen Gras 	pwd.pw_shell = p;
10255c007436SBen Gras 	while (*p++ != '\0')
10265c007436SBen Gras 		continue;
10275c007436SBen Gras 
10285c007436SBen Gras 	READPWTIMEVAR(pwd.pw_expire);
10295c007436SBen Gras 
10305c007436SBen Gras 	if (lorder != BYTE_ORDER) {
10315c007436SBen Gras 		pwd.pw_uid = SWAP(pwd.pw_uid);
10325c007436SBen Gras 		pwd.pw_gid = SWAP(pwd.pw_gid);
10335c007436SBen Gras 	}
10345c007436SBen Gras 
10355c007436SBen Gras 	*tpwd = &pwd;
10365c007436SBen Gras 	return (0);
10375c007436SBen Gras }
10385c007436SBen Gras 
10395c007436SBen Gras void
putyptoken(struct pwddb * db)10405c007436SBen Gras putyptoken(struct pwddb *db)
10415c007436SBen Gras {
10425c007436SBen Gras 	DBT data, key;
10435c007436SBen Gras 
10445c007436SBen Gras 	key.data = __UNCONST(__yp_token);
10455c007436SBen Gras 	key.size = strlen(__yp_token);
104684d9c625SLionel Sambuc 	data.data = NULL;
10475c007436SBen Gras 	data.size = 0;
10485c007436SBen Gras 
10495c007436SBen Gras 	if ((*db->db->put)(db->db, &key, &data, R_NOOVERWRITE) == -1)
10505c007436SBen Gras 		wr_error(db->dbname);
10515c007436SBen Gras }
10525c007436SBen Gras 
10535c007436SBen Gras void
usage(void)10545c007436SBen Gras usage(void)
10555c007436SBen Gras {
10565c007436SBen Gras 
10575c007436SBen Gras 	(void)fprintf(stderr,
10585c007436SBen Gras 	    "Usage: %s [-BLlpsvw] [-c cachesize] [-d directory] [-u user] "
10595c007436SBen Gras 	    "[-V version] file\n",
10605c007436SBen Gras 	    getprogname());
10615c007436SBen Gras 	exit(EXIT_FAILURE);
10625c007436SBen Gras }
1063