change conventions on static routine, ``call_accepted'';
[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
506c5020 15static char sccsid[] = "@(#)pwd_mkdb.c 5.4 (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
c557c546
KB
119 data.data = (u_char *)buf;
120 key.data = (u_char *)tbuf;
6257c216
KB
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);
c557c546 139 data.size = p - buf;
6257c216
KB
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);
c557c546
KB
145 key.size = len + 1;
146 if ((dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1)
147 error("put");
6257c216
KB
148
149 /* Store insecure by number. */
150 tbuf[0] = _PW_KEYBYNUM;
151 bcopy((char *)&cnt, tbuf + 1, sizeof(cnt));
c557c546
KB
152 key.size = sizeof(cnt) + 1;
153 if ((dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1)
154 error("put");
6257c216
KB
155
156 /* Store insecure by uid. */
157 tbuf[0] = _PW_KEYBYUID;
158 bcopy((char *)&pwd.pw_uid, tbuf + 1, sizeof(pwd.pw_uid));
c557c546
KB
159 key.size = sizeof(pwd.pw_uid) + 1;
160 if ((dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1)
161 error("put");
6257c216
KB
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);
c557c546 179 data.size = p - buf;
6257c216
KB
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);
c557c546
KB
185 key.size = len + 1;
186 if ((dp->put)(edp, &key, &data, R_NOOVERWRITE) == -1)
187 error("put");
6257c216
KB
188
189 /* Store secure by number. */
190 tbuf[0] = _PW_KEYBYNUM;
191 bcopy((char *)&cnt, tbuf + 1, sizeof(cnt));
c557c546
KB
192 key.size = sizeof(cnt) + 1;
193 if ((dp->put)(edp, &key, &data, R_NOOVERWRITE) == -1)
194 error("put");
6257c216
KB
195
196 /* Store secure by uid. */
197 tbuf[0] = _PW_KEYBYUID;
198 bcopy((char *)&pwd.pw_uid, tbuf + 1, sizeof(pwd.pw_uid));
c557c546
KB
199 key.size = sizeof(pwd.pw_uid) + 1;
200 if ((dp->put)(edp, &key, &data, R_NOOVERWRITE) == -1)
201 error("put");
6257c216
KB
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 }
c557c546
KB
209 (void)(dp->close)(dp);
210 (void)(edp->close)(edp);
211 if (makeold) {
212 (void)fsync(oldfp);
6257c216 213 (void)fclose(oldfp);
c557c546 214 }
6257c216
KB
215
216 /* Set master.passwd permissions, in case caller forgot. */
506c5020 217 (void)fchmod(fileno(fp), S_IRUSR|S_IWUSR);
6257c216
KB
218 (void)fclose(fp);
219
220 /* Install as the real password files. */
c557c546 221 (void)sprintf(buf, "%s.tmp", _PATH_MP_DB);
6257c216 222 mv(buf, _PATH_MP_DB);
c557c546 223 (void)sprintf(buf, "%s.tmp", _PATH_SMP_DB);
6257c216
KB
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
239scan(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);
263fmt: errno = EFTYPE;
264 error(pname);
265 exit(1);
266 }
267}
268
269mv(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
c557c546
KB
283error(name)
284 char *name;
285{
286 (void)fprintf(stderr, "pwd_mkdb: %s: %s\n", name, strerror(errno));
287 cleanup();
288 exit(1);
289}
290
6257c216
KB
291cleanup()
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
6257c216
KB
310usage()
311{
312 (void)fprintf(stderr, "usage: pwd_mkdb [-p] file\n");
313 exit(1);
314}