pwd_mkdb.c revision 1.31 1 1.31 sketch /* $NetBSD: pwd_mkdb.c,v 1.31 2006/09/23 17:17:04 sketch Exp $ */
2 1.19 ad
3 1.11 fair /*
4 1.5 mycroft * Copyright (c) 1991, 1993, 1994
5 1.5 mycroft * The Regents of the University of California. All rights reserved.
6 1.26 agc *
7 1.26 agc * Redistribution and use in source and binary forms, with or without
8 1.26 agc * modification, are permitted provided that the following conditions
9 1.26 agc * are met:
10 1.26 agc * 1. Redistributions of source code must retain the above copyright
11 1.26 agc * notice, this list of conditions and the following disclaimer.
12 1.26 agc * 2. Redistributions in binary form must reproduce the above copyright
13 1.26 agc * notice, this list of conditions and the following disclaimer in the
14 1.26 agc * documentation and/or other materials provided with the distribution.
15 1.26 agc * 3. Neither the name of the University nor the names of its contributors
16 1.26 agc * may be used to endorse or promote products derived from this software
17 1.26 agc * without specific prior written permission.
18 1.26 agc *
19 1.26 agc * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 1.26 agc * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 1.26 agc * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 1.26 agc * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 1.26 agc * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 1.26 agc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 1.26 agc * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 1.26 agc * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 1.26 agc * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 1.26 agc * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 1.26 agc * SUCH DAMAGE.
30 1.26 agc */
31 1.26 agc
32 1.26 agc /*
33 1.6 phil * Portions Copyright(C) 1994, Jason Downs. All rights reserved.
34 1.1 cgd *
35 1.1 cgd * Redistribution and use in source and binary forms, with or without
36 1.1 cgd * modification, are permitted provided that the following conditions
37 1.1 cgd * are met:
38 1.1 cgd * 1. Redistributions of source code must retain the above copyright
39 1.1 cgd * notice, this list of conditions and the following disclaimer.
40 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright
41 1.1 cgd * notice, this list of conditions and the following disclaimer in the
42 1.1 cgd * documentation and/or other materials provided with the distribution.
43 1.1 cgd *
44 1.27 agc * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS
45 1.27 agc * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
46 1.27 agc * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
47 1.27 agc * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT,
48 1.27 agc * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
49 1.27 agc * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
50 1.27 agc * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
51 1.27 agc * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
52 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
53 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
54 1.1 cgd * SUCH DAMAGE.
55 1.1 cgd */
56 1.1 cgd
57 1.28 lukem #if HAVE_NBTOOL_CONFIG_H
58 1.28 lukem #include "nbtool_config.h"
59 1.23 tv #endif
60 1.23 tv
61 1.10 lukem #include <sys/cdefs.h>
62 1.28 lukem #if !defined(lint)
63 1.17 mycroft __COPYRIGHT("@(#) Copyright (c) 2000\n\
64 1.17 mycroft The NetBSD Foundation, Inc. All rights reserved.\n\
65 1.17 mycroft Copyright (c) 1991, 1993, 1994\n\
66 1.10 lukem The Regents of the University of California. All rights reserved.\n");
67 1.17 mycroft __SCCSID("from: @(#)pwd_mkdb.c 8.5 (Berkeley) 4/20/94");
68 1.31 sketch __RCSID("$NetBSD: pwd_mkdb.c,v 1.31 2006/09/23 17:17:04 sketch Exp $");
69 1.1 cgd #endif /* not lint */
70 1.1 cgd
71 1.29 jmc #if HAVE_NBTOOL_CONFIG_H
72 1.29 jmc #include "compat_pwd.h"
73 1.29 jmc #else
74 1.29 jmc #include <pwd.h>
75 1.29 jmc #endif
76 1.29 jmc
77 1.1 cgd #include <sys/param.h>
78 1.1 cgd #include <sys/stat.h>
79 1.5 mycroft
80 1.1 cgd #include <db.h>
81 1.24 tv #include <err.h>
82 1.1 cgd #include <errno.h>
83 1.5 mycroft #include <fcntl.h>
84 1.1 cgd #include <limits.h>
85 1.5 mycroft #include <signal.h>
86 1.1 cgd #include <stdio.h>
87 1.5 mycroft #include <stdlib.h>
88 1.1 cgd #include <string.h>
89 1.5 mycroft #include <unistd.h>
90 1.24 tv #include <util.h>
91 1.23 tv
92 1.22 ad #define MAX_CACHESIZE 8*1024*1024
93 1.22 ad #define MIN_CACHESIZE 2*1024*1024
94 1.22 ad
95 1.19 ad #define PERM_INSECURE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
96 1.19 ad #define PERM_SECURE (S_IRUSR | S_IWUSR)
97 1.1 cgd
98 1.28 lukem #if HAVE_NBTOOL_CONFIG_H
99 1.23 tv static const char __yp_token[] = "__YP!";
100 1.23 tv #else
101 1.22 ad /* Pull this out of the C library. */
102 1.6 phil extern const char __yp_token[];
103 1.23 tv #endif
104 1.6 phil
105 1.5 mycroft HASHINFO openinfo = {
106 1.5 mycroft 4096, /* bsize */
107 1.5 mycroft 32, /* ffactor */
108 1.5 mycroft 256, /* nelem */
109 1.22 ad 0, /* cachesize */
110 1.5 mycroft NULL, /* hash() */
111 1.5 mycroft 0 /* lorder */
112 1.5 mycroft };
113 1.1 cgd
114 1.22 ad #define FILE_INSECURE 0x01
115 1.22 ad #define FILE_SECURE 0x02
116 1.22 ad #define FILE_ORIG 0x04
117 1.22 ad
118 1.22 ad static char *pname; /* password file name */
119 1.22 ad static char prefix[MAXPATHLEN];
120 1.22 ad static char oldpwdfile[MAX(MAXPATHLEN, LINE_MAX * 2)];
121 1.22 ad static char pwd_db_tmp[MAX(MAXPATHLEN, LINE_MAX * 2)];
122 1.22 ad static char pwd_Sdb_tmp[MAX(MAXPATHLEN, LINE_MAX * 2)];
123 1.22 ad static int lorder = BYTE_ORDER;
124 1.22 ad static int clean;
125 1.22 ad
126 1.22 ad void bailout(void);
127 1.22 ad void cp(const char *, const char *, mode_t);
128 1.22 ad int deldbent(DB *, const char *, int, void *);
129 1.19 ad void error(const char *);
130 1.22 ad int getdbent(DB *, const char *, int, void *, struct passwd **);
131 1.22 ad void inconsistancy(void);
132 1.22 ad void install(const char *, const char *);
133 1.19 ad int main(int, char **);
134 1.22 ad void putdbents(DB *, struct passwd *, const char *, int, const char *, int,
135 1.22 ad int, int);
136 1.22 ad void putyptoken(DB *, const char *);
137 1.19 ad void rm(const char *);
138 1.19 ad int scan(FILE *, struct passwd *, int *, int *);
139 1.19 ad void usage(void);
140 1.22 ad void wr_error(const char *);
141 1.5 mycroft
142 1.5 mycroft int
143 1.19 ad main(int argc, char *argv[])
144 1.1 cgd {
145 1.22 ad int ch, makeold, tfd, lineno, found, rv, hasyp, secureonly;
146 1.22 ad struct passwd pwd, *tpwd;
147 1.22 ad char *username;
148 1.5 mycroft DB *dp, *edp;
149 1.1 cgd FILE *fp, *oldfp;
150 1.1 cgd sigset_t set;
151 1.22 ad int dbflg, uid_dbflg, newuser, olduid, flags;
152 1.22 ad char buf[MAXPATHLEN];
153 1.22 ad struct stat st;
154 1.22 ad u_int cachesize;
155 1.1 cgd
156 1.21 tron prefix[0] = '\0';
157 1.1 cgd makeold = 0;
158 1.22 ad oldfp = NULL;
159 1.22 ad username = NULL;
160 1.22 ad hasyp = 0;
161 1.22 ad secureonly = 0;
162 1.30 lukem found = 0;
163 1.30 lukem newuser = 0;
164 1.30 lukem dp = NULL;
165 1.31 sketch cachesize = 0;
166 1.22 ad
167 1.31 sketch while ((ch = getopt(argc, argv, "BLc:d:psu:v")) != -1)
168 1.22 ad switch (ch) {
169 1.22 ad case 'B': /* big-endian output */
170 1.22 ad lorder = BIG_ENDIAN;
171 1.22 ad break;
172 1.22 ad case 'L': /* little-endian output */
173 1.22 ad lorder = LITTLE_ENDIAN;
174 1.22 ad break;
175 1.31 sketch case 'c':
176 1.31 sketch cachesize = atoi(optarg) * 1024 * 1024;
177 1.31 sketch break;
178 1.19 ad case 'd': /* set prefix */
179 1.25 itojun strlcpy(prefix, optarg, sizeof(prefix));
180 1.8 lukem break;
181 1.1 cgd case 'p': /* create V7 "file.orig" */
182 1.1 cgd makeold = 1;
183 1.1 cgd break;
184 1.22 ad case 's': /* modify secure db only */
185 1.22 ad secureonly = 1;
186 1.1 cgd break;
187 1.22 ad case 'u': /* modify one user only */
188 1.22 ad username = optarg;
189 1.17 mycroft break;
190 1.22 ad case 'v': /* backward compatible */
191 1.17 mycroft break;
192 1.1 cgd case '?':
193 1.1 cgd default:
194 1.1 cgd usage();
195 1.1 cgd }
196 1.1 cgd argc -= optind;
197 1.1 cgd argv += optind;
198 1.1 cgd
199 1.1 cgd if (argc != 1)
200 1.1 cgd usage();
201 1.22 ad if (username != NULL)
202 1.22 ad if (username[0] == '+' || username[0] == '-')
203 1.22 ad usage();
204 1.22 ad if (secureonly)
205 1.22 ad makeold = 0;
206 1.4 cgd
207 1.1 cgd /*
208 1.5 mycroft * This could be changed to allow the user to interrupt.
209 1.5 mycroft * Probably not worth the effort.
210 1.1 cgd */
211 1.1 cgd sigemptyset(&set);
212 1.1 cgd sigaddset(&set, SIGTSTP);
213 1.1 cgd sigaddset(&set, SIGHUP);
214 1.1 cgd sigaddset(&set, SIGINT);
215 1.1 cgd sigaddset(&set, SIGQUIT);
216 1.1 cgd sigaddset(&set, SIGTERM);
217 1.1 cgd (void)sigprocmask(SIG_BLOCK, &set, (sigset_t *)NULL);
218 1.1 cgd
219 1.5 mycroft /* We don't care what the user wants. */
220 1.5 mycroft (void)umask(0);
221 1.5 mycroft
222 1.22 ad if (username == NULL)
223 1.22 ad flags = O_RDWR | O_CREAT | O_EXCL;
224 1.22 ad else
225 1.22 ad flags = O_RDWR;
226 1.22 ad
227 1.1 cgd pname = *argv;
228 1.1 cgd /* Open the original password file */
229 1.19 ad if ((fp = fopen(pname, "r")) == NULL)
230 1.1 cgd error(pname);
231 1.1 cgd
232 1.17 mycroft openinfo.lorder = lorder;
233 1.17 mycroft
234 1.22 ad if (fstat(fileno(fp), &st) == -1)
235 1.22 ad error(pname);
236 1.22 ad
237 1.31 sketch if (cachesize) {
238 1.31 sketch openinfo.cachesize = cachesize;
239 1.31 sketch } else {
240 1.31 sketch /* Tweak openinfo values for large passwd files. */
241 1.31 sketch cachesize = st.st_size * 20;
242 1.31 sketch if (cachesize > MAX_CACHESIZE)
243 1.31 sketch cachesize = MAX_CACHESIZE;
244 1.31 sketch else if (cachesize < MIN_CACHESIZE)
245 1.31 sketch cachesize = MIN_CACHESIZE;
246 1.31 sketch openinfo.cachesize = cachesize;
247 1.31 sketch }
248 1.22 ad
249 1.1 cgd /* Open the temporary insecure password database. */
250 1.22 ad if (!secureonly) {
251 1.22 ad (void)snprintf(pwd_db_tmp, sizeof(pwd_db_tmp), "%s%s.tmp",
252 1.22 ad prefix, _PATH_MP_DB);
253 1.22 ad if (username != NULL) {
254 1.22 ad snprintf(buf, sizeof(buf), "%s" _PATH_MP_DB, prefix);
255 1.22 ad cp(buf, pwd_db_tmp, PERM_INSECURE);
256 1.22 ad }
257 1.22 ad dp = dbopen(pwd_db_tmp, flags, PERM_INSECURE, DB_HASH,
258 1.22 ad &openinfo);
259 1.22 ad if (dp == NULL)
260 1.22 ad error(pwd_db_tmp);
261 1.22 ad clean |= FILE_INSECURE;
262 1.22 ad }
263 1.22 ad
264 1.22 ad /* Open the temporary encrypted password database. */
265 1.22 ad (void)snprintf(pwd_Sdb_tmp, sizeof(pwd_Sdb_tmp), "%s%s.tmp", prefix,
266 1.22 ad _PATH_SMP_DB);
267 1.22 ad if (username != NULL) {
268 1.22 ad snprintf(buf, sizeof(buf), "%s" _PATH_SMP_DB, prefix);
269 1.22 ad cp(buf, pwd_Sdb_tmp, PERM_SECURE);
270 1.22 ad }
271 1.22 ad edp = dbopen(pwd_Sdb_tmp, flags, PERM_SECURE, DB_HASH, &openinfo);
272 1.22 ad if (!edp)
273 1.22 ad error(pwd_Sdb_tmp);
274 1.22 ad clean |= FILE_SECURE;
275 1.1 cgd
276 1.1 cgd /*
277 1.1 cgd * Open file for old password file. Minor trickiness -- don't want to
278 1.1 cgd * chance the file already existing, since someone (stupidly) might
279 1.1 cgd * still be using this for permission checking. So, open it first and
280 1.5 mycroft * fdopen the resulting fd. The resulting file should be readable by
281 1.5 mycroft * everyone.
282 1.1 cgd */
283 1.1 cgd if (makeold) {
284 1.11 fair (void)snprintf(oldpwdfile, sizeof(oldpwdfile), "%s.orig",
285 1.19 ad pname);
286 1.19 ad if ((tfd = open(oldpwdfile, O_WRONLY | O_CREAT | O_EXCL,
287 1.19 ad PERM_INSECURE)) < 0)
288 1.11 fair error(oldpwdfile);
289 1.22 ad clean |= FILE_ORIG;
290 1.5 mycroft if ((oldfp = fdopen(tfd, "w")) == NULL)
291 1.11 fair error(oldpwdfile);
292 1.22 ad }
293 1.22 ad
294 1.22 ad if (username != NULL) {
295 1.22 ad uid_dbflg = 0;
296 1.22 ad dbflg = 0;
297 1.22 ad
298 1.22 ad /*
299 1.22 ad * Determine if this is a new entry.
300 1.22 ad */
301 1.22 ad if (getdbent(edp, pwd_Sdb_tmp, _PW_KEYBYNAME, username, &tpwd))
302 1.22 ad newuser = 1;
303 1.22 ad else {
304 1.22 ad newuser = 0;
305 1.22 ad olduid = tpwd->pw_uid;
306 1.22 ad }
307 1.22 ad
308 1.22 ad } else {
309 1.22 ad uid_dbflg = R_NOOVERWRITE;
310 1.22 ad dbflg = R_NOOVERWRITE;
311 1.1 cgd }
312 1.1 cgd
313 1.1 cgd /*
314 1.6 phil * If we see something go by that looks like YP, we save a special
315 1.6 phil * pointer record, which if YP is enabled in the C lib, will speed
316 1.6 phil * things up.
317 1.1 cgd */
318 1.19 ad for (lineno = 0; scan(fp, &pwd, &flags, &lineno);) {
319 1.9 thorpej /*
320 1.22 ad * Create original format password file entry.
321 1.9 thorpej */
322 1.11 fair if (makeold) {
323 1.5 mycroft (void)fprintf(oldfp, "%s:*:%d:%d:%s:%s:%s\n",
324 1.5 mycroft pwd.pw_name, pwd.pw_uid, pwd.pw_gid, pwd.pw_gecos,
325 1.5 mycroft pwd.pw_dir, pwd.pw_shell);
326 1.19 ad if (ferror(oldfp))
327 1.11 fair wr_error(oldpwdfile);
328 1.11 fair }
329 1.22 ad
330 1.22 ad if (username == NULL) {
331 1.22 ad /* Look like YP? */
332 1.22 ad if (pwd.pw_name[0] == '+' || pwd.pw_name[0] == '-')
333 1.22 ad hasyp++;
334 1.22 ad
335 1.22 ad /* Warn about potentially unsafe uid/gid overrides. */
336 1.22 ad if (pwd.pw_name[0] == '+') {
337 1.22 ad if ((flags & _PASSWORD_NOUID) == 0 &&
338 1.22 ad pwd.pw_uid == 0)
339 1.22 ad warnx("line %d: superuser override "
340 1.22 ad "in YP inclusion", lineno);
341 1.22 ad if ((flags & _PASSWORD_NOGID) == 0 &&
342 1.22 ad pwd.pw_gid == 0)
343 1.22 ad warnx("line %d: wheel override "
344 1.22 ad "in YP inclusion", lineno);
345 1.22 ad }
346 1.22 ad
347 1.22 ad /* Write the database entry out. */
348 1.22 ad if (!secureonly)
349 1.22 ad putdbents(dp, &pwd, "*", flags, pwd_db_tmp,
350 1.22 ad lineno, dbflg, uid_dbflg);
351 1.22 ad continue;
352 1.22 ad } else if (strcmp(username, pwd.pw_name) != 0)
353 1.22 ad continue;
354 1.22 ad
355 1.22 ad if (found) {
356 1.22 ad warnx("user `%s' listed twice in password file",
357 1.22 ad username);
358 1.22 ad bailout();
359 1.22 ad }
360 1.22 ad
361 1.22 ad /*
362 1.22 ad * Ensure that the text file and database agree on
363 1.22 ad * which line the record is from.
364 1.22 ad */
365 1.22 ad rv = getdbent(edp, pwd_Sdb_tmp, _PW_KEYBYNUM, &lineno, &tpwd);
366 1.22 ad if (newuser) {
367 1.22 ad if (rv == 0)
368 1.22 ad inconsistancy();
369 1.22 ad } else if (rv == -1 ||
370 1.22 ad strcmp(username, tpwd->pw_name) != 0)
371 1.22 ad inconsistancy();
372 1.22 ad else if (olduid != pwd.pw_uid) {
373 1.22 ad /*
374 1.22 ad * If we're changing UID, remove the BYUID
375 1.22 ad * record for the old UID only if it has the
376 1.22 ad * same username.
377 1.22 ad */
378 1.22 ad if (!getdbent(edp, pwd_Sdb_tmp, _PW_KEYBYUID, &olduid,
379 1.22 ad &tpwd)) {
380 1.22 ad if (strcmp(username, tpwd->pw_name) == 0) {
381 1.22 ad if (!secureonly)
382 1.22 ad deldbent(dp, pwd_db_tmp,
383 1.22 ad _PW_KEYBYUID, &olduid);
384 1.22 ad deldbent(edp, pwd_Sdb_tmp,
385 1.22 ad _PW_KEYBYUID, &olduid);
386 1.22 ad }
387 1.22 ad } else
388 1.22 ad inconsistancy();
389 1.22 ad }
390 1.22 ad
391 1.22 ad /*
392 1.22 ad * If there's an existing BYUID record for the new UID and
393 1.22 ad * the username doesn't match then be sure not to overwrite
394 1.22 ad * it.
395 1.22 ad */
396 1.22 ad if (!getdbent(edp, pwd_Sdb_tmp, _PW_KEYBYUID, &pwd.pw_uid,
397 1.22 ad &tpwd))
398 1.22 ad if (strcmp(username, tpwd->pw_name) != 0)
399 1.22 ad uid_dbflg = R_NOOVERWRITE;
400 1.22 ad
401 1.22 ad /* Write the database entries out */
402 1.22 ad if (!secureonly)
403 1.22 ad putdbents(dp, &pwd, "*", flags, pwd_db_tmp, lineno,
404 1.22 ad dbflg, uid_dbflg);
405 1.22 ad putdbents(edp, &pwd, pwd.pw_passwd, flags, pwd_Sdb_tmp,
406 1.22 ad lineno, dbflg, uid_dbflg);
407 1.22 ad
408 1.22 ad found = 1;
409 1.22 ad if (!makeold)
410 1.22 ad break;
411 1.22 ad }
412 1.22 ad
413 1.22 ad if (!secureonly) {
414 1.22 ad /* Store YP token if needed. */
415 1.22 ad if (hasyp)
416 1.22 ad putyptoken(dp, pwd_db_tmp);
417 1.22 ad
418 1.22 ad /* Close the insecure database. */
419 1.22 ad if ((*dp->close)(dp) < 0)
420 1.22 ad wr_error(pwd_db_tmp);
421 1.22 ad }
422 1.22 ad
423 1.22 ad /*
424 1.22 ad * If rebuilding the databases, we re-parse the text file and write
425 1.22 ad * the secure entries out in a separate pass.
426 1.22 ad */
427 1.22 ad if (username == NULL) {
428 1.22 ad rewind(fp);
429 1.22 ad for (lineno = 0; scan(fp, &pwd, &flags, &lineno);)
430 1.22 ad putdbents(edp, &pwd, pwd.pw_passwd, flags, pwd_Sdb_tmp,
431 1.22 ad lineno, dbflg, uid_dbflg);
432 1.22 ad
433 1.22 ad /* Store YP token if needed. */
434 1.22 ad if (hasyp)
435 1.22 ad putyptoken(edp, pwd_Sdb_tmp);
436 1.22 ad } else if (!found) {
437 1.22 ad warnx("user `%s' not found in password file", username);
438 1.22 ad bailout();
439 1.5 mycroft }
440 1.6 phil
441 1.22 ad /* Close the secure database. */
442 1.22 ad if ((*edp->close)(edp) < 0)
443 1.22 ad wr_error(pwd_Sdb_tmp);
444 1.22 ad
445 1.22 ad /* Install as the real password files. */
446 1.22 ad if (!secureonly)
447 1.22 ad install(pwd_db_tmp, _PATH_MP_DB);
448 1.22 ad install(pwd_Sdb_tmp, _PATH_SMP_DB);
449 1.6 phil
450 1.22 ad /* Install the V7 password file. */
451 1.5 mycroft if (makeold) {
452 1.19 ad if (fflush(oldfp) == EOF)
453 1.11 fair wr_error(oldpwdfile);
454 1.19 ad if (fclose(oldfp) == EOF)
455 1.11 fair wr_error(oldpwdfile);
456 1.22 ad install(oldpwdfile, _PATH_PASSWD);
457 1.5 mycroft }
458 1.5 mycroft
459 1.1 cgd /* Set master.passwd permissions, in case caller forgot. */
460 1.1 cgd (void)fchmod(fileno(fp), S_IRUSR|S_IWUSR);
461 1.19 ad if (fclose(fp) == EOF)
462 1.11 fair wr_error(pname);
463 1.1 cgd
464 1.19 ad /*
465 1.22 ad * Move the temporary master password file LAST -- chpass(1),
466 1.22 ad * passwd(1), vipw(8) and friends all use its existance to block
467 1.22 ad * other incarnations of themselves. The rename means that
468 1.22 ad * everything is unlocked, as the original file can no longer be
469 1.22 ad * accessed.
470 1.19 ad */
471 1.19 ad install(pname, _PATH_MASTERPASSWD);
472 1.19 ad exit(EXIT_SUCCESS);
473 1.19 ad /* NOTREACHED */
474 1.1 cgd }
475 1.1 cgd
476 1.5 mycroft int
477 1.19 ad scan(FILE *fp, struct passwd *pw, int *flags, int *lineno)
478 1.1 cgd {
479 1.1 cgd static char line[LINE_MAX];
480 1.1 cgd char *p;
481 1.17 mycroft int oflags;
482 1.1 cgd
483 1.19 ad if (fgets(line, sizeof(line), fp) == NULL)
484 1.5 mycroft return (0);
485 1.19 ad (*lineno)++;
486 1.19 ad
487 1.1 cgd /*
488 1.1 cgd * ``... if I swallow anything evil, put your fingers down my
489 1.1 cgd * throat...''
490 1.1 cgd * -- The Who
491 1.1 cgd */
492 1.19 ad if ((p = strchr(line, '\n')) == NULL) {
493 1.5 mycroft warnx("line too long");
494 1.19 ad errno = EFTYPE; /* XXX */
495 1.19 ad error(pname);
496 1.1 cgd }
497 1.1 cgd *p = '\0';
498 1.15 lukem if (strcmp(line, "+") == 0)
499 1.15 lukem strcpy(line, "+:::::::::"); /* pw_scan() can't handle "+" */
500 1.17 mycroft oflags = 0;
501 1.17 mycroft if (!pw_scan(line, pw, &oflags)) {
502 1.19 ad warnx("at line #%d", *lineno);
503 1.19 ad errno = EFTYPE; /* XXX */
504 1.1 cgd error(pname);
505 1.1 cgd }
506 1.17 mycroft *flags = oflags;
507 1.5 mycroft
508 1.5 mycroft return (1);
509 1.1 cgd }
510 1.1 cgd
511 1.5 mycroft void
512 1.19 ad install(const char *from, const char *to)
513 1.1 cgd {
514 1.1 cgd char buf[MAXPATHLEN];
515 1.19 ad int sverrno;
516 1.1 cgd
517 1.19 ad snprintf(buf, sizeof(buf), "%s%s", prefix, to);
518 1.19 ad if (rename(from, buf)) {
519 1.19 ad sverrno = errno;
520 1.19 ad (void)snprintf(buf, sizeof(buf), "%s to %s", from, buf);
521 1.1 cgd errno = sverrno;
522 1.1 cgd error(buf);
523 1.1 cgd }
524 1.1 cgd }
525 1.1 cgd
526 1.5 mycroft void
527 1.22 ad rm(const char *victim)
528 1.22 ad {
529 1.22 ad
530 1.22 ad if (unlink(victim) < 0)
531 1.22 ad warn("unlink(%s)", victim);
532 1.22 ad }
533 1.22 ad
534 1.22 ad void
535 1.22 ad cp(const char *from, const char *to, mode_t mode)
536 1.22 ad {
537 1.22 ad static char buf[MAXBSIZE];
538 1.22 ad int from_fd, rcount, to_fd, wcount, sverrno;
539 1.22 ad
540 1.22 ad if ((from_fd = open(from, O_RDONLY, 0)) < 0)
541 1.22 ad error(from);
542 1.22 ad if ((to_fd = open(to, O_WRONLY | O_CREAT | O_EXCL, mode)) < 0)
543 1.22 ad error(to);
544 1.22 ad while ((rcount = read(from_fd, buf, MAXBSIZE)) > 0) {
545 1.22 ad wcount = write(to_fd, buf, rcount);
546 1.22 ad if (rcount != wcount || wcount == -1) {
547 1.22 ad sverrno = errno;
548 1.22 ad (void)snprintf(buf, sizeof(buf), "%s to %s", from, to);
549 1.22 ad errno = sverrno;
550 1.22 ad error(buf);
551 1.22 ad }
552 1.22 ad }
553 1.22 ad
554 1.22 ad if (rcount < 0) {
555 1.22 ad sverrno = errno;
556 1.22 ad (void)snprintf(buf, sizeof(buf), "%s to %s", from, to);
557 1.22 ad errno = sverrno;
558 1.22 ad error(buf);
559 1.22 ad }
560 1.22 ad }
561 1.22 ad
562 1.22 ad void
563 1.19 ad wr_error(const char *str)
564 1.11 fair {
565 1.19 ad char errbuf[BUFSIZ];
566 1.19 ad int sverrno;
567 1.19 ad
568 1.19 ad sverrno = errno;
569 1.11 fair
570 1.11 fair (void)snprintf(errbuf, sizeof(errbuf),
571 1.19 ad "attempt to write %s failed", str);
572 1.11 fair
573 1.11 fair errno = sverrno;
574 1.11 fair error(errbuf);
575 1.11 fair }
576 1.11 fair
577 1.11 fair void
578 1.19 ad error(const char *str)
579 1.1 cgd {
580 1.5 mycroft
581 1.19 ad warn("%s", str);
582 1.22 ad bailout();
583 1.1 cgd }
584 1.1 cgd
585 1.5 mycroft void
586 1.22 ad inconsistancy(void)
587 1.11 fair {
588 1.19 ad
589 1.22 ad warnx("text files and databases are inconsistent");
590 1.22 ad warnx("re-build the databases without -u");
591 1.22 ad bailout();
592 1.11 fair }
593 1.11 fair
594 1.11 fair void
595 1.22 ad bailout(void)
596 1.1 cgd {
597 1.19 ad
598 1.22 ad if ((clean & FILE_ORIG) != 0)
599 1.11 fair rm(oldpwdfile);
600 1.22 ad if ((clean & FILE_SECURE) != 0)
601 1.11 fair rm(pwd_Sdb_tmp);
602 1.22 ad if ((clean & FILE_INSECURE) != 0)
603 1.11 fair rm(pwd_db_tmp);
604 1.22 ad
605 1.22 ad exit(EXIT_FAILURE);
606 1.1 cgd }
607 1.1 cgd
608 1.19 ad /*
609 1.19 ad * Write entries to a database for a single user.
610 1.19 ad *
611 1.19 ad * The databases actually contain three copies of the original data. Each
612 1.19 ad * password file entry is converted into a rough approximation of a ``struct
613 1.19 ad * passwd'', with the strings placed inline. This object is then stored as
614 1.19 ad * the data for three separate keys. The first key * is the pw_name field
615 1.19 ad * prepended by the _PW_KEYBYNAME character. The second key is the pw_uid
616 1.19 ad * field prepended by the _PW_KEYBYUID character. The third key is the line
617 1.19 ad * number in the original file prepended by the _PW_KEYBYNUM character.
618 1.19 ad * (The special characters are prepended to ensure that the keys do not
619 1.19 ad * collide.)
620 1.19 ad */
621 1.19 ad #define COMPACT(e) for (t = e; (*p++ = *t++) != '\0';)
622 1.19 ad
623 1.19 ad void
624 1.22 ad putdbents(DB *dp, struct passwd *pw, const char *passwd, int flags,
625 1.22 ad const char *fn, int lineno, int dbflg, int uid_dbflg)
626 1.19 ad {
627 1.19 ad struct passwd pwd;
628 1.19 ad char buf[MAX(MAXPATHLEN, LINE_MAX * 2)], tbuf[1024], *p;
629 1.19 ad DBT data, key;
630 1.19 ad const char *t;
631 1.19 ad u_int32_t x;
632 1.19 ad int len;
633 1.19 ad
634 1.19 ad memcpy(&pwd, pw, sizeof(pwd));
635 1.19 ad data.data = (u_char *)buf;
636 1.19 ad key.data = (u_char *)tbuf;
637 1.19 ad
638 1.19 ad if (lorder != BYTE_ORDER) {
639 1.19 ad M_32_SWAP(pwd.pw_uid);
640 1.19 ad M_32_SWAP(pwd.pw_gid);
641 1.19 ad M_32_SWAP(pwd.pw_change);
642 1.19 ad M_32_SWAP(pwd.pw_expire);
643 1.19 ad }
644 1.19 ad
645 1.19 ad /* Create insecure data. */
646 1.19 ad p = buf;
647 1.19 ad COMPACT(pwd.pw_name);
648 1.19 ad COMPACT(passwd);
649 1.19 ad memmove(p, &pwd.pw_uid, sizeof(pwd.pw_uid));
650 1.19 ad p += sizeof(pwd.pw_uid);
651 1.19 ad memmove(p, &pwd.pw_gid, sizeof(pwd.pw_gid));
652 1.19 ad p += sizeof(pwd.pw_gid);
653 1.19 ad memmove(p, &pwd.pw_change, sizeof(pwd.pw_change));
654 1.19 ad p += sizeof(pwd.pw_change);
655 1.19 ad COMPACT(pwd.pw_class);
656 1.19 ad COMPACT(pwd.pw_gecos);
657 1.19 ad COMPACT(pwd.pw_dir);
658 1.19 ad COMPACT(pwd.pw_shell);
659 1.19 ad memmove(p, &pwd.pw_expire, sizeof(pwd.pw_expire));
660 1.19 ad p += sizeof(pwd.pw_expire);
661 1.19 ad x = flags;
662 1.19 ad if (lorder != BYTE_ORDER)
663 1.19 ad M_32_SWAP(x);
664 1.19 ad memmove(p, &x, sizeof(x));
665 1.19 ad p += sizeof(flags);
666 1.19 ad data.size = p - buf;
667 1.19 ad
668 1.19 ad /* Store insecure by name. */
669 1.19 ad tbuf[0] = _PW_KEYBYNAME;
670 1.19 ad len = strlen(pwd.pw_name);
671 1.19 ad memmove(tbuf + 1, pwd.pw_name, len);
672 1.19 ad key.size = len + 1;
673 1.22 ad if ((*dp->put)(dp, &key, &data, dbflg) == -1)
674 1.19 ad wr_error(fn);
675 1.22 ad
676 1.19 ad /* Store insecure by number. */
677 1.19 ad tbuf[0] = _PW_KEYBYNUM;
678 1.19 ad x = lineno;
679 1.19 ad if (lorder != BYTE_ORDER)
680 1.19 ad M_32_SWAP(x);
681 1.19 ad memmove(tbuf + 1, &x, sizeof(x));
682 1.19 ad key.size = sizeof(x) + 1;
683 1.22 ad if ((*dp->put)(dp, &key, &data, dbflg) == -1)
684 1.19 ad wr_error(fn);
685 1.19 ad
686 1.19 ad /* Store insecure by uid. */
687 1.19 ad tbuf[0] = _PW_KEYBYUID;
688 1.19 ad memmove(tbuf + 1, &pwd.pw_uid, sizeof(pwd.pw_uid));
689 1.19 ad key.size = sizeof(pwd.pw_uid) + 1;
690 1.22 ad if ((*dp->put)(dp, &key, &data, uid_dbflg) == -1)
691 1.22 ad wr_error(fn);
692 1.22 ad }
693 1.22 ad
694 1.22 ad int
695 1.22 ad deldbent(DB *dp, const char *fn, int type, void *keyp)
696 1.22 ad {
697 1.22 ad char tbuf[1024];
698 1.22 ad DBT key;
699 1.22 ad u_int32_t x;
700 1.22 ad int len, rv;
701 1.22 ad
702 1.22 ad key.data = (u_char *)tbuf;
703 1.22 ad
704 1.22 ad switch (tbuf[0] = type) {
705 1.22 ad case _PW_KEYBYNAME:
706 1.22 ad len = strlen((char *)keyp);
707 1.22 ad memcpy(tbuf + 1, keyp, len);
708 1.22 ad key.size = len + 1;
709 1.22 ad break;
710 1.22 ad
711 1.22 ad case _PW_KEYBYNUM:
712 1.22 ad case _PW_KEYBYUID:
713 1.22 ad x = *(int *)keyp;
714 1.22 ad if (lorder != BYTE_ORDER)
715 1.22 ad M_32_SWAP(x);
716 1.22 ad memmove(tbuf + 1, &x, sizeof(x));
717 1.22 ad key.size = sizeof(x) + 1;
718 1.22 ad break;
719 1.22 ad }
720 1.22 ad
721 1.22 ad if ((rv = (*dp->del)(dp, &key, 0)) == -1)
722 1.19 ad wr_error(fn);
723 1.22 ad return (rv);
724 1.22 ad }
725 1.22 ad
726 1.22 ad int
727 1.22 ad getdbent(DB *dp, const char *fn, int type, void *keyp, struct passwd **tpwd)
728 1.22 ad {
729 1.22 ad static char buf[MAX(MAXPATHLEN, LINE_MAX * 2)];
730 1.22 ad static struct passwd pwd;
731 1.22 ad char tbuf[1024], *p;
732 1.22 ad DBT key, data;
733 1.22 ad u_int32_t x;
734 1.22 ad int len, rv;
735 1.22 ad
736 1.22 ad data.data = (u_char *)buf;
737 1.22 ad data.size = sizeof(buf);
738 1.22 ad key.data = (u_char *)tbuf;
739 1.22 ad
740 1.22 ad switch (tbuf[0] = type) {
741 1.22 ad case _PW_KEYBYNAME:
742 1.22 ad len = strlen((char *)keyp);
743 1.22 ad memcpy(tbuf + 1, keyp, len);
744 1.22 ad key.size = len + 1;
745 1.22 ad break;
746 1.22 ad
747 1.22 ad case _PW_KEYBYNUM:
748 1.22 ad case _PW_KEYBYUID:
749 1.22 ad x = *(int *)keyp;
750 1.22 ad if (lorder != BYTE_ORDER)
751 1.22 ad M_32_SWAP(x);
752 1.22 ad memmove(tbuf + 1, &x, sizeof(x));
753 1.22 ad key.size = sizeof(x) + 1;
754 1.22 ad break;
755 1.22 ad }
756 1.22 ad
757 1.22 ad if ((rv = (*dp->get)(dp, &key, &data, 0)) == 1)
758 1.22 ad return (rv);
759 1.22 ad if (rv == -1)
760 1.22 ad error(pwd_Sdb_tmp);
761 1.22 ad
762 1.22 ad p = (char *)data.data;
763 1.22 ad
764 1.22 ad pwd.pw_name = p;
765 1.22 ad while (*p++ != '\0')
766 1.22 ad ;
767 1.22 ad pwd.pw_passwd = p;
768 1.22 ad while (*p++ != '\0')
769 1.22 ad ;
770 1.22 ad
771 1.22 ad memcpy(&pwd.pw_uid, p, sizeof(pwd.pw_uid));
772 1.22 ad p += sizeof(pwd.pw_uid);
773 1.22 ad memcpy(&pwd.pw_gid, p, sizeof(pwd.pw_gid));
774 1.22 ad p += sizeof(pwd.pw_gid);
775 1.22 ad memcpy(&pwd.pw_change, p, sizeof(pwd.pw_change));
776 1.22 ad p += sizeof(pwd.pw_change);
777 1.22 ad
778 1.22 ad pwd.pw_class = p;
779 1.22 ad while (*p++ != '\0')
780 1.22 ad ;
781 1.22 ad pwd.pw_gecos = p;
782 1.22 ad while (*p++ != '\0')
783 1.22 ad ;
784 1.22 ad pwd.pw_dir = p;
785 1.22 ad while (*p++ != '\0')
786 1.22 ad ;
787 1.22 ad pwd.pw_shell = p;
788 1.22 ad while (*p++ != '\0')
789 1.22 ad ;
790 1.22 ad
791 1.22 ad memcpy(&pwd.pw_expire, p, sizeof(pwd.pw_expire));
792 1.22 ad p += sizeof(pwd.pw_expire);
793 1.22 ad
794 1.22 ad if (lorder != BYTE_ORDER) {
795 1.22 ad M_32_SWAP(pwd.pw_uid);
796 1.22 ad M_32_SWAP(pwd.pw_gid);
797 1.22 ad M_32_SWAP(pwd.pw_change);
798 1.22 ad M_32_SWAP(pwd.pw_expire);
799 1.22 ad }
800 1.22 ad
801 1.22 ad *tpwd = &pwd;
802 1.22 ad return (0);
803 1.19 ad }
804 1.19 ad
805 1.19 ad void
806 1.19 ad putyptoken(DB *dp, const char *fn)
807 1.19 ad {
808 1.19 ad DBT data, key;
809 1.19 ad
810 1.19 ad key.data = (u_char *)__yp_token;
811 1.19 ad key.size = strlen(__yp_token);
812 1.19 ad data.data = (u_char *)NULL;
813 1.19 ad data.size = 0;
814 1.19 ad
815 1.22 ad if ((*dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1)
816 1.19 ad wr_error(fn);
817 1.19 ad }
818 1.19 ad
819 1.5 mycroft void
820 1.19 ad usage(void)
821 1.1 cgd {
822 1.5 mycroft
823 1.22 ad (void)fprintf(stderr,
824 1.31 sketch "usage: pwd_mkdb [-BLps] [-c cachesize] [-d directory] [-u user] file\n");
825 1.19 ad exit(EXIT_FAILURE);
826 1.1 cgd }
827