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 #if 0 35 #ifndef lint 36 static const char copyright[] = 37 "@(#) Copyright (c) 1991, 1993, 1994\n\ 38 The Regents of the University of California. All rights reserved.\n"; 39 #endif /* not lint */ 40 41 #ifndef lint 42 static char sccsid[] = "@(#)pwd_mkdb.c 8.5 (Berkeley) 4/20/94"; 43 #endif /* not lint */ 44 #endif 45 #include <sys/cdefs.h> 46 __FBSDID("$FreeBSD$"); 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 73 HASHINFO openinfo = { 74 4096, /* bsize */ 75 32, /* ffactor */ 76 256, /* nelem */ 77 2048 * 1024, /* cachesize */ 78 NULL, /* hash() */ 79 0 /* lorder */ 80 }; 81 82 static enum state { FILE_INSECURE, FILE_SECURE, FILE_ORIG } clean; 83 static struct passwd pwd; /* password structure */ 84 static char *pname; /* password file name */ 85 static char prefix[MAXPATHLEN]; 86 87 static int is_comment; /* flag for comments */ 88 static char line[LINE_MAX]; 89 90 void cleanup(void); 91 void error(const char *); 92 void cp(char *, char *, mode_t mode); 93 void mv(char *, char *); 94 int scan(FILE *, struct passwd *); 95 static void usage(void); 96 97 int 98 main(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 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(fp, pw) 628 FILE *fp; 629 struct passwd *pw; 630 { 631 static int lcnt; 632 char *p; 633 634 if (!fgets(line, sizeof(line), fp)) 635 return (0); 636 ++lcnt; 637 /* 638 * ``... if I swallow anything evil, put your fingers down my 639 * throat...'' 640 * -- The Who 641 */ 642 if (!(p = strchr(line, '\n'))) { 643 /* 644 * XXX: This may also happen if the last line in a 645 * file does not have a trailing newline. 646 */ 647 warnx("line #%d too long", lcnt); 648 goto fmt; 649 650 } 651 *p = '\0'; 652 653 /* 654 * Ignore comments: ^[ \t]*# 655 */ 656 for (p = line; *p != '\0'; p++) 657 if (*p != ' ' && *p != '\t') 658 break; 659 if (*p == '#' || *p == '\0') { 660 is_comment = 1; 661 return(1); 662 } else 663 is_comment = 0; 664 665 if (!__pw_scan(line, pw, _PWSCAN_WARN|_PWSCAN_MASTER)) { 666 warnx("at line #%d", lcnt); 667 fmt: errno = EFTYPE; /* XXX */ 668 error(pname); 669 } 670 671 return (1); 672 } 673 674 void 675 cp(from, to, mode) 676 char *from, *to; 677 mode_t mode; 678 { 679 static char buf[MAXBSIZE]; 680 int from_fd, rcount, to_fd, wcount; 681 682 if ((from_fd = open(from, O_RDONLY, 0)) < 0) 683 error(from); 684 if ((to_fd = open(to, O_WRONLY|O_CREAT|O_EXCL, mode)) < 0) 685 error(to); 686 while ((rcount = read(from_fd, buf, MAXBSIZE)) > 0) { 687 wcount = write(to_fd, buf, rcount); 688 if (rcount != wcount || wcount == -1) { 689 int sverrno = errno; 690 691 (void)snprintf(buf, sizeof(buf), "%s to %s", from, to); 692 errno = sverrno; 693 error(buf); 694 } 695 } 696 if (rcount < 0) { 697 int sverrno = errno; 698 699 (void)snprintf(buf, sizeof(buf), "%s to %s", from, to); 700 errno = sverrno; 701 error(buf); 702 } 703 } 704 705 706 void 707 mv(from, to) 708 char *from, *to; 709 { 710 char buf[MAXPATHLEN]; 711 712 if (rename(from, to)) { 713 int sverrno = errno; 714 (void)snprintf(buf, sizeof(buf), "%s to %s", from, to); 715 errno = sverrno; 716 error(buf); 717 } 718 } 719 720 void 721 error(name) 722 const char *name; 723 { 724 725 warn("%s", name); 726 cleanup(); 727 exit(1); 728 } 729 730 void 731 cleanup() 732 { 733 char buf[MAXPATHLEN]; 734 735 switch(clean) { 736 case FILE_ORIG: 737 (void)snprintf(buf, sizeof(buf), "%s.orig", pname); 738 (void)unlink(buf); 739 /* FALLTHROUGH */ 740 case FILE_SECURE: 741 (void)snprintf(buf, sizeof(buf), "%s/%s.tmp", prefix, _SMP_DB); 742 (void)unlink(buf); 743 /* FALLTHROUGH */ 744 case FILE_INSECURE: 745 (void)snprintf(buf, sizeof(buf), "%s/%s.tmp", prefix, _MP_DB); 746 (void)unlink(buf); 747 } 748 } 749 750 static void 751 usage() 752 { 753 754 (void)fprintf(stderr, 755 "usage: pwd_mkdb [-C] [-N] [-p] [-d <dest dir>] [-s <cachesize>] [-u <local username>] file\n"); 756 exit(1); 757 } 758