pwd_mkdb.c revision 2934
1139804Simp/*-
222521Sdyson * Copyright (c) 1991, 1993, 1994
31541Srgrimes *	The Regents of the University of California.  All rights reserved.
41541Srgrimes *
522521Sdyson * Redistribution and use in source and binary forms, with or without
622521Sdyson * modification, are permitted provided that the following conditions
722521Sdyson * are met:
81541Srgrimes * 1. Redistributions of source code must retain the above copyright
91541Srgrimes *    notice, this list of conditions and the following disclaimer.
101541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111541Srgrimes *    notice, this list of conditions and the following disclaimer in the
121541Srgrimes *    documentation and/or other materials provided with the distribution.
131541Srgrimes * 3. All advertising materials mentioning features or use of this software
141541Srgrimes *    must display the following acknowledgement:
151541Srgrimes *	This product includes software developed by the University of
161541Srgrimes *	California, Berkeley and its contributors.
171541Srgrimes * 4. Neither the name of the University nor the names of its contributors
181541Srgrimes *    may be used to endorse or promote products derived from this software
191541Srgrimes *    without specific prior written permission.
201541Srgrimes *
211541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311541Srgrimes * SUCH DAMAGE.
3223521Sbde */
331541Srgrimes
341541Srgrimes#ifndef lint
35116182Sobrienstatic char copyright[] =
36116182Sobrien"@(#) Copyright (c) 1991, 1993, 1994\n\
37116182Sobrien	The Regents of the University of California.  All rights reserved.\n";
38190829Srwatson#endif /* not lint */
39190141Skib
40190141Skib#ifndef lint
411541Srgrimesstatic char sccsid[] = "@(#)pwd_mkdb.c	8.5 (Berkeley) 4/20/94";
42228433Savg#endif /* not lint */
43183155Sjhb
44183155Sjhb#include <sys/param.h>
4512820Sphk#include <sys/stat.h>
4676166Smarkm
47183155Sjhb#include <db.h>
48230129Smm#include <err.h>
49183155Sjhb#include <errno.h>
501541Srgrimes#include <fcntl.h>
51183155Sjhb#include <limits.h>
52187839Sjhb#include <pwd.h>
53190829Srwatson#include <signal.h>
54102870Siedowse#include <stdio.h>
55183155Sjhb#include <stdlib.h>
5651906Sphk#include <string.h>
57183155Sjhb#include <unistd.h>
58190141Skib
59190141Skib#include "pw_scan.h"
60190141Skib
611541Srgrimes#define	INSECURE	1
62116289Sdes#define	SECURE		2
63116289Sdes#define	PERM_INSECURE	(S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
64190829Srwatson#define	PERM_SECURE	(S_IRUSR|S_IWUSR)
65260817Savg
66190829SrwatsonHASHINFO openinfo = {
67260817Savg	4096,		/* bsize */
68190829Srwatson	32,		/* ffactor */
69260817Savg	256,		/* nelem */
70260817Savg	2048 * 1024,	/* cachesize */
71253075Savg	NULL,		/* hash() */
72260817Savg	0		/* lorder */
73260817Savg};
74253075Savg
75260817Savgstatic enum state { FILE_INSECURE, FILE_SECURE, FILE_ORIG } clean;
76190829Srwatsonstatic struct passwd pwd;			/* password structure */
77260817Savgstatic char *pname;				/* password file name */
78211616Srpaulostatic char prefix[MAXPATHLEN];
79260817Savg
80190829Srwatsonvoid	cleanup __P((void));
81260817Savgvoid	error __P((char *));
82260817Savgvoid	mv __P((char *, char *));
83260817Savgint	scan __P((FILE *, struct passwd *));
84260817Savgvoid	usage __P((void));
85190829Srwatson
86260817Savgint
87190829Srwatsonmain(argc, argv)
88190829Srwatson	int argc;
8951906Sphk	char *argv[];
9059652Sgreen{
9159652Sgreen	DB *dp, *edp;
9259652Sgreen	DBT data, key;
9359652Sgreen	FILE *fp, *oldfp;
9459652Sgreen	sigset_t set;
9560938Sjake	int ch, cnt, len, makeold, tfd, yp_enabled = 0;
9660938Sjake	char *p, *t;
9760938Sjake	char buf[MAX(MAXPATHLEN, LINE_MAX * 2)], tbuf[1024];
9859652Sgreen	char buf2[MAXPATHLEN];
9959652Sgreen
10059652Sgreen	strcpy(prefix, _PATH_PWD);
10159652Sgreen	makeold = 0;
102190829Srwatson	while ((ch = getopt(argc, argv, "d:pv")) != EOF)
10359652Sgreen		switch(ch) {
10459652Sgreen		case 'd':
10559652Sgreen			strcpy(prefix, optarg);
106230441Skib			break;
107230441Skib		case 'p':			/* create V7 "file.orig" */
108232420Srmacklem			makeold = 1;
109232420Srmacklem			break;
110232420Srmacklem		case 'v':                       /* backward compatible */
111232420Srmacklem			break;
112230441Skib		case '?':
113230441Skib		default:
114230441Skib			usage();
115230441Skib		}
116230441Skib	argc -= optind;
117230441Skib	argv += optind;
118230441Skib
119230441Skib	if (argc != 1)
120230441Skib		usage();
121230441Skib
122232420Srmacklem	/*
123230441Skib	 * This could be changed to allow the user to interrupt.
124230441Skib	 * Probably not worth the effort.
125230441Skib	 */
126230441Skib	sigemptyset(&set);
127230441Skib	sigaddset(&set, SIGTSTP);
128230441Skib	sigaddset(&set, SIGHUP);
129230441Skib	sigaddset(&set, SIGINT);
130230441Skib	sigaddset(&set, SIGQUIT);
131230441Skib	sigaddset(&set, SIGTERM);
132230441Skib	(void)sigprocmask(SIG_BLOCK, &set, (sigset_t *)NULL);
133232420Srmacklem
134230441Skib	/* We don't care what the user wants. */
135230441Skib	(void)umask(0);
1361541Srgrimes
1371541Srgrimes	pname = *argv;
1381541Srgrimes	/* Open the original password file */
1391541Srgrimes	if (!(fp = fopen(pname, "r")))
1401541Srgrimes		error(pname);
1411541Srgrimes
1421541Srgrimes	/* Open the temporary insecure password database. */
1431541Srgrimes	(void)snprintf(buf, sizeof(buf), "%s/%s.tmp", prefix, _MP_DB);
14422521Sdyson	dp = dbopen(buf,
14522521Sdyson	    O_RDWR|O_CREAT|O_EXCL, PERM_INSECURE, DB_HASH, &openinfo);
1466968Sphk	if (dp == NULL)
1471541Srgrimes		error(buf);
1481541Srgrimes	clean = FILE_INSECURE;
1491541Srgrimes
1501541Srgrimes	/*
1511541Srgrimes	 * Open file for old password file.  Minor trickiness -- don't want to
1521541Srgrimes	 * chance the file already existing, since someone (stupidly) might
153302234Sbdrewery	 * still be using this for permission checking.  So, open it first and
1541541Srgrimes	 * fdopen the resulting fd.  The resulting file should be readable by
15574501Speter	 * everyone.
15674501Speter	 */
15760938Sjake	if (makeold) {
15860938Sjake		(void)snprintf(buf, sizeof(buf), "%s.orig", pname);
15923521Sbde		if ((tfd = open(buf,
160213916Skib		    O_WRONLY|O_CREAT|O_EXCL, PERM_INSECURE)) < 0)
161213916Skib			error(buf);
16225453Sphk		if ((oldfp = fdopen(tfd, "w")) == NULL)
163213916Skib			error(buf);
164213916Skib		clean = FILE_ORIG;
165213916Skib	}
166213916Skib
167213916Skib	/*
16823521Sbde	 * The databases actually contain three copies of the original data.
169213916Skib	 * Each password file entry is converted into a rough approximation
170213916Skib	 * of a ``struct passwd'', with the strings placed inline.  This
17175654Stanimura	 * object is then stored as the data for three separate keys.  The
172213916Skib	 * first key * is the pw_name field prepended by the _PW_KEYBYNAME
173213916Skib	 * character.  The second key is the pw_uid field prepended by the
174213916Skib	 * _PW_KEYBYUID character.  The third key is the line number in the
175213916Skib	 * original file prepended by the _PW_KEYBYNUM character.  (The special
176213916Skib	 * characters are prepended to ensure that the keys do not collide.)
1771541Srgrimes	 */
178213916Skib	data.data = (u_char *)buf;
179213916Skib	key.data = (u_char *)tbuf;
180187839Sjhb	for (cnt = 1; scan(fp, &pwd); ++cnt) {
181187839Sjhb		if(pwd.pw_name[0] == '+') {
182120792Sjeff			if(pwd.pw_name[1] && !yp_enabled) {
183187839Sjhb				yp_enabled = 1;
184187839Sjhb			} else if(!pwd.pw_name[1]) {
185187839Sjhb				yp_enabled = -1;
186187839Sjhb			}
187187839Sjhb		}
188120792Sjeff#define	COMPACT(e)	t = e; while (*p++ = *t++);
189116289Sdes		/* Create insecure data. */
190116289Sdes		p = buf;
191116289Sdes		COMPACT(pwd.pw_name);
192116289Sdes		COMPACT("*");
193116289Sdes		memmove(p, &pwd.pw_uid, sizeof(int));
194116289Sdes		p += sizeof(int);
195116289Sdes		memmove(p, &pwd.pw_gid, sizeof(int));
196116289Sdes		p += sizeof(int);
197230441Skib		memmove(p, &pwd.pw_change, sizeof(time_t));
198116289Sdes		p += sizeof(time_t);
199232420Srmacklem		COMPACT(pwd.pw_class);
200116289Sdes		COMPACT(pwd.pw_gecos);
201190829Srwatson		COMPACT(pwd.pw_dir);
202116289Sdes		COMPACT(pwd.pw_shell);
203230441Skib		memmove(p, &pwd.pw_expire, sizeof(time_t));
204230441Skib		p += sizeof(time_t);
205230441Skib		memmove(p, &pwd.pw_fields, sizeof pwd.pw_fields);
206116289Sdes		p += sizeof pwd.pw_fields;
207232420Srmacklem		data.size = p - buf;
208232420Srmacklem
209232420Srmacklem		/* Store insecure by name. */
210232420Srmacklem		tbuf[0] = _PW_KEYBYNAME;
211232420Srmacklem		len = strlen(pwd.pw_name);
212232420Srmacklem		memmove(tbuf + 1, pwd.pw_name, len);
213230441Skib		key.size = len + 1;
214230441Skib		if ((dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1)
215230441Skib			error("put");
216230441Skib
217230441Skib		/* Store insecure by number. */
218230441Skib		tbuf[0] = _PW_KEYBYNUM;
219230441Skib		memmove(tbuf + 1, &cnt, sizeof(cnt));
220230441Skib		key.size = sizeof(cnt) + 1;
221230441Skib		if ((dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1)
222230441Skib			error("put");
223230441Skib
224230441Skib		/* Store insecure by uid. */
225230441Skib		tbuf[0] = _PW_KEYBYUID;
226230441Skib		memmove(tbuf + 1, &pwd.pw_uid, sizeof(pwd.pw_uid));
227230441Skib		key.size = sizeof(pwd.pw_uid) + 1;
228230441Skib		if ((dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1)
229230441Skib			error("put");
230230441Skib
231230441Skib		/* Create original format password file entry */
232232420Srmacklem		if (makeold)
233232420Srmacklem			(void)fprintf(oldfp, "%s:*:%d:%d:%s:%s:%s\n",
234232420Srmacklem			    pwd.pw_name, pwd.pw_uid, pwd.pw_gid, pwd.pw_gecos,
235230441Skib			    pwd.pw_dir, pwd.pw_shell);
236230441Skib	}
237230441Skib	/* If YP enabled, set flag. */
238230441Skib	if(yp_enabled) {
239230441Skib		buf[0] = yp_enabled + 2;
240230441Skib		data.size = 1;
241230441Skib		tbuf[0] = _PW_KEYYPENABLED;
242230441Skib		key.size = 1;
243230441Skib		if ((dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1)
244230441Skib			error("put");
245230441Skib	}
246230441Skib
247230441Skib	(void)(dp->close)(dp);
248230441Skib	if (makeold) {
249230489Skib		(void)fflush(oldfp);
250230489Skib		(void)fclose(oldfp);
251230489Skib	}
252230489Skib
253230552Skib	/* Open the temporary encrypted password database. */
254230552Skib	(void)snprintf(buf, sizeof(buf), "%s/%s.tmp", prefix, _SMP_DB);
255230552Skib	edp = dbopen(buf,
256230489Skib	    O_RDWR|O_CREAT|O_EXCL, PERM_SECURE, DB_HASH, &openinfo);
257230489Skib	if (!edp)
258230489Skib		error(buf);
259230489Skib	clean = FILE_SECURE;
260230489Skib
261230489Skib	rewind(fp);
262230489Skib	for (cnt = 1; scan(fp, &pwd); ++cnt) {
26323521Sbde
264213916Skib		/* Create secure data. */
265213916Skib		p = buf;
26691690Seivind		COMPACT(pwd.pw_name);
26791690Seivind		COMPACT(pwd.pw_passwd);
268273736Shselasky		memmove(p, &pwd.pw_uid, sizeof(int));
269215304Sbrucec		p += sizeof(int);
27023521Sbde		memmove(p, &pwd.pw_gid, sizeof(int));
27129788Sphk		p += sizeof(int);
27229788Sphk		memmove(p, &pwd.pw_change, sizeof(time_t));
27329788Sphk		p += sizeof(time_t);
274215283Sbrucec		COMPACT(pwd.pw_class);
275215304Sbrucec		COMPACT(pwd.pw_gecos);
276215281Sbrucec		COMPACT(pwd.pw_dir);
277215281Sbrucec		COMPACT(pwd.pw_shell);
278215281Sbrucec		memmove(p, &pwd.pw_expire, sizeof(time_t));
279215281Sbrucec		p += sizeof(time_t);
280215283Sbrucec		memmove(p, &pwd.pw_fields, sizeof pwd.pw_fields);
281215304Sbrucec		p += sizeof pwd.pw_fields;
282215283Sbrucec		data.size = p - buf;
283215304Sbrucec
284215283Sbrucec		/* Store secure by name. */
285215304Sbrucec		tbuf[0] = _PW_KEYBYNAME;
286215283Sbrucec		len = strlen(pwd.pw_name);
287215304Sbrucec		memmove(tbuf + 1, pwd.pw_name, len);
288215283Sbrucec		key.size = len + 1;
289215304Sbrucec		if ((dp->put)(edp, &key, &data, R_NOOVERWRITE) == -1)
290215283Sbrucec			error("put");
291215304Sbrucec
292320756Smjg		/* Store secure by number. */
293215304Sbrucec		tbuf[0] = _PW_KEYBYNUM;
294215283Sbrucec		memmove(tbuf + 1, &cnt, sizeof(cnt));
295215304Sbrucec		key.size = sizeof(cnt) + 1;
296215283Sbrucec		if ((dp->put)(edp, &key, &data, R_NOOVERWRITE) == -1)
297215304Sbrucec			error("put");
298215283Sbrucec
299215304Sbrucec		/* Store secure by uid. */
300215283Sbrucec		tbuf[0] = _PW_KEYBYUID;
301215304Sbrucec		memmove(tbuf + 1, &pwd.pw_uid, sizeof(pwd.pw_uid));
30229788Sphk		key.size = sizeof(pwd.pw_uid) + 1;
303187658Sjhb		if ((dp->put)(edp, &key, &data, R_NOOVERWRITE) == -1)
304215304Sbrucec			error("put");
305215304Sbrucec	}
30629788Sphk	/* If YP enabled, set flag. */
307140712Sjeff	if(yp_enabled) {
308194601Skib		buf[0] = yp_enabled + 2;
309194601Skib		data.size = 1;
310144318Sdas		tbuf[0] = _PW_KEYYPENABLED;
311144318Sdas		key.size = 1;
3126968Sphk		if ((dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1)
31369774Sphk			error("put");
31451906Sphk	}
315189593Sjhb
31625453Sphk	(void)(edp->close)(edp);
31775402Speter
31875402Speter	/* Set master.passwd permissions, in case caller forgot. */
319227309Sed	(void)fchmod(fileno(fp), S_IRUSR|S_IWUSR);
320227309Sed	(void)fclose(fp);
32175402Speter
32275402Speter	/* Install as the real password files. */
32375402Speter	(void)snprintf(buf, sizeof(buf), "%s/%s.tmp", prefix, _MP_DB);
32475402Speter	(void)snprintf(buf2, sizeof(buf2), "%s/%s", prefix, _MP_DB);
32575402Speter	mv(buf, buf2);
32675402Speter	(void)snprintf(buf, sizeof(buf), "%s/%s.tmp", prefix, _SMP_DB);
327289418Spho	(void)snprintf(buf2, sizeof(buf2), "%s/%s", prefix, _SMP_DB);
32875402Speter	mv(buf, buf2);
329288079Smckusick	if (makeold) {
33075402Speter		(void)snprintf(buf2, sizeof(buf2), "%s/%s", prefix, _PASSWD);
33175402Speter		(void)snprintf(buf, sizeof(buf), "%s.orig", pname);
33275402Speter		mv(buf, buf2);
333288079Smckusick	}
334288079Smckusick	/*
335288079Smckusick	 * Move the master password LAST -- chpass(1), passwd(1) and vipw(8)
336187839Sjhb	 * all use flock(2) on it to block other incarnations of themselves.
337288079Smckusick	 * The rename means that everything is unlocked, as the original file
338288079Smckusick	 * can no longer be accessed.
33975402Speter	 */
340288079Smckusick	(void)snprintf(buf, sizeof(buf), "%s/%s", prefix, _MASTERPASSWD);
341288079Smckusick	mv(pname, buf);
342288079Smckusick	exit(0);
343288079Smckusick}
344288079Smckusick
345288079Smckusickint
346288079Smckusickscan(fp, pw)
347288079Smckusick	FILE *fp;
348288079Smckusick	struct passwd *pw;
349288079Smckusick{
35075402Speter	static int lcnt;
351187658Sjhb	static char line[LINE_MAX];
352215304Sbrucec	char *p;
353215304Sbrucec
35475402Speter	if (!fgets(line, sizeof(line), fp))
35575402Speter		return (0);
35675402Speter	++lcnt;
35775402Speter	/*
35875402Speter	 * ``... if I swallow anything evil, put your fingers down my
35975402Speter	 * throat...''
36075402Speter	 *	-- The Who
36175402Speter	 */
36275402Speter	if (!(p = strchr(line, '\n'))) {
36375402Speter		warnx("line too long");
36475402Speter		goto fmt;
36575402Speter
36675402Speter	}
36775402Speter	*p = '\0';
36875402Speter	if (!pw_scan(line, pw)) {
36975402Speter		warnx("at line #%d", lcnt);
37075402Speterfmt:		errno = EFTYPE;	/* XXX */
37175402Speter		error(pname);
37275402Speter	}
37375402Speter
374187839Sjhb	return (1);
37575402Speter}
37675402Speter
37775402Spetervoid
378187839Sjhbmv(from, to)
37975402Speter	char *from, *to;
38075402Speter{
38175402Speter	char buf[MAXPATHLEN];
38275402Speter
38375402Speter	if (rename(from, to)) {
38475402Speter		int sverrno = errno;
385232156Smaxim		(void)snprintf(buf, sizeof(buf), "%s to %s", from, to);
38698994Salfred		errno = sverrno;
38775402Speter		error(buf);
38875402Speter	}
38998994Salfred}
39075402Speter
39175402Spetervoid
39298994Salfrederror(name)
39375402Speter	char *name;
39475402Speter{
39598994Salfred
39675402Speter	warn(name);
39775402Speter	cleanup();
39875402Speter	exit(1);
39975402Speter}
400187658Sjhb
401215304Sbrucecvoid
402232156Smaximcleanup()
403189593Sjhb{
40475402Speter	char buf[MAXPATHLEN];
40575402Speter
406110952Sarr	switch(clean) {
407110952Sarr	case FILE_ORIG:
408110952Sarr		(void)snprintf(buf, sizeof(buf), "%s.orig", pname);
409110952Sarr		(void)unlink(buf);
41022521Sdyson		/* FALLTHROUGH */
41125453Sphk	case FILE_SECURE:
412320756Smjg		(void)snprintf(buf, sizeof(buf), "%s/%s.tmp", prefix, _SMP_DB);
41325453Sphk		(void)unlink(buf);
414120792Sjeff		/* FALLTHROUGH */
415120792Sjeff	case FILE_INSECURE:
416187839Sjhb		(void)snprintf(buf, sizeof(buf), "%s/%s.tmp", prefix, _MP_DB);
417147326Sjeff		(void)unlink(buf);
418190829Srwatson	}
419289798Savg}
420289798Savg
421190829Srwatsonvoid
422289798Savgusage()
423289798Savg{
424190829Srwatson
425120792Sjeff	(void)fprintf(stderr, "usage: pwd_mkdb [-p] [-d <dest dir>] file\n");
42625453Sphk	exit(1);
427190533Skan}
428190533Skan