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