147159Sbostic /*- 261863Sbostic * Copyright (c) 1991, 1993 361863Sbostic * The Regents of the University of California. All rights reserved. 447159Sbostic * 547159Sbostic * %sccs.include.redist.c% 647159Sbostic */ 747159Sbostic 847159Sbostic #ifndef lint 961863Sbostic static char copyright[] = 1061863Sbostic "@(#) Copyright (c) 1991, 1993\n\ 1161863Sbostic The Regents of the University of California. All rights reserved.\n"; 1247159Sbostic #endif /* not lint */ 1347159Sbostic 1447159Sbostic #ifndef lint 15*66580Spendry static char sccsid[] = "@(#)pwd_mkdb.c 8.2 (Berkeley) 04/01/94"; 1647159Sbostic #endif /* not lint */ 1747159Sbostic 1847159Sbostic #include <sys/param.h> 1947159Sbostic #include <sys/stat.h> 2060596Sbostic 2147161Sbostic #include <db.h> 22*66580Spendry #include <err.h> 2347159Sbostic #include <errno.h> 2460596Sbostic #include <fcntl.h> 2547159Sbostic #include <limits.h> 2660596Sbostic #include <pwd.h> 2760596Sbostic #include <signal.h> 2847159Sbostic #include <stdio.h> 2960596Sbostic #include <stdlib.h> 3047159Sbostic #include <string.h> 3160596Sbostic #include <unistd.h> 3247159Sbostic 33*66580Spendry #include "pw_scan.h" 34*66580Spendry 3547159Sbostic #define INSECURE 1 3647159Sbostic #define SECURE 2 3747159Sbostic #define PERM_INSECURE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) 3847159Sbostic #define PERM_SECURE (S_IRUSR|S_IWUSR) 3947159Sbostic 4060596Sbostic HASHINFO openinfo = { 4160596Sbostic 4096, /* bsize */ 4260596Sbostic 32, /* ffactor */ 4360596Sbostic 256, /* nelem */ 4460596Sbostic 2048 * 1024, /* cachesize */ 4560596Sbostic NULL, /* hash() */ 4660596Sbostic 0 /* lorder */ 4760596Sbostic }; 4860596Sbostic 4947159Sbostic static enum state { FILE_INSECURE, FILE_SECURE, FILE_ORIG } clean; 5047159Sbostic static struct passwd pwd; /* password structure */ 5147159Sbostic static char *pname; /* password file name */ 5247159Sbostic 5360596Sbostic void cleanup __P((void)); 5460596Sbostic void error __P((char *)); 5560596Sbostic void mv __P((char *, char *)); 5660596Sbostic int scan __P((FILE *, struct passwd *)); 5760596Sbostic void usage __P((void)); 5860596Sbostic 5960596Sbostic int 6047159Sbostic main(argc, argv) 6147159Sbostic int argc; 6260596Sbostic char *argv[]; 6347159Sbostic { 6460596Sbostic DB *dp, *edp; 6560596Sbostic DBT data, key; 6647159Sbostic FILE *fp, *oldfp; 6747159Sbostic sigset_t set; 68*66580Spendry int ch, cnt, len, makeold, tfd; 69*66580Spendry char *p, *t; 7047159Sbostic char buf[MAX(MAXPATHLEN, LINE_MAX * 2)], tbuf[1024]; 7147159Sbostic 7247159Sbostic makeold = 0; 7347159Sbostic while ((ch = getopt(argc, argv, "pv")) != EOF) 7447159Sbostic switch(ch) { 7547159Sbostic case 'p': /* create V7 "file.orig" */ 7647159Sbostic makeold = 1; 7747159Sbostic break; 7847159Sbostic case 'v': /* backward compatible */ 7947159Sbostic break; 8047159Sbostic case '?': 8147159Sbostic default: 8247159Sbostic usage(); 8347159Sbostic } 8447159Sbostic argc -= optind; 8547159Sbostic argv += optind; 8647159Sbostic 8747159Sbostic if (argc != 1) 8847159Sbostic usage(); 8947159Sbostic 9047159Sbostic /* 9160596Sbostic * This could be changed to allow the user to interrupt. 9260596Sbostic * Probably not worth the effort. 9347159Sbostic */ 9447159Sbostic sigemptyset(&set); 9547159Sbostic sigaddset(&set, SIGTSTP); 9647159Sbostic sigaddset(&set, SIGHUP); 9747159Sbostic sigaddset(&set, SIGINT); 9847159Sbostic sigaddset(&set, SIGQUIT); 9947159Sbostic sigaddset(&set, SIGTERM); 10047159Sbostic (void)sigprocmask(SIG_BLOCK, &set, (sigset_t *)NULL); 10147159Sbostic 10247159Sbostic pname = *argv; 10347159Sbostic /* Open the original password file */ 10447159Sbostic if (!(fp = fopen(pname, "r"))) 10547159Sbostic error(pname); 10647159Sbostic 10747161Sbostic /* Open the temporary insecure password database. */ 10860596Sbostic (void)snprintf(buf, sizeof(buf), "%s.tmp", _PATH_MP_DB); 10960596Sbostic dp = dbopen(buf, 11060596Sbostic O_RDWR|O_CREAT|O_EXCL, PERM_INSECURE, DB_HASH, &openinfo); 11160596Sbostic if (dp == NULL) 11247159Sbostic error(buf); 11347159Sbostic clean = FILE_INSECURE; 11447159Sbostic 11547159Sbostic /* 11647159Sbostic * Open file for old password file. Minor trickiness -- don't want to 11747159Sbostic * chance the file already existing, since someone (stupidly) might 11847159Sbostic * still be using this for permission checking. So, open it first and 11947159Sbostic * fdopen the resulting fd. Don't really care who reads it. 12047159Sbostic */ 12147159Sbostic if (makeold) { 12260596Sbostic (void)snprintf(buf, sizeof(buf), "%s.orig", pname); 12347159Sbostic if ((tfd = open(buf, 12447159Sbostic O_WRONLY|O_CREAT|O_EXCL, PERM_INSECURE)) < 0) 12547159Sbostic error(buf); 12660596Sbostic if ((oldfp = fdopen(tfd, "w")) == NULL) 12747159Sbostic error(buf); 12847159Sbostic clean = FILE_ORIG; 12947159Sbostic } 13047159Sbostic 13149253Sbostic /* 13249253Sbostic * The databases actually contain three copies of the original data. 13349253Sbostic * Each password file entry is converted into a rough approximation 13449253Sbostic * of a ``struct passwd'', with the strings placed inline. This 13549253Sbostic * object is then stored as the data for three separate keys. The 13649253Sbostic * first key * is the pw_name field prepended by the _PW_KEYBYNAME 13749253Sbostic * character. The second key is the pw_uid field prepended by the 13849253Sbostic * _PW_KEYBYUID character. The third key is the line number in the 13949253Sbostic * original file prepended by the _PW_KEYBYNUM character. (The special 14049253Sbostic * characters are prepended to ensure that the keys do not collide.) 14149253Sbostic */ 14247161Sbostic data.data = (u_char *)buf; 14347161Sbostic key.data = (u_char *)tbuf; 14447159Sbostic for (cnt = 1; scan(fp, &pwd); ++cnt) { 14547159Sbostic #define COMPACT(e) t = e; while (*p++ = *t++); 14647159Sbostic /* Create insecure data. */ 14747159Sbostic p = buf; 14847159Sbostic COMPACT(pwd.pw_name); 14947159Sbostic COMPACT("*"); 15060596Sbostic memmove(p, &pwd.pw_uid, sizeof(int)); 15147159Sbostic p += sizeof(int); 15260596Sbostic memmove(p, &pwd.pw_gid, sizeof(int)); 15347159Sbostic p += sizeof(int); 15460596Sbostic memmove(p, &pwd.pw_change, sizeof(time_t)); 15547159Sbostic p += sizeof(time_t); 15647159Sbostic COMPACT(pwd.pw_class); 15747159Sbostic COMPACT(pwd.pw_gecos); 15847159Sbostic COMPACT(pwd.pw_dir); 15947159Sbostic COMPACT(pwd.pw_shell); 16060596Sbostic memmove(p, &pwd.pw_expire, sizeof(time_t)); 16147159Sbostic p += sizeof(time_t); 16247161Sbostic data.size = p - buf; 16347159Sbostic 16447159Sbostic /* Store insecure by name. */ 16547159Sbostic tbuf[0] = _PW_KEYBYNAME; 16647159Sbostic len = strlen(pwd.pw_name); 16760596Sbostic memmove(tbuf + 1, pwd.pw_name, len); 16847161Sbostic key.size = len + 1; 16947161Sbostic if ((dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1) 17047161Sbostic error("put"); 17147159Sbostic 17247159Sbostic /* Store insecure by number. */ 17347159Sbostic tbuf[0] = _PW_KEYBYNUM; 17460596Sbostic memmove(tbuf + 1, &cnt, sizeof(cnt)); 17547161Sbostic key.size = sizeof(cnt) + 1; 17647161Sbostic if ((dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1) 17747161Sbostic error("put"); 17847159Sbostic 17947159Sbostic /* Store insecure by uid. */ 18047159Sbostic tbuf[0] = _PW_KEYBYUID; 18160596Sbostic memmove(tbuf + 1, &pwd.pw_uid, sizeof(pwd.pw_uid)); 18247161Sbostic key.size = sizeof(pwd.pw_uid) + 1; 18347161Sbostic if ((dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1) 18447161Sbostic error("put"); 18547159Sbostic 18660596Sbostic /* Create original format password file entry */ 18760596Sbostic if (makeold) 18860596Sbostic (void)fprintf(oldfp, "%s:*:%d:%d:%s:%s:%s\n", 18960596Sbostic pwd.pw_name, pwd.pw_uid, pwd.pw_gid, pwd.pw_gecos, 19060596Sbostic pwd.pw_dir, pwd.pw_shell); 19160596Sbostic } 19260596Sbostic (void)(dp->close)(dp); 19360596Sbostic if (makeold) { 19460596Sbostic (void)fflush(oldfp); 19560596Sbostic (void)fclose(oldfp); 19660596Sbostic } 19760596Sbostic 19860596Sbostic /* Open the temporary encrypted password database. */ 19960596Sbostic (void)snprintf(buf, sizeof(buf), "%s.tmp", _PATH_SMP_DB); 20060596Sbostic edp = dbopen(buf, 20160596Sbostic O_RDWR|O_CREAT|O_EXCL, PERM_SECURE, DB_HASH, &openinfo); 20260596Sbostic if (!edp) 20360596Sbostic error(buf); 20460596Sbostic clean = FILE_SECURE; 20560596Sbostic 20660596Sbostic rewind(fp); 20760596Sbostic for (cnt = 1; scan(fp, &pwd); ++cnt) { 20860596Sbostic 20947159Sbostic /* Create secure data. */ 21047159Sbostic p = buf; 21147159Sbostic COMPACT(pwd.pw_name); 21247159Sbostic COMPACT(pwd.pw_passwd); 21360596Sbostic memmove(p, &pwd.pw_uid, sizeof(int)); 21447159Sbostic p += sizeof(int); 21560596Sbostic memmove(p, &pwd.pw_gid, sizeof(int)); 21647159Sbostic p += sizeof(int); 21760596Sbostic memmove(p, &pwd.pw_change, sizeof(time_t)); 21847159Sbostic p += sizeof(time_t); 21947159Sbostic COMPACT(pwd.pw_class); 22047159Sbostic COMPACT(pwd.pw_gecos); 22147159Sbostic COMPACT(pwd.pw_dir); 22247159Sbostic COMPACT(pwd.pw_shell); 22360596Sbostic memmove(p, &pwd.pw_expire, sizeof(time_t)); 22447159Sbostic p += sizeof(time_t); 22547161Sbostic data.size = p - buf; 22647159Sbostic 22747159Sbostic /* Store secure by name. */ 22847159Sbostic tbuf[0] = _PW_KEYBYNAME; 22947159Sbostic len = strlen(pwd.pw_name); 23060596Sbostic memmove(tbuf + 1, pwd.pw_name, len); 23147161Sbostic key.size = len + 1; 23247161Sbostic if ((dp->put)(edp, &key, &data, R_NOOVERWRITE) == -1) 23347161Sbostic error("put"); 23447159Sbostic 23547159Sbostic /* Store secure by number. */ 23647159Sbostic tbuf[0] = _PW_KEYBYNUM; 23760596Sbostic memmove(tbuf + 1, &cnt, sizeof(cnt)); 23847161Sbostic key.size = sizeof(cnt) + 1; 23947161Sbostic if ((dp->put)(edp, &key, &data, R_NOOVERWRITE) == -1) 24047161Sbostic error("put"); 24147159Sbostic 24247159Sbostic /* Store secure by uid. */ 24347159Sbostic tbuf[0] = _PW_KEYBYUID; 24460596Sbostic memmove(tbuf + 1, &pwd.pw_uid, sizeof(pwd.pw_uid)); 24547161Sbostic key.size = sizeof(pwd.pw_uid) + 1; 24647161Sbostic if ((dp->put)(edp, &key, &data, R_NOOVERWRITE) == -1) 24747161Sbostic error("put"); 24860596Sbostic } 24947159Sbostic 25047161Sbostic (void)(edp->close)(edp); 25147159Sbostic 25247159Sbostic /* Set master.passwd permissions, in case caller forgot. */ 25347162Sbostic (void)fchmod(fileno(fp), S_IRUSR|S_IWUSR); 25447159Sbostic (void)fclose(fp); 25547159Sbostic 25647159Sbostic /* Install as the real password files. */ 25760596Sbostic (void)snprintf(buf, sizeof(buf), "%s.tmp", _PATH_MP_DB); 25847159Sbostic mv(buf, _PATH_MP_DB); 25960596Sbostic (void)snprintf(buf, sizeof(buf), "%s.tmp", _PATH_SMP_DB); 26047159Sbostic mv(buf, _PATH_SMP_DB); 26147159Sbostic if (makeold) { 26260596Sbostic (void)snprintf(buf, sizeof(buf), "%s.orig", pname); 26347159Sbostic mv(buf, _PATH_PASSWD); 26447159Sbostic } 26547159Sbostic /* 26647159Sbostic * Move the master password LAST -- chpass(1), passwd(1) and vipw(8) 26747159Sbostic * all use flock(2) on it to block other incarnations of themselves. 26847159Sbostic * The rename means that everything is unlocked, as the original file 26947159Sbostic * can no longer be accessed. 27047159Sbostic */ 27147159Sbostic mv(pname, _PATH_MASTERPASSWD); 27247159Sbostic exit(0); 27347159Sbostic } 27447159Sbostic 27560596Sbostic int 27647159Sbostic scan(fp, pw) 27747159Sbostic FILE *fp; 27847159Sbostic struct passwd *pw; 27947159Sbostic { 28047159Sbostic static int lcnt; 28147159Sbostic static char line[LINE_MAX]; 28247159Sbostic char *p; 28347159Sbostic 28447159Sbostic if (!fgets(line, sizeof(line), fp)) 285*66580Spendry return (0); 28647159Sbostic ++lcnt; 28747159Sbostic /* 28847159Sbostic * ``... if I swallow anything evil, put your fingers down my 28947159Sbostic * throat...'' 29047159Sbostic * -- The Who 29147159Sbostic */ 29260596Sbostic if (!(p = strchr(line, '\n'))) { 293*66580Spendry warnx("line too long"); 29447159Sbostic goto fmt; 29547159Sbostic 29647159Sbostic } 29747159Sbostic *p = '\0'; 29847159Sbostic if (!pw_scan(line, pw)) { 299*66580Spendry warnx("at line #%d", lcnt); 300*66580Spendry fmt: errno = EFTYPE; /* XXX */ 30147159Sbostic error(pname); 30247159Sbostic } 303*66580Spendry 304*66580Spendry return (1); 30547159Sbostic } 30647159Sbostic 30760596Sbostic void 30847159Sbostic mv(from, to) 30947159Sbostic char *from, *to; 31047159Sbostic { 31147159Sbostic char buf[MAXPATHLEN]; 31247159Sbostic 31347159Sbostic if (rename(from, to)) { 314*66580Spendry int sverrno = errno; 31560596Sbostic (void)snprintf(buf, sizeof(buf), "%s to %s", from, to); 31647159Sbostic errno = sverrno; 31747159Sbostic error(buf); 31847159Sbostic } 31947159Sbostic } 32047159Sbostic 32160596Sbostic void 32247161Sbostic error(name) 32347161Sbostic char *name; 32447161Sbostic { 325*66580Spendry 326*66580Spendry warn(name); 32747161Sbostic cleanup(); 32847161Sbostic exit(1); 32947161Sbostic } 33047161Sbostic 33160596Sbostic void 33247159Sbostic cleanup() 33347159Sbostic { 33447159Sbostic char buf[MAXPATHLEN]; 33547159Sbostic 33647159Sbostic switch(clean) { 33747159Sbostic case FILE_ORIG: 33860596Sbostic (void)snprintf(buf, sizeof(buf), "%s.orig", pname); 33947159Sbostic (void)unlink(buf); 34047159Sbostic /* FALLTHROUGH */ 34147159Sbostic case FILE_SECURE: 34260596Sbostic (void)snprintf(buf, sizeof(buf), "%s.tmp", _PATH_SMP_DB); 34347159Sbostic (void)unlink(buf); 34447159Sbostic /* FALLTHROUGH */ 34547159Sbostic case FILE_INSECURE: 34660596Sbostic (void)snprintf(buf, sizeof(buf), "%s.tmp", _PATH_MP_DB); 34747159Sbostic (void)unlink(buf); 34847159Sbostic } 34947159Sbostic } 35047159Sbostic 35160596Sbostic void 35247159Sbostic usage() 35347159Sbostic { 354*66580Spendry 35547159Sbostic (void)fprintf(stderr, "usage: pwd_mkdb [-p] file\n"); 35647159Sbostic exit(1); 35747159Sbostic } 358