11553Srgrimes/*- 21553Srgrimes * Copyright (c) 1991, 1993, 1994 31553Srgrimes * The Regents of the University of California. All rights reserved. 41553Srgrimes * 51553Srgrimes * Redistribution and use in source and binary forms, with or without 61553Srgrimes * modification, are permitted provided that the following conditions 71553Srgrimes * are met: 81553Srgrimes * 1. Redistributions of source code must retain the above copyright 91553Srgrimes * notice, this list of conditions and the following disclaimer. 101553Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111553Srgrimes * notice, this list of conditions and the following disclaimer in the 121553Srgrimes * documentation and/or other materials provided with the distribution. 131553Srgrimes * 4. Neither the name of the University nor the names of its contributors 141553Srgrimes * may be used to endorse or promote products derived from this software 151553Srgrimes * without specific prior written permission. 161553Srgrimes * 171553Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181553Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191553Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201553Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211553Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221553Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231553Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241553Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251553Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261553Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271553Srgrimes * SUCH DAMAGE. 281553Srgrimes */ 291553Srgrimes 30114601Sobrien#if 0 311553Srgrimes#ifndef lint 3230260Scharnierstatic const char copyright[] = 331553Srgrimes"@(#) Copyright (c) 1991, 1993, 1994\n\ 341553Srgrimes The Regents of the University of California. All rights reserved.\n"; 351553Srgrimes#endif /* not lint */ 361553Srgrimes 371553Srgrimes#ifndef lint 381553Srgrimesstatic char sccsid[] = "@(#)pwd_mkdb.c 8.5 (Berkeley) 4/20/94"; 39114601Sobrien#endif /* not lint */ 4030260Scharnier#endif 41146755Scharnier 42114601Sobrien#include <sys/cdefs.h> 43114601Sobrien__FBSDID("$FreeBSD: releng/10.3/usr.sbin/pwd_mkdb/pwd_mkdb.c 296431 2016-03-06 18:22:24Z dwmalone $"); 441553Srgrimes 451553Srgrimes#include <sys/param.h> 46142832Sru#include <sys/endian.h> 471553Srgrimes#include <sys/stat.h> 48113596Snectar#include <arpa/inet.h> 491553Srgrimes 501553Srgrimes#include <db.h> 511553Srgrimes#include <err.h> 521553Srgrimes#include <errno.h> 531553Srgrimes#include <fcntl.h> 54285205Sgarga#include <libgen.h> 551553Srgrimes#include <limits.h> 561553Srgrimes#include <pwd.h> 571553Srgrimes#include <signal.h> 581553Srgrimes#include <stdio.h> 591553Srgrimes#include <stdlib.h> 601553Srgrimes#include <string.h> 611553Srgrimes#include <unistd.h> 621553Srgrimes 631553Srgrimes#include "pw_scan.h" 641553Srgrimes 651553Srgrimes#define INSECURE 1 661553Srgrimes#define SECURE 2 671553Srgrimes#define PERM_INSECURE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) 681553Srgrimes#define PERM_SECURE (S_IRUSR|S_IWUSR) 69113666Snectar#define LEGACY_VERSION(x) _PW_VERSIONED(x, 3) 70113666Snectar#define CURRENT_VERSION(x) _PW_VERSIONED(x, 4) 711553Srgrimes 72227257Sedstatic HASHINFO openinfo = { 731553Srgrimes 4096, /* bsize */ 741553Srgrimes 32, /* ffactor */ 751553Srgrimes 256, /* nelem */ 761553Srgrimes 2048 * 1024, /* cachesize */ 771553Srgrimes NULL, /* hash() */ 78142832Sru BYTE_ORDER /* lorder */ 791553Srgrimes}; 801553Srgrimes 811553Srgrimesstatic enum state { FILE_INSECURE, FILE_SECURE, FILE_ORIG } clean; 821553Srgrimesstatic struct passwd pwd; /* password structure */ 831553Srgrimesstatic char *pname; /* password file name */ 842551Sgpalmerstatic char prefix[MAXPATHLEN]; 851553Srgrimes 8639777Sdtstatic int is_comment; /* flag for comments */ 8723517Swoschstatic char line[LINE_MAX]; 8823517Swosch 8999819Salfredvoid cleanup(void); 9099819Salfredvoid error(const char *); 9199819Salfredvoid cp(char *, char *, mode_t mode); 9299819Salfredvoid mv(char *, char *); 9399819Salfredint scan(FILE *, struct passwd *); 9499819Salfredstatic void usage(void); 951553Srgrimes 961553Srgrimesint 9799819Salfredmain(int argc, char *argv[]) 981553Srgrimes{ 99113596Snectar static char verskey[] = _PWD_VERSION_KEY; 100113596Snectar char version = _PWD_CURRENT_VERSION; 10116876Sguido DB *dp, *sdp, *pw_db; 10216876Sguido DBT data, sdata, key; 1031553Srgrimes FILE *fp, *oldfp; 1041553Srgrimes sigset_t set; 10599819Salfred int ch, cnt, ypcnt, makeold, tfd, yp_enabled = 0; 10699819Salfred unsigned int len; 107113596Snectar uint32_t store; 10899819Salfred const char *t; 10999819Salfred char *p; 1101553Srgrimes char buf[MAX(MAXPATHLEN, LINE_MAX * 2)], tbuf[1024]; 11116876Sguido char sbuf[MAX(MAXPATHLEN, LINE_MAX * 2)]; 1122551Sgpalmer char buf2[MAXPATHLEN]; 11316876Sguido char sbuf2[MAXPATHLEN]; 11416876Sguido char *username; 11516876Sguido u_int method, methoduid; 116132509Simp int Cflag, dflag, iflag; 11741712Sdillon int nblock = 0; 1181553Srgrimes 119132509Simp iflag = dflag = Cflag = 0; 1202551Sgpalmer strcpy(prefix, _PATH_PWD); 1211553Srgrimes makeold = 0; 12216876Sguido username = NULL; 123146755Scharnier oldfp = NULL; 124142832Sru while ((ch = getopt(argc, argv, "BCLNd:ips:u:v")) != -1) 1251553Srgrimes switch(ch) { 126142832Sru case 'B': /* big-endian output */ 127142832Sru openinfo.lorder = BIG_ENDIAN; 128142832Sru break; 12932397Swosch case 'C': /* verify only */ 13032397Swosch Cflag = 1; 13117672Swosch break; 132142832Sru case 'L': /* little-endian output */ 133142832Sru openinfo.lorder = LITTLE_ENDIAN; 134142832Sru break; 135132507Simp case 'N': /* do not wait for lock */ 136132507Simp nblock = LOCK_NB; /* will fail if locked */ 137132507Simp break; 1382551Sgpalmer case 'd': 139132509Simp dflag++; 140132507Simp strlcpy(prefix, optarg, sizeof(prefix)); 1412551Sgpalmer break; 142132509Simp case 'i': 143132509Simp iflag++; 144132509Simp break; 1451553Srgrimes case 'p': /* create V7 "file.orig" */ 1461553Srgrimes makeold = 1; 1471553Srgrimes break; 14835286Sphk case 's': /* change default cachesize */ 14935286Sphk openinfo.cachesize = atoi(optarg) * 1024 * 1024; 15035286Sphk break; 15116876Sguido case 'u': /* only update this record */ 15216876Sguido username = optarg; 15316876Sguido break; 1542551Sgpalmer case 'v': /* backward compatible */ 1551553Srgrimes break; 1561553Srgrimes default: 1571553Srgrimes usage(); 1581553Srgrimes } 1591553Srgrimes argc -= optind; 1601553Srgrimes argv += optind; 1611553Srgrimes 16216946Smartin if (argc != 1 || (username && (*username == '+' || *username == '-'))) 1631553Srgrimes usage(); 1641553Srgrimes 1651553Srgrimes /* 1661553Srgrimes * This could be changed to allow the user to interrupt. 1671553Srgrimes * Probably not worth the effort. 1681553Srgrimes */ 1691553Srgrimes sigemptyset(&set); 1701553Srgrimes sigaddset(&set, SIGTSTP); 1711553Srgrimes sigaddset(&set, SIGHUP); 1721553Srgrimes sigaddset(&set, SIGINT); 1731553Srgrimes sigaddset(&set, SIGQUIT); 1741553Srgrimes sigaddset(&set, SIGTERM); 1751553Srgrimes (void)sigprocmask(SIG_BLOCK, &set, (sigset_t *)NULL); 1761553Srgrimes 1771553Srgrimes /* We don't care what the user wants. */ 1781553Srgrimes (void)umask(0); 1791553Srgrimes 1801553Srgrimes pname = *argv; 1811553Srgrimes 18241712Sdillon /* 18341712Sdillon * Open and lock the original password file. We have to check 18441712Sdillon * the hardlink count after we get the lock to handle any potential 18541712Sdillon * unlink/rename race. 18641712Sdillon * 18741712Sdillon * This lock is necessary when someone runs pwd_mkdb manually, directly 18841712Sdillon * on master.passwd, to handle the case where a user might try to 18941712Sdillon * change his password while pwd_mkdb is running. 19041712Sdillon */ 19141712Sdillon for (;;) { 19241712Sdillon struct stat st; 19341712Sdillon 19441712Sdillon if (!(fp = fopen(pname, "r"))) 19541712Sdillon error(pname); 196132509Simp if (flock(fileno(fp), LOCK_EX|nblock) < 0 && !(dflag && iflag)) 19741712Sdillon error("flock"); 19841712Sdillon if (fstat(fileno(fp), &st) < 0) 19941712Sdillon error(pname); 20041712Sdillon if (st.st_nlink != 0) 20141712Sdillon break; 20241712Sdillon fclose(fp); 20341712Sdillon fp = NULL; 20441712Sdillon } 20541712Sdillon 20617672Swosch /* check only if password database is valid */ 20732397Swosch if (Cflag) { 208192432Sbrian while (scan(fp, &pwd)) 209192432Sbrian if (!is_comment && strlen(pwd.pw_name) >= MAXLOGNAME) { 210192432Sbrian warnx("%s: username too long", pwd.pw_name); 211192432Sbrian exit(1); 212192432Sbrian } 21317672Swosch exit(0); 21417672Swosch } 21517672Swosch 2161553Srgrimes /* Open the temporary insecure password database. */ 2172551Sgpalmer (void)snprintf(buf, sizeof(buf), "%s/%s.tmp", prefix, _MP_DB); 21816876Sguido (void)snprintf(sbuf, sizeof(sbuf), "%s/%s.tmp", prefix, _SMP_DB); 21917125Sbde if (username) { 220114159Snectar int use_version; 221114159Snectar 22216876Sguido (void)snprintf(buf2, sizeof(buf2), "%s/%s", prefix, _MP_DB); 22316876Sguido (void)snprintf(sbuf2, sizeof(sbuf2), "%s/%s", prefix, _SMP_DB); 2241553Srgrimes 22516876Sguido clean = FILE_INSECURE; 22616876Sguido cp(buf2, buf, PERM_INSECURE); 22716876Sguido dp = dbopen(buf, 228296431Sdwmalone O_RDWR|O_EXCL, PERM_INSECURE, DB_HASH, &openinfo); 22916876Sguido if (dp == NULL) 23016876Sguido error(buf); 23116876Sguido 23216876Sguido clean = FILE_SECURE; 23316876Sguido cp(sbuf2, sbuf, PERM_SECURE); 23416876Sguido sdp = dbopen(sbuf, 235296431Sdwmalone O_RDWR|O_EXCL, PERM_SECURE, DB_HASH, &openinfo); 23616876Sguido if (sdp == NULL) 23716876Sguido error(sbuf); 23816876Sguido 23916876Sguido /* 24016876Sguido * Do some trouble to check if we should store this users 24116876Sguido * uid. Don't use getpwnam/getpwuid as that interferes 24216876Sguido * with NIS. 24316876Sguido */ 24416876Sguido pw_db = dbopen(_PATH_MP_DB, O_RDONLY, 0, DB_HASH, NULL); 24516876Sguido if (!pw_db) 24616876Sguido error(_MP_DB); 247114159Snectar 248114159Snectar key.data = verskey; 249114159Snectar key.size = sizeof(verskey)-1; 250114159Snectar if ((pw_db->get)(pw_db, &key, &data, 0) == 0) 251114159Snectar use_version = *(unsigned char *)data.data; 252114159Snectar else 253114159Snectar use_version = 3; 254114159Snectar buf[0] = _PW_VERSIONED(_PW_KEYBYNAME, use_version); 25516876Sguido len = strlen(username); 25616876Sguido 25716876Sguido /* Only check that username fits in buffer */ 25816876Sguido memmove(buf + 1, username, MIN(len, sizeof(buf) - 1)); 25916876Sguido key.data = (u_char *)buf; 26016876Sguido key.size = len + 1; 26116876Sguido if ((pw_db->get)(pw_db, &key, &data, 0) == 0) { 26216876Sguido p = (char *)data.data; 26316876Sguido 26416876Sguido /* jump over pw_name and pw_passwd, to get to pw_uid */ 26517125Sbde while (*p++) 26617125Sbde ; 26717125Sbde while (*p++) 26817125Sbde ; 26916876Sguido 270114159Snectar buf[0] = _PW_VERSIONED(_PW_KEYBYUID, use_version); 271114159Snectar memmove(buf + 1, p, sizeof(store)); 27216876Sguido key.data = (u_char *)buf; 273114159Snectar key.size = sizeof(store) + 1; 27416876Sguido 27516876Sguido if ((pw_db->get)(pw_db, &key, &data, 0) == 0) { 27616876Sguido /* First field of data.data holds pw_pwname */ 27717125Sbde if (!strcmp(data.data, username)) 27816876Sguido methoduid = 0; 27916876Sguido else 28016876Sguido methoduid = R_NOOVERWRITE; 28116876Sguido } else { 28216876Sguido methoduid = R_NOOVERWRITE; 28316876Sguido } 28416876Sguido } else { 28516876Sguido methoduid = R_NOOVERWRITE; 28616876Sguido } 28733413Sguido if ((pw_db->close)(pw_db)) 28833413Sguido error("close pw_db"); 28916876Sguido method = 0; 29016876Sguido } else { 29116876Sguido dp = dbopen(buf, 292296431Sdwmalone O_RDWR|O_CREAT|O_EXCL, PERM_INSECURE, DB_HASH, &openinfo); 29316876Sguido if (dp == NULL) 29416876Sguido error(buf); 29516876Sguido clean = FILE_INSECURE; 29616876Sguido 29716876Sguido sdp = dbopen(sbuf, 298296431Sdwmalone O_RDWR|O_CREAT|O_EXCL, PERM_SECURE, DB_HASH, &openinfo); 29916876Sguido if (sdp == NULL) 30016876Sguido error(sbuf); 30116876Sguido clean = FILE_SECURE; 30216876Sguido 30316876Sguido method = R_NOOVERWRITE; 30416876Sguido methoduid = R_NOOVERWRITE; 30516876Sguido } 30616876Sguido 3071553Srgrimes /* 3081553Srgrimes * Open file for old password file. Minor trickiness -- don't want to 3091553Srgrimes * chance the file already existing, since someone (stupidly) might 3101553Srgrimes * still be using this for permission checking. So, open it first and 3111553Srgrimes * fdopen the resulting fd. The resulting file should be readable by 3121553Srgrimes * everyone. 3131553Srgrimes */ 3141553Srgrimes if (makeold) { 3151553Srgrimes (void)snprintf(buf, sizeof(buf), "%s.orig", pname); 3161553Srgrimes if ((tfd = open(buf, 3171553Srgrimes O_WRONLY|O_CREAT|O_EXCL, PERM_INSECURE)) < 0) 3181553Srgrimes error(buf); 3191553Srgrimes if ((oldfp = fdopen(tfd, "w")) == NULL) 3201553Srgrimes error(buf); 3211553Srgrimes clean = FILE_ORIG; 3221553Srgrimes } 3231553Srgrimes 3241553Srgrimes /* 3251553Srgrimes * The databases actually contain three copies of the original data. 3261553Srgrimes * Each password file entry is converted into a rough approximation 3271553Srgrimes * of a ``struct passwd'', with the strings placed inline. This 3281553Srgrimes * object is then stored as the data for three separate keys. The 3291553Srgrimes * first key * is the pw_name field prepended by the _PW_KEYBYNAME 3301553Srgrimes * character. The second key is the pw_uid field prepended by the 3311553Srgrimes * _PW_KEYBYUID character. The third key is the line number in the 3321553Srgrimes * original file prepended by the _PW_KEYBYNUM character. (The special 3331553Srgrimes * characters are prepended to ensure that the keys do not collide.) 3341553Srgrimes */ 335113596Snectar /* In order to transition this file into a machine-independent 336113596Snectar * form, we have to change the format of entries. However, since 337113596Snectar * older binaries will still expect the old MD format entries, we 338114159Snectar * create those as usual and use versioned tags for the new entries. 339113596Snectar */ 340114159Snectar if (username == NULL) { 341114159Snectar /* Do not add the VERSION tag when updating a single 342114159Snectar * user. When operating on `old format' databases, this 343114159Snectar * would result in applications `seeing' only the updated 344114159Snectar * entries. 345114159Snectar */ 346114159Snectar key.data = verskey; 347114159Snectar key.size = sizeof(verskey)-1; 348114159Snectar data.data = &version; 349114159Snectar data.size = 1; 350114159Snectar if ((dp->put)(dp, &key, &data, 0) == -1) 351114159Snectar error("put"); 352114159Snectar if ((dp->put)(sdp, &key, &data, 0) == -1) 353114159Snectar error("put"); 354114159Snectar } 355223818Sgordon ypcnt = 0; 3561553Srgrimes data.data = (u_char *)buf; 35716876Sguido sdata.data = (u_char *)sbuf; 3581553Srgrimes key.data = (u_char *)tbuf; 3591553Srgrimes for (cnt = 1; scan(fp, &pwd); ++cnt) { 36039777Sdt if (!is_comment && 361223818Sgordon (pwd.pw_name[0] == '+' || pwd.pw_name[0] == '-')) { 3627277Swpaul yp_enabled = 1; 363223818Sgordon ypcnt++; 364223818Sgordon } 36551025Speter if (is_comment) 36651025Speter --cnt; 36730260Scharnier#define COMPACT(e) t = e; while ((*p++ = *t++)); 368113596Snectar#define SCALAR(e) store = htonl((uint32_t)(e)); \ 369113596Snectar memmove(p, &store, sizeof(store)); \ 370113596Snectar p += sizeof(store); 371142832Sru#define LSCALAR(e) store = HTOL((uint32_t)(e)); \ 372142832Sru memmove(p, &store, sizeof(store)); \ 373142832Sru p += sizeof(store); 374142832Sru#define HTOL(e) (openinfo.lorder == BYTE_ORDER ? \ 375142832Sru (uint32_t)(e) : \ 376142832Sru bswap32((uint32_t)(e))) 37739777Sdt if (!is_comment && 37823517Swosch (!username || (strcmp(username, pwd.pw_name) == 0))) { 37916876Sguido /* Create insecure data. */ 38016876Sguido p = buf; 38116876Sguido COMPACT(pwd.pw_name); 38216876Sguido COMPACT("*"); 383113596Snectar SCALAR(pwd.pw_uid); 384113596Snectar SCALAR(pwd.pw_gid); 385113596Snectar SCALAR(pwd.pw_change); 386113596Snectar COMPACT(pwd.pw_class); 387113596Snectar COMPACT(pwd.pw_gecos); 388113596Snectar COMPACT(pwd.pw_dir); 389113596Snectar COMPACT(pwd.pw_shell); 390113596Snectar SCALAR(pwd.pw_expire); 391113596Snectar SCALAR(pwd.pw_fields); 392113596Snectar data.size = p - buf; 393113596Snectar 394113596Snectar /* Create secure data. */ 395113596Snectar p = sbuf; 396113596Snectar COMPACT(pwd.pw_name); 397113596Snectar COMPACT(pwd.pw_passwd); 398113596Snectar SCALAR(pwd.pw_uid); 399113596Snectar SCALAR(pwd.pw_gid); 400113596Snectar SCALAR(pwd.pw_change); 401113596Snectar COMPACT(pwd.pw_class); 402113596Snectar COMPACT(pwd.pw_gecos); 403113596Snectar COMPACT(pwd.pw_dir); 404113596Snectar COMPACT(pwd.pw_shell); 405113596Snectar SCALAR(pwd.pw_expire); 406113596Snectar SCALAR(pwd.pw_fields); 407113596Snectar sdata.size = p - sbuf; 408113596Snectar 409113596Snectar /* Store insecure by name. */ 410113666Snectar tbuf[0] = CURRENT_VERSION(_PW_KEYBYNAME); 411113596Snectar len = strlen(pwd.pw_name); 412113596Snectar memmove(tbuf + 1, pwd.pw_name, len); 413113596Snectar key.size = len + 1; 414113596Snectar if ((dp->put)(dp, &key, &data, method) == -1) 415113596Snectar error("put"); 416113596Snectar 417113596Snectar /* Store insecure by number. */ 418113666Snectar tbuf[0] = CURRENT_VERSION(_PW_KEYBYNUM); 419113596Snectar store = htonl(cnt); 420113596Snectar memmove(tbuf + 1, &store, sizeof(store)); 421113596Snectar key.size = sizeof(store) + 1; 422113596Snectar if ((dp->put)(dp, &key, &data, method) == -1) 423113596Snectar error("put"); 424113596Snectar 425113596Snectar /* Store insecure by uid. */ 426113666Snectar tbuf[0] = CURRENT_VERSION(_PW_KEYBYUID); 427113596Snectar store = htonl(pwd.pw_uid); 428113596Snectar memmove(tbuf + 1, &store, sizeof(store)); 429113596Snectar key.size = sizeof(store) + 1; 430113596Snectar if ((dp->put)(dp, &key, &data, methoduid) == -1) 431113596Snectar error("put"); 432113596Snectar 433113596Snectar /* Store secure by name. */ 434113666Snectar tbuf[0] = CURRENT_VERSION(_PW_KEYBYNAME); 435113596Snectar len = strlen(pwd.pw_name); 436113596Snectar memmove(tbuf + 1, pwd.pw_name, len); 437113596Snectar key.size = len + 1; 438113596Snectar if ((sdp->put)(sdp, &key, &sdata, method) == -1) 439113596Snectar error("put"); 440113596Snectar 441113596Snectar /* Store secure by number. */ 442113666Snectar tbuf[0] = CURRENT_VERSION(_PW_KEYBYNUM); 443113596Snectar store = htonl(cnt); 444113596Snectar memmove(tbuf + 1, &store, sizeof(store)); 445113596Snectar key.size = sizeof(store) + 1; 446113596Snectar if ((sdp->put)(sdp, &key, &sdata, method) == -1) 447113596Snectar error("put"); 448113596Snectar 449113596Snectar /* Store secure by uid. */ 450113666Snectar tbuf[0] = CURRENT_VERSION(_PW_KEYBYUID); 451113596Snectar store = htonl(pwd.pw_uid); 452113596Snectar memmove(tbuf + 1, &store, sizeof(store)); 453113596Snectar key.size = sizeof(store) + 1; 454113596Snectar if ((sdp->put)(sdp, &key, &sdata, methoduid) == -1) 455113596Snectar error("put"); 456113596Snectar 457113596Snectar /* Store insecure and secure special plus and special minus */ 458113596Snectar if (pwd.pw_name[0] == '+' || pwd.pw_name[0] == '-') { 459113666Snectar tbuf[0] = CURRENT_VERSION(_PW_KEYYPBYNUM); 460113596Snectar store = htonl(ypcnt); 461113596Snectar memmove(tbuf + 1, &store, sizeof(store)); 462113596Snectar key.size = sizeof(store) + 1; 463113596Snectar if ((dp->put)(dp, &key, &data, method) == -1) 464113596Snectar error("put"); 465113596Snectar if ((sdp->put)(sdp, &key, &sdata, method) == -1) 466113596Snectar error("put"); 467113596Snectar } 468113596Snectar 469113596Snectar /* Create insecure data. (legacy version) */ 470113596Snectar p = buf; 471113596Snectar COMPACT(pwd.pw_name); 472113596Snectar COMPACT("*"); 473142832Sru LSCALAR(pwd.pw_uid); 474142832Sru LSCALAR(pwd.pw_gid); 475142832Sru LSCALAR(pwd.pw_change); 47616876Sguido COMPACT(pwd.pw_class); 47716876Sguido COMPACT(pwd.pw_gecos); 47816876Sguido COMPACT(pwd.pw_dir); 47916876Sguido COMPACT(pwd.pw_shell); 480142832Sru LSCALAR(pwd.pw_expire); 481142832Sru LSCALAR(pwd.pw_fields); 48216876Sguido data.size = p - buf; 4831553Srgrimes 484113596Snectar /* Create secure data. (legacy version) */ 48516876Sguido p = sbuf; 48616876Sguido COMPACT(pwd.pw_name); 48716876Sguido COMPACT(pwd.pw_passwd); 488142832Sru LSCALAR(pwd.pw_uid); 489142832Sru LSCALAR(pwd.pw_gid); 490142832Sru LSCALAR(pwd.pw_change); 49116876Sguido COMPACT(pwd.pw_class); 49216876Sguido COMPACT(pwd.pw_gecos); 49316876Sguido COMPACT(pwd.pw_dir); 49416876Sguido COMPACT(pwd.pw_shell); 495142832Sru LSCALAR(pwd.pw_expire); 496142832Sru LSCALAR(pwd.pw_fields); 49716876Sguido sdata.size = p - sbuf; 4981553Srgrimes 49916876Sguido /* Store insecure by name. */ 500113666Snectar tbuf[0] = LEGACY_VERSION(_PW_KEYBYNAME); 50116876Sguido len = strlen(pwd.pw_name); 50216876Sguido memmove(tbuf + 1, pwd.pw_name, len); 50316876Sguido key.size = len + 1; 50416876Sguido if ((dp->put)(dp, &key, &data, method) == -1) 50516876Sguido error("put"); 5061553Srgrimes 50716876Sguido /* Store insecure by number. */ 508113666Snectar tbuf[0] = LEGACY_VERSION(_PW_KEYBYNUM); 509142832Sru store = HTOL(cnt); 510142832Sru memmove(tbuf + 1, &store, sizeof(store)); 511142832Sru key.size = sizeof(store) + 1; 51216876Sguido if ((dp->put)(dp, &key, &data, method) == -1) 51316876Sguido error("put"); 5141553Srgrimes 51516876Sguido /* Store insecure by uid. */ 516113666Snectar tbuf[0] = LEGACY_VERSION(_PW_KEYBYUID); 517142832Sru store = HTOL(pwd.pw_uid); 518142832Sru memmove(tbuf + 1, &store, sizeof(store)); 519142832Sru key.size = sizeof(store) + 1; 52016876Sguido if ((dp->put)(dp, &key, &data, methoduid) == -1) 52116876Sguido error("put"); 52216876Sguido 52316876Sguido /* Store secure by name. */ 524113666Snectar tbuf[0] = LEGACY_VERSION(_PW_KEYBYNAME); 52516876Sguido len = strlen(pwd.pw_name); 52616876Sguido memmove(tbuf + 1, pwd.pw_name, len); 52716876Sguido key.size = len + 1; 52816876Sguido if ((sdp->put)(sdp, &key, &sdata, method) == -1) 52916876Sguido error("put"); 53016876Sguido 53116876Sguido /* Store secure by number. */ 532113666Snectar tbuf[0] = LEGACY_VERSION(_PW_KEYBYNUM); 533142832Sru store = HTOL(cnt); 534142832Sru memmove(tbuf + 1, &store, sizeof(store)); 535142832Sru key.size = sizeof(store) + 1; 53616876Sguido if ((sdp->put)(sdp, &key, &sdata, method) == -1) 5377257Swpaul error("put"); 53816876Sguido 53916876Sguido /* Store secure by uid. */ 540113666Snectar tbuf[0] = LEGACY_VERSION(_PW_KEYBYUID); 541142832Sru store = HTOL(pwd.pw_uid); 542142832Sru memmove(tbuf + 1, &store, sizeof(store)); 543142832Sru key.size = sizeof(store) + 1; 54416876Sguido if ((sdp->put)(sdp, &key, &sdata, methoduid) == -1) 54516876Sguido error("put"); 54616876Sguido 54716876Sguido /* Store insecure and secure special plus and special minus */ 54816876Sguido if (pwd.pw_name[0] == '+' || pwd.pw_name[0] == '-') { 549113666Snectar tbuf[0] = LEGACY_VERSION(_PW_KEYYPBYNUM); 550142832Sru store = HTOL(ypcnt); 551142832Sru memmove(tbuf + 1, &store, sizeof(store)); 552142832Sru key.size = sizeof(store) + 1; 55316876Sguido if ((dp->put)(dp, &key, &data, method) == -1) 55416876Sguido error("put"); 55516876Sguido if ((sdp->put)(sdp, &key, &sdata, method) == -1) 55616876Sguido error("put"); 55716876Sguido } 5587257Swpaul } 5591553Srgrimes /* Create original format password file entry */ 56039777Sdt if (is_comment && makeold){ /* copy comments */ 56133434Sguido if (fprintf(oldfp, "%s\n", line) < 0) 56233413Sguido error("write old"); 56333614Sguido } else if (makeold) { 56419085Swpaul char uidstr[20]; 56519085Swpaul char gidstr[20]; 56619085Swpaul 56757868Spaul snprintf(uidstr, sizeof(uidstr), "%u", pwd.pw_uid); 56857868Spaul snprintf(gidstr, sizeof(gidstr), "%u", pwd.pw_gid); 56919085Swpaul 57033413Sguido if (fprintf(oldfp, "%s:*:%s:%s:%s:%s:%s\n", 57119085Swpaul pwd.pw_name, pwd.pw_fields & _PWF_UID ? uidstr : "", 57219085Swpaul pwd.pw_fields & _PWF_GID ? gidstr : "", 57333434Sguido pwd.pw_gecos, pwd.pw_dir, pwd.pw_shell) < 0) 57433413Sguido error("write old"); 57519085Swpaul } 5761553Srgrimes } 5772916Swollman /* If YP enabled, set flag. */ 57817125Sbde if (yp_enabled) { 5792934Swollman buf[0] = yp_enabled + 2; 5802934Swollman data.size = 1; 5812916Swollman key.size = 1; 582113666Snectar tbuf[0] = CURRENT_VERSION(_PW_KEYYPENABLED); 58316876Sguido if ((dp->put)(dp, &key, &data, method) == -1) 5842916Swollman error("put"); 58516876Sguido if ((sdp->put)(sdp, &key, &data, method) == -1) 58616876Sguido error("put"); 587113666Snectar tbuf[0] = LEGACY_VERSION(_PW_KEYYPENABLED); 588113666Snectar key.size = 1; 589113666Snectar if ((dp->put)(dp, &key, &data, method) == -1) 590113666Snectar error("put"); 591113666Snectar if ((sdp->put)(sdp, &key, &data, method) == -1) 592113666Snectar error("put"); 5932916Swollman } 5942916Swollman 59528385Sjlemon if ((dp->close)(dp) == -1) 59628385Sjlemon error("close"); 59728385Sjlemon if ((sdp->close)(sdp) == -1) 59828385Sjlemon error("close"); 5991553Srgrimes if (makeold) { 6001553Srgrimes (void)fflush(oldfp); 60133413Sguido if (fclose(oldfp) == EOF) 60233413Sguido error("close old"); 6031553Srgrimes } 6041553Srgrimes 6051553Srgrimes /* Set master.passwd permissions, in case caller forgot. */ 6061553Srgrimes (void)fchmod(fileno(fp), S_IRUSR|S_IWUSR); 6071553Srgrimes 6081553Srgrimes /* Install as the real password files. */ 6092551Sgpalmer (void)snprintf(buf, sizeof(buf), "%s/%s.tmp", prefix, _MP_DB); 6102551Sgpalmer (void)snprintf(buf2, sizeof(buf2), "%s/%s", prefix, _MP_DB); 6112551Sgpalmer mv(buf, buf2); 6122551Sgpalmer (void)snprintf(buf, sizeof(buf), "%s/%s.tmp", prefix, _SMP_DB); 6132551Sgpalmer (void)snprintf(buf2, sizeof(buf2), "%s/%s", prefix, _SMP_DB); 6142551Sgpalmer mv(buf, buf2); 6151553Srgrimes if (makeold) { 6162551Sgpalmer (void)snprintf(buf2, sizeof(buf2), "%s/%s", prefix, _PASSWD); 6171553Srgrimes (void)snprintf(buf, sizeof(buf), "%s.orig", pname); 6188857Srgrimes mv(buf, buf2); 6191553Srgrimes } 6201553Srgrimes /* 6211553Srgrimes * Move the master password LAST -- chpass(1), passwd(1) and vipw(8) 6221553Srgrimes * all use flock(2) on it to block other incarnations of themselves. 6231553Srgrimes * The rename means that everything is unlocked, as the original file 6241553Srgrimes * can no longer be accessed. 6251553Srgrimes */ 6262551Sgpalmer (void)snprintf(buf, sizeof(buf), "%s/%s", prefix, _MASTERPASSWD); 6278857Srgrimes mv(pname, buf); 62841712Sdillon 62941712Sdillon /* 63041712Sdillon * Close locked password file after rename() 63141712Sdillon */ 63241712Sdillon if (fclose(fp) == EOF) 63341712Sdillon error("close fp"); 63441712Sdillon 6351553Srgrimes exit(0); 6361553Srgrimes} 6371553Srgrimes 6381553Srgrimesint 639147395Sddscan(FILE *fp, struct passwd *pw) 6401553Srgrimes{ 6411553Srgrimes static int lcnt; 642147395Sdd size_t len; 6431553Srgrimes char *p; 6441553Srgrimes 645147395Sdd p = fgetln(fp, &len); 646147395Sdd if (p == NULL) 6471553Srgrimes return (0); 6481553Srgrimes ++lcnt; 6491553Srgrimes /* 6501553Srgrimes * ``... if I swallow anything evil, put your fingers down my 6511553Srgrimes * throat...'' 6521553Srgrimes * -- The Who 6531553Srgrimes */ 654147395Sdd if (len > 0 && p[len - 1] == '\n') 655147395Sdd len--; 656147395Sdd if (len >= sizeof(line) - 1) { 65791923Sdd warnx("line #%d too long", lcnt); 6581553Srgrimes goto fmt; 6591553Srgrimes } 660147395Sdd memcpy(line, p, len); 661147395Sdd line[len] = '\0'; 66223517Swosch 66323517Swosch /* 66423517Swosch * Ignore comments: ^[ \t]*# 66523517Swosch */ 66623517Swosch for (p = line; *p != '\0'; p++) 66723517Swosch if (*p != ' ' && *p != '\t') 66823517Swosch break; 66923517Swosch if (*p == '#' || *p == '\0') { 67039777Sdt is_comment = 1; 67123517Swosch return(1); 67223517Swosch } else 67339777Sdt is_comment = 0; 67423517Swosch 67565532Snectar if (!__pw_scan(line, pw, _PWSCAN_WARN|_PWSCAN_MASTER)) { 6761553Srgrimes warnx("at line #%d", lcnt); 6771553Srgrimesfmt: errno = EFTYPE; /* XXX */ 6781553Srgrimes error(pname); 6791553Srgrimes } 6801553Srgrimes 6811553Srgrimes return (1); 6821553Srgrimes} 6831553Srgrimes 68416876Sguidovoid 685141607Sstefanfcp(char *from, char *to, mode_t mode) 68616876Sguido{ 68716876Sguido static char buf[MAXBSIZE]; 68816876Sguido int from_fd, rcount, to_fd, wcount; 68916876Sguido 69016876Sguido if ((from_fd = open(from, O_RDONLY, 0)) < 0) 69116876Sguido error(from); 69216876Sguido if ((to_fd = open(to, O_WRONLY|O_CREAT|O_EXCL, mode)) < 0) 69316876Sguido error(to); 69416876Sguido while ((rcount = read(from_fd, buf, MAXBSIZE)) > 0) { 69516876Sguido wcount = write(to_fd, buf, rcount); 69616876Sguido if (rcount != wcount || wcount == -1) { 69716876Sguido int sverrno = errno; 69816876Sguido 69916876Sguido (void)snprintf(buf, sizeof(buf), "%s to %s", from, to); 70016876Sguido errno = sverrno; 70116876Sguido error(buf); 70216876Sguido } 70316876Sguido } 70416876Sguido if (rcount < 0) { 70516876Sguido int sverrno = errno; 70616876Sguido 70716876Sguido (void)snprintf(buf, sizeof(buf), "%s to %s", from, to); 70816876Sguido errno = sverrno; 70916876Sguido error(buf); 71016876Sguido } 71116876Sguido} 71216876Sguido 71316876Sguido 7141553Srgrimesvoid 715141607Sstefanfmv(char *from, char *to) 7161553Srgrimes{ 7171553Srgrimes char buf[MAXPATHLEN]; 718285205Sgarga char *to_dir; 719285205Sgarga int to_dir_fd = -1; 7201553Srgrimes 721285205Sgarga /* 722285205Sgarga * Make sure file is safe on disk. To improve performance we will call 723285205Sgarga * fsync() to the directory where file lies 724285205Sgarga */ 725285205Sgarga if (rename(from, to) != 0 || 726285205Sgarga (to_dir = dirname(to)) == NULL || 727285205Sgarga (to_dir_fd = open(to_dir, O_RDONLY|O_DIRECTORY)) == -1 || 728285205Sgarga fsync(to_dir_fd) != 0) { 7291553Srgrimes int sverrno = errno; 7301553Srgrimes (void)snprintf(buf, sizeof(buf), "%s to %s", from, to); 7311553Srgrimes errno = sverrno; 732285205Sgarga if (to_dir_fd != -1) 733285205Sgarga close(to_dir_fd); 7341553Srgrimes error(buf); 7351553Srgrimes } 736285205Sgarga 737285205Sgarga if (to_dir_fd != -1) 738285205Sgarga close(to_dir_fd); 7391553Srgrimes} 7401553Srgrimes 7411553Srgrimesvoid 742141607Sstefanferror(const char *name) 7431553Srgrimes{ 7441553Srgrimes 74530260Scharnier warn("%s", name); 7461553Srgrimes cleanup(); 7471553Srgrimes exit(1); 7481553Srgrimes} 7491553Srgrimes 7501553Srgrimesvoid 751141607Sstefanfcleanup(void) 7521553Srgrimes{ 7531553Srgrimes char buf[MAXPATHLEN]; 7541553Srgrimes 7551553Srgrimes switch(clean) { 7561553Srgrimes case FILE_ORIG: 7571553Srgrimes (void)snprintf(buf, sizeof(buf), "%s.orig", pname); 7581553Srgrimes (void)unlink(buf); 7591553Srgrimes /* FALLTHROUGH */ 7601553Srgrimes case FILE_SECURE: 7612551Sgpalmer (void)snprintf(buf, sizeof(buf), "%s/%s.tmp", prefix, _SMP_DB); 7621553Srgrimes (void)unlink(buf); 7631553Srgrimes /* FALLTHROUGH */ 7641553Srgrimes case FILE_INSECURE: 7652551Sgpalmer (void)snprintf(buf, sizeof(buf), "%s/%s.tmp", prefix, _MP_DB); 7661553Srgrimes (void)unlink(buf); 7671553Srgrimes } 7681553Srgrimes} 7691553Srgrimes 77030260Scharnierstatic void 771141607Sstefanfusage(void) 7721553Srgrimes{ 7731553Srgrimes 77430260Scharnier (void)fprintf(stderr, 775142832Sru"usage: pwd_mkdb [-BCiLNp] [-d directory] [-s cachesize] [-u username] file\n"); 7761553Srgrimes exit(1); 7771553Srgrimes} 778