1/*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright (c) 1991, 1993, 1994
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#if 0
33#ifndef lint
34static const char copyright[] =
35"@(#) Copyright (c) 1991, 1993, 1994\n\
36	The Regents of the University of California.  All rights reserved.\n";
37#endif /* not lint */
38
39#ifndef lint
40static char sccsid[] = "@(#)pwd_mkdb.c	8.5 (Berkeley) 4/20/94";
41#endif /* not lint */
42#endif
43
44#include <sys/cdefs.h>
45__FBSDID("$FreeBSD$");
46
47#include <sys/param.h>
48#include <sys/endian.h>
49#include <sys/stat.h>
50#include <arpa/inet.h>
51
52#include <db.h>
53#include <err.h>
54#include <errno.h>
55#include <fcntl.h>
56#include <libgen.h>
57#include <limits.h>
58#include <pwd.h>
59#include <signal.h>
60#include <stdio.h>
61#include <stdlib.h>
62#include <string.h>
63#include <unistd.h>
64
65#include "pw_scan.h"
66
67#define	INSECURE	1
68#define	SECURE		2
69#define	PERM_INSECURE	(S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
70#define	PERM_SECURE	(S_IRUSR|S_IWUSR)
71#define LEGACY_VERSION(x)  _PW_VERSIONED(x, 3)
72#define CURRENT_VERSION(x) _PW_VERSIONED(x, 4)
73
74static HASHINFO openinfo = {
75	4096,		/* bsize */
76	32,		/* ffactor */
77	256,		/* nelem */
78	2048 * 1024,	/* cachesize */
79	NULL,		/* hash() */
80	BIG_ENDIAN	/* lorder */
81};
82
83static enum state { FILE_INSECURE, FILE_SECURE, FILE_ORIG } clean;
84static struct passwd pwd;			/* password structure */
85static char *pname;				/* password file name */
86static char prefix[MAXPATHLEN];
87
88static int is_comment;	/* flag for comments */
89static char line[LINE_MAX];
90
91void	cleanup(void);
92void	error(const char *);
93void	cp(char *, char *, mode_t mode);
94void	mv(char *, char *);
95int	scan(FILE *, struct passwd *);
96static void	usage(void);
97
98int
99main(int argc, char *argv[])
100{
101	static char verskey[] = _PWD_VERSION_KEY;
102	char version = _PWD_CURRENT_VERSION;
103	DB *dp, *sdp, *pw_db;
104	DBT data, sdata, key;
105	FILE *fp, *oldfp;
106	sigset_t set;
107	int ch, cnt, ypcnt, makeold, tfd, yp_enabled = 0;
108	unsigned int len;
109	uint32_t store;
110	const char *t;
111	char *p;
112	char buf[MAX(MAXPATHLEN, LINE_MAX * 2)], tbuf[1024];
113	char sbuf[MAX(MAXPATHLEN, LINE_MAX * 2)];
114	char buf2[MAXPATHLEN];
115	char sbuf2[MAXPATHLEN];
116	char *username;
117	u_int method, methoduid;
118	int Cflag, dflag, iflag;
119	int nblock = 0;
120
121	iflag = dflag = Cflag = 0;
122	strcpy(prefix, _PATH_PWD);
123	makeold = 0;
124	username = NULL;
125	oldfp = NULL;
126	while ((ch = getopt(argc, argv, "BCLNd:ips:u:v")) != -1)
127		switch(ch) {
128		case 'B':			/* big-endian output */
129			warnx("endiannes options (-B/-L) are deprecated");
130			openinfo.lorder = BIG_ENDIAN;
131			break;
132		case 'C':                       /* verify only */
133			Cflag = 1;
134			break;
135		case 'L':			/* little-endian output */
136			warnx("endiannes options (-B/-L) are deprecated");
137			openinfo.lorder = LITTLE_ENDIAN;
138			break;
139		case 'N':			/* do not wait for lock	*/
140			nblock = LOCK_NB;	/* will fail if locked */
141			break;
142		case 'd':
143			dflag++;
144			strlcpy(prefix, optarg, sizeof(prefix));
145			break;
146		case 'i':
147			iflag++;
148			break;
149		case 'p':			/* create V7 "file.orig" */
150			makeold = 1;
151			break;
152		case 's':			/* change default cachesize */
153			openinfo.cachesize = atoi(optarg) * 1024 * 1024;
154			break;
155		case 'u':			/* only update this record */
156			username = optarg;
157			break;
158		case 'v':                       /* backward compatible */
159			break;
160		default:
161			usage();
162		}
163	argc -= optind;
164	argv += optind;
165
166	if (argc != 1 || (username && (*username == '+' || *username == '-')))
167		usage();
168
169	/*
170	 * This could be changed to allow the user to interrupt.
171	 * Probably not worth the effort.
172	 */
173	sigemptyset(&set);
174	sigaddset(&set, SIGTSTP);
175	sigaddset(&set, SIGHUP);
176	sigaddset(&set, SIGINT);
177	sigaddset(&set, SIGQUIT);
178	sigaddset(&set, SIGTERM);
179	(void)sigprocmask(SIG_BLOCK, &set, (sigset_t *)NULL);
180
181	/* We don't care what the user wants. */
182	(void)umask(0);
183
184	pname = *argv;
185
186	/*
187	 * Open and lock the original password file.  We have to check
188	 * the hardlink count after we get the lock to handle any potential
189	 * unlink/rename race.
190	 *
191	 * This lock is necessary when someone runs pwd_mkdb manually, directly
192	 * on master.passwd, to handle the case where a user might try to
193	 * change his password while pwd_mkdb is running.
194	 */
195	for (;;) {
196		struct stat st;
197
198		if (!(fp = fopen(pname, "r")))
199			error(pname);
200		if (flock(fileno(fp), LOCK_EX|nblock) < 0 && !(dflag && iflag))
201			error("flock");
202		if (fstat(fileno(fp), &st) < 0)
203			error(pname);
204		if (st.st_nlink != 0)
205			break;
206		fclose(fp);
207		fp = NULL;
208	}
209
210	/* check only if password database is valid */
211	if (Cflag) {
212		while (scan(fp, &pwd))
213			if (!is_comment && strlen(pwd.pw_name) >= MAXLOGNAME) {
214				warnx("%s: username too long", pwd.pw_name);
215				exit(1);
216			}
217		exit(0);
218	}
219
220	/* Open the temporary insecure password database. */
221	(void)snprintf(buf, sizeof(buf), "%s/%s.tmp", prefix, _MP_DB);
222	(void)snprintf(sbuf, sizeof(sbuf), "%s/%s.tmp", prefix, _SMP_DB);
223	if (username) {
224		int use_version;
225
226		(void)snprintf(buf2, sizeof(buf2), "%s/%s", prefix, _MP_DB);
227		(void)snprintf(sbuf2, sizeof(sbuf2), "%s/%s", prefix, _SMP_DB);
228
229		clean = FILE_INSECURE;
230		cp(buf2, buf, PERM_INSECURE);
231		dp = dbopen(buf,
232		    O_RDWR|O_EXCL, PERM_INSECURE, DB_HASH, &openinfo);
233		if (dp == NULL)
234			error(buf);
235
236		clean = FILE_SECURE;
237		cp(sbuf2, sbuf, PERM_SECURE);
238		sdp = dbopen(sbuf,
239		    O_RDWR|O_EXCL, PERM_SECURE, DB_HASH, &openinfo);
240		if (sdp == NULL)
241			error(sbuf);
242
243		/*
244		 * Do some trouble to check if we should store this users
245		 * uid. Don't use getpwnam/getpwuid as that interferes
246		 * with NIS.
247		 */
248		pw_db = dbopen(_PATH_MP_DB, O_RDONLY, 0, DB_HASH, NULL);
249		if (!pw_db)
250			error(_MP_DB);
251
252		key.data = verskey;
253		key.size = sizeof(verskey)-1;
254		if ((pw_db->get)(pw_db, &key, &data, 0) == 0)
255			use_version = *(unsigned char *)data.data;
256		else
257			use_version = 3;
258		buf[0] = _PW_VERSIONED(_PW_KEYBYNAME, use_version);
259		len = strlen(username);
260
261		/* Only check that username fits in buffer */
262		memmove(buf + 1, username, MIN(len, sizeof(buf) - 1));
263		key.data = (u_char *)buf;
264		key.size = len + 1;
265		if ((pw_db->get)(pw_db, &key, &data, 0) == 0) {
266			p = (char *)data.data;
267
268			/* jump over pw_name and pw_passwd, to get to pw_uid */
269			while (*p++)
270				;
271			while (*p++)
272				;
273
274			buf[0] = _PW_VERSIONED(_PW_KEYBYUID, use_version);
275			memmove(buf + 1, p, sizeof(store));
276			key.data = (u_char *)buf;
277			key.size = sizeof(store) + 1;
278
279			if ((pw_db->get)(pw_db, &key, &data, 0) == 0) {
280				/* First field of data.data holds pw_pwname */
281				if (!strcmp(data.data, username))
282					methoduid = 0;
283				else
284					methoduid = R_NOOVERWRITE;
285			} else {
286				methoduid = R_NOOVERWRITE;
287			}
288		} else {
289			methoduid = R_NOOVERWRITE;
290		}
291		if ((pw_db->close)(pw_db))
292			error("close pw_db");
293		method = 0;
294	} else {
295		dp = dbopen(buf,
296		    O_RDWR|O_CREAT|O_EXCL, PERM_INSECURE, DB_HASH, &openinfo);
297		if (dp == NULL)
298			error(buf);
299		clean = FILE_INSECURE;
300
301		sdp = dbopen(sbuf,
302		    O_RDWR|O_CREAT|O_EXCL, PERM_SECURE, DB_HASH, &openinfo);
303		if (sdp == NULL)
304			error(sbuf);
305		clean = FILE_SECURE;
306
307		method = R_NOOVERWRITE;
308		methoduid = R_NOOVERWRITE;
309	}
310
311	/*
312	 * Open file for old password file.  Minor trickiness -- don't want to
313	 * chance the file already existing, since someone (stupidly) might
314	 * still be using this for permission checking.  So, open it first and
315	 * fdopen the resulting fd.  The resulting file should be readable by
316	 * everyone.
317	 */
318	if (makeold) {
319		(void)snprintf(buf, sizeof(buf), "%s.orig", pname);
320		if ((tfd = open(buf,
321		    O_WRONLY|O_CREAT|O_EXCL, PERM_INSECURE)) < 0)
322			error(buf);
323		if ((oldfp = fdopen(tfd, "w")) == NULL)
324			error(buf);
325		clean = FILE_ORIG;
326	}
327
328	/*
329	 * The databases actually contain three copies of the original data.
330	 * Each password file entry is converted into a rough approximation
331	 * of a ``struct passwd'', with the strings placed inline.  This
332	 * object is then stored as the data for three separate keys.  The
333	 * first key * is the pw_name field prepended by the _PW_KEYBYNAME
334	 * character.  The second key is the pw_uid field prepended by the
335	 * _PW_KEYBYUID character.  The third key is the line number in the
336	 * original file prepended by the _PW_KEYBYNUM character.  (The special
337	 * characters are prepended to ensure that the keys do not collide.)
338	 */
339	/* In order to transition this file into a machine-independent
340	 * form, we have to change the format of entries.  However, since
341	 * older binaries will still expect the old MD format entries, we
342	 * create those as usual and use versioned tags for the new entries.
343	 */
344	if (username == NULL) {
345		/* Do not add the VERSION tag when updating a single
346		 * user.  When operating on `old format' databases, this
347		 * would result in applications `seeing' only the updated
348		 * entries.
349		 */
350		key.data = verskey;
351		key.size = sizeof(verskey)-1;
352		data.data = &version;
353		data.size = 1;
354		if ((dp->put)(dp, &key, &data, 0) == -1)
355			error("put");
356		if ((sdp->put)(sdp, &key, &data, 0) == -1)
357			error("put");
358	}
359	ypcnt = 0;
360	data.data = (u_char *)buf;
361	sdata.data = (u_char *)sbuf;
362	key.data = (u_char *)tbuf;
363	for (cnt = 1; scan(fp, &pwd); ++cnt) {
364		if (!is_comment &&
365		    (pwd.pw_name[0] == '+' || pwd.pw_name[0] == '-')) {
366			yp_enabled = 1;
367			ypcnt++;
368		}
369		if (is_comment)
370			--cnt;
371#define	COMPACT(e)	t = e; while ((*p++ = *t++));
372#define SCALAR(e)	store = htonl((uint32_t)(e));      \
373			memmove(p, &store, sizeof(store)); \
374			p += sizeof(store);
375#define	LSCALAR(e)	store = HTOL((uint32_t)(e));       \
376			memmove(p, &store, sizeof(store)); \
377			p += sizeof(store);
378#define	HTOL(e)		(openinfo.lorder == BYTE_ORDER ? \
379			(uint32_t)(e) : \
380			bswap32((uint32_t)(e)))
381		if (!is_comment &&
382		    (!username || (strcmp(username, pwd.pw_name) == 0))) {
383			/* Create insecure data. */
384			p = buf;
385			COMPACT(pwd.pw_name);
386			COMPACT("*");
387			SCALAR(pwd.pw_uid);
388			SCALAR(pwd.pw_gid);
389			SCALAR(pwd.pw_change);
390			COMPACT(pwd.pw_class);
391			COMPACT(pwd.pw_gecos);
392			COMPACT(pwd.pw_dir);
393			COMPACT(pwd.pw_shell);
394			SCALAR(pwd.pw_expire);
395			SCALAR(pwd.pw_fields);
396			data.size = p - buf;
397
398			/* Create secure data. */
399			p = sbuf;
400			COMPACT(pwd.pw_name);
401			COMPACT(pwd.pw_passwd);
402			SCALAR(pwd.pw_uid);
403			SCALAR(pwd.pw_gid);
404			SCALAR(pwd.pw_change);
405			COMPACT(pwd.pw_class);
406			COMPACT(pwd.pw_gecos);
407			COMPACT(pwd.pw_dir);
408			COMPACT(pwd.pw_shell);
409			SCALAR(pwd.pw_expire);
410			SCALAR(pwd.pw_fields);
411			sdata.size = p - sbuf;
412
413			/* Store insecure by name. */
414			tbuf[0] = CURRENT_VERSION(_PW_KEYBYNAME);
415			len = strlen(pwd.pw_name);
416			memmove(tbuf + 1, pwd.pw_name, len);
417			key.size = len + 1;
418			if ((dp->put)(dp, &key, &data, method) == -1)
419				error("put");
420
421			/* Store insecure by number. */
422			tbuf[0] = CURRENT_VERSION(_PW_KEYBYNUM);
423			store = htonl(cnt);
424			memmove(tbuf + 1, &store, sizeof(store));
425			key.size = sizeof(store) + 1;
426			if ((dp->put)(dp, &key, &data, method) == -1)
427				error("put");
428
429			/* Store insecure by uid. */
430			tbuf[0] = CURRENT_VERSION(_PW_KEYBYUID);
431			store = htonl(pwd.pw_uid);
432			memmove(tbuf + 1, &store, sizeof(store));
433			key.size = sizeof(store) + 1;
434			if ((dp->put)(dp, &key, &data, methoduid) == -1)
435				error("put");
436
437			/* Store secure by name. */
438			tbuf[0] = CURRENT_VERSION(_PW_KEYBYNAME);
439			len = strlen(pwd.pw_name);
440			memmove(tbuf + 1, pwd.pw_name, len);
441			key.size = len + 1;
442			if ((sdp->put)(sdp, &key, &sdata, method) == -1)
443				error("put");
444
445			/* Store secure by number. */
446			tbuf[0] = CURRENT_VERSION(_PW_KEYBYNUM);
447			store = htonl(cnt);
448			memmove(tbuf + 1, &store, sizeof(store));
449			key.size = sizeof(store) + 1;
450			if ((sdp->put)(sdp, &key, &sdata, method) == -1)
451				error("put");
452
453			/* Store secure by uid. */
454			tbuf[0] = CURRENT_VERSION(_PW_KEYBYUID);
455			store = htonl(pwd.pw_uid);
456			memmove(tbuf + 1, &store, sizeof(store));
457			key.size = sizeof(store) + 1;
458			if ((sdp->put)(sdp, &key, &sdata, methoduid) == -1)
459				error("put");
460
461			/* Store insecure and secure special plus and special minus */
462			if (pwd.pw_name[0] == '+' || pwd.pw_name[0] == '-') {
463				tbuf[0] = CURRENT_VERSION(_PW_KEYYPBYNUM);
464				store = htonl(ypcnt);
465				memmove(tbuf + 1, &store, sizeof(store));
466				key.size = sizeof(store) + 1;
467				if ((dp->put)(dp, &key, &data, method) == -1)
468					error("put");
469				if ((sdp->put)(sdp, &key, &sdata, method) == -1)
470					error("put");
471			}
472		}
473		/* Create original format password file entry */
474		if (is_comment && makeold){	/* copy comments */
475			if (fprintf(oldfp, "%s\n", line) < 0)
476				error("write old");
477		} else if (makeold) {
478			char uidstr[20];
479			char gidstr[20];
480
481			snprintf(uidstr, sizeof(uidstr), "%u", pwd.pw_uid);
482			snprintf(gidstr, sizeof(gidstr), "%u", pwd.pw_gid);
483
484			if (fprintf(oldfp, "%s:*:%s:%s:%s:%s:%s\n",
485			    pwd.pw_name, pwd.pw_fields & _PWF_UID ? uidstr : "",
486			    pwd.pw_fields & _PWF_GID ? gidstr : "",
487			    pwd.pw_gecos, pwd.pw_dir, pwd.pw_shell) < 0)
488				error("write old");
489		}
490	}
491	/* If YP enabled, set flag. */
492	if (yp_enabled) {
493		buf[0] = yp_enabled + 2;
494		data.size = 1;
495		key.size = 1;
496		tbuf[0] = CURRENT_VERSION(_PW_KEYYPENABLED);
497		if ((dp->put)(dp, &key, &data, method) == -1)
498			error("put");
499		if ((sdp->put)(sdp, &key, &data, method) == -1)
500			error("put");
501	}
502
503	if ((dp->close)(dp) == -1)
504		error("close");
505	if ((sdp->close)(sdp) == -1)
506		error("close");
507	if (makeold) {
508		(void)fflush(oldfp);
509		if (fclose(oldfp) == EOF)
510			error("close old");
511	}
512
513	/* Set master.passwd permissions, in case caller forgot. */
514	(void)fchmod(fileno(fp), S_IRUSR|S_IWUSR);
515
516	/* Install as the real password files. */
517	(void)snprintf(buf, sizeof(buf), "%s/%s.tmp", prefix, _MP_DB);
518	(void)snprintf(buf2, sizeof(buf2), "%s/%s", prefix, _MP_DB);
519	mv(buf, buf2);
520	(void)snprintf(buf, sizeof(buf), "%s/%s.tmp", prefix, _SMP_DB);
521	(void)snprintf(buf2, sizeof(buf2), "%s/%s", prefix, _SMP_DB);
522	mv(buf, buf2);
523	if (makeold) {
524		(void)snprintf(buf2, sizeof(buf2), "%s/%s", prefix, _PASSWD);
525		(void)snprintf(buf, sizeof(buf), "%s.orig", pname);
526		mv(buf, buf2);
527	}
528	/*
529	 * Move the master password LAST -- chpass(1), passwd(1) and vipw(8)
530	 * all use flock(2) on it to block other incarnations of themselves.
531	 * The rename means that everything is unlocked, as the original file
532	 * can no longer be accessed.
533	 */
534	(void)snprintf(buf, sizeof(buf), "%s/%s", prefix, _MASTERPASSWD);
535	mv(pname, buf);
536
537	/*
538	 * Close locked password file after rename()
539	 */
540	if (fclose(fp) == EOF)
541		error("close fp");
542
543	exit(0);
544}
545
546int
547scan(FILE *fp, struct passwd *pw)
548{
549	static int lcnt;
550	size_t len;
551	char *p;
552
553	p = fgetln(fp, &len);
554	if (p == NULL)
555		return (0);
556	++lcnt;
557	/*
558	 * ``... if I swallow anything evil, put your fingers down my
559	 * throat...''
560	 *	-- The Who
561	 */
562	if (len > 0 && p[len - 1] == '\n')
563		len--;
564	if (len >= sizeof(line) - 1) {
565		warnx("line #%d too long", lcnt);
566		goto fmt;
567	}
568	memcpy(line, p, len);
569	line[len] = '\0';
570
571	/*
572	 * Ignore comments: ^[ \t]*#
573	 */
574	for (p = line; *p != '\0'; p++)
575		if (*p != ' ' && *p != '\t')
576			break;
577	if (*p == '#' || *p == '\0') {
578		is_comment = 1;
579		return(1);
580	} else
581		is_comment = 0;
582
583	if (!__pw_scan(line, pw, _PWSCAN_WARN|_PWSCAN_MASTER)) {
584		warnx("at line #%d", lcnt);
585fmt:		errno = EFTYPE;	/* XXX */
586		error(pname);
587	}
588
589	return (1);
590}
591
592void
593cp(char *from, char *to, mode_t mode)
594{
595	static char buf[MAXBSIZE];
596	int from_fd, rcount, to_fd, wcount;
597
598	if ((from_fd = open(from, O_RDONLY, 0)) < 0)
599		error(from);
600	if ((to_fd = open(to, O_WRONLY|O_CREAT|O_EXCL, mode)) < 0)
601		error(to);
602	while ((rcount = read(from_fd, buf, MAXBSIZE)) > 0) {
603		wcount = write(to_fd, buf, rcount);
604		if (rcount != wcount || wcount == -1) {
605			int sverrno = errno;
606
607			(void)snprintf(buf, sizeof(buf), "%s to %s", from, to);
608			errno = sverrno;
609			error(buf);
610		}
611	}
612	if (rcount < 0) {
613		int sverrno = errno;
614
615		(void)snprintf(buf, sizeof(buf), "%s to %s", from, to);
616		errno = sverrno;
617		error(buf);
618	}
619}
620
621
622void
623mv(char *from, char *to)
624{
625	char buf[MAXPATHLEN];
626	char *to_dir;
627	int to_dir_fd = -1;
628
629	/*
630	 * Make sure file is safe on disk. To improve performance we will call
631	 * fsync() to the directory where file lies
632	 */
633	if (rename(from, to) != 0 ||
634	    (to_dir = dirname(to)) == NULL ||
635	    (to_dir_fd = open(to_dir, O_RDONLY|O_DIRECTORY)) == -1 ||
636	    fsync(to_dir_fd) != 0) {
637		int sverrno = errno;
638		(void)snprintf(buf, sizeof(buf), "%s to %s", from, to);
639		errno = sverrno;
640		if (to_dir_fd != -1)
641			close(to_dir_fd);
642		error(buf);
643	}
644
645	if (to_dir_fd != -1)
646		close(to_dir_fd);
647}
648
649void
650error(const char *name)
651{
652
653	warn("%s", name);
654	cleanup();
655	exit(1);
656}
657
658void
659cleanup(void)
660{
661	char buf[MAXPATHLEN];
662
663	switch(clean) {
664	case FILE_ORIG:
665		(void)snprintf(buf, sizeof(buf), "%s.orig", pname);
666		(void)unlink(buf);
667		/* FALLTHROUGH */
668	case FILE_SECURE:
669		(void)snprintf(buf, sizeof(buf), "%s/%s.tmp", prefix, _SMP_DB);
670		(void)unlink(buf);
671		/* FALLTHROUGH */
672	case FILE_INSECURE:
673		(void)snprintf(buf, sizeof(buf), "%s/%s.tmp", prefix, _MP_DB);
674		(void)unlink(buf);
675	}
676}
677
678static void
679usage(void)
680{
681
682	(void)fprintf(stderr,
683"usage: pwd_mkdb [-BCiLNp] [-d directory] [-s cachesize] [-u username] file\n");
684	exit(1);
685}
686