use DBM_SUFFIX; db(3) now appends ".db" when old interface is used.
[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
5641bcd3 15static char sccsid[] = "@(#)pwd_mkdb.c 5.2 (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>
22#include <ndbm.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
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;
48 DBM *dp, *edp;
49 sigset_t set;
50 datum key, data;
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 password database. */
90 (void)sprintf(buf, "%s.tmp", _PATH_MP_DB);
91 if (!(dp = dbm_open(buf, O_WRONLY|O_CREAT|O_EXCL, PERM_INSECURE)))
92 error(buf);
93 clean = FILE_INSECURE;
94
95 /* Open the encrypted password database. */
96 (void)sprintf(buf, "%s.tmp", _PATH_SMP_DB);
97 if (!(edp = dbm_open(buf, O_WRONLY|O_CREAT|O_EXCL, PERM_SECURE)))
98 error(buf);
99 clean = FILE_SECURE;
100
101 /*
102 * Open file for old password file. Minor trickiness -- don't want to
103 * chance the file already existing, since someone (stupidly) might
104 * still be using this for permission checking. So, open it first and
105 * fdopen the resulting fd. Don't really care who reads it.
106 */
107 if (makeold) {
108 (void)sprintf(buf, "%s.orig", pname);
109 if ((tfd = open(buf,
110 O_WRONLY|O_CREAT|O_EXCL, PERM_INSECURE)) < 0)
111 error(buf);
112 if (!(oldfp = fdopen(tfd, "w")))
113 error(buf);
114 clean = FILE_ORIG;
115 }
116
117 data.dptr = buf;
118 key.dptr = tbuf;
119 for (cnt = 1; scan(fp, &pwd); ++cnt) {
120#define COMPACT(e) t = e; while (*p++ = *t++);
121 /* Create insecure data. */
122 p = buf;
123 COMPACT(pwd.pw_name);
124 COMPACT("*");
125 bcopy((char *)&pwd.pw_uid, p, sizeof(int));
126 p += sizeof(int);
127 bcopy((char *)&pwd.pw_gid, p, sizeof(int));
128 p += sizeof(int);
129 bcopy((char *)&pwd.pw_change, p, sizeof(time_t));
130 p += sizeof(time_t);
131 COMPACT(pwd.pw_class);
132 COMPACT(pwd.pw_gecos);
133 COMPACT(pwd.pw_dir);
134 COMPACT(pwd.pw_shell);
135 bcopy((char *)&pwd.pw_expire, p, sizeof(time_t));
136 p += sizeof(time_t);
137 data.dsize = p - buf;
138
139 /* Store insecure by name. */
140 tbuf[0] = _PW_KEYBYNAME;
141 len = strlen(pwd.pw_name);
142 bcopy(pwd.pw_name, tbuf + 1, len);
143 key.dsize = len + 1;
144 if (dbm_store(dp, key, data, DBM_INSERT) < 0)
145 error("dbm file");
146
147 /* Store insecure by number. */
148 tbuf[0] = _PW_KEYBYNUM;
149 bcopy((char *)&cnt, tbuf + 1, sizeof(cnt));
150 key.dsize = sizeof(cnt) + 1;
151 if (dbm_store(dp, key, data, DBM_INSERT) < 0)
152 error("dbm file");
153
154 /* Store insecure by uid. */
155 tbuf[0] = _PW_KEYBYUID;
156 bcopy((char *)&pwd.pw_uid, tbuf + 1, sizeof(pwd.pw_uid));
157 key.dsize = sizeof(pwd.pw_uid) + 1;
158 if (dbm_store(dp, key, data, DBM_INSERT) < 0)
159 error("dbm file");
160
161 /* Create secure data. */
162 p = buf;
163 COMPACT(pwd.pw_name);
164 COMPACT(pwd.pw_passwd);
165 bcopy((char *)&pwd.pw_uid, p, sizeof(int));
166 p += sizeof(int);
167 bcopy((char *)&pwd.pw_gid, p, sizeof(int));
168 p += sizeof(int);
169 bcopy((char *)&pwd.pw_change, p, sizeof(time_t));
170 p += sizeof(time_t);
171 COMPACT(pwd.pw_class);
172 COMPACT(pwd.pw_gecos);
173 COMPACT(pwd.pw_dir);
174 COMPACT(pwd.pw_shell);
175 bcopy((char *)&pwd.pw_expire, p, sizeof(time_t));
176 p += sizeof(time_t);
177 data.dsize = p - buf;
178
179 /* Store secure by name. */
180 tbuf[0] = _PW_KEYBYNAME;
181 len = strlen(pwd.pw_name);
182 bcopy(pwd.pw_name, tbuf + 1, len);
183 key.dsize = len + 1;
184 if (dbm_store(edp, key, data, DBM_INSERT) < 0)
185 error("dbm file");
186
187 /* Store secure by number. */
188 tbuf[0] = _PW_KEYBYNUM;
189 bcopy((char *)&cnt, tbuf + 1, sizeof(cnt));
190 key.dsize = sizeof(cnt) + 1;
191 if (dbm_store(edp, key, data, DBM_INSERT) < 0)
192 error("dbm file");
193
194 /* Store secure by uid. */
195 tbuf[0] = _PW_KEYBYUID;
196 bcopy((char *)&pwd.pw_uid, tbuf + 1, sizeof(pwd.pw_uid));
197 key.dsize = sizeof(pwd.pw_uid) + 1;
198 if (dbm_store(edp, key, data, DBM_INSERT) < 0)
199 error("dbm file");
200
201 /* Create original format password file entry */
202 if (makeold)
203 (void)fprintf(oldfp, "%s:*:%d:%d:%s:%s:%s\n",
204 pwd.pw_name, pwd.pw_uid, pwd.pw_gid, pwd.pw_gecos,
205 pwd.pw_dir, pwd.pw_shell);
206 }
207 (void)dbm_close(edp);
208 (void)dbm_close(dp);
209 if (makeold)
210 (void)fclose(oldfp);
211
212 /* Set master.passwd permissions, in case caller forgot. */
213 (void)fchmod(fp, S_IRUSR|S_IWUSR);
214 (void)fclose(fp);
215
216 /* Install as the real password files. */
5641bcd3 217 (void)sprintf(buf, "%s.tmp.%s", _PATH_MP_DB, DBM_SUFFIX);
6257c216 218 mv(buf, _PATH_MP_DB);
5641bcd3 219 (void)sprintf(buf, "%s.tmp.%s", _PATH_SMP_DB, DBM_SUFFIX);
6257c216
KB
220 mv(buf, _PATH_SMP_DB);
221 if (makeold) {
222 (void)sprintf(buf, "%s.orig", pname);
223 mv(buf, _PATH_PASSWD);
224 }
225 /*
226 * Move the master password LAST -- chpass(1), passwd(1) and vipw(8)
227 * all use flock(2) on it to block other incarnations of themselves.
228 * The rename means that everything is unlocked, as the original file
229 * can no longer be accessed.
230 */
231 mv(pname, _PATH_MASTERPASSWD);
232 exit(0);
233}
234
235scan(fp, pw)
236 FILE *fp;
237 struct passwd *pw;
238{
239 static int lcnt;
240 static char line[LINE_MAX];
241 char *p;
242
243 if (!fgets(line, sizeof(line), fp))
244 return(0);
245 ++lcnt;
246 /*
247 * ``... if I swallow anything evil, put your fingers down my
248 * throat...''
249 * -- The Who
250 */
251 if (!(p = index(line, '\n'))) {
252 (void)fprintf(stderr, "pwd_mkdb: line too long\n");
253 goto fmt;
254
255 }
256 *p = '\0';
257 if (!pw_scan(line, pw)) {
258 (void)fprintf(stderr, "pwd_mkdb: at line #%d.\n", lcnt);
259fmt: errno = EFTYPE;
260 error(pname);
261 exit(1);
262 }
263}
264
265mv(from, to)
266 char *from, *to;
267{
268 int sverrno;
269 char buf[MAXPATHLEN];
270
271 if (rename(from, to)) {
272 sverrno = errno;
273 (void)sprintf(buf, "%s to %s", from, to);
274 errno = sverrno;
275 error(buf);
276 }
277}
278
279cleanup()
280{
281 char buf[MAXPATHLEN];
282
283 switch(clean) {
284 case FILE_ORIG:
285 (void)sprintf(buf, "%s.orig", pname);
286 (void)unlink(buf);
287 /* FALLTHROUGH */
288 case FILE_SECURE:
289 (void)sprintf(buf, "%s.tmp", _PATH_SMP_DB);
290 (void)unlink(buf);
291 /* FALLTHROUGH */
292 case FILE_INSECURE:
293 (void)sprintf(buf, "%s.tmp", _PATH_MP_DB);
294 (void)unlink(buf);
295 }
296}
297
298error(name)
299 char *name;
300{
301 (void)fprintf(stderr, "pwd_mkdb: %s: %s\n", name, strerror(errno));
302 cleanup();
303 exit(1);
304}
305
306usage()
307{
308 (void)fprintf(stderr, "usage: pwd_mkdb [-p] file\n");
309 exit(1);
310}