lint, prettyness police
[unix-history] / usr / src / usr.sbin / pwd_mkdb / pwd_mkdb.c
CommitLineData
6257c216 1/*-
6b914905
KB
2 * Copyright (c) 1991, 1993
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
KB
9static char copyright[] =
10"@(#) Copyright (c) 1991, 1993\n\
11 The Regents of the University of California. All rights reserved.\n";
6257c216
KB
12#endif /* not lint */
13
14#ifndef lint
439197e9 15static char sccsid[] = "@(#)pwd_mkdb.c 8.2 (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
102 pname = *argv;
103 /* Open the original password file */
104 if (!(fp = fopen(pname, "r")))
105 error(pname);
106
c557c546 107 /* Open the temporary insecure password database. */
650fe310
KB
108 (void)snprintf(buf, sizeof(buf), "%s.tmp", _PATH_MP_DB);
109 dp = dbopen(buf,
110 O_RDWR|O_CREAT|O_EXCL, PERM_INSECURE, DB_HASH, &openinfo);
111 if (dp == NULL)
6257c216
KB
112 error(buf);
113 clean = FILE_INSECURE;
114
6257c216
KB
115 /*
116 * Open file for old password file. Minor trickiness -- don't want to
117 * chance the file already existing, since someone (stupidly) might
118 * still be using this for permission checking. So, open it first and
119 * fdopen the resulting fd. Don't really care who reads it.
120 */
121 if (makeold) {
650fe310 122 (void)snprintf(buf, sizeof(buf), "%s.orig", pname);
6257c216
KB
123 if ((tfd = open(buf,
124 O_WRONLY|O_CREAT|O_EXCL, PERM_INSECURE)) < 0)
125 error(buf);
650fe310 126 if ((oldfp = fdopen(tfd, "w")) == NULL)
6257c216
KB
127 error(buf);
128 clean = FILE_ORIG;
129 }
130
32d4d55f
KB
131 /*
132 * The databases actually contain three copies of the original data.
133 * Each password file entry is converted into a rough approximation
134 * of a ``struct passwd'', with the strings placed inline. This
135 * object is then stored as the data for three separate keys. The
136 * first key * is the pw_name field prepended by the _PW_KEYBYNAME
137 * character. The second key is the pw_uid field prepended by the
138 * _PW_KEYBYUID character. The third key is the line number in the
139 * original file prepended by the _PW_KEYBYNUM character. (The special
140 * characters are prepended to ensure that the keys do not collide.)
141 */
c557c546
KB
142 data.data = (u_char *)buf;
143 key.data = (u_char *)tbuf;
6257c216
KB
144 for (cnt = 1; scan(fp, &pwd); ++cnt) {
145#define COMPACT(e) t = e; while (*p++ = *t++);
146 /* Create insecure data. */
147 p = buf;
148 COMPACT(pwd.pw_name);
149 COMPACT("*");
650fe310 150 memmove(p, &pwd.pw_uid, sizeof(int));
6257c216 151 p += sizeof(int);
650fe310 152 memmove(p, &pwd.pw_gid, sizeof(int));
6257c216 153 p += sizeof(int);
650fe310 154 memmove(p, &pwd.pw_change, sizeof(time_t));
6257c216
KB
155 p += sizeof(time_t);
156 COMPACT(pwd.pw_class);
157 COMPACT(pwd.pw_gecos);
158 COMPACT(pwd.pw_dir);
159 COMPACT(pwd.pw_shell);
650fe310 160 memmove(p, &pwd.pw_expire, sizeof(time_t));
6257c216 161 p += sizeof(time_t);
c557c546 162 data.size = p - buf;
6257c216
KB
163
164 /* Store insecure by name. */
165 tbuf[0] = _PW_KEYBYNAME;
166 len = strlen(pwd.pw_name);
650fe310 167 memmove(tbuf + 1, pwd.pw_name, len);
c557c546
KB
168 key.size = len + 1;
169 if ((dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1)
170 error("put");
6257c216
KB
171
172 /* Store insecure by number. */
173 tbuf[0] = _PW_KEYBYNUM;
650fe310 174 memmove(tbuf + 1, &cnt, sizeof(cnt));
c557c546
KB
175 key.size = sizeof(cnt) + 1;
176 if ((dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1)
177 error("put");
6257c216
KB
178
179 /* Store insecure by uid. */
180 tbuf[0] = _PW_KEYBYUID;
650fe310 181 memmove(tbuf + 1, &pwd.pw_uid, sizeof(pwd.pw_uid));
c557c546
KB
182 key.size = sizeof(pwd.pw_uid) + 1;
183 if ((dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1)
184 error("put");
6257c216 185
650fe310
KB
186 /* Create original format password file entry */
187 if (makeold)
188 (void)fprintf(oldfp, "%s:*:%d:%d:%s:%s:%s\n",
189 pwd.pw_name, pwd.pw_uid, pwd.pw_gid, pwd.pw_gecos,
190 pwd.pw_dir, pwd.pw_shell);
191 }
192 (void)(dp->close)(dp);
193 if (makeold) {
194 (void)fflush(oldfp);
195 (void)fclose(oldfp);
196 }
197
198 /* Open the temporary encrypted password database. */
199 (void)snprintf(buf, sizeof(buf), "%s.tmp", _PATH_SMP_DB);
200 edp = dbopen(buf,
201 O_RDWR|O_CREAT|O_EXCL, PERM_SECURE, DB_HASH, &openinfo);
202 if (!edp)
203 error(buf);
204 clean = FILE_SECURE;
205
206 rewind(fp);
207 for (cnt = 1; scan(fp, &pwd); ++cnt) {
208
6257c216
KB
209 /* Create secure data. */
210 p = buf;
211 COMPACT(pwd.pw_name);
212 COMPACT(pwd.pw_passwd);
650fe310 213 memmove(p, &pwd.pw_uid, sizeof(int));
6257c216 214 p += sizeof(int);
650fe310 215 memmove(p, &pwd.pw_gid, sizeof(int));
6257c216 216 p += sizeof(int);
650fe310 217 memmove(p, &pwd.pw_change, sizeof(time_t));
6257c216
KB
218 p += sizeof(time_t);
219 COMPACT(pwd.pw_class);
220 COMPACT(pwd.pw_gecos);
221 COMPACT(pwd.pw_dir);
222 COMPACT(pwd.pw_shell);
650fe310 223 memmove(p, &pwd.pw_expire, sizeof(time_t));
6257c216 224 p += sizeof(time_t);
c557c546 225 data.size = p - buf;
6257c216
KB
226
227 /* Store secure by name. */
228 tbuf[0] = _PW_KEYBYNAME;
229 len = strlen(pwd.pw_name);
650fe310 230 memmove(tbuf + 1, pwd.pw_name, len);
c557c546
KB
231 key.size = len + 1;
232 if ((dp->put)(edp, &key, &data, R_NOOVERWRITE) == -1)
233 error("put");
6257c216
KB
234
235 /* Store secure by number. */
236 tbuf[0] = _PW_KEYBYNUM;
650fe310 237 memmove(tbuf + 1, &cnt, sizeof(cnt));
c557c546
KB
238 key.size = sizeof(cnt) + 1;
239 if ((dp->put)(edp, &key, &data, R_NOOVERWRITE) == -1)
240 error("put");
6257c216
KB
241
242 /* Store secure by uid. */
243 tbuf[0] = _PW_KEYBYUID;
650fe310 244 memmove(tbuf + 1, &pwd.pw_uid, sizeof(pwd.pw_uid));
c557c546
KB
245 key.size = sizeof(pwd.pw_uid) + 1;
246 if ((dp->put)(edp, &key, &data, R_NOOVERWRITE) == -1)
247 error("put");
6257c216 248 }
650fe310 249
c557c546 250 (void)(edp->close)(edp);
6257c216
KB
251
252 /* Set master.passwd permissions, in case caller forgot. */
506c5020 253 (void)fchmod(fileno(fp), S_IRUSR|S_IWUSR);
6257c216
KB
254 (void)fclose(fp);
255
256 /* Install as the real password files. */
650fe310 257 (void)snprintf(buf, sizeof(buf), "%s.tmp", _PATH_MP_DB);
6257c216 258 mv(buf, _PATH_MP_DB);
650fe310 259 (void)snprintf(buf, sizeof(buf), "%s.tmp", _PATH_SMP_DB);
6257c216
KB
260 mv(buf, _PATH_SMP_DB);
261 if (makeold) {
650fe310 262 (void)snprintf(buf, sizeof(buf), "%s.orig", pname);
6257c216
KB
263 mv(buf, _PATH_PASSWD);
264 }
265 /*
266 * Move the master password LAST -- chpass(1), passwd(1) and vipw(8)
267 * all use flock(2) on it to block other incarnations of themselves.
268 * The rename means that everything is unlocked, as the original file
269 * can no longer be accessed.
270 */
271 mv(pname, _PATH_MASTERPASSWD);
272 exit(0);
273}
274
650fe310 275int
6257c216
KB
276scan(fp, pw)
277 FILE *fp;
278 struct passwd *pw;
279{
280 static int lcnt;
281 static char line[LINE_MAX];
282 char *p;
283
284 if (!fgets(line, sizeof(line), fp))
439197e9 285 return (0);
6257c216
KB
286 ++lcnt;
287 /*
288 * ``... if I swallow anything evil, put your fingers down my
289 * throat...''
290 * -- The Who
291 */
650fe310 292 if (!(p = strchr(line, '\n'))) {
439197e9 293 warnx("line too long");
6257c216
KB
294 goto fmt;
295
296 }
297 *p = '\0';
298 if (!pw_scan(line, pw)) {
439197e9
JSP
299 warnx("at line #%d", lcnt);
300fmt: errno = EFTYPE; /* XXX */
6257c216 301 error(pname);
6257c216 302 }
439197e9
JSP
303
304 return (1);
6257c216
KB
305}
306
650fe310 307void
6257c216
KB
308mv(from, to)
309 char *from, *to;
310{
6257c216
KB
311 char buf[MAXPATHLEN];
312
313 if (rename(from, to)) {
439197e9 314 int sverrno = errno;
650fe310 315 (void)snprintf(buf, sizeof(buf), "%s to %s", from, to);
6257c216
KB
316 errno = sverrno;
317 error(buf);
318 }
319}
320
650fe310 321void
c557c546
KB
322error(name)
323 char *name;
324{
439197e9
JSP
325
326 warn(name);
c557c546
KB
327 cleanup();
328 exit(1);
329}
330
650fe310 331void
6257c216
KB
332cleanup()
333{
334 char buf[MAXPATHLEN];
335
336 switch(clean) {
337 case FILE_ORIG:
650fe310 338 (void)snprintf(buf, sizeof(buf), "%s.orig", pname);
6257c216
KB
339 (void)unlink(buf);
340 /* FALLTHROUGH */
341 case FILE_SECURE:
650fe310 342 (void)snprintf(buf, sizeof(buf), "%s.tmp", _PATH_SMP_DB);
6257c216
KB
343 (void)unlink(buf);
344 /* FALLTHROUGH */
345 case FILE_INSECURE:
650fe310 346 (void)snprintf(buf, sizeof(buf), "%s.tmp", _PATH_MP_DB);
6257c216
KB
347 (void)unlink(buf);
348 }
349}
350
650fe310 351void
6257c216
KB
352usage()
353{
439197e9 354
6257c216
KB
355 (void)fprintf(stderr, "usage: pwd_mkdb [-p] file\n");
356 exit(1);
357}