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