* Copyright (c) 1991 The Regents of the University of California.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
"@(#) Copyright (c) 1991 The Regents of the University of California.\n\
static char sccsid
[] = "@(#)pwd_mkdb.c 5.5 (Berkeley) 5/6/91";
/* Compact pwd.db/spwd.db structure by Alex G. Bulushev, bag@demos.su */
# define HI_CACHE (512 * 1024)
# define HI_SCACHE (128 * 1024)
# define HI_CACHE (2048 * 1024)
#define PERM_INSECURE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
#define PERM_SECURE (S_IRUSR|S_IWUSR)
HI_CACHE
, /* cachesize */
HI_SCACHE
, /* cachesize */
char *progname
= "pwd_mkdb";
static enum state
{ FILE_INSECURE
, FILE_SECURE
, FILE_ORIG
} clean
;
static struct passwd pwd
; /* password structure */
static char *pname
; /* password file name */
static char prefix
[MAXPATHLEN
];
register int len
, makeold
;
char buf
[MAX(MAXPATHLEN
, LINE_MAX
* 2)], tbuf
[1024];
strcpy(prefix
, _PATH_PWD
);
while ((ch
= getopt(argc
, argv
, "d:pv")) != EOF
)
case 'p': /* create V7 "file.orig" */
case 'v': /* backward compatible */
* This could be done to allow the user to interrupt. Probably
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)sprintf(buf
, "%s/%s.tmp", prefix
, _MP_DB
);
O_RDWR
|O_CREAT
|O_EXCL
, PERM_INSECURE
, DB_HASH
, &openinfo
);
/* Open the temporary encrypted password database. */
(void)sprintf(buf
, "%s/%s.tmp", prefix
, _SMP_DB
);
O_RDWR
|O_CREAT
|O_EXCL
, PERM_SECURE
, DB_HASH
, &sopeninfo
);
* 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)sprintf(buf
, "%s.orig", pname
);
O_WRONLY
|O_CREAT
|O_EXCL
, PERM_INSECURE
)) < 0)
if (!(oldfp
= fdopen(tfd
, "w")))
* 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
) {
pdata
.data
= (u_char
*)&cnt
;
pdata
.size
= sizeof(int);
sdata
.data
= (u_char
*)pwd
.pw_passwd
;
sdata
.size
= strlen(pwd
.pw_passwd
) + 1;
#define COMPACT(e) t = e; while (*p++ = *t++);
/* Create insecure data. */
bcopy((char *)&pwd
.pw_uid
, p
, sizeof(int));
bcopy((char *)&pwd
.pw_gid
, p
, sizeof(int));
bcopy((char *)&pwd
.pw_change
, p
, sizeof(time_t));
bcopy((char *)&pwd
.pw_expire
, p
, sizeof(time_t));
/* Store insecure by name. */
len
= strlen(pwd
.pw_name
);
bcopy(pwd
.pw_name
, tbuf
+ 1, len
);
if ((dp
->put
)(dp
, &key
, &pdata
, R_NOOVERWRITE
) == -1)
if ((dp
->put
)(dp
, &key
, &data
, R_NOOVERWRITE
) == -1)
/* Store insecure by uid. */
bcopy((char *)&pwd
.pw_uid
, tbuf
+ 1, sizeof(pwd
.pw_uid
));
key
.size
= sizeof(pwd
.pw_uid
) + 1;
if ((dp
->put
)(dp
, &key
, &pdata
, R_NOOVERWRITE
) == -1)
if ((dp
->put
)(dp
, &key
, &data
, R_NOOVERWRITE
) == -1)
/* Store insecure by number. */
bcopy((char *)&cnt
, tbuf
+ 1, sizeof(cnt
));
key
.size
= sizeof(cnt
) + 1;
if ((dp
->put
)(dp
, &key
, &data
, R_NOOVERWRITE
) == -1)
if ((edp
->put
)(edp
, &key
, &sdata
, 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
);
(void)fsync(fileno(oldfp
));
/* Open the temporary encrypted password database. */
(void)sprintf(buf
, "%s/%s.tmp", prefix
, _SMP_DB
);
O_RDWR
|O_CREAT
|O_EXCL
, PERM_SECURE
, DB_HASH
, &openinfo
);
for (cnt
= 1; scan(fp
, &pwd
); ++cnt
) {
/* Create secure data. */
bcopy((char *)&pwd
.pw_uid
, p
, sizeof(int));
bcopy((char *)&pwd
.pw_gid
, p
, sizeof(int));
bcopy((char *)&pwd
.pw_change
, p
, sizeof(time_t));
bcopy((char *)&pwd
.pw_expire
, p
, sizeof(time_t));
/* Store secure by name. */
len
= strlen(pwd
.pw_name
);
bcopy(pwd
.pw_name
, tbuf
+ 1, len
);
if ((edp
->put
)(edp
, &key
, &data
, R_NOOVERWRITE
) == -1)
/* Store secure by number. */
bcopy((char *)&cnt
, tbuf
+ 1, sizeof(cnt
));
key
.size
= sizeof(cnt
) + 1;
if ((edp
->put
)(edp
, &key
, &data
, R_NOOVERWRITE
) == -1)
/* Store secure by uid. */
bcopy((char *)&pwd
.pw_uid
, tbuf
+ 1, sizeof(pwd
.pw_uid
));
key
.size
= sizeof(pwd
.pw_uid
) + 1;
if ((edp
->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)sprintf(buf
, "%s/%s.tmp", prefix
, _MP_DB
);
(void)sprintf(buf2
, "%s/%s", prefix
, _MP_DB
);
(void)sprintf(buf
, "%s/%s.tmp", prefix
, _SMP_DB
);
(void)sprintf(buf2
, "%s/%s", prefix
, _SMP_DB
);
(void)sprintf(buf2
, "%s/%s", prefix
, _PASSWD
);
(void)sprintf(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.
(void)sprintf(buf
, "%s/%s", prefix
, _MASTERPASSWD
);
static char line
[LINE_MAX
];
if (!fgets(line
, sizeof(line
), fp
))
* ``... if I swallow anything evil, put your fingers down my
if (!(p
= index(line
, '\n'))) {
(void)fprintf(stderr
, "pwd_mkdb: line too long\n");
if (!pw_scan(line
, pw
)) {
(void)fprintf(stderr
, "pwd_mkdb: at line #%d.\n", lcnt
);
(void)sprintf(buf
, "%s to %s", from
, to
);
(void)fprintf(stderr
, "pwd_mkdb: %s: %s\n", name
, strerror(errno
));
(void)sprintf(buf
, "%s.orig", pname
);
(void)sprintf(buf
, "%s/%s.tmp", prefix
, _SMP_DB
);
(void)sprintf(buf
, "%s/%s.tmp", prefix
, _MP_DB
);
(void)fprintf(stderr
, "usage: pwd_mkdb [-p] [-d <dest dir>] file\n");