xref: /original-bsd/usr.sbin/pwd_mkdb/pwd_mkdb.c (revision 95a66346)
1 /*-
2  * Copyright (c) 1991 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 char copyright[] =
10 "@(#) Copyright (c) 1991 The Regents of the University of California.\n\
11  All rights reserved.\n";
12 #endif /* not lint */
13 
14 #ifndef lint
15 static char sccsid[] = "@(#)pwd_mkdb.c	5.4 (Berkeley) 03/08/91";
16 #endif /* not lint */
17 
18 #include <sys/param.h>
19 #include <sys/stat.h>
20 #include <signal.h>
21 #include <fcntl.h>
22 #include <db.h>
23 #include <pwd.h>
24 #include <errno.h>
25 #include <limits.h>
26 #include <stdio.h>
27 #include <string.h>
28 
29 #define	INSECURE	1
30 #define	SECURE		2
31 #define	PERM_INSECURE	(S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
32 #define	PERM_SECURE	(S_IRUSR|S_IWUSR)
33 
34 char *progname = "pwd_mkdb";
35 
36 static enum state { FILE_INSECURE, FILE_SECURE, FILE_ORIG } clean;
37 static struct passwd pwd;			/* password structure */
38 static char *pname;				/* password file name */
39 
40 main(argc, argv)
41 	int argc;
42 	char **argv;
43 {
44 	extern int optind;
45 	register int len, makeold;
46 	register char *p, *t;
47 	FILE *fp, *oldfp;
48 	DB *dp, *edp;
49 	sigset_t set;
50 	DBT data, key;
51 	int ch, cnt, tfd;
52 	char buf[MAX(MAXPATHLEN, LINE_MAX * 2)], tbuf[1024];
53 
54 	makeold = 0;
55 	while ((ch = getopt(argc, argv, "pv")) != EOF)
56 		switch(ch) {
57 		case 'p':			/* create V7 "file.orig" */
58 			makeold = 1;
59 			break;
60 		case 'v':			/* backward compatible */
61 			break;
62 		case '?':
63 		default:
64 			usage();
65 		}
66 	argc -= optind;
67 	argv += optind;
68 
69 	if (argc != 1)
70 		usage();
71 
72 	/*
73 	 * This could be done to allow the user to interrupt.  Probably
74 	 * not worth the effort.
75 	 */
76 	sigemptyset(&set);
77 	sigaddset(&set, SIGTSTP);
78 	sigaddset(&set, SIGHUP);
79 	sigaddset(&set, SIGINT);
80 	sigaddset(&set, SIGQUIT);
81 	sigaddset(&set, SIGTERM);
82 	(void)sigprocmask(SIG_BLOCK, &set, (sigset_t *)NULL);
83 
84 	pname = *argv;
85 	/* Open the original password file */
86 	if (!(fp = fopen(pname, "r")))
87 		error(pname);
88 
89 	/* Open the temporary insecure password database. */
90 	(void)sprintf(buf, "%s.tmp", _PATH_MP_DB);
91 	dp = hash_open(buf, O_WRONLY|O_CREAT|O_EXCL, PERM_INSECURE, NULL);
92 	if (!dp)
93 		error(buf);
94 	clean = FILE_INSECURE;
95 
96 	/* Open the temporary encrypted password database. */
97 	(void)sprintf(buf, "%s.tmp", _PATH_SMP_DB);
98 	edp = hash_open(buf, O_WRONLY|O_CREAT|O_EXCL, PERM_SECURE, NULL);
99 	if (!edp)
100 		error(buf);
101 	clean = FILE_SECURE;
102 
103 	/*
104 	 * Open file for old password file.  Minor trickiness -- don't want to
105 	 * chance the file already existing, since someone (stupidly) might
106 	 * still be using this for permission checking.  So, open it first and
107 	 * fdopen the resulting fd.  Don't really care who reads it.
108 	 */
109 	if (makeold) {
110 		(void)sprintf(buf, "%s.orig", pname);
111 		if ((tfd = open(buf,
112 		    O_WRONLY|O_CREAT|O_EXCL, PERM_INSECURE)) < 0)
113 			error(buf);
114 		if (!(oldfp = fdopen(tfd, "w")))
115 			error(buf);
116 		clean = FILE_ORIG;
117 	}
118 
119 	data.data = (u_char *)buf;
120 	key.data = (u_char *)tbuf;
121 	for (cnt = 1; scan(fp, &pwd); ++cnt) {
122 #define	COMPACT(e)	t = e; while (*p++ = *t++);
123 		/* Create insecure data. */
124 		p = buf;
125 		COMPACT(pwd.pw_name);
126 		COMPACT("*");
127 		bcopy((char *)&pwd.pw_uid, p, sizeof(int));
128 		p += sizeof(int);
129 		bcopy((char *)&pwd.pw_gid, p, sizeof(int));
130 		p += sizeof(int);
131 		bcopy((char *)&pwd.pw_change, p, sizeof(time_t));
132 		p += sizeof(time_t);
133 		COMPACT(pwd.pw_class);
134 		COMPACT(pwd.pw_gecos);
135 		COMPACT(pwd.pw_dir);
136 		COMPACT(pwd.pw_shell);
137 		bcopy((char *)&pwd.pw_expire, p, sizeof(time_t));
138 		p += sizeof(time_t);
139 		data.size = p - buf;
140 
141 		/* Store insecure by name. */
142 		tbuf[0] = _PW_KEYBYNAME;
143 		len = strlen(pwd.pw_name);
144 		bcopy(pwd.pw_name, tbuf + 1, len);
145 		key.size = len + 1;
146 		if ((dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1)
147 			error("put");
148 
149 		/* Store insecure by number. */
150 		tbuf[0] = _PW_KEYBYNUM;
151 		bcopy((char *)&cnt, tbuf + 1, sizeof(cnt));
152 		key.size = sizeof(cnt) + 1;
153 		if ((dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1)
154 			error("put");
155 
156 		/* Store insecure by uid. */
157 		tbuf[0] = _PW_KEYBYUID;
158 		bcopy((char *)&pwd.pw_uid, tbuf + 1, sizeof(pwd.pw_uid));
159 		key.size = sizeof(pwd.pw_uid) + 1;
160 		if ((dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1)
161 			error("put");
162 
163 		/* Create secure data. */
164 		p = buf;
165 		COMPACT(pwd.pw_name);
166 		COMPACT(pwd.pw_passwd);
167 		bcopy((char *)&pwd.pw_uid, p, sizeof(int));
168 		p += sizeof(int);
169 		bcopy((char *)&pwd.pw_gid, p, sizeof(int));
170 		p += sizeof(int);
171 		bcopy((char *)&pwd.pw_change, p, sizeof(time_t));
172 		p += sizeof(time_t);
173 		COMPACT(pwd.pw_class);
174 		COMPACT(pwd.pw_gecos);
175 		COMPACT(pwd.pw_dir);
176 		COMPACT(pwd.pw_shell);
177 		bcopy((char *)&pwd.pw_expire, p, sizeof(time_t));
178 		p += sizeof(time_t);
179 		data.size = p - buf;
180 
181 		/* Store secure by name. */
182 		tbuf[0] = _PW_KEYBYNAME;
183 		len = strlen(pwd.pw_name);
184 		bcopy(pwd.pw_name, tbuf + 1, len);
185 		key.size = len + 1;
186 		if ((dp->put)(edp, &key, &data, R_NOOVERWRITE) == -1)
187 			error("put");
188 
189 		/* Store secure by number. */
190 		tbuf[0] = _PW_KEYBYNUM;
191 		bcopy((char *)&cnt, tbuf + 1, sizeof(cnt));
192 		key.size = sizeof(cnt) + 1;
193 		if ((dp->put)(edp, &key, &data, R_NOOVERWRITE) == -1)
194 			error("put");
195 
196 		/* Store secure by uid. */
197 		tbuf[0] = _PW_KEYBYUID;
198 		bcopy((char *)&pwd.pw_uid, tbuf + 1, sizeof(pwd.pw_uid));
199 		key.size = sizeof(pwd.pw_uid) + 1;
200 		if ((dp->put)(edp, &key, &data, R_NOOVERWRITE) == -1)
201 			error("put");
202 
203 		/* Create original format password file entry */
204 		if (makeold)
205 			(void)fprintf(oldfp, "%s:*:%d:%d:%s:%s:%s\n",
206 			    pwd.pw_name, pwd.pw_uid, pwd.pw_gid, pwd.pw_gecos,
207 			    pwd.pw_dir, pwd.pw_shell);
208 	}
209 	(void)(dp->close)(dp);
210 	(void)(edp->close)(edp);
211 	if (makeold) {
212 		(void)fsync(oldfp);
213 		(void)fclose(oldfp);
214 	}
215 
216 	/* Set master.passwd permissions, in case caller forgot. */
217 	(void)fchmod(fileno(fp), S_IRUSR|S_IWUSR);
218 	(void)fclose(fp);
219 
220 	/* Install as the real password files. */
221 	(void)sprintf(buf, "%s.tmp", _PATH_MP_DB);
222 	mv(buf, _PATH_MP_DB);
223 	(void)sprintf(buf, "%s.tmp", _PATH_SMP_DB);
224 	mv(buf, _PATH_SMP_DB);
225 	if (makeold) {
226 		(void)sprintf(buf, "%s.orig", pname);
227 		mv(buf, _PATH_PASSWD);
228 	}
229 	/*
230 	 * Move the master password LAST -- chpass(1), passwd(1) and vipw(8)
231 	 * all use flock(2) on it to block other incarnations of themselves.
232 	 * The rename means that everything is unlocked, as the original file
233 	 * can no longer be accessed.
234 	 */
235 	mv(pname, _PATH_MASTERPASSWD);
236 	exit(0);
237 }
238 
239 scan(fp, pw)
240 	FILE *fp;
241 	struct passwd *pw;
242 {
243 	static int lcnt;
244 	static char line[LINE_MAX];
245 	char *p;
246 
247 	if (!fgets(line, sizeof(line), fp))
248 		return(0);
249 	++lcnt;
250 	/*
251 	 * ``... if I swallow anything evil, put your fingers down my
252 	 * throat...''
253 	 *	-- The Who
254 	 */
255 	if (!(p = index(line, '\n'))) {
256 		(void)fprintf(stderr, "pwd_mkdb: line too long\n");
257 		goto fmt;
258 
259 	}
260 	*p = '\0';
261 	if (!pw_scan(line, pw)) {
262 		(void)fprintf(stderr, "pwd_mkdb: at line #%d.\n", lcnt);
263 fmt:		errno = EFTYPE;
264 		error(pname);
265 		exit(1);
266 	}
267 }
268 
269 mv(from, to)
270 	char *from, *to;
271 {
272 	int sverrno;
273 	char buf[MAXPATHLEN];
274 
275 	if (rename(from, to)) {
276 		sverrno = errno;
277 		(void)sprintf(buf, "%s to %s", from, to);
278 		errno = sverrno;
279 		error(buf);
280 	}
281 }
282 
283 error(name)
284 	char *name;
285 {
286 	(void)fprintf(stderr, "pwd_mkdb: %s: %s\n", name, strerror(errno));
287 	cleanup();
288 	exit(1);
289 }
290 
291 cleanup()
292 {
293 	char buf[MAXPATHLEN];
294 
295 	switch(clean) {
296 	case FILE_ORIG:
297 		(void)sprintf(buf, "%s.orig", pname);
298 		(void)unlink(buf);
299 		/* FALLTHROUGH */
300 	case FILE_SECURE:
301 		(void)sprintf(buf, "%s.tmp", _PATH_SMP_DB);
302 		(void)unlink(buf);
303 		/* FALLTHROUGH */
304 	case FILE_INSECURE:
305 		(void)sprintf(buf, "%s.tmp", _PATH_MP_DB);
306 		(void)unlink(buf);
307 	}
308 }
309 
310 usage()
311 {
312 	(void)fprintf(stderr, "usage: pwd_mkdb [-p] file\n");
313 	exit(1);
314 }
315