pwd_mkdb.c revision 113666
1/*- 2 * Copyright (c) 1991, 1993, 1994 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34#ifndef lint 35static const char copyright[] = 36"@(#) Copyright (c) 1991, 1993, 1994\n\ 37 The Regents of the University of California. All rights reserved.\n"; 38#endif /* not lint */ 39 40#ifndef lint 41#if 0 42static char sccsid[] = "@(#)pwd_mkdb.c 8.5 (Berkeley) 4/20/94"; 43#endif 44static const char rcsid[] = 45 "$FreeBSD: head/usr.sbin/pwd_mkdb/pwd_mkdb.c 113666 2003-04-18 14:11:17Z nectar $"; 46#endif /* not lint */ 47 48#include <sys/param.h> 49#include <sys/stat.h> 50#include <arpa/inet.h> 51 52#include <db.h> 53#include <err.h> 54#include <errno.h> 55#include <fcntl.h> 56#include <limits.h> 57#include <pwd.h> 58#include <signal.h> 59#include <stdio.h> 60#include <stdlib.h> 61#include <string.h> 62#include <unistd.h> 63 64#include "pw_scan.h" 65 66#define INSECURE 1 67#define SECURE 2 68#define PERM_INSECURE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) 69#define PERM_SECURE (S_IRUSR|S_IWUSR) 70#define LEGACY_VERSION(x) _PW_VERSIONED(x, 3) 71#define CURRENT_VERSION(x) _PW_VERSIONED(x, 4) 72 73HASHINFO openinfo = { 74 4096, /* bsize */ 75 32, /* ffactor */ 76 256, /* nelem */ 77 2048 * 1024, /* cachesize */ 78 NULL, /* hash() */ 79 0 /* lorder */ 80}; 81 82static enum state { FILE_INSECURE, FILE_SECURE, FILE_ORIG } clean; 83static struct passwd pwd; /* password structure */ 84static char *pname; /* password file name */ 85static char prefix[MAXPATHLEN]; 86 87static int is_comment; /* flag for comments */ 88static char line[LINE_MAX]; 89 90void cleanup(void); 91void error(const char *); 92void cp(char *, char *, mode_t mode); 93void mv(char *, char *); 94int scan(FILE *, struct passwd *); 95static void usage(void); 96 97int 98main(int argc, char *argv[]) 99{ 100 static char verskey[] = _PWD_VERSION_KEY; 101 char version = _PWD_CURRENT_VERSION; 102 DB *dp, *sdp, *pw_db; 103 DBT data, sdata, key; 104 FILE *fp, *oldfp; 105 sigset_t set; 106 int ch, cnt, ypcnt, makeold, tfd, yp_enabled = 0; 107 unsigned int len; 108 int32_t pw_change, pw_expire; 109 uint32_t store; 110 const char *t; 111 char *p; 112 char buf[MAX(MAXPATHLEN, LINE_MAX * 2)], tbuf[1024]; 113 char sbuf[MAX(MAXPATHLEN, LINE_MAX * 2)]; 114 char buf2[MAXPATHLEN]; 115 char sbuf2[MAXPATHLEN]; 116 char *username; 117 u_int method, methoduid; 118 int Cflag; 119 int nblock = 0; 120 121 Cflag = 0; 122 strcpy(prefix, _PATH_PWD); 123 makeold = 0; 124 username = NULL; 125 while ((ch = getopt(argc, argv, "Cd:ps:u:vN")) != -1) 126 switch(ch) { 127 case 'C': /* verify only */ 128 Cflag = 1; 129 break; 130 case 'd': 131 strncpy(prefix, optarg, sizeof prefix - 1); 132 break; 133 case 'p': /* create V7 "file.orig" */ 134 makeold = 1; 135 break; 136 case 's': /* change default cachesize */ 137 openinfo.cachesize = atoi(optarg) * 1024 * 1024; 138 break; 139 case 'u': /* only update this record */ 140 username = optarg; 141 break; 142 case 'v': /* backward compatible */ 143 break; 144 case 'N': /* do not wait for lock */ 145 nblock = LOCK_NB; 146 break; 147 default: 148 usage(); 149 } 150 argc -= optind; 151 argv += optind; 152 153 if (argc != 1 || (username && (*username == '+' || *username == '-'))) 154 usage(); 155 156 /* 157 * This could be changed to allow the user to interrupt. 158 * Probably not worth the effort. 159 */ 160 sigemptyset(&set); 161 sigaddset(&set, SIGTSTP); 162 sigaddset(&set, SIGHUP); 163 sigaddset(&set, SIGINT); 164 sigaddset(&set, SIGQUIT); 165 sigaddset(&set, SIGTERM); 166 (void)sigprocmask(SIG_BLOCK, &set, (sigset_t *)NULL); 167 168 /* We don't care what the user wants. */ 169 (void)umask(0); 170 171 pname = *argv; 172 173 /* 174 * Open and lock the original password file. We have to check 175 * the hardlink count after we get the lock to handle any potential 176 * unlink/rename race. 177 * 178 * This lock is necessary when someone runs pwd_mkdb manually, directly 179 * on master.passwd, to handle the case where a user might try to 180 * change his password while pwd_mkdb is running. 181 */ 182 for (;;) { 183 struct stat st; 184 185 if (!(fp = fopen(pname, "r"))) 186 error(pname); 187 if (flock(fileno(fp), LOCK_EX|nblock) < 0) 188 error("flock"); 189 if (fstat(fileno(fp), &st) < 0) 190 error(pname); 191 if (st.st_nlink != 0) 192 break; 193 fclose(fp); 194 fp = NULL; 195 } 196 197 /* check only if password database is valid */ 198 if (Cflag) { 199 for (cnt = 1; scan(fp, &pwd); ++cnt); 200 exit(0); 201 } 202 203 /* Open the temporary insecure password database. */ 204 (void)snprintf(buf, sizeof(buf), "%s/%s.tmp", prefix, _MP_DB); 205 (void)snprintf(sbuf, sizeof(sbuf), "%s/%s.tmp", prefix, _SMP_DB); 206 if (username) { 207 (void)snprintf(buf2, sizeof(buf2), "%s/%s", prefix, _MP_DB); 208 (void)snprintf(sbuf2, sizeof(sbuf2), "%s/%s", prefix, _SMP_DB); 209 210 clean = FILE_INSECURE; 211 cp(buf2, buf, PERM_INSECURE); 212 dp = dbopen(buf, 213 O_RDWR|O_EXCL, PERM_INSECURE, DB_HASH, &openinfo); 214 if (dp == NULL) 215 error(buf); 216 217 clean = FILE_SECURE; 218 cp(sbuf2, sbuf, PERM_SECURE); 219 sdp = dbopen(sbuf, 220 O_RDWR|O_EXCL, PERM_SECURE, DB_HASH, &openinfo); 221 if (sdp == NULL) 222 error(sbuf); 223 224 /* 225 * Do some trouble to check if we should store this users 226 * uid. Don't use getpwnam/getpwuid as that interferes 227 * with NIS. 228 */ 229 pw_db = dbopen(_PATH_MP_DB, O_RDONLY, 0, DB_HASH, NULL); 230 if (!pw_db) 231 error(_MP_DB); 232 buf[0] = CURRENT_VERSION(_PW_KEYBYNAME); 233 len = strlen(username); 234 235 /* Only check that username fits in buffer */ 236 memmove(buf + 1, username, MIN(len, sizeof(buf) - 1)); 237 key.data = (u_char *)buf; 238 key.size = len + 1; 239 if ((pw_db->get)(pw_db, &key, &data, 0) == 0) { 240 p = (char *)data.data; 241 242 /* jump over pw_name and pw_passwd, to get to pw_uid */ 243 while (*p++) 244 ; 245 while (*p++) 246 ; 247 248 buf[0] = CURRENT_VERSION(_PW_KEYBYUID); 249 memmove(buf + 1, p, sizeof(int)); 250 key.data = (u_char *)buf; 251 key.size = sizeof(int) + 1; 252 253 if ((pw_db->get)(pw_db, &key, &data, 0) == 0) { 254 /* First field of data.data holds pw_pwname */ 255 if (!strcmp(data.data, username)) 256 methoduid = 0; 257 else 258 methoduid = R_NOOVERWRITE; 259 } else { 260 methoduid = R_NOOVERWRITE; 261 } 262 } else { 263 methoduid = R_NOOVERWRITE; 264 } 265 if ((pw_db->close)(pw_db)) 266 error("close pw_db"); 267 method = 0; 268 } else { 269 dp = dbopen(buf, 270 O_RDWR|O_CREAT|O_EXCL, PERM_INSECURE, DB_HASH, &openinfo); 271 if (dp == NULL) 272 error(buf); 273 clean = FILE_INSECURE; 274 275 sdp = dbopen(sbuf, 276 O_RDWR|O_CREAT|O_EXCL, PERM_SECURE, DB_HASH, &openinfo); 277 if (sdp == NULL) 278 error(sbuf); 279 clean = FILE_SECURE; 280 281 method = R_NOOVERWRITE; 282 methoduid = R_NOOVERWRITE; 283 } 284 285 /* 286 * Open file for old password file. Minor trickiness -- don't want to 287 * chance the file already existing, since someone (stupidly) might 288 * still be using this for permission checking. So, open it first and 289 * fdopen the resulting fd. The resulting file should be readable by 290 * everyone. 291 */ 292 if (makeold) { 293 (void)snprintf(buf, sizeof(buf), "%s.orig", pname); 294 if ((tfd = open(buf, 295 O_WRONLY|O_CREAT|O_EXCL, PERM_INSECURE)) < 0) 296 error(buf); 297 if ((oldfp = fdopen(tfd, "w")) == NULL) 298 error(buf); 299 clean = FILE_ORIG; 300 } 301 302 /* 303 * The databases actually contain three copies of the original data. 304 * Each password file entry is converted into a rough approximation 305 * of a ``struct passwd'', with the strings placed inline. This 306 * object is then stored as the data for three separate keys. The 307 * first key * is the pw_name field prepended by the _PW_KEYBYNAME 308 * character. The second key is the pw_uid field prepended by the 309 * _PW_KEYBYUID character. The third key is the line number in the 310 * original file prepended by the _PW_KEYBYNUM character. (The special 311 * characters are prepended to ensure that the keys do not collide.) 312 */ 313 /* In order to transition this file into a machine-independent 314 * form, we have to change the format of entries. However, since 315 * older binaries will still expect the old MD format entries, we 316 * create * those as usual and use versioned tags for the new entries. 317 */ 318 key.data = verskey; 319 key.size = sizeof(verskey)-1; 320 data.data = &version; 321 data.size = 1; 322 if ((dp->put)(dp, &key, &data, 0) == -1) 323 error("put"); 324 if ((dp->put)(sdp, &key, &data, 0) == -1) 325 error("put"); 326 ypcnt = 1; 327 data.data = (u_char *)buf; 328 sdata.data = (u_char *)sbuf; 329 key.data = (u_char *)tbuf; 330 for (cnt = 1; scan(fp, &pwd); ++cnt) { 331 if (!is_comment && 332 (pwd.pw_name[0] == '+' || pwd.pw_name[0] == '-')) 333 yp_enabled = 1; 334 if (is_comment) 335 --cnt; 336#define COMPACT(e) t = e; while ((*p++ = *t++)); 337#define SCALAR(e) store = htonl((uint32_t)(e)); \ 338 memmove(p, &store, sizeof(store)); \ 339 p += sizeof(store); 340 if (!is_comment && 341 (!username || (strcmp(username, pwd.pw_name) == 0))) { 342 pw_change = pwd.pw_change; 343 pw_expire = pwd.pw_expire; 344 /* Create insecure data. */ 345 p = buf; 346 COMPACT(pwd.pw_name); 347 COMPACT("*"); 348 SCALAR(pwd.pw_uid); 349 SCALAR(pwd.pw_gid); 350 SCALAR(pwd.pw_change); 351 COMPACT(pwd.pw_class); 352 COMPACT(pwd.pw_gecos); 353 COMPACT(pwd.pw_dir); 354 COMPACT(pwd.pw_shell); 355 SCALAR(pwd.pw_expire); 356 SCALAR(pwd.pw_fields); 357 data.size = p - buf; 358 359 /* Create secure data. */ 360 p = sbuf; 361 COMPACT(pwd.pw_name); 362 COMPACT(pwd.pw_passwd); 363 SCALAR(pwd.pw_uid); 364 SCALAR(pwd.pw_gid); 365 SCALAR(pwd.pw_change); 366 COMPACT(pwd.pw_class); 367 COMPACT(pwd.pw_gecos); 368 COMPACT(pwd.pw_dir); 369 COMPACT(pwd.pw_shell); 370 SCALAR(pwd.pw_expire); 371 SCALAR(pwd.pw_fields); 372 sdata.size = p - sbuf; 373 374 /* Store insecure by name. */ 375 tbuf[0] = CURRENT_VERSION(_PW_KEYBYNAME); 376 len = strlen(pwd.pw_name); 377 memmove(tbuf + 1, pwd.pw_name, len); 378 key.size = len + 1; 379 if ((dp->put)(dp, &key, &data, method) == -1) 380 error("put"); 381 382 /* Store insecure by number. */ 383 tbuf[0] = CURRENT_VERSION(_PW_KEYBYNUM); 384 store = htonl(cnt); 385 memmove(tbuf + 1, &store, sizeof(store)); 386 key.size = sizeof(store) + 1; 387 if ((dp->put)(dp, &key, &data, method) == -1) 388 error("put"); 389 390 /* Store insecure by uid. */ 391 tbuf[0] = CURRENT_VERSION(_PW_KEYBYUID); 392 store = htonl(pwd.pw_uid); 393 memmove(tbuf + 1, &store, sizeof(store)); 394 key.size = sizeof(store) + 1; 395 if ((dp->put)(dp, &key, &data, methoduid) == -1) 396 error("put"); 397 398 /* Store secure by name. */ 399 tbuf[0] = CURRENT_VERSION(_PW_KEYBYNAME); 400 len = strlen(pwd.pw_name); 401 memmove(tbuf + 1, pwd.pw_name, len); 402 key.size = len + 1; 403 if ((sdp->put)(sdp, &key, &sdata, method) == -1) 404 error("put"); 405 406 /* Store secure by number. */ 407 tbuf[0] = CURRENT_VERSION(_PW_KEYBYNUM); 408 store = htonl(cnt); 409 memmove(tbuf + 1, &store, sizeof(store)); 410 key.size = sizeof(store) + 1; 411 if ((sdp->put)(sdp, &key, &sdata, method) == -1) 412 error("put"); 413 414 /* Store secure by uid. */ 415 tbuf[0] = CURRENT_VERSION(_PW_KEYBYUID); 416 store = htonl(pwd.pw_uid); 417 memmove(tbuf + 1, &store, sizeof(store)); 418 key.size = sizeof(store) + 1; 419 if ((sdp->put)(sdp, &key, &sdata, methoduid) == -1) 420 error("put"); 421 422 /* Store insecure and secure special plus and special minus */ 423 if (pwd.pw_name[0] == '+' || pwd.pw_name[0] == '-') { 424 tbuf[0] = CURRENT_VERSION(_PW_KEYYPBYNUM); 425 store = htonl(ypcnt); 426 memmove(tbuf + 1, &store, sizeof(store)); 427 ypcnt++; 428 key.size = sizeof(store) + 1; 429 if ((dp->put)(dp, &key, &data, method) == -1) 430 error("put"); 431 if ((sdp->put)(sdp, &key, &sdata, method) == -1) 432 error("put"); 433 } 434 435 /* Create insecure data. (legacy version) */ 436 p = buf; 437 COMPACT(pwd.pw_name); 438 COMPACT("*"); 439 memmove(p, &pwd.pw_uid, sizeof(pwd.pw_uid)); 440 p += sizeof(int); 441 memmove(p, &pwd.pw_gid, sizeof(pwd.pw_gid)); 442 p += sizeof(int); 443 memmove(p, &pw_change, sizeof(pw_change)); 444 p += sizeof(pw_change); 445 COMPACT(pwd.pw_class); 446 COMPACT(pwd.pw_gecos); 447 COMPACT(pwd.pw_dir); 448 COMPACT(pwd.pw_shell); 449 memmove(p, &pw_expire, sizeof(pw_expire)); 450 p += sizeof(pw_expire); 451 memmove(p, &pwd.pw_fields, sizeof pwd.pw_fields); 452 p += sizeof pwd.pw_fields; 453 data.size = p - buf; 454 455 /* Create secure data. (legacy version) */ 456 p = sbuf; 457 COMPACT(pwd.pw_name); 458 COMPACT(pwd.pw_passwd); 459 memmove(p, &pwd.pw_uid, sizeof(pwd.pw_uid)); 460 p += sizeof(int); 461 memmove(p, &pwd.pw_gid, sizeof(pwd.pw_gid)); 462 p += sizeof(int); 463 memmove(p, &pw_change, sizeof(pw_change)); 464 p += sizeof(pw_change); 465 COMPACT(pwd.pw_class); 466 COMPACT(pwd.pw_gecos); 467 COMPACT(pwd.pw_dir); 468 COMPACT(pwd.pw_shell); 469 memmove(p, &pw_expire, sizeof(pw_expire)); 470 p += sizeof(pw_expire); 471 memmove(p, &pwd.pw_fields, sizeof pwd.pw_fields); 472 p += sizeof pwd.pw_fields; 473 sdata.size = p - sbuf; 474 475 /* Store insecure by name. */ 476 tbuf[0] = LEGACY_VERSION(_PW_KEYBYNAME); 477 len = strlen(pwd.pw_name); 478 memmove(tbuf + 1, pwd.pw_name, len); 479 key.size = len + 1; 480 if ((dp->put)(dp, &key, &data, method) == -1) 481 error("put"); 482 483 /* Store insecure by number. */ 484 tbuf[0] = LEGACY_VERSION(_PW_KEYBYNUM); 485 memmove(tbuf + 1, &cnt, sizeof(cnt)); 486 key.size = sizeof(cnt) + 1; 487 if ((dp->put)(dp, &key, &data, method) == -1) 488 error("put"); 489 490 /* Store insecure by uid. */ 491 tbuf[0] = LEGACY_VERSION(_PW_KEYBYUID); 492 memmove(tbuf + 1, &pwd.pw_uid, sizeof(pwd.pw_uid)); 493 key.size = sizeof(pwd.pw_uid) + 1; 494 if ((dp->put)(dp, &key, &data, methoduid) == -1) 495 error("put"); 496 497 /* Store secure by name. */ 498 tbuf[0] = LEGACY_VERSION(_PW_KEYBYNAME); 499 len = strlen(pwd.pw_name); 500 memmove(tbuf + 1, pwd.pw_name, len); 501 key.size = len + 1; 502 if ((sdp->put)(sdp, &key, &sdata, method) == -1) 503 error("put"); 504 505 /* Store secure by number. */ 506 tbuf[0] = LEGACY_VERSION(_PW_KEYBYNUM); 507 memmove(tbuf + 1, &cnt, sizeof(cnt)); 508 key.size = sizeof(cnt) + 1; 509 if ((sdp->put)(sdp, &key, &sdata, method) == -1) 510 error("put"); 511 512 /* Store secure by uid. */ 513 tbuf[0] = LEGACY_VERSION(_PW_KEYBYUID); 514 memmove(tbuf + 1, &pwd.pw_uid, sizeof(pwd.pw_uid)); 515 key.size = sizeof(pwd.pw_uid) + 1; 516 if ((sdp->put)(sdp, &key, &sdata, methoduid) == -1) 517 error("put"); 518 519 /* Store insecure and secure special plus and special minus */ 520 if (pwd.pw_name[0] == '+' || pwd.pw_name[0] == '-') { 521 tbuf[0] = LEGACY_VERSION(_PW_KEYYPBYNUM); 522 memmove(tbuf + 1, &ypcnt, sizeof(cnt)); 523 ypcnt++; 524 key.size = sizeof(cnt) + 1; 525 if ((dp->put)(dp, &key, &data, method) == -1) 526 error("put"); 527 if ((sdp->put)(sdp, &key, &sdata, method) == -1) 528 error("put"); 529 } 530 } 531 /* Create original format password file entry */ 532 if (is_comment && makeold){ /* copy comments */ 533 if (fprintf(oldfp, "%s\n", line) < 0) 534 error("write old"); 535 } else if (makeold) { 536 char uidstr[20]; 537 char gidstr[20]; 538 539 snprintf(uidstr, sizeof(uidstr), "%u", pwd.pw_uid); 540 snprintf(gidstr, sizeof(gidstr), "%u", pwd.pw_gid); 541 542 if (fprintf(oldfp, "%s:*:%s:%s:%s:%s:%s\n", 543 pwd.pw_name, pwd.pw_fields & _PWF_UID ? uidstr : "", 544 pwd.pw_fields & _PWF_GID ? gidstr : "", 545 pwd.pw_gecos, pwd.pw_dir, pwd.pw_shell) < 0) 546 error("write old"); 547 } 548 } 549 /* If YP enabled, set flag. */ 550 if (yp_enabled) { 551 buf[0] = yp_enabled + 2; 552 data.size = 1; 553 key.size = 1; 554 tbuf[0] = CURRENT_VERSION(_PW_KEYYPENABLED); 555 if ((dp->put)(dp, &key, &data, method) == -1) 556 error("put"); 557 if ((sdp->put)(sdp, &key, &data, method) == -1) 558 error("put"); 559 tbuf[0] = LEGACY_VERSION(_PW_KEYYPENABLED); 560 key.size = 1; 561 if ((dp->put)(dp, &key, &data, method) == -1) 562 error("put"); 563 if ((sdp->put)(sdp, &key, &data, method) == -1) 564 error("put"); 565 } 566 567 if ((dp->close)(dp) == -1) 568 error("close"); 569 if ((sdp->close)(sdp) == -1) 570 error("close"); 571 if (makeold) { 572 (void)fflush(oldfp); 573 if (fclose(oldfp) == EOF) 574 error("close old"); 575 } 576 577 /* Set master.passwd permissions, in case caller forgot. */ 578 (void)fchmod(fileno(fp), S_IRUSR|S_IWUSR); 579 580 /* Install as the real password files. */ 581 (void)snprintf(buf, sizeof(buf), "%s/%s.tmp", prefix, _MP_DB); 582 (void)snprintf(buf2, sizeof(buf2), "%s/%s", prefix, _MP_DB); 583 mv(buf, buf2); 584 (void)snprintf(buf, sizeof(buf), "%s/%s.tmp", prefix, _SMP_DB); 585 (void)snprintf(buf2, sizeof(buf2), "%s/%s", prefix, _SMP_DB); 586 mv(buf, buf2); 587 if (makeold) { 588 (void)snprintf(buf2, sizeof(buf2), "%s/%s", prefix, _PASSWD); 589 (void)snprintf(buf, sizeof(buf), "%s.orig", pname); 590 mv(buf, buf2); 591 } 592 /* 593 * Move the master password LAST -- chpass(1), passwd(1) and vipw(8) 594 * all use flock(2) on it to block other incarnations of themselves. 595 * The rename means that everything is unlocked, as the original file 596 * can no longer be accessed. 597 */ 598 (void)snprintf(buf, sizeof(buf), "%s/%s", prefix, _MASTERPASSWD); 599 mv(pname, buf); 600 601 /* 602 * Close locked password file after rename() 603 */ 604 if (fclose(fp) == EOF) 605 error("close fp"); 606 607 exit(0); 608} 609 610int 611scan(fp, pw) 612 FILE *fp; 613 struct passwd *pw; 614{ 615 static int lcnt; 616 char *p; 617 618 if (!fgets(line, sizeof(line), fp)) 619 return (0); 620 ++lcnt; 621 /* 622 * ``... if I swallow anything evil, put your fingers down my 623 * throat...'' 624 * -- The Who 625 */ 626 if (!(p = strchr(line, '\n'))) { 627 /* 628 * XXX: This may also happen if the last line in a 629 * file does not have a trailing newline. 630 */ 631 warnx("line #%d too long", lcnt); 632 goto fmt; 633 634 } 635 *p = '\0'; 636 637 /* 638 * Ignore comments: ^[ \t]*# 639 */ 640 for (p = line; *p != '\0'; p++) 641 if (*p != ' ' && *p != '\t') 642 break; 643 if (*p == '#' || *p == '\0') { 644 is_comment = 1; 645 return(1); 646 } else 647 is_comment = 0; 648 649 if (!__pw_scan(line, pw, _PWSCAN_WARN|_PWSCAN_MASTER)) { 650 warnx("at line #%d", lcnt); 651fmt: errno = EFTYPE; /* XXX */ 652 error(pname); 653 } 654 655 return (1); 656} 657 658void 659cp(from, to, mode) 660 char *from, *to; 661 mode_t mode; 662{ 663 static char buf[MAXBSIZE]; 664 int from_fd, rcount, to_fd, wcount; 665 666 if ((from_fd = open(from, O_RDONLY, 0)) < 0) 667 error(from); 668 if ((to_fd = open(to, O_WRONLY|O_CREAT|O_EXCL, mode)) < 0) 669 error(to); 670 while ((rcount = read(from_fd, buf, MAXBSIZE)) > 0) { 671 wcount = write(to_fd, buf, rcount); 672 if (rcount != wcount || wcount == -1) { 673 int sverrno = errno; 674 675 (void)snprintf(buf, sizeof(buf), "%s to %s", from, to); 676 errno = sverrno; 677 error(buf); 678 } 679 } 680 if (rcount < 0) { 681 int sverrno = errno; 682 683 (void)snprintf(buf, sizeof(buf), "%s to %s", from, to); 684 errno = sverrno; 685 error(buf); 686 } 687} 688 689 690void 691mv(from, to) 692 char *from, *to; 693{ 694 char buf[MAXPATHLEN]; 695 696 if (rename(from, to)) { 697 int sverrno = errno; 698 (void)snprintf(buf, sizeof(buf), "%s to %s", from, to); 699 errno = sverrno; 700 error(buf); 701 } 702} 703 704void 705error(name) 706 const char *name; 707{ 708 709 warn("%s", name); 710 cleanup(); 711 exit(1); 712} 713 714void 715cleanup() 716{ 717 char buf[MAXPATHLEN]; 718 719 switch(clean) { 720 case FILE_ORIG: 721 (void)snprintf(buf, sizeof(buf), "%s.orig", pname); 722 (void)unlink(buf); 723 /* FALLTHROUGH */ 724 case FILE_SECURE: 725 (void)snprintf(buf, sizeof(buf), "%s/%s.tmp", prefix, _SMP_DB); 726 (void)unlink(buf); 727 /* FALLTHROUGH */ 728 case FILE_INSECURE: 729 (void)snprintf(buf, sizeof(buf), "%s/%s.tmp", prefix, _MP_DB); 730 (void)unlink(buf); 731 } 732} 733 734static void 735usage() 736{ 737 738 (void)fprintf(stderr, 739"usage: pwd_mkdb [-C] [-N] [-p] [-d <dest dir>] [-s <cachesize>] [-u <local username>] file\n"); 740 exit(1); 741} 742