147159Sbostic /*-
266650Spendry * Copyright (c) 1991, 1993, 1994
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[] =
1066650Spendry "@(#) Copyright (c) 1991, 1993, 1994\n\
1161863Sbostic The Regents of the University of California. All rights reserved.\n";
1247159Sbostic #endif /* not lint */
1347159Sbostic
1447159Sbostic #ifndef lint
15*67042Sbostic static char sccsid[] = "@(#)pwd_mkdb.c 8.5 (Berkeley) 04/20/94";
1647159Sbostic #endif /* not lint */
1747159Sbostic
1847159Sbostic #include <sys/param.h>
1947159Sbostic #include <sys/stat.h>
2060596Sbostic
2147161Sbostic #include <db.h>
2266580Spendry #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
3366580Spendry #include "pw_scan.h"
3466580Spendry
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
main(argc,argv)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;
6866580Spendry int ch, cnt, len, makeold, tfd;
6966580Spendry 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
102*67042Sbostic /* We don't care what the user wants. */
103*67042Sbostic (void)umask(0);
104*67042Sbostic
10547159Sbostic pname = *argv;
10647159Sbostic /* Open the original password file */
10747159Sbostic if (!(fp = fopen(pname, "r")))
10847159Sbostic error(pname);
10947159Sbostic
11047161Sbostic /* Open the temporary insecure password database. */
11160596Sbostic (void)snprintf(buf, sizeof(buf), "%s.tmp", _PATH_MP_DB);
11260596Sbostic dp = dbopen(buf,
11360596Sbostic O_RDWR|O_CREAT|O_EXCL, PERM_INSECURE, DB_HASH, &openinfo);
11460596Sbostic if (dp == NULL)
11547159Sbostic error(buf);
11647159Sbostic clean = FILE_INSECURE;
11747159Sbostic
11847159Sbostic /*
11947159Sbostic * Open file for old password file. Minor trickiness -- don't want to
12047159Sbostic * chance the file already existing, since someone (stupidly) might
12147159Sbostic * still be using this for permission checking. So, open it first and
12266816Sbostic * fdopen the resulting fd. The resulting file should be readable by
123*67042Sbostic * everyone.
12447159Sbostic */
12547159Sbostic if (makeold) {
12660596Sbostic (void)snprintf(buf, sizeof(buf), "%s.orig", pname);
12747159Sbostic if ((tfd = open(buf,
12847159Sbostic O_WRONLY|O_CREAT|O_EXCL, PERM_INSECURE)) < 0)
12947159Sbostic error(buf);
13060596Sbostic if ((oldfp = fdopen(tfd, "w")) == NULL)
13147159Sbostic error(buf);
13247159Sbostic clean = FILE_ORIG;
13347159Sbostic }
13447159Sbostic
13549253Sbostic /*
13649253Sbostic * The databases actually contain three copies of the original data.
13749253Sbostic * Each password file entry is converted into a rough approximation
13849253Sbostic * of a ``struct passwd'', with the strings placed inline. This
13949253Sbostic * object is then stored as the data for three separate keys. The
14049253Sbostic * first key * is the pw_name field prepended by the _PW_KEYBYNAME
14149253Sbostic * character. The second key is the pw_uid field prepended by the
14249253Sbostic * _PW_KEYBYUID character. The third key is the line number in the
14349253Sbostic * original file prepended by the _PW_KEYBYNUM character. (The special
14449253Sbostic * characters are prepended to ensure that the keys do not collide.)
14549253Sbostic */
14647161Sbostic data.data = (u_char *)buf;
14747161Sbostic key.data = (u_char *)tbuf;
14847159Sbostic for (cnt = 1; scan(fp, &pwd); ++cnt) {
14947159Sbostic #define COMPACT(e) t = e; while (*p++ = *t++);
15047159Sbostic /* Create insecure data. */
15147159Sbostic p = buf;
15247159Sbostic COMPACT(pwd.pw_name);
15347159Sbostic COMPACT("*");
15460596Sbostic memmove(p, &pwd.pw_uid, sizeof(int));
15547159Sbostic p += sizeof(int);
15660596Sbostic memmove(p, &pwd.pw_gid, sizeof(int));
15747159Sbostic p += sizeof(int);
15860596Sbostic memmove(p, &pwd.pw_change, sizeof(time_t));
15947159Sbostic p += sizeof(time_t);
16047159Sbostic COMPACT(pwd.pw_class);
16147159Sbostic COMPACT(pwd.pw_gecos);
16247159Sbostic COMPACT(pwd.pw_dir);
16347159Sbostic COMPACT(pwd.pw_shell);
16460596Sbostic memmove(p, &pwd.pw_expire, sizeof(time_t));
16547159Sbostic p += sizeof(time_t);
16647161Sbostic data.size = p - buf;
16747159Sbostic
16847159Sbostic /* Store insecure by name. */
16947159Sbostic tbuf[0] = _PW_KEYBYNAME;
17047159Sbostic len = strlen(pwd.pw_name);
17160596Sbostic memmove(tbuf + 1, pwd.pw_name, len);
17247161Sbostic key.size = len + 1;
17347161Sbostic if ((dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1)
17447161Sbostic error("put");
17547159Sbostic
17647159Sbostic /* Store insecure by number. */
17747159Sbostic tbuf[0] = _PW_KEYBYNUM;
17860596Sbostic memmove(tbuf + 1, &cnt, sizeof(cnt));
17947161Sbostic key.size = sizeof(cnt) + 1;
18047161Sbostic if ((dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1)
18147161Sbostic error("put");
18247159Sbostic
18347159Sbostic /* Store insecure by uid. */
18447159Sbostic tbuf[0] = _PW_KEYBYUID;
18560596Sbostic memmove(tbuf + 1, &pwd.pw_uid, sizeof(pwd.pw_uid));
18647161Sbostic key.size = sizeof(pwd.pw_uid) + 1;
18747161Sbostic if ((dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1)
18847161Sbostic error("put");
18947159Sbostic
19060596Sbostic /* Create original format password file entry */
19160596Sbostic if (makeold)
19260596Sbostic (void)fprintf(oldfp, "%s:*:%d:%d:%s:%s:%s\n",
19360596Sbostic pwd.pw_name, pwd.pw_uid, pwd.pw_gid, pwd.pw_gecos,
19460596Sbostic pwd.pw_dir, pwd.pw_shell);
19560596Sbostic }
19660596Sbostic (void)(dp->close)(dp);
19760596Sbostic if (makeold) {
19860596Sbostic (void)fflush(oldfp);
19960596Sbostic (void)fclose(oldfp);
20060596Sbostic }
20160596Sbostic
20260596Sbostic /* Open the temporary encrypted password database. */
20360596Sbostic (void)snprintf(buf, sizeof(buf), "%s.tmp", _PATH_SMP_DB);
20460596Sbostic edp = dbopen(buf,
20560596Sbostic O_RDWR|O_CREAT|O_EXCL, PERM_SECURE, DB_HASH, &openinfo);
20660596Sbostic if (!edp)
20760596Sbostic error(buf);
20860596Sbostic clean = FILE_SECURE;
20960596Sbostic
21060596Sbostic rewind(fp);
21160596Sbostic for (cnt = 1; scan(fp, &pwd); ++cnt) {
21260596Sbostic
21347159Sbostic /* Create secure data. */
21447159Sbostic p = buf;
21547159Sbostic COMPACT(pwd.pw_name);
21647159Sbostic COMPACT(pwd.pw_passwd);
21760596Sbostic memmove(p, &pwd.pw_uid, sizeof(int));
21847159Sbostic p += sizeof(int);
21960596Sbostic memmove(p, &pwd.pw_gid, sizeof(int));
22047159Sbostic p += sizeof(int);
22160596Sbostic memmove(p, &pwd.pw_change, sizeof(time_t));
22247159Sbostic p += sizeof(time_t);
22347159Sbostic COMPACT(pwd.pw_class);
22447159Sbostic COMPACT(pwd.pw_gecos);
22547159Sbostic COMPACT(pwd.pw_dir);
22647159Sbostic COMPACT(pwd.pw_shell);
22760596Sbostic memmove(p, &pwd.pw_expire, sizeof(time_t));
22847159Sbostic p += sizeof(time_t);
22947161Sbostic data.size = p - buf;
23047159Sbostic
23147159Sbostic /* Store secure by name. */
23247159Sbostic tbuf[0] = _PW_KEYBYNAME;
23347159Sbostic len = strlen(pwd.pw_name);
23460596Sbostic memmove(tbuf + 1, pwd.pw_name, len);
23547161Sbostic key.size = len + 1;
23647161Sbostic if ((dp->put)(edp, &key, &data, R_NOOVERWRITE) == -1)
23747161Sbostic error("put");
23847159Sbostic
23947159Sbostic /* Store secure by number. */
24047159Sbostic tbuf[0] = _PW_KEYBYNUM;
24160596Sbostic memmove(tbuf + 1, &cnt, sizeof(cnt));
24247161Sbostic key.size = sizeof(cnt) + 1;
24347161Sbostic if ((dp->put)(edp, &key, &data, R_NOOVERWRITE) == -1)
24447161Sbostic error("put");
24547159Sbostic
24647159Sbostic /* Store secure by uid. */
24747159Sbostic tbuf[0] = _PW_KEYBYUID;
24860596Sbostic memmove(tbuf + 1, &pwd.pw_uid, sizeof(pwd.pw_uid));
24947161Sbostic key.size = sizeof(pwd.pw_uid) + 1;
25047161Sbostic if ((dp->put)(edp, &key, &data, R_NOOVERWRITE) == -1)
25147161Sbostic error("put");
25260596Sbostic }
25347159Sbostic
25447161Sbostic (void)(edp->close)(edp);
25547159Sbostic
25647159Sbostic /* Set master.passwd permissions, in case caller forgot. */
25747162Sbostic (void)fchmod(fileno(fp), S_IRUSR|S_IWUSR);
25847159Sbostic (void)fclose(fp);
25947159Sbostic
26047159Sbostic /* Install as the real password files. */
26160596Sbostic (void)snprintf(buf, sizeof(buf), "%s.tmp", _PATH_MP_DB);
26247159Sbostic mv(buf, _PATH_MP_DB);
26360596Sbostic (void)snprintf(buf, sizeof(buf), "%s.tmp", _PATH_SMP_DB);
26447159Sbostic mv(buf, _PATH_SMP_DB);
26547159Sbostic if (makeold) {
26660596Sbostic (void)snprintf(buf, sizeof(buf), "%s.orig", pname);
26747159Sbostic mv(buf, _PATH_PASSWD);
26847159Sbostic }
26947159Sbostic /*
27047159Sbostic * Move the master password LAST -- chpass(1), passwd(1) and vipw(8)
27147159Sbostic * all use flock(2) on it to block other incarnations of themselves.
27247159Sbostic * The rename means that everything is unlocked, as the original file
27347159Sbostic * can no longer be accessed.
27447159Sbostic */
27547159Sbostic mv(pname, _PATH_MASTERPASSWD);
27647159Sbostic exit(0);
27747159Sbostic }
27847159Sbostic
27960596Sbostic int
scan(fp,pw)28047159Sbostic scan(fp, pw)
28147159Sbostic FILE *fp;
28247159Sbostic struct passwd *pw;
28347159Sbostic {
28447159Sbostic static int lcnt;
28547159Sbostic static char line[LINE_MAX];
28647159Sbostic char *p;
28747159Sbostic
28847159Sbostic if (!fgets(line, sizeof(line), fp))
28966580Spendry return (0);
29047159Sbostic ++lcnt;
29147159Sbostic /*
29247159Sbostic * ``... if I swallow anything evil, put your fingers down my
29347159Sbostic * throat...''
29447159Sbostic * -- The Who
29547159Sbostic */
29660596Sbostic if (!(p = strchr(line, '\n'))) {
29766580Spendry warnx("line too long");
29847159Sbostic goto fmt;
29947159Sbostic
30047159Sbostic }
30147159Sbostic *p = '\0';
30247159Sbostic if (!pw_scan(line, pw)) {
30366580Spendry warnx("at line #%d", lcnt);
30466580Spendry fmt: errno = EFTYPE; /* XXX */
30547159Sbostic error(pname);
30647159Sbostic }
30766580Spendry
30866580Spendry return (1);
30947159Sbostic }
31047159Sbostic
31160596Sbostic void
mv(from,to)31247159Sbostic mv(from, to)
31347159Sbostic char *from, *to;
31447159Sbostic {
31547159Sbostic char buf[MAXPATHLEN];
31647159Sbostic
31747159Sbostic if (rename(from, to)) {
31866580Spendry int sverrno = errno;
31960596Sbostic (void)snprintf(buf, sizeof(buf), "%s to %s", from, to);
32047159Sbostic errno = sverrno;
32147159Sbostic error(buf);
32247159Sbostic }
32347159Sbostic }
32447159Sbostic
32560596Sbostic void
error(name)32647161Sbostic error(name)
32747161Sbostic char *name;
32847161Sbostic {
32966580Spendry
33066580Spendry warn(name);
33147161Sbostic cleanup();
33247161Sbostic exit(1);
33347161Sbostic }
33447161Sbostic
33560596Sbostic void
cleanup()33647159Sbostic cleanup()
33747159Sbostic {
33847159Sbostic char buf[MAXPATHLEN];
33947159Sbostic
34047159Sbostic switch(clean) {
34147159Sbostic case FILE_ORIG:
34260596Sbostic (void)snprintf(buf, sizeof(buf), "%s.orig", pname);
34347159Sbostic (void)unlink(buf);
34447159Sbostic /* FALLTHROUGH */
34547159Sbostic case FILE_SECURE:
34660596Sbostic (void)snprintf(buf, sizeof(buf), "%s.tmp", _PATH_SMP_DB);
34747159Sbostic (void)unlink(buf);
34847159Sbostic /* FALLTHROUGH */
34947159Sbostic case FILE_INSECURE:
35060596Sbostic (void)snprintf(buf, sizeof(buf), "%s.tmp", _PATH_MP_DB);
35147159Sbostic (void)unlink(buf);
35247159Sbostic }
35347159Sbostic }
35447159Sbostic
35560596Sbostic void
usage()35647159Sbostic usage()
35747159Sbostic {
35866580Spendry
35947159Sbostic (void)fprintf(stderr, "usage: pwd_mkdb [-p] file\n");
36047159Sbostic exit(1);
36147159Sbostic }
362