pwd_mkdb.c revision 2934
1139804Simp/*- 222521Sdyson * Copyright (c) 1991, 1993, 1994 31541Srgrimes * The Regents of the University of California. All rights reserved. 41541Srgrimes * 522521Sdyson * Redistribution and use in source and binary forms, with or without 622521Sdyson * modification, are permitted provided that the following conditions 722521Sdyson * are met: 81541Srgrimes * 1. Redistributions of source code must retain the above copyright 91541Srgrimes * notice, this list of conditions and the following disclaimer. 101541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111541Srgrimes * notice, this list of conditions and the following disclaimer in the 121541Srgrimes * documentation and/or other materials provided with the distribution. 131541Srgrimes * 3. All advertising materials mentioning features or use of this software 141541Srgrimes * must display the following acknowledgement: 151541Srgrimes * This product includes software developed by the University of 161541Srgrimes * California, Berkeley and its contributors. 171541Srgrimes * 4. Neither the name of the University nor the names of its contributors 181541Srgrimes * may be used to endorse or promote products derived from this software 191541Srgrimes * without specific prior written permission. 201541Srgrimes * 211541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311541Srgrimes * SUCH DAMAGE. 3223521Sbde */ 331541Srgrimes 341541Srgrimes#ifndef lint 35116182Sobrienstatic char copyright[] = 36116182Sobrien"@(#) Copyright (c) 1991, 1993, 1994\n\ 37116182Sobrien The Regents of the University of California. All rights reserved.\n"; 38190829Srwatson#endif /* not lint */ 39190141Skib 40190141Skib#ifndef lint 411541Srgrimesstatic char sccsid[] = "@(#)pwd_mkdb.c 8.5 (Berkeley) 4/20/94"; 42228433Savg#endif /* not lint */ 43183155Sjhb 44183155Sjhb#include <sys/param.h> 4512820Sphk#include <sys/stat.h> 4676166Smarkm 47183155Sjhb#include <db.h> 48230129Smm#include <err.h> 49183155Sjhb#include <errno.h> 501541Srgrimes#include <fcntl.h> 51183155Sjhb#include <limits.h> 52187839Sjhb#include <pwd.h> 53190829Srwatson#include <signal.h> 54102870Siedowse#include <stdio.h> 55183155Sjhb#include <stdlib.h> 5651906Sphk#include <string.h> 57183155Sjhb#include <unistd.h> 58190141Skib 59190141Skib#include "pw_scan.h" 60190141Skib 611541Srgrimes#define INSECURE 1 62116289Sdes#define SECURE 2 63116289Sdes#define PERM_INSECURE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) 64190829Srwatson#define PERM_SECURE (S_IRUSR|S_IWUSR) 65260817Savg 66190829SrwatsonHASHINFO openinfo = { 67260817Savg 4096, /* bsize */ 68190829Srwatson 32, /* ffactor */ 69260817Savg 256, /* nelem */ 70260817Savg 2048 * 1024, /* cachesize */ 71253075Savg NULL, /* hash() */ 72260817Savg 0 /* lorder */ 73260817Savg}; 74253075Savg 75260817Savgstatic enum state { FILE_INSECURE, FILE_SECURE, FILE_ORIG } clean; 76190829Srwatsonstatic struct passwd pwd; /* password structure */ 77260817Savgstatic char *pname; /* password file name */ 78211616Srpaulostatic char prefix[MAXPATHLEN]; 79260817Savg 80190829Srwatsonvoid cleanup __P((void)); 81260817Savgvoid error __P((char *)); 82260817Savgvoid mv __P((char *, char *)); 83260817Savgint scan __P((FILE *, struct passwd *)); 84260817Savgvoid usage __P((void)); 85190829Srwatson 86260817Savgint 87190829Srwatsonmain(argc, argv) 88190829Srwatson int argc; 8951906Sphk char *argv[]; 9059652Sgreen{ 9159652Sgreen DB *dp, *edp; 9259652Sgreen DBT data, key; 9359652Sgreen FILE *fp, *oldfp; 9459652Sgreen sigset_t set; 9560938Sjake int ch, cnt, len, makeold, tfd, yp_enabled = 0; 9660938Sjake char *p, *t; 9760938Sjake char buf[MAX(MAXPATHLEN, LINE_MAX * 2)], tbuf[1024]; 9859652Sgreen char buf2[MAXPATHLEN]; 9959652Sgreen 10059652Sgreen strcpy(prefix, _PATH_PWD); 10159652Sgreen makeold = 0; 102190829Srwatson while ((ch = getopt(argc, argv, "d:pv")) != EOF) 10359652Sgreen switch(ch) { 10459652Sgreen case 'd': 10559652Sgreen strcpy(prefix, optarg); 106230441Skib break; 107230441Skib case 'p': /* create V7 "file.orig" */ 108232420Srmacklem makeold = 1; 109232420Srmacklem break; 110232420Srmacklem case 'v': /* backward compatible */ 111232420Srmacklem break; 112230441Skib case '?': 113230441Skib default: 114230441Skib usage(); 115230441Skib } 116230441Skib argc -= optind; 117230441Skib argv += optind; 118230441Skib 119230441Skib if (argc != 1) 120230441Skib usage(); 121230441Skib 122232420Srmacklem /* 123230441Skib * This could be changed to allow the user to interrupt. 124230441Skib * Probably not worth the effort. 125230441Skib */ 126230441Skib sigemptyset(&set); 127230441Skib sigaddset(&set, SIGTSTP); 128230441Skib sigaddset(&set, SIGHUP); 129230441Skib sigaddset(&set, SIGINT); 130230441Skib sigaddset(&set, SIGQUIT); 131230441Skib sigaddset(&set, SIGTERM); 132230441Skib (void)sigprocmask(SIG_BLOCK, &set, (sigset_t *)NULL); 133232420Srmacklem 134230441Skib /* We don't care what the user wants. */ 135230441Skib (void)umask(0); 1361541Srgrimes 1371541Srgrimes pname = *argv; 1381541Srgrimes /* Open the original password file */ 1391541Srgrimes if (!(fp = fopen(pname, "r"))) 1401541Srgrimes error(pname); 1411541Srgrimes 1421541Srgrimes /* Open the temporary insecure password database. */ 1431541Srgrimes (void)snprintf(buf, sizeof(buf), "%s/%s.tmp", prefix, _MP_DB); 14422521Sdyson dp = dbopen(buf, 14522521Sdyson O_RDWR|O_CREAT|O_EXCL, PERM_INSECURE, DB_HASH, &openinfo); 1466968Sphk if (dp == NULL) 1471541Srgrimes error(buf); 1481541Srgrimes clean = FILE_INSECURE; 1491541Srgrimes 1501541Srgrimes /* 1511541Srgrimes * Open file for old password file. Minor trickiness -- don't want to 1521541Srgrimes * chance the file already existing, since someone (stupidly) might 153302234Sbdrewery * still be using this for permission checking. So, open it first and 1541541Srgrimes * fdopen the resulting fd. The resulting file should be readable by 15574501Speter * everyone. 15674501Speter */ 15760938Sjake if (makeold) { 15860938Sjake (void)snprintf(buf, sizeof(buf), "%s.orig", pname); 15923521Sbde if ((tfd = open(buf, 160213916Skib O_WRONLY|O_CREAT|O_EXCL, PERM_INSECURE)) < 0) 161213916Skib error(buf); 16225453Sphk if ((oldfp = fdopen(tfd, "w")) == NULL) 163213916Skib error(buf); 164213916Skib clean = FILE_ORIG; 165213916Skib } 166213916Skib 167213916Skib /* 16823521Sbde * The databases actually contain three copies of the original data. 169213916Skib * Each password file entry is converted into a rough approximation 170213916Skib * of a ``struct passwd'', with the strings placed inline. This 17175654Stanimura * object is then stored as the data for three separate keys. The 172213916Skib * first key * is the pw_name field prepended by the _PW_KEYBYNAME 173213916Skib * character. The second key is the pw_uid field prepended by the 174213916Skib * _PW_KEYBYUID character. The third key is the line number in the 175213916Skib * original file prepended by the _PW_KEYBYNUM character. (The special 176213916Skib * characters are prepended to ensure that the keys do not collide.) 1771541Srgrimes */ 178213916Skib data.data = (u_char *)buf; 179213916Skib key.data = (u_char *)tbuf; 180187839Sjhb for (cnt = 1; scan(fp, &pwd); ++cnt) { 181187839Sjhb if(pwd.pw_name[0] == '+') { 182120792Sjeff if(pwd.pw_name[1] && !yp_enabled) { 183187839Sjhb yp_enabled = 1; 184187839Sjhb } else if(!pwd.pw_name[1]) { 185187839Sjhb yp_enabled = -1; 186187839Sjhb } 187187839Sjhb } 188120792Sjeff#define COMPACT(e) t = e; while (*p++ = *t++); 189116289Sdes /* Create insecure data. */ 190116289Sdes p = buf; 191116289Sdes COMPACT(pwd.pw_name); 192116289Sdes COMPACT("*"); 193116289Sdes memmove(p, &pwd.pw_uid, sizeof(int)); 194116289Sdes p += sizeof(int); 195116289Sdes memmove(p, &pwd.pw_gid, sizeof(int)); 196116289Sdes p += sizeof(int); 197230441Skib memmove(p, &pwd.pw_change, sizeof(time_t)); 198116289Sdes p += sizeof(time_t); 199232420Srmacklem COMPACT(pwd.pw_class); 200116289Sdes COMPACT(pwd.pw_gecos); 201190829Srwatson COMPACT(pwd.pw_dir); 202116289Sdes COMPACT(pwd.pw_shell); 203230441Skib memmove(p, &pwd.pw_expire, sizeof(time_t)); 204230441Skib p += sizeof(time_t); 205230441Skib memmove(p, &pwd.pw_fields, sizeof pwd.pw_fields); 206116289Sdes p += sizeof pwd.pw_fields; 207232420Srmacklem data.size = p - buf; 208232420Srmacklem 209232420Srmacklem /* Store insecure by name. */ 210232420Srmacklem tbuf[0] = _PW_KEYBYNAME; 211232420Srmacklem len = strlen(pwd.pw_name); 212232420Srmacklem memmove(tbuf + 1, pwd.pw_name, len); 213230441Skib key.size = len + 1; 214230441Skib if ((dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1) 215230441Skib error("put"); 216230441Skib 217230441Skib /* Store insecure by number. */ 218230441Skib tbuf[0] = _PW_KEYBYNUM; 219230441Skib memmove(tbuf + 1, &cnt, sizeof(cnt)); 220230441Skib key.size = sizeof(cnt) + 1; 221230441Skib if ((dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1) 222230441Skib error("put"); 223230441Skib 224230441Skib /* Store insecure by uid. */ 225230441Skib tbuf[0] = _PW_KEYBYUID; 226230441Skib memmove(tbuf + 1, &pwd.pw_uid, sizeof(pwd.pw_uid)); 227230441Skib key.size = sizeof(pwd.pw_uid) + 1; 228230441Skib if ((dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1) 229230441Skib error("put"); 230230441Skib 231230441Skib /* Create original format password file entry */ 232232420Srmacklem if (makeold) 233232420Srmacklem (void)fprintf(oldfp, "%s:*:%d:%d:%s:%s:%s\n", 234232420Srmacklem pwd.pw_name, pwd.pw_uid, pwd.pw_gid, pwd.pw_gecos, 235230441Skib pwd.pw_dir, pwd.pw_shell); 236230441Skib } 237230441Skib /* If YP enabled, set flag. */ 238230441Skib if(yp_enabled) { 239230441Skib buf[0] = yp_enabled + 2; 240230441Skib data.size = 1; 241230441Skib tbuf[0] = _PW_KEYYPENABLED; 242230441Skib key.size = 1; 243230441Skib if ((dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1) 244230441Skib error("put"); 245230441Skib } 246230441Skib 247230441Skib (void)(dp->close)(dp); 248230441Skib if (makeold) { 249230489Skib (void)fflush(oldfp); 250230489Skib (void)fclose(oldfp); 251230489Skib } 252230489Skib 253230552Skib /* Open the temporary encrypted password database. */ 254230552Skib (void)snprintf(buf, sizeof(buf), "%s/%s.tmp", prefix, _SMP_DB); 255230552Skib edp = dbopen(buf, 256230489Skib O_RDWR|O_CREAT|O_EXCL, PERM_SECURE, DB_HASH, &openinfo); 257230489Skib if (!edp) 258230489Skib error(buf); 259230489Skib clean = FILE_SECURE; 260230489Skib 261230489Skib rewind(fp); 262230489Skib for (cnt = 1; scan(fp, &pwd); ++cnt) { 26323521Sbde 264213916Skib /* Create secure data. */ 265213916Skib p = buf; 26691690Seivind COMPACT(pwd.pw_name); 26791690Seivind COMPACT(pwd.pw_passwd); 268273736Shselasky memmove(p, &pwd.pw_uid, sizeof(int)); 269215304Sbrucec p += sizeof(int); 27023521Sbde memmove(p, &pwd.pw_gid, sizeof(int)); 27129788Sphk p += sizeof(int); 27229788Sphk memmove(p, &pwd.pw_change, sizeof(time_t)); 27329788Sphk p += sizeof(time_t); 274215283Sbrucec COMPACT(pwd.pw_class); 275215304Sbrucec COMPACT(pwd.pw_gecos); 276215281Sbrucec COMPACT(pwd.pw_dir); 277215281Sbrucec COMPACT(pwd.pw_shell); 278215281Sbrucec memmove(p, &pwd.pw_expire, sizeof(time_t)); 279215281Sbrucec p += sizeof(time_t); 280215283Sbrucec memmove(p, &pwd.pw_fields, sizeof pwd.pw_fields); 281215304Sbrucec p += sizeof pwd.pw_fields; 282215283Sbrucec data.size = p - buf; 283215304Sbrucec 284215283Sbrucec /* Store secure by name. */ 285215304Sbrucec tbuf[0] = _PW_KEYBYNAME; 286215283Sbrucec len = strlen(pwd.pw_name); 287215304Sbrucec memmove(tbuf + 1, pwd.pw_name, len); 288215283Sbrucec key.size = len + 1; 289215304Sbrucec if ((dp->put)(edp, &key, &data, R_NOOVERWRITE) == -1) 290215283Sbrucec error("put"); 291215304Sbrucec 292320756Smjg /* Store secure by number. */ 293215304Sbrucec tbuf[0] = _PW_KEYBYNUM; 294215283Sbrucec memmove(tbuf + 1, &cnt, sizeof(cnt)); 295215304Sbrucec key.size = sizeof(cnt) + 1; 296215283Sbrucec if ((dp->put)(edp, &key, &data, R_NOOVERWRITE) == -1) 297215304Sbrucec error("put"); 298215283Sbrucec 299215304Sbrucec /* Store secure by uid. */ 300215283Sbrucec tbuf[0] = _PW_KEYBYUID; 301215304Sbrucec memmove(tbuf + 1, &pwd.pw_uid, sizeof(pwd.pw_uid)); 30229788Sphk key.size = sizeof(pwd.pw_uid) + 1; 303187658Sjhb if ((dp->put)(edp, &key, &data, R_NOOVERWRITE) == -1) 304215304Sbrucec error("put"); 305215304Sbrucec } 30629788Sphk /* If YP enabled, set flag. */ 307140712Sjeff if(yp_enabled) { 308194601Skib buf[0] = yp_enabled + 2; 309194601Skib data.size = 1; 310144318Sdas tbuf[0] = _PW_KEYYPENABLED; 311144318Sdas key.size = 1; 3126968Sphk if ((dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1) 31369774Sphk error("put"); 31451906Sphk } 315189593Sjhb 31625453Sphk (void)(edp->close)(edp); 31775402Speter 31875402Speter /* Set master.passwd permissions, in case caller forgot. */ 319227309Sed (void)fchmod(fileno(fp), S_IRUSR|S_IWUSR); 320227309Sed (void)fclose(fp); 32175402Speter 32275402Speter /* Install as the real password files. */ 32375402Speter (void)snprintf(buf, sizeof(buf), "%s/%s.tmp", prefix, _MP_DB); 32475402Speter (void)snprintf(buf2, sizeof(buf2), "%s/%s", prefix, _MP_DB); 32575402Speter mv(buf, buf2); 32675402Speter (void)snprintf(buf, sizeof(buf), "%s/%s.tmp", prefix, _SMP_DB); 327289418Spho (void)snprintf(buf2, sizeof(buf2), "%s/%s", prefix, _SMP_DB); 32875402Speter mv(buf, buf2); 329288079Smckusick if (makeold) { 33075402Speter (void)snprintf(buf2, sizeof(buf2), "%s/%s", prefix, _PASSWD); 33175402Speter (void)snprintf(buf, sizeof(buf), "%s.orig", pname); 33275402Speter mv(buf, buf2); 333288079Smckusick } 334288079Smckusick /* 335288079Smckusick * Move the master password LAST -- chpass(1), passwd(1) and vipw(8) 336187839Sjhb * all use flock(2) on it to block other incarnations of themselves. 337288079Smckusick * The rename means that everything is unlocked, as the original file 338288079Smckusick * can no longer be accessed. 33975402Speter */ 340288079Smckusick (void)snprintf(buf, sizeof(buf), "%s/%s", prefix, _MASTERPASSWD); 341288079Smckusick mv(pname, buf); 342288079Smckusick exit(0); 343288079Smckusick} 344288079Smckusick 345288079Smckusickint 346288079Smckusickscan(fp, pw) 347288079Smckusick FILE *fp; 348288079Smckusick struct passwd *pw; 349288079Smckusick{ 35075402Speter static int lcnt; 351187658Sjhb static char line[LINE_MAX]; 352215304Sbrucec char *p; 353215304Sbrucec 35475402Speter if (!fgets(line, sizeof(line), fp)) 35575402Speter return (0); 35675402Speter ++lcnt; 35775402Speter /* 35875402Speter * ``... if I swallow anything evil, put your fingers down my 35975402Speter * throat...'' 36075402Speter * -- The Who 36175402Speter */ 36275402Speter if (!(p = strchr(line, '\n'))) { 36375402Speter warnx("line too long"); 36475402Speter goto fmt; 36575402Speter 36675402Speter } 36775402Speter *p = '\0'; 36875402Speter if (!pw_scan(line, pw)) { 36975402Speter warnx("at line #%d", lcnt); 37075402Speterfmt: errno = EFTYPE; /* XXX */ 37175402Speter error(pname); 37275402Speter } 37375402Speter 374187839Sjhb return (1); 37575402Speter} 37675402Speter 37775402Spetervoid 378187839Sjhbmv(from, to) 37975402Speter char *from, *to; 38075402Speter{ 38175402Speter char buf[MAXPATHLEN]; 38275402Speter 38375402Speter if (rename(from, to)) { 38475402Speter int sverrno = errno; 385232156Smaxim (void)snprintf(buf, sizeof(buf), "%s to %s", from, to); 38698994Salfred errno = sverrno; 38775402Speter error(buf); 38875402Speter } 38998994Salfred} 39075402Speter 39175402Spetervoid 39298994Salfrederror(name) 39375402Speter char *name; 39475402Speter{ 39598994Salfred 39675402Speter warn(name); 39775402Speter cleanup(); 39875402Speter exit(1); 39975402Speter} 400187658Sjhb 401215304Sbrucecvoid 402232156Smaximcleanup() 403189593Sjhb{ 40475402Speter char buf[MAXPATHLEN]; 40575402Speter 406110952Sarr switch(clean) { 407110952Sarr case FILE_ORIG: 408110952Sarr (void)snprintf(buf, sizeof(buf), "%s.orig", pname); 409110952Sarr (void)unlink(buf); 41022521Sdyson /* FALLTHROUGH */ 41125453Sphk case FILE_SECURE: 412320756Smjg (void)snprintf(buf, sizeof(buf), "%s/%s.tmp", prefix, _SMP_DB); 41325453Sphk (void)unlink(buf); 414120792Sjeff /* FALLTHROUGH */ 415120792Sjeff case FILE_INSECURE: 416187839Sjhb (void)snprintf(buf, sizeof(buf), "%s/%s.tmp", prefix, _MP_DB); 417147326Sjeff (void)unlink(buf); 418190829Srwatson } 419289798Savg} 420289798Savg 421190829Srwatsonvoid 422289798Savgusage() 423289798Savg{ 424190829Srwatson 425120792Sjeff (void)fprintf(stderr, "usage: pwd_mkdb [-p] [-d <dest dir>] file\n"); 42625453Sphk exit(1); 427190533Skan} 428190533Skan