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, dflag, iflag; 119 int nblock = 0; 120 121 iflag = dflag = Cflag = 0; 122 strcpy(prefix, _PATH_PWD); 123 makeold = 0; 124 username = NULL; 125 while ((ch = getopt(argc, argv, "CNd:ps:u:v")) != -1) 126 switch(ch) { 127 case 'C': /* verify only */ 128 Cflag = 1; 129 break; 130 case 'N': /* do not wait for lock */ 131 nblock = LOCK_NB; /* will fail if locked */ 132 break; 133 case 'd': 134 dflag++; 135 strlcpy(prefix, optarg, sizeof(prefix)); 136 break; 137 case 'i': 138 iflag++; 139 break; 140 case 'p': /* create V7 "file.orig" */ 141 makeold = 1; 142 break; 143 case 's': /* change default cachesize */ 144 openinfo.cachesize = atoi(optarg) * 1024 * 1024; 145 break; 146 case 'u': /* only update this record */ 147 username = optarg; 148 break; 149 case 'v': /* backward compatible */ 150 break; 151 default: 152 usage(); 153 } 154 argc -= optind; 155 argv += optind; 156 157 if (argc != 1 || (username && (*username == '+' || *username == '-'))) 158 usage(); 159 160 /* 161 * This could be changed to allow the user to interrupt. 162 * Probably not worth the effort. 163 */ 164 sigemptyset(&set); 165 sigaddset(&set, SIGTSTP); 166 sigaddset(&set, SIGHUP); 167 sigaddset(&set, SIGINT); 168 sigaddset(&set, SIGQUIT); 169 sigaddset(&set, SIGTERM); 170 (void)sigprocmask(SIG_BLOCK, &set, (sigset_t *)NULL); 171 172 /* We don't care what the user wants. */ 173 (void)umask(0); 174 175 pname = *argv; 176 177 /* 178 * Open and lock the original password file. We have to check 179 * the hardlink count after we get the lock to handle any potential 180 * unlink/rename race. 181 * 182 * This lock is necessary when someone runs pwd_mkdb manually, directly 183 * on master.passwd, to handle the case where a user might try to 184 * change his password while pwd_mkdb is running. 185 */ 186 for (;;) { 187 struct stat st; 188 189 if (!(fp = fopen(pname, "r"))) 190 error(pname); 191 if (flock(fileno(fp), LOCK_EX|nblock) < 0 && !(dflag && iflag)) 192 error("flock"); 193 if (fstat(fileno(fp), &st) < 0) 194 error(pname); 195 if (st.st_nlink != 0) 196 break; 197 fclose(fp); 198 fp = NULL; 199 } 200 201 /* check only if password database is valid */ 202 if (Cflag) { 203 for (cnt = 1; scan(fp, &pwd); ++cnt); 204 exit(0); 205 } 206 207 /* Open the temporary insecure password database. */ 208 (void)snprintf(buf, sizeof(buf), "%s/%s.tmp", prefix, _MP_DB); 209 (void)snprintf(sbuf, sizeof(sbuf), "%s/%s.tmp", prefix, _SMP_DB); 210 if (username) { 211 int use_version; 212 213 (void)snprintf(buf2, sizeof(buf2), "%s/%s", prefix, _MP_DB); 214 (void)snprintf(sbuf2, sizeof(sbuf2), "%s/%s", prefix, _SMP_DB); 215 216 clean = FILE_INSECURE; 217 cp(buf2, buf, PERM_INSECURE); 218 dp = dbopen(buf, 219 O_RDWR|O_EXCL, PERM_INSECURE, DB_HASH, &openinfo); 220 if (dp == NULL) 221 error(buf); 222 223 clean = FILE_SECURE; 224 cp(sbuf2, sbuf, PERM_SECURE); 225 sdp = dbopen(sbuf, 226 O_RDWR|O_EXCL, PERM_SECURE, DB_HASH, &openinfo); 227 if (sdp == NULL) 228 error(sbuf); 229 230 /* 231 * Do some trouble to check if we should store this users 232 * uid. Don't use getpwnam/getpwuid as that interferes 233 * with NIS. 234 */ 235 pw_db = dbopen(_PATH_MP_DB, O_RDONLY, 0, DB_HASH, NULL); 236 if (!pw_db) 237 error(_MP_DB); 238 239 key.data = verskey; 240 key.size = sizeof(verskey)-1; 241 if ((pw_db->get)(pw_db, &key, &data, 0) == 0) 242 use_version = *(unsigned char *)data.data; 243 else 244 use_version = 3; 245 buf[0] = _PW_VERSIONED(_PW_KEYBYNAME, use_version); 246 len = strlen(username); 247 248 /* Only check that username fits in buffer */ 249 memmove(buf + 1, username, MIN(len, sizeof(buf) - 1)); 250 key.data = (u_char *)buf; 251 key.size = len + 1; 252 if ((pw_db->get)(pw_db, &key, &data, 0) == 0) { 253 p = (char *)data.data; 254 255 /* jump over pw_name and pw_passwd, to get to pw_uid */ 256 while (*p++) 257 ; 258 while (*p++) 259 ; 260 261 buf[0] = _PW_VERSIONED(_PW_KEYBYUID, use_version); 262 memmove(buf + 1, p, sizeof(store)); 263 key.data = (u_char *)buf; 264 key.size = sizeof(store) + 1; 265 266 if ((pw_db->get)(pw_db, &key, &data, 0) == 0) { 267 /* First field of data.data holds pw_pwname */ 268 if (!strcmp(data.data, username)) 269 methoduid = 0; 270 else 271 methoduid = R_NOOVERWRITE; 272 } else { 273 methoduid = R_NOOVERWRITE; 274 } 275 } else { 276 methoduid = R_NOOVERWRITE; 277 } 278 if ((pw_db->close)(pw_db)) 279 error("close pw_db"); 280 method = 0; 281 } else { 282 dp = dbopen(buf, 283 O_RDWR|O_CREAT|O_EXCL, PERM_INSECURE, DB_HASH, &openinfo); 284 if (dp == NULL) 285 error(buf); 286 clean = FILE_INSECURE; 287 288 sdp = dbopen(sbuf, 289 O_RDWR|O_CREAT|O_EXCL, PERM_SECURE, DB_HASH, &openinfo); 290 if (sdp == NULL) 291 error(sbuf); 292 clean = FILE_SECURE; 293 294 method = R_NOOVERWRITE; 295 methoduid = R_NOOVERWRITE; 296 } 297 298 /* 299 * Open file for old password file. Minor trickiness -- don't want to 300 * chance the file already existing, since someone (stupidly) might 301 * still be using this for permission checking. So, open it first and 302 * fdopen the resulting fd. The resulting file should be readable by 303 * everyone. 304 */ 305 if (makeold) { 306 (void)snprintf(buf, sizeof(buf), "%s.orig", pname); 307 if ((tfd = open(buf, 308 O_WRONLY|O_CREAT|O_EXCL, PERM_INSECURE)) < 0) 309 error(buf); 310 if ((oldfp = fdopen(tfd, "w")) == NULL) 311 error(buf); 312 clean = FILE_ORIG; 313 } 314 315 /* 316 * The databases actually contain three copies of the original data. 317 * Each password file entry is converted into a rough approximation 318 * of a ``struct passwd'', with the strings placed inline. This 319 * object is then stored as the data for three separate keys. The 320 * first key * is the pw_name field prepended by the _PW_KEYBYNAME 321 * character. The second key is the pw_uid field prepended by the 322 * _PW_KEYBYUID character. The third key is the line number in the 323 * original file prepended by the _PW_KEYBYNUM character. (The special 324 * characters are prepended to ensure that the keys do not collide.) 325 */ 326 /* In order to transition this file into a machine-independent 327 * form, we have to change the format of entries. However, since 328 * older binaries will still expect the old MD format entries, we 329 * create those as usual and use versioned tags for the new entries. 330 */ 331 if (username == NULL) { 332 /* Do not add the VERSION tag when updating a single 333 * user. When operating on `old format' databases, this 334 * would result in applications `seeing' only the updated 335 * entries. 336 */ 337 key.data = verskey; 338 key.size = sizeof(verskey)-1; 339 data.data = &version; 340 data.size = 1; 341 if ((dp->put)(dp, &key, &data, 0) == -1) 342 error("put"); 343 if ((dp->put)(sdp, &key, &data, 0) == -1) 344 error("put"); 345 } 346 ypcnt = 1; 347 data.data = (u_char *)buf; 348 sdata.data = (u_char *)sbuf; 349 key.data = (u_char *)tbuf; 350 for (cnt = 1; scan(fp, &pwd); ++cnt) { 351 if (!is_comment && 352 (pwd.pw_name[0] == '+' || pwd.pw_name[0] == '-')) 353 yp_enabled = 1; 354 if (is_comment) 355 --cnt; 356 #define COMPACT(e) t = e; while ((*p++ = *t++)); 357 #define SCALAR(e) store = htonl((uint32_t)(e)); \ 358 memmove(p, &store, sizeof(store)); \ 359 p += sizeof(store); 360 if (!is_comment && 361 (!username || (strcmp(username, pwd.pw_name) == 0))) { 362 pw_change = pwd.pw_change; 363 pw_expire = pwd.pw_expire; 364 /* Create insecure data. */ 365 p = buf; 366 COMPACT(pwd.pw_name); 367 COMPACT("*"); 368 SCALAR(pwd.pw_uid); 369 SCALAR(pwd.pw_gid); 370 SCALAR(pwd.pw_change); 371 COMPACT(pwd.pw_class); 372 COMPACT(pwd.pw_gecos); 373 COMPACT(pwd.pw_dir); 374 COMPACT(pwd.pw_shell); 375 SCALAR(pwd.pw_expire); 376 SCALAR(pwd.pw_fields); 377 data.size = p - buf; 378 379 /* Create secure data. */ 380 p = sbuf; 381 COMPACT(pwd.pw_name); 382 COMPACT(pwd.pw_passwd); 383 SCALAR(pwd.pw_uid); 384 SCALAR(pwd.pw_gid); 385 SCALAR(pwd.pw_change); 386 COMPACT(pwd.pw_class); 387 COMPACT(pwd.pw_gecos); 388 COMPACT(pwd.pw_dir); 389 COMPACT(pwd.pw_shell); 390 SCALAR(pwd.pw_expire); 391 SCALAR(pwd.pw_fields); 392 sdata.size = p - sbuf; 393 394 /* Store insecure by name. */ 395 tbuf[0] = CURRENT_VERSION(_PW_KEYBYNAME); 396 len = strlen(pwd.pw_name); 397 memmove(tbuf + 1, pwd.pw_name, len); 398 key.size = len + 1; 399 if ((dp->put)(dp, &key, &data, method) == -1) 400 error("put"); 401 402 /* Store insecure by number. */ 403 tbuf[0] = CURRENT_VERSION(_PW_KEYBYNUM); 404 store = htonl(cnt); 405 memmove(tbuf + 1, &store, sizeof(store)); 406 key.size = sizeof(store) + 1; 407 if ((dp->put)(dp, &key, &data, method) == -1) 408 error("put"); 409 410 /* Store insecure by uid. */ 411 tbuf[0] = CURRENT_VERSION(_PW_KEYBYUID); 412 store = htonl(pwd.pw_uid); 413 memmove(tbuf + 1, &store, sizeof(store)); 414 key.size = sizeof(store) + 1; 415 if ((dp->put)(dp, &key, &data, methoduid) == -1) 416 error("put"); 417 418 /* Store secure by name. */ 419 tbuf[0] = CURRENT_VERSION(_PW_KEYBYNAME); 420 len = strlen(pwd.pw_name); 421 memmove(tbuf + 1, pwd.pw_name, len); 422 key.size = len + 1; 423 if ((sdp->put)(sdp, &key, &sdata, method) == -1) 424 error("put"); 425 426 /* Store secure by number. */ 427 tbuf[0] = CURRENT_VERSION(_PW_KEYBYNUM); 428 store = htonl(cnt); 429 memmove(tbuf + 1, &store, sizeof(store)); 430 key.size = sizeof(store) + 1; 431 if ((sdp->put)(sdp, &key, &sdata, method) == -1) 432 error("put"); 433 434 /* Store secure by uid. */ 435 tbuf[0] = CURRENT_VERSION(_PW_KEYBYUID); 436 store = htonl(pwd.pw_uid); 437 memmove(tbuf + 1, &store, sizeof(store)); 438 key.size = sizeof(store) + 1; 439 if ((sdp->put)(sdp, &key, &sdata, methoduid) == -1) 440 error("put"); 441 442 /* Store insecure and secure special plus and special minus */ 443 if (pwd.pw_name[0] == '+' || pwd.pw_name[0] == '-') { 444 tbuf[0] = CURRENT_VERSION(_PW_KEYYPBYNUM); 445 store = htonl(ypcnt); 446 memmove(tbuf + 1, &store, sizeof(store)); 447 ypcnt++; 448 key.size = sizeof(store) + 1; 449 if ((dp->put)(dp, &key, &data, method) == -1) 450 error("put"); 451 if ((sdp->put)(sdp, &key, &sdata, method) == -1) 452 error("put"); 453 } 454 455 /* Create insecure data. (legacy version) */ 456 p = buf; 457 COMPACT(pwd.pw_name); 458 COMPACT("*"); 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 data.size = p - buf; 474 475 /* Create secure data. (legacy version) */ 476 p = sbuf; 477 COMPACT(pwd.pw_name); 478 COMPACT(pwd.pw_passwd); 479 memmove(p, &pwd.pw_uid, sizeof(pwd.pw_uid)); 480 p += sizeof(int); 481 memmove(p, &pwd.pw_gid, sizeof(pwd.pw_gid)); 482 p += sizeof(int); 483 memmove(p, &pw_change, sizeof(pw_change)); 484 p += sizeof(pw_change); 485 COMPACT(pwd.pw_class); 486 COMPACT(pwd.pw_gecos); 487 COMPACT(pwd.pw_dir); 488 COMPACT(pwd.pw_shell); 489 memmove(p, &pw_expire, sizeof(pw_expire)); 490 p += sizeof(pw_expire); 491 memmove(p, &pwd.pw_fields, sizeof pwd.pw_fields); 492 p += sizeof pwd.pw_fields; 493 sdata.size = p - sbuf; 494 495 /* Store insecure by name. */ 496 tbuf[0] = LEGACY_VERSION(_PW_KEYBYNAME); 497 len = strlen(pwd.pw_name); 498 memmove(tbuf + 1, pwd.pw_name, len); 499 key.size = len + 1; 500 if ((dp->put)(dp, &key, &data, method) == -1) 501 error("put"); 502 503 /* Store insecure by number. */ 504 tbuf[0] = LEGACY_VERSION(_PW_KEYBYNUM); 505 memmove(tbuf + 1, &cnt, sizeof(cnt)); 506 key.size = sizeof(cnt) + 1; 507 if ((dp->put)(dp, &key, &data, method) == -1) 508 error("put"); 509 510 /* Store insecure by uid. */ 511 tbuf[0] = LEGACY_VERSION(_PW_KEYBYUID); 512 memmove(tbuf + 1, &pwd.pw_uid, sizeof(pwd.pw_uid)); 513 key.size = sizeof(pwd.pw_uid) + 1; 514 if ((dp->put)(dp, &key, &data, methoduid) == -1) 515 error("put"); 516 517 /* Store secure by name. */ 518 tbuf[0] = LEGACY_VERSION(_PW_KEYBYNAME); 519 len = strlen(pwd.pw_name); 520 memmove(tbuf + 1, pwd.pw_name, len); 521 key.size = len + 1; 522 if ((sdp->put)(sdp, &key, &sdata, method) == -1) 523 error("put"); 524 525 /* Store secure by number. */ 526 tbuf[0] = LEGACY_VERSION(_PW_KEYBYNUM); 527 memmove(tbuf + 1, &cnt, sizeof(cnt)); 528 key.size = sizeof(cnt) + 1; 529 if ((sdp->put)(sdp, &key, &sdata, method) == -1) 530 error("put"); 531 532 /* Store secure by uid. */ 533 tbuf[0] = LEGACY_VERSION(_PW_KEYBYUID); 534 memmove(tbuf + 1, &pwd.pw_uid, sizeof(pwd.pw_uid)); 535 key.size = sizeof(pwd.pw_uid) + 1; 536 if ((sdp->put)(sdp, &key, &sdata, methoduid) == -1) 537 error("put"); 538 539 /* Store insecure and secure special plus and special minus */ 540 if (pwd.pw_name[0] == '+' || pwd.pw_name[0] == '-') { 541 tbuf[0] = LEGACY_VERSION(_PW_KEYYPBYNUM); 542 memmove(tbuf + 1, &ypcnt, sizeof(cnt)); 543 ypcnt++; 544 key.size = sizeof(cnt) + 1; 545 if ((dp->put)(dp, &key, &data, method) == -1) 546 error("put"); 547 if ((sdp->put)(sdp, &key, &sdata, method) == -1) 548 error("put"); 549 } 550 } 551 /* Create original format password file entry */ 552 if (is_comment && makeold){ /* copy comments */ 553 if (fprintf(oldfp, "%s\n", line) < 0) 554 error("write old"); 555 } else if (makeold) { 556 char uidstr[20]; 557 char gidstr[20]; 558 559 snprintf(uidstr, sizeof(uidstr), "%u", pwd.pw_uid); 560 snprintf(gidstr, sizeof(gidstr), "%u", pwd.pw_gid); 561 562 if (fprintf(oldfp, "%s:*:%s:%s:%s:%s:%s\n", 563 pwd.pw_name, pwd.pw_fields & _PWF_UID ? uidstr : "", 564 pwd.pw_fields & _PWF_GID ? gidstr : "", 565 pwd.pw_gecos, pwd.pw_dir, pwd.pw_shell) < 0) 566 error("write old"); 567 } 568 } 569 /* If YP enabled, set flag. */ 570 if (yp_enabled) { 571 buf[0] = yp_enabled + 2; 572 data.size = 1; 573 key.size = 1; 574 tbuf[0] = CURRENT_VERSION(_PW_KEYYPENABLED); 575 if ((dp->put)(dp, &key, &data, method) == -1) 576 error("put"); 577 if ((sdp->put)(sdp, &key, &data, method) == -1) 578 error("put"); 579 tbuf[0] = LEGACY_VERSION(_PW_KEYYPENABLED); 580 key.size = 1; 581 if ((dp->put)(dp, &key, &data, method) == -1) 582 error("put"); 583 if ((sdp->put)(sdp, &key, &data, method) == -1) 584 error("put"); 585 } 586 587 if ((dp->close)(dp) == -1) 588 error("close"); 589 if ((sdp->close)(sdp) == -1) 590 error("close"); 591 if (makeold) { 592 (void)fflush(oldfp); 593 if (fclose(oldfp) == EOF) 594 error("close old"); 595 } 596 597 /* Set master.passwd permissions, in case caller forgot. */ 598 (void)fchmod(fileno(fp), S_IRUSR|S_IWUSR); 599 600 /* Install as the real password files. */ 601 (void)snprintf(buf, sizeof(buf), "%s/%s.tmp", prefix, _MP_DB); 602 (void)snprintf(buf2, sizeof(buf2), "%s/%s", prefix, _MP_DB); 603 mv(buf, buf2); 604 (void)snprintf(buf, sizeof(buf), "%s/%s.tmp", prefix, _SMP_DB); 605 (void)snprintf(buf2, sizeof(buf2), "%s/%s", prefix, _SMP_DB); 606 mv(buf, buf2); 607 if (makeold) { 608 (void)snprintf(buf2, sizeof(buf2), "%s/%s", prefix, _PASSWD); 609 (void)snprintf(buf, sizeof(buf), "%s.orig", pname); 610 mv(buf, buf2); 611 } 612 /* 613 * Move the master password LAST -- chpass(1), passwd(1) and vipw(8) 614 * all use flock(2) on it to block other incarnations of themselves. 615 * The rename means that everything is unlocked, as the original file 616 * can no longer be accessed. 617 */ 618 (void)snprintf(buf, sizeof(buf), "%s/%s", prefix, _MASTERPASSWD); 619 mv(pname, buf); 620 621 /* 622 * Close locked password file after rename() 623 */ 624 if (fclose(fp) == EOF) 625 error("close fp"); 626 627 exit(0); 628 } 629 630 int 631 scan(fp, pw) 632 FILE *fp; 633 struct passwd *pw; 634 { 635 static int lcnt; 636 char *p; 637 638 if (!fgets(line, sizeof(line), fp)) 639 return (0); 640 ++lcnt; 641 /* 642 * ``... if I swallow anything evil, put your fingers down my 643 * throat...'' 644 * -- The Who 645 */ 646 if (!(p = strchr(line, '\n'))) { 647 /* 648 * XXX: This may also happen if the last line in a 649 * file does not have a trailing newline. 650 */ 651 warnx("line #%d too long", lcnt); 652 goto fmt; 653 654 } 655 *p = '\0'; 656 657 /* 658 * Ignore comments: ^[ \t]*# 659 */ 660 for (p = line; *p != '\0'; p++) 661 if (*p != ' ' && *p != '\t') 662 break; 663 if (*p == '#' || *p == '\0') { 664 is_comment = 1; 665 return(1); 666 } else 667 is_comment = 0; 668 669 if (!__pw_scan(line, pw, _PWSCAN_WARN|_PWSCAN_MASTER)) { 670 warnx("at line #%d", lcnt); 671 fmt: errno = EFTYPE; /* XXX */ 672 error(pname); 673 } 674 675 return (1); 676 } 677 678 void 679 cp(from, to, mode) 680 char *from, *to; 681 mode_t mode; 682 { 683 static char buf[MAXBSIZE]; 684 int from_fd, rcount, to_fd, wcount; 685 686 if ((from_fd = open(from, O_RDONLY, 0)) < 0) 687 error(from); 688 if ((to_fd = open(to, O_WRONLY|O_CREAT|O_EXCL, mode)) < 0) 689 error(to); 690 while ((rcount = read(from_fd, buf, MAXBSIZE)) > 0) { 691 wcount = write(to_fd, buf, rcount); 692 if (rcount != wcount || wcount == -1) { 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 if (rcount < 0) { 701 int sverrno = errno; 702 703 (void)snprintf(buf, sizeof(buf), "%s to %s", from, to); 704 errno = sverrno; 705 error(buf); 706 } 707 } 708 709 710 void 711 mv(from, to) 712 char *from, *to; 713 { 714 char buf[MAXPATHLEN]; 715 716 if (rename(from, to)) { 717 int sverrno = errno; 718 (void)snprintf(buf, sizeof(buf), "%s to %s", from, to); 719 errno = sverrno; 720 error(buf); 721 } 722 } 723 724 void 725 error(name) 726 const char *name; 727 { 728 729 warn("%s", name); 730 cleanup(); 731 exit(1); 732 } 733 734 void 735 cleanup() 736 { 737 char buf[MAXPATHLEN]; 738 739 switch(clean) { 740 case FILE_ORIG: 741 (void)snprintf(buf, sizeof(buf), "%s.orig", pname); 742 (void)unlink(buf); 743 /* FALLTHROUGH */ 744 case FILE_SECURE: 745 (void)snprintf(buf, sizeof(buf), "%s/%s.tmp", prefix, _SMP_DB); 746 (void)unlink(buf); 747 /* FALLTHROUGH */ 748 case FILE_INSECURE: 749 (void)snprintf(buf, sizeof(buf), "%s/%s.tmp", prefix, _MP_DB); 750 (void)unlink(buf); 751 } 752 } 753 754 static void 755 usage() 756 { 757 758 (void)fprintf(stderr, 759 "usage: pwd_mkdb [-C] [-N] [-i] [-p] [-d <dest dir>] [-s <cachesize>] [-u <local username>] file\n"); 760 exit(1); 761 } 762