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