mdoc version three
[unix-history] / usr / src / usr.sbin / pwd_mkdb / pwd_mkdb.c
CommitLineData
6257c216
KB
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
9char 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
32d4d55f 15static char sccsid[] = "@(#)pwd_mkdb.c 5.5 (Berkeley) %G%";
6257c216
KB
16#endif /* not lint */
17
18#include <sys/param.h>
19#include <sys/stat.h>
20#include <signal.h>
21#include <fcntl.h>
c557c546 22#include <db.h>
6257c216
KB
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
34char *progname = "pwd_mkdb";
35
36static enum state { FILE_INSECURE, FILE_SECURE, FILE_ORIG } clean;
37static struct passwd pwd; /* password structure */
38static char *pname; /* password file name */
39
40main(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;
c557c546 48 DB *dp, *edp;
6257c216 49 sigset_t set;
c557c546 50 DBT data, key;
6257c216
KB
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
c557c546 89 /* Open the temporary insecure password database. */
6257c216 90 (void)sprintf(buf, "%s.tmp", _PATH_MP_DB);
c557c546
KB
91 dp = hash_open(buf, O_WRONLY|O_CREAT|O_EXCL, PERM_INSECURE, NULL);
92 if (!dp)
6257c216
KB
93 error(buf);
94 clean = FILE_INSECURE;
95
c557c546 96 /* Open the temporary encrypted password database. */
6257c216 97 (void)sprintf(buf, "%s.tmp", _PATH_SMP_DB);
c557c546
KB
98 edp = hash_open(buf, O_WRONLY|O_CREAT|O_EXCL, PERM_SECURE, NULL);
99 if (!edp)
6257c216
KB
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
32d4d55f
KB
119 /*
120 * The databases actually contain three copies of the original data.
121 * Each password file entry is converted into a rough approximation
122 * of a ``struct passwd'', with the strings placed inline. This
123 * object is then stored as the data for three separate keys. The
124 * first key * is the pw_name field prepended by the _PW_KEYBYNAME
125 * character. The second key is the pw_uid field prepended by the
126 * _PW_KEYBYUID character. The third key is the line number in the
127 * original file prepended by the _PW_KEYBYNUM character. (The special
128 * characters are prepended to ensure that the keys do not collide.)
129 */
c557c546
KB
130 data.data = (u_char *)buf;
131 key.data = (u_char *)tbuf;
6257c216
KB
132 for (cnt = 1; scan(fp, &pwd); ++cnt) {
133#define COMPACT(e) t = e; while (*p++ = *t++);
134 /* Create insecure data. */
135 p = buf;
136 COMPACT(pwd.pw_name);
137 COMPACT("*");
138 bcopy((char *)&pwd.pw_uid, p, sizeof(int));
139 p += sizeof(int);
140 bcopy((char *)&pwd.pw_gid, p, sizeof(int));
141 p += sizeof(int);
142 bcopy((char *)&pwd.pw_change, p, sizeof(time_t));
143 p += sizeof(time_t);
144 COMPACT(pwd.pw_class);
145 COMPACT(pwd.pw_gecos);
146 COMPACT(pwd.pw_dir);
147 COMPACT(pwd.pw_shell);
148 bcopy((char *)&pwd.pw_expire, p, sizeof(time_t));
149 p += sizeof(time_t);
c557c546 150 data.size = p - buf;
6257c216
KB
151
152 /* Store insecure by name. */
153 tbuf[0] = _PW_KEYBYNAME;
154 len = strlen(pwd.pw_name);
155 bcopy(pwd.pw_name, tbuf + 1, len);
c557c546
KB
156 key.size = len + 1;
157 if ((dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1)
158 error("put");
6257c216
KB
159
160 /* Store insecure by number. */
161 tbuf[0] = _PW_KEYBYNUM;
162 bcopy((char *)&cnt, tbuf + 1, sizeof(cnt));
c557c546
KB
163 key.size = sizeof(cnt) + 1;
164 if ((dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1)
165 error("put");
6257c216
KB
166
167 /* Store insecure by uid. */
168 tbuf[0] = _PW_KEYBYUID;
169 bcopy((char *)&pwd.pw_uid, tbuf + 1, sizeof(pwd.pw_uid));
c557c546
KB
170 key.size = sizeof(pwd.pw_uid) + 1;
171 if ((dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1)
172 error("put");
6257c216
KB
173
174 /* Create secure data. */
175 p = buf;
176 COMPACT(pwd.pw_name);
177 COMPACT(pwd.pw_passwd);
178 bcopy((char *)&pwd.pw_uid, p, sizeof(int));
179 p += sizeof(int);
180 bcopy((char *)&pwd.pw_gid, p, sizeof(int));
181 p += sizeof(int);
182 bcopy((char *)&pwd.pw_change, p, sizeof(time_t));
183 p += sizeof(time_t);
184 COMPACT(pwd.pw_class);
185 COMPACT(pwd.pw_gecos);
186 COMPACT(pwd.pw_dir);
187 COMPACT(pwd.pw_shell);
188 bcopy((char *)&pwd.pw_expire, p, sizeof(time_t));
189 p += sizeof(time_t);
c557c546 190 data.size = p - buf;
6257c216
KB
191
192 /* Store secure by name. */
193 tbuf[0] = _PW_KEYBYNAME;
194 len = strlen(pwd.pw_name);
195 bcopy(pwd.pw_name, tbuf + 1, len);
c557c546
KB
196 key.size = len + 1;
197 if ((dp->put)(edp, &key, &data, R_NOOVERWRITE) == -1)
198 error("put");
6257c216
KB
199
200 /* Store secure by number. */
201 tbuf[0] = _PW_KEYBYNUM;
202 bcopy((char *)&cnt, tbuf + 1, sizeof(cnt));
c557c546
KB
203 key.size = sizeof(cnt) + 1;
204 if ((dp->put)(edp, &key, &data, R_NOOVERWRITE) == -1)
205 error("put");
6257c216
KB
206
207 /* Store secure by uid. */
208 tbuf[0] = _PW_KEYBYUID;
209 bcopy((char *)&pwd.pw_uid, tbuf + 1, sizeof(pwd.pw_uid));
c557c546
KB
210 key.size = sizeof(pwd.pw_uid) + 1;
211 if ((dp->put)(edp, &key, &data, R_NOOVERWRITE) == -1)
212 error("put");
6257c216
KB
213
214 /* Create original format password file entry */
215 if (makeold)
216 (void)fprintf(oldfp, "%s:*:%d:%d:%s:%s:%s\n",
217 pwd.pw_name, pwd.pw_uid, pwd.pw_gid, pwd.pw_gecos,
218 pwd.pw_dir, pwd.pw_shell);
219 }
c557c546
KB
220 (void)(dp->close)(dp);
221 (void)(edp->close)(edp);
222 if (makeold) {
223 (void)fsync(oldfp);
6257c216 224 (void)fclose(oldfp);
c557c546 225 }
6257c216
KB
226
227 /* Set master.passwd permissions, in case caller forgot. */
506c5020 228 (void)fchmod(fileno(fp), S_IRUSR|S_IWUSR);
6257c216
KB
229 (void)fclose(fp);
230
231 /* Install as the real password files. */
c557c546 232 (void)sprintf(buf, "%s.tmp", _PATH_MP_DB);
6257c216 233 mv(buf, _PATH_MP_DB);
c557c546 234 (void)sprintf(buf, "%s.tmp", _PATH_SMP_DB);
6257c216
KB
235 mv(buf, _PATH_SMP_DB);
236 if (makeold) {
237 (void)sprintf(buf, "%s.orig", pname);
238 mv(buf, _PATH_PASSWD);
239 }
240 /*
241 * Move the master password LAST -- chpass(1), passwd(1) and vipw(8)
242 * all use flock(2) on it to block other incarnations of themselves.
243 * The rename means that everything is unlocked, as the original file
244 * can no longer be accessed.
245 */
246 mv(pname, _PATH_MASTERPASSWD);
247 exit(0);
248}
249
250scan(fp, pw)
251 FILE *fp;
252 struct passwd *pw;
253{
254 static int lcnt;
255 static char line[LINE_MAX];
256 char *p;
257
258 if (!fgets(line, sizeof(line), fp))
259 return(0);
260 ++lcnt;
261 /*
262 * ``... if I swallow anything evil, put your fingers down my
263 * throat...''
264 * -- The Who
265 */
266 if (!(p = index(line, '\n'))) {
267 (void)fprintf(stderr, "pwd_mkdb: line too long\n");
268 goto fmt;
269
270 }
271 *p = '\0';
272 if (!pw_scan(line, pw)) {
273 (void)fprintf(stderr, "pwd_mkdb: at line #%d.\n", lcnt);
274fmt: errno = EFTYPE;
275 error(pname);
276 exit(1);
277 }
278}
279
280mv(from, to)
281 char *from, *to;
282{
283 int sverrno;
284 char buf[MAXPATHLEN];
285
286 if (rename(from, to)) {
287 sverrno = errno;
288 (void)sprintf(buf, "%s to %s", from, to);
289 errno = sverrno;
290 error(buf);
291 }
292}
293
c557c546
KB
294error(name)
295 char *name;
296{
297 (void)fprintf(stderr, "pwd_mkdb: %s: %s\n", name, strerror(errno));
298 cleanup();
299 exit(1);
300}
301
6257c216
KB
302cleanup()
303{
304 char buf[MAXPATHLEN];
305
306 switch(clean) {
307 case FILE_ORIG:
308 (void)sprintf(buf, "%s.orig", pname);
309 (void)unlink(buf);
310 /* FALLTHROUGH */
311 case FILE_SECURE:
312 (void)sprintf(buf, "%s.tmp", _PATH_SMP_DB);
313 (void)unlink(buf);
314 /* FALLTHROUGH */
315 case FILE_INSECURE:
316 (void)sprintf(buf, "%s.tmp", _PATH_MP_DB);
317 (void)unlink(buf);
318 }
319}
320
6257c216
KB
321usage()
322{
323 (void)fprintf(stderr, "usage: pwd_mkdb [-p] file\n");
324 exit(1);
325}