* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
* %sccs.include.redist.c%
static char copyright
[] =
"@(#) Copyright (c) 1991, 1993\n\
The Regents of the University of California. All rights reserved.\n";
static char sccsid
[] = "@(#)pwd_mkdb.c 8.2 (Berkeley) %G%";
#define PERM_INSECURE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
#define PERM_SECURE (S_IRUSR|S_IWUSR)
2048 * 1024, /* cachesize */
static enum state
{ FILE_INSECURE
, FILE_SECURE
, FILE_ORIG
} clean
;
static struct passwd pwd
; /* password structure */
static char *pname
; /* password file name */
void cleanup
__P((void));
void error
__P((char *));
void mv
__P((char *, char *));
int scan
__P((FILE *, struct passwd
*));
int ch
, cnt
, len
, makeold
, tfd
;
char buf
[MAX(MAXPATHLEN
, LINE_MAX
* 2)], tbuf
[1024];
while ((ch
= getopt(argc
, argv
, "pv")) != EOF
)
case 'p': /* create V7 "file.orig" */
case 'v': /* backward compatible */
* This could be changed to allow the user to interrupt.
* Probably not worth the effort.
sigaddset(&set
, SIGTSTP
);
sigaddset(&set
, SIGQUIT
);
sigaddset(&set
, SIGTERM
);
(void)sigprocmask(SIG_BLOCK
, &set
, (sigset_t
*)NULL
);
/* Open the original password file */
if (!(fp
= fopen(pname
, "r")))
/* Open the temporary insecure password database. */
(void)snprintf(buf
, sizeof(buf
), "%s.tmp", _PATH_MP_DB
);
O_RDWR
|O_CREAT
|O_EXCL
, PERM_INSECURE
, DB_HASH
, &openinfo
);
* Open file for old password file. Minor trickiness -- don't want to
* chance the file already existing, since someone (stupidly) might
* still be using this for permission checking. So, open it first and
* fdopen the resulting fd. Don't really care who reads it.
(void)snprintf(buf
, sizeof(buf
), "%s.orig", pname
);
O_WRONLY
|O_CREAT
|O_EXCL
, PERM_INSECURE
)) < 0)
if ((oldfp
= fdopen(tfd
, "w")) == NULL
)
* The databases actually contain three copies of the original data.
* Each password file entry is converted into a rough approximation
* of a ``struct passwd'', with the strings placed inline. This
* object is then stored as the data for three separate keys. The
* first key * is the pw_name field prepended by the _PW_KEYBYNAME
* character. The second key is the pw_uid field prepended by the
* _PW_KEYBYUID character. The third key is the line number in the
* original file prepended by the _PW_KEYBYNUM character. (The special
* characters are prepended to ensure that the keys do not collide.)
data
.data
= (u_char
*)buf
;
key
.data
= (u_char
*)tbuf
;
for (cnt
= 1; scan(fp
, &pwd
); ++cnt
) {
#define COMPACT(e) t = e; while (*p++ = *t++);
/* Create insecure data. */
memmove(p
, &pwd
.pw_uid
, sizeof(int));
memmove(p
, &pwd
.pw_gid
, sizeof(int));
memmove(p
, &pwd
.pw_change
, sizeof(time_t));
memmove(p
, &pwd
.pw_expire
, sizeof(time_t));
/* Store insecure by name. */
len
= strlen(pwd
.pw_name
);
memmove(tbuf
+ 1, pwd
.pw_name
, len
);
if ((dp
->put
)(dp
, &key
, &data
, R_NOOVERWRITE
) == -1)
/* Store insecure by number. */
memmove(tbuf
+ 1, &cnt
, sizeof(cnt
));
key
.size
= sizeof(cnt
) + 1;
if ((dp
->put
)(dp
, &key
, &data
, R_NOOVERWRITE
) == -1)
/* Store insecure by uid. */
memmove(tbuf
+ 1, &pwd
.pw_uid
, sizeof(pwd
.pw_uid
));
key
.size
= sizeof(pwd
.pw_uid
) + 1;
if ((dp
->put
)(dp
, &key
, &data
, R_NOOVERWRITE
) == -1)
/* Create original format password file entry */
(void)fprintf(oldfp
, "%s:*:%d:%d:%s:%s:%s\n",
pwd
.pw_name
, pwd
.pw_uid
, pwd
.pw_gid
, pwd
.pw_gecos
,
pwd
.pw_dir
, pwd
.pw_shell
);
/* Open the temporary encrypted password database. */
(void)snprintf(buf
, sizeof(buf
), "%s.tmp", _PATH_SMP_DB
);
O_RDWR
|O_CREAT
|O_EXCL
, PERM_SECURE
, DB_HASH
, &openinfo
);
for (cnt
= 1; scan(fp
, &pwd
); ++cnt
) {
/* Create secure data. */
memmove(p
, &pwd
.pw_uid
, sizeof(int));
memmove(p
, &pwd
.pw_gid
, sizeof(int));
memmove(p
, &pwd
.pw_change
, sizeof(time_t));
memmove(p
, &pwd
.pw_expire
, sizeof(time_t));
/* Store secure by name. */
len
= strlen(pwd
.pw_name
);
memmove(tbuf
+ 1, pwd
.pw_name
, len
);
if ((dp
->put
)(edp
, &key
, &data
, R_NOOVERWRITE
) == -1)
/* Store secure by number. */
memmove(tbuf
+ 1, &cnt
, sizeof(cnt
));
key
.size
= sizeof(cnt
) + 1;
if ((dp
->put
)(edp
, &key
, &data
, R_NOOVERWRITE
) == -1)
/* Store secure by uid. */
memmove(tbuf
+ 1, &pwd
.pw_uid
, sizeof(pwd
.pw_uid
));
key
.size
= sizeof(pwd
.pw_uid
) + 1;
if ((dp
->put
)(edp
, &key
, &data
, R_NOOVERWRITE
) == -1)
/* Set master.passwd permissions, in case caller forgot. */
(void)fchmod(fileno(fp
), S_IRUSR
|S_IWUSR
);
/* Install as the real password files. */
(void)snprintf(buf
, sizeof(buf
), "%s.tmp", _PATH_MP_DB
);
(void)snprintf(buf
, sizeof(buf
), "%s.tmp", _PATH_SMP_DB
);
(void)snprintf(buf
, sizeof(buf
), "%s.orig", pname
);
* Move the master password LAST -- chpass(1), passwd(1) and vipw(8)
* all use flock(2) on it to block other incarnations of themselves.
* The rename means that everything is unlocked, as the original file
* can no longer be accessed.
mv(pname
, _PATH_MASTERPASSWD
);
static char line
[LINE_MAX
];
if (!fgets(line
, sizeof(line
), fp
))
* ``... if I swallow anything evil, put your fingers down my
if (!(p
= strchr(line
, '\n'))) {
if (!pw_scan(line
, pw
)) {
warnx("at line #%d", lcnt
);
fmt
: errno
= EFTYPE
; /* XXX */
(void)snprintf(buf
, sizeof(buf
), "%s to %s", from
, to
);
(void)snprintf(buf
, sizeof(buf
), "%s.orig", pname
);
(void)snprintf(buf
, sizeof(buf
), "%s.tmp", _PATH_SMP_DB
);
(void)snprintf(buf
, sizeof(buf
), "%s.tmp", _PATH_MP_DB
);
(void)fprintf(stderr
, "usage: pwd_mkdb [-p] file\n");