don't use chmod, reset the initial umask
[unix-history] / usr / src / usr.sbin / pwd_mkdb / pwd_mkdb.c
CommitLineData
6257c216 1/*-
d78dcdff 2 * Copyright (c) 1991, 1993, 1994
6b914905 3 * The Regents of the University of California. All rights reserved.
6257c216
KB
4 *
5 * %sccs.include.redist.c%
6 */
7
8#ifndef lint
6b914905 9static char copyright[] =
d78dcdff 10"@(#) Copyright (c) 1991, 1993, 1994\n\
6b914905 11 The Regents of the University of California. All rights reserved.\n";
6257c216
KB
12#endif /* not lint */
13
14#ifndef lint
5792589c 15static char sccsid[] = "@(#)pwd_mkdb.c 8.5 (Berkeley) %G%";
6257c216
KB
16#endif /* not lint */
17
18#include <sys/param.h>
19#include <sys/stat.h>
650fe310 20
c557c546 21#include <db.h>
439197e9 22#include <err.h>
6257c216 23#include <errno.h>
650fe310 24#include <fcntl.h>
6257c216 25#include <limits.h>
650fe310
KB
26#include <pwd.h>
27#include <signal.h>
6257c216 28#include <stdio.h>
650fe310 29#include <stdlib.h>
6257c216 30#include <string.h>
650fe310 31#include <unistd.h>
6257c216 32
439197e9
JSP
33#include "pw_scan.h"
34
6257c216
KB
35#define INSECURE 1
36#define SECURE 2
37#define PERM_INSECURE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
38#define PERM_SECURE (S_IRUSR|S_IWUSR)
39
650fe310
KB
40HASHINFO openinfo = {
41 4096, /* bsize */
42 32, /* ffactor */
43 256, /* nelem */
44 2048 * 1024, /* cachesize */
45 NULL, /* hash() */
46 0 /* lorder */
47};
48
6257c216
KB
49static enum state { FILE_INSECURE, FILE_SECURE, FILE_ORIG } clean;
50static struct passwd pwd; /* password structure */
51static char *pname; /* password file name */
52
650fe310
KB
53void cleanup __P((void));
54void error __P((char *));
55void mv __P((char *, char *));
56int scan __P((FILE *, struct passwd *));
57void usage __P((void));
58
59int
6257c216
KB
60main(argc, argv)
61 int argc;
650fe310 62 char *argv[];
6257c216 63{
c557c546 64 DB *dp, *edp;
c557c546 65 DBT data, key;
650fe310
KB
66 FILE *fp, *oldfp;
67 sigset_t set;
439197e9
JSP
68 int ch, cnt, len, makeold, tfd;
69 char *p, *t;
6257c216
KB
70 char buf[MAX(MAXPATHLEN, LINE_MAX * 2)], tbuf[1024];
71
72 makeold = 0;
73 while ((ch = getopt(argc, argv, "pv")) != EOF)
74 switch(ch) {
75 case 'p': /* create V7 "file.orig" */
76 makeold = 1;
77 break;
78 case 'v': /* backward compatible */
79 break;
80 case '?':
81 default:
82 usage();
83 }
84 argc -= optind;
85 argv += optind;
86
87 if (argc != 1)
88 usage();
89
90 /*
650fe310
KB
91 * This could be changed to allow the user to interrupt.
92 * Probably not worth the effort.
6257c216
KB
93 */
94 sigemptyset(&set);
95 sigaddset(&set, SIGTSTP);
96 sigaddset(&set, SIGHUP);
97 sigaddset(&set, SIGINT);
98 sigaddset(&set, SIGQUIT);
99 sigaddset(&set, SIGTERM);
100 (void)sigprocmask(SIG_BLOCK, &set, (sigset_t *)NULL);
101
5792589c
KB
102 /* We don't care what the user wants. */
103 (void)umask(0);
104
6257c216
KB
105 pname = *argv;
106 /* Open the original password file */
107 if (!(fp = fopen(pname, "r")))
108 error(pname);
109
c557c546 110 /* Open the temporary insecure password database. */
650fe310
KB
111 (void)snprintf(buf, sizeof(buf), "%s.tmp", _PATH_MP_DB);
112 dp = dbopen(buf,
113 O_RDWR|O_CREAT|O_EXCL, PERM_INSECURE, DB_HASH, &openinfo);
114 if (dp == NULL)
6257c216
KB
115 error(buf);
116 clean = FILE_INSECURE;
117
6257c216
KB
118 /*
119 * Open file for old password file. Minor trickiness -- don't want to
120 * chance the file already existing, since someone (stupidly) might
121 * still be using this for permission checking. So, open it first and
61cc9a71 122 * fdopen the resulting fd. The resulting file should be readable by
5792589c 123 * everyone.
6257c216
KB
124 */
125 if (makeold) {
650fe310 126 (void)snprintf(buf, sizeof(buf), "%s.orig", pname);
6257c216
KB
127 if ((tfd = open(buf,
128 O_WRONLY|O_CREAT|O_EXCL, PERM_INSECURE)) < 0)
129 error(buf);
650fe310 130 if ((oldfp = fdopen(tfd, "w")) == NULL)
6257c216
KB
131 error(buf);
132 clean = FILE_ORIG;
133 }
134
32d4d55f
KB
135 /*
136 * The databases actually contain three copies of the original data.
137 * Each password file entry is converted into a rough approximation
138 * of a ``struct passwd'', with the strings placed inline. This
139 * object is then stored as the data for three separate keys. The
140 * first key * is the pw_name field prepended by the _PW_KEYBYNAME
141 * character. The second key is the pw_uid field prepended by the
142 * _PW_KEYBYUID character. The third key is the line number in the
143 * original file prepended by the _PW_KEYBYNUM character. (The special
144 * characters are prepended to ensure that the keys do not collide.)
145 */
c557c546
KB
146 data.data = (u_char *)buf;
147 key.data = (u_char *)tbuf;
6257c216
KB
148 for (cnt = 1; scan(fp, &pwd); ++cnt) {
149#define COMPACT(e) t = e; while (*p++ = *t++);
150 /* Create insecure data. */
151 p = buf;
152 COMPACT(pwd.pw_name);
153 COMPACT("*");
650fe310 154 memmove(p, &pwd.pw_uid, sizeof(int));
6257c216 155 p += sizeof(int);
650fe310 156 memmove(p, &pwd.pw_gid, sizeof(int));
6257c216 157 p += sizeof(int);
650fe310 158 memmove(p, &pwd.pw_change, sizeof(time_t));
6257c216
KB
159 p += sizeof(time_t);
160 COMPACT(pwd.pw_class);
161 COMPACT(pwd.pw_gecos);
162 COMPACT(pwd.pw_dir);
163 COMPACT(pwd.pw_shell);
650fe310 164 memmove(p, &pwd.pw_expire, sizeof(time_t));
6257c216 165 p += sizeof(time_t);
c557c546 166 data.size = p - buf;
6257c216
KB
167
168 /* Store insecure by name. */
169 tbuf[0] = _PW_KEYBYNAME;
170 len = strlen(pwd.pw_name);
650fe310 171 memmove(tbuf + 1, pwd.pw_name, len);
c557c546
KB
172 key.size = len + 1;
173 if ((dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1)
174 error("put");
6257c216
KB
175
176 /* Store insecure by number. */
177 tbuf[0] = _PW_KEYBYNUM;
650fe310 178 memmove(tbuf + 1, &cnt, sizeof(cnt));
c557c546
KB
179 key.size = sizeof(cnt) + 1;
180 if ((dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1)
181 error("put");
6257c216
KB
182
183 /* Store insecure by uid. */
184 tbuf[0] = _PW_KEYBYUID;
650fe310 185 memmove(tbuf + 1, &pwd.pw_uid, sizeof(pwd.pw_uid));
c557c546
KB
186 key.size = sizeof(pwd.pw_uid) + 1;
187 if ((dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1)
188 error("put");
6257c216 189
650fe310
KB
190 /* Create original format password file entry */
191 if (makeold)
192 (void)fprintf(oldfp, "%s:*:%d:%d:%s:%s:%s\n",
193 pwd.pw_name, pwd.pw_uid, pwd.pw_gid, pwd.pw_gecos,
194 pwd.pw_dir, pwd.pw_shell);
195 }
196 (void)(dp->close)(dp);
197 if (makeold) {
198 (void)fflush(oldfp);
199 (void)fclose(oldfp);
200 }
201
202 /* Open the temporary encrypted password database. */
203 (void)snprintf(buf, sizeof(buf), "%s.tmp", _PATH_SMP_DB);
204 edp = dbopen(buf,
205 O_RDWR|O_CREAT|O_EXCL, PERM_SECURE, DB_HASH, &openinfo);
206 if (!edp)
207 error(buf);
208 clean = FILE_SECURE;
209
210 rewind(fp);
211 for (cnt = 1; scan(fp, &pwd); ++cnt) {
212
6257c216
KB
213 /* Create secure data. */
214 p = buf;
215 COMPACT(pwd.pw_name);
216 COMPACT(pwd.pw_passwd);
650fe310 217 memmove(p, &pwd.pw_uid, sizeof(int));
6257c216 218 p += sizeof(int);
650fe310 219 memmove(p, &pwd.pw_gid, sizeof(int));
6257c216 220 p += sizeof(int);
650fe310 221 memmove(p, &pwd.pw_change, sizeof(time_t));
6257c216
KB
222 p += sizeof(time_t);
223 COMPACT(pwd.pw_class);
224 COMPACT(pwd.pw_gecos);
225 COMPACT(pwd.pw_dir);
226 COMPACT(pwd.pw_shell);
650fe310 227 memmove(p, &pwd.pw_expire, sizeof(time_t));
6257c216 228 p += sizeof(time_t);
c557c546 229 data.size = p - buf;
6257c216
KB
230
231 /* Store secure by name. */
232 tbuf[0] = _PW_KEYBYNAME;
233 len = strlen(pwd.pw_name);
650fe310 234 memmove(tbuf + 1, pwd.pw_name, len);
c557c546
KB
235 key.size = len + 1;
236 if ((dp->put)(edp, &key, &data, R_NOOVERWRITE) == -1)
237 error("put");
6257c216
KB
238
239 /* Store secure by number. */
240 tbuf[0] = _PW_KEYBYNUM;
650fe310 241 memmove(tbuf + 1, &cnt, sizeof(cnt));
c557c546
KB
242 key.size = sizeof(cnt) + 1;
243 if ((dp->put)(edp, &key, &data, R_NOOVERWRITE) == -1)
244 error("put");
6257c216
KB
245
246 /* Store secure by uid. */
247 tbuf[0] = _PW_KEYBYUID;
650fe310 248 memmove(tbuf + 1, &pwd.pw_uid, sizeof(pwd.pw_uid));
c557c546
KB
249 key.size = sizeof(pwd.pw_uid) + 1;
250 if ((dp->put)(edp, &key, &data, R_NOOVERWRITE) == -1)
251 error("put");
6257c216 252 }
650fe310 253
c557c546 254 (void)(edp->close)(edp);
6257c216
KB
255
256 /* Set master.passwd permissions, in case caller forgot. */
506c5020 257 (void)fchmod(fileno(fp), S_IRUSR|S_IWUSR);
6257c216
KB
258 (void)fclose(fp);
259
260 /* Install as the real password files. */
650fe310 261 (void)snprintf(buf, sizeof(buf), "%s.tmp", _PATH_MP_DB);
6257c216 262 mv(buf, _PATH_MP_DB);
650fe310 263 (void)snprintf(buf, sizeof(buf), "%s.tmp", _PATH_SMP_DB);
6257c216
KB
264 mv(buf, _PATH_SMP_DB);
265 if (makeold) {
650fe310 266 (void)snprintf(buf, sizeof(buf), "%s.orig", pname);
6257c216
KB
267 mv(buf, _PATH_PASSWD);
268 }
269 /*
270 * Move the master password LAST -- chpass(1), passwd(1) and vipw(8)
271 * all use flock(2) on it to block other incarnations of themselves.
272 * The rename means that everything is unlocked, as the original file
273 * can no longer be accessed.
274 */
275 mv(pname, _PATH_MASTERPASSWD);
276 exit(0);
277}
278
650fe310 279int
6257c216
KB
280scan(fp, pw)
281 FILE *fp;
282 struct passwd *pw;
283{
284 static int lcnt;
285 static char line[LINE_MAX];
286 char *p;
287
288 if (!fgets(line, sizeof(line), fp))
439197e9 289 return (0);
6257c216
KB
290 ++lcnt;
291 /*
292 * ``... if I swallow anything evil, put your fingers down my
293 * throat...''
294 * -- The Who
295 */
650fe310 296 if (!(p = strchr(line, '\n'))) {
439197e9 297 warnx("line too long");
6257c216
KB
298 goto fmt;
299
300 }
301 *p = '\0';
302 if (!pw_scan(line, pw)) {
439197e9
JSP
303 warnx("at line #%d", lcnt);
304fmt: errno = EFTYPE; /* XXX */
6257c216 305 error(pname);
6257c216 306 }
439197e9
JSP
307
308 return (1);
6257c216
KB
309}
310
650fe310 311void
6257c216
KB
312mv(from, to)
313 char *from, *to;
314{
6257c216
KB
315 char buf[MAXPATHLEN];
316
317 if (rename(from, to)) {
439197e9 318 int sverrno = errno;
650fe310 319 (void)snprintf(buf, sizeof(buf), "%s to %s", from, to);
6257c216
KB
320 errno = sverrno;
321 error(buf);
322 }
323}
324
650fe310 325void
c557c546
KB
326error(name)
327 char *name;
328{
439197e9
JSP
329
330 warn(name);
c557c546
KB
331 cleanup();
332 exit(1);
333}
334
650fe310 335void
6257c216
KB
336cleanup()
337{
338 char buf[MAXPATHLEN];
339
340 switch(clean) {
341 case FILE_ORIG:
650fe310 342 (void)snprintf(buf, sizeof(buf), "%s.orig", pname);
6257c216
KB
343 (void)unlink(buf);
344 /* FALLTHROUGH */
345 case FILE_SECURE:
650fe310 346 (void)snprintf(buf, sizeof(buf), "%s.tmp", _PATH_SMP_DB);
6257c216
KB
347 (void)unlink(buf);
348 /* FALLTHROUGH */
349 case FILE_INSECURE:
650fe310 350 (void)snprintf(buf, sizeof(buf), "%s.tmp", _PATH_MP_DB);
6257c216
KB
351 (void)unlink(buf);
352 }
353}
354
650fe310 355void
6257c216
KB
356usage()
357{
439197e9 358
6257c216
KB
359 (void)fprintf(stderr, "usage: pwd_mkdb [-p] file\n");
360 exit(1);
361}