Subject: bin/7366: pwd_mkdb improvement
To: None <gnats-bugs@gnats.netbsd.org>
From: Takahiro Kambe <taca@sky.yamashina.kyoto.jp>
List: netbsd-bugs
Date: 04/13/1999 01:05:19
>Number: 7366
>Category: bin
>Synopsis: pwd_mkdb(8) -p option.
>Confidential: no
>Severity: non-critical
>Priority: low
>Responsible: bin-bug-people (Utility Bug People)
>State: open
>Class: change-request
>Submitter-Id: net
>Arrival-Date: Mon Apr 12 09:20:01 1999
>Last-Modified:
>Originator: Takahiro Kambe
>Organization:
>Release: NetBSD-current 1999/4/2
>Environment:
System: NetBSD edge.sky.yamashina.kyoto.jp 1.4_ALPHA NetBSD 1.4_ALPHA (ALN4PCVT) #34: Sun Apr 4 20:14:43 JST 1999 taca@edge.sky.yamashina.kyoto.jp:/usr/src/sys/arch/i386/compile/ALN4PCVT i386
>Description:
FreeBSD 2.2.8's pwd_mkdb(8) has -u option, which update only one user's
DB recored. This imporve perforemanse under many users in the passwd
file. I ported this option into NetBSD current, borrows codes from
FreeBSD.
>How-To-Repeat:
>Fix:
I attached the patch, which simply introduce -u option to pwd_mkdb(8),
and some modification to passwd(1) and chpass(1) for utilizing it.
Some discussion:
1. I want to add an argument pw_mkdb(3) which lives in libutil(3),
src/lib/libutil/passwd.c:
int pw_mkdb(char *username);
If username is NULL, it act as current pw_mkdb(3). But this breaks
binary compatibility, at least some period.
So I added pw_mkdb_user() to commands which use pw_mkdb(3).
2. Pwd_mkdb(8) scan the file twice which supplied it's argument.
So, more improvement might be done.
3. Handling of temporary file might be buggy in this patch.
Thnaks in advise.
--
taca
Index: usr.sbin/pwd_mkdb/pwd_mkdb.c
--- usr.sbin/pwd_mkdb/pwd_mkdb.c.orig Thu Jan 14 00:45:30 1999
+++ usr.sbin/pwd_mkdb/pwd_mkdb.c Mon Apr 12 00:00:18 1999
@@ -91,9 +91,11 @@
void error __P((char *));
void wr_error __P((char *));
int main __P((int, char **));
+void cp __P((char *, char *, mode_t));
void mv __P((char *, char *));
void rm __P((char *));
int scan __P((FILE *, struct passwd *, int *));
+int check_user_db __P((char *));
void usage __P((void));
int
@@ -105,17 +107,22 @@
DBT data, key;
FILE *fp, *oldfp;
sigset_t set;
- int ch, cnt, len, makeold, tfd, flags;
+ int ch, cnt, len, makeold, tfd, flags, fflag;
char *p;
const char *t;
char buf[MAX(MAXPATHLEN, LINE_MAX * 2)], tbuf[1024];
+ char pwd_db[MAXPATHLEN], pwd_sdb[MAXPATHLEN];
int hasyp = 0;
DBT ypdata, ypkey;
+ char *username;
+ int method, methoduid;
oldfp = NULL;
strcpy(prefix, "/");
makeold = 0;
- while ((ch = getopt(argc, argv, "d:pv")) != -1)
+ username = NULL;
+
+ while ((ch = getopt(argc, argv, "cd:pu:v")) != -1)
switch(ch) {
case 'd':
strncpy(prefix, optarg, sizeof(prefix));
@@ -124,6 +131,9 @@
case 'p': /* create V7 "file.orig" */
makeold = 1;
break;
+ case 'u': /* only update this record */
+ username = optarg;
+ break;
case 'v': /* backward compatible */
break;
case '?':
@@ -133,7 +143,7 @@
argc -= optind;
argv += optind;
- if (argc != 1)
+ if (argc != 1 || (username && (*username == '+' || *username == '-')))
usage();
/*
@@ -156,11 +166,25 @@
if (!(fp = fopen(pname, "r")))
error(pname);
- /* Open the temporary insecure password database. */
(void)snprintf(pwd_db_tmp, sizeof(pwd_db_tmp), "%s%s.tmp", prefix,
_PATH_MP_DB);
- dp = dbopen(pwd_db_tmp,
- O_RDWR|O_CREAT|O_EXCL, PERM_INSECURE, DB_HASH, &openinfo);
+
+ if (username) {
+ (void)snprintf(pwd_db, sizeof(pwd_db), "%s/%s", prefix,
+ _PATH_MP_DB);
+ clean = FILE_INSECURE;
+ cp(pwd_db, pwd_db_tmp, PERM_INSECURE);
+ fflag = O_RDWR;
+ method = 0;
+ methoduid = check_user_db(username);
+ } else {
+ fflag = O_RDWR|O_CREAT|O_EXCL;
+ method = R_NOOVERWRITE;
+ methoduid = R_NOOVERWRITE;
+ }
+
+ /* Open the temporary insecure password database. */
+ dp = dbopen(pwd_db_tmp, fflag, PERM_INSECURE, DB_HASH, &openinfo);
if (dp == NULL)
error(pwd_db_tmp);
clean = FILE_INSECURE;
@@ -220,47 +244,49 @@
cnt);
}
- /* Create insecure data. */
- p = buf;
- COMPACT(pwd.pw_name);
- COMPACT("*");
- memmove(p, &pwd.pw_uid, sizeof(int));
- p += sizeof(int);
- memmove(p, &pwd.pw_gid, sizeof(int));
- p += sizeof(int);
- memmove(p, &pwd.pw_change, sizeof(time_t));
- p += sizeof(time_t);
- COMPACT(pwd.pw_class);
- COMPACT(pwd.pw_gecos);
- COMPACT(pwd.pw_dir);
- COMPACT(pwd.pw_shell);
- memmove(p, &pwd.pw_expire, sizeof(time_t));
- p += sizeof(time_t);
- memmove(p, &flags, sizeof(int));
- p += sizeof(int);
- data.size = p - buf;
-
- /* Store insecure by name. */
- tbuf[0] = _PW_KEYBYNAME;
- len = strlen(pwd.pw_name);
- memmove(tbuf + 1, pwd.pw_name, len);
- key.size = len + 1;
- if ((dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1)
- wr_error(pwd_db_tmp);
-
- /* Store insecure by number. */
- tbuf[0] = _PW_KEYBYNUM;
- memmove(tbuf + 1, &cnt, sizeof(cnt));
- key.size = sizeof(cnt) + 1;
- if ((dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1)
+ if (!username || (strcmp(username, pwd.pw_name) == 0)) {
+ /* Create insecure data. */
+ p = buf;
+ COMPACT(pwd.pw_name);
+ COMPACT("*");
+ memmove(p, &pwd.pw_uid, sizeof(int));
+ p += sizeof(int);
+ memmove(p, &pwd.pw_gid, sizeof(int));
+ p += sizeof(int);
+ memmove(p, &pwd.pw_change, sizeof(time_t));
+ p += sizeof(time_t);
+ COMPACT(pwd.pw_class);
+ COMPACT(pwd.pw_gecos);
+ COMPACT(pwd.pw_dir);
+ COMPACT(pwd.pw_shell);
+ memmove(p, &pwd.pw_expire, sizeof(time_t));
+ p += sizeof(time_t);
+ memmove(p, &flags, sizeof(int));
+ p += sizeof(int);
+ data.size = p - buf;
+
+ /* Store insecure by name. */
+ tbuf[0] = _PW_KEYBYNAME;
+ len = strlen(pwd.pw_name);
+ memmove(tbuf + 1, pwd.pw_name, len);
+ key.size = len + 1;
+ if ((dp->put)(dp, &key, &data, method) == -1)
wr_error(pwd_db_tmp);
- /* Store insecure by uid. */
- tbuf[0] = _PW_KEYBYUID;
- 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)
- wr_error(pwd_db_tmp);
+ /* Store insecure by number. */
+ tbuf[0] = _PW_KEYBYNUM;
+ memmove(tbuf + 1, &cnt, sizeof(cnt));
+ key.size = sizeof(cnt) + 1;
+ if ((dp->put)(dp, &key, &data, method) == -1)
+ wr_error(pwd_db_tmp);
+
+ /* Store insecure by uid. */
+ tbuf[0] = _PW_KEYBYUID;
+ memmove(tbuf + 1, &pwd.pw_uid, sizeof(pwd.pw_uid));
+ key.size = sizeof(pwd.pw_uid) + 1;
+ if ((dp->put)(dp, &key, &data, methoduid) == -1)
+ wr_error(pwd_db_tmp);
+ }
/* Create original format password file entry */
if (makeold) {
@@ -274,13 +300,13 @@
}
/* Store YP token, if needed. */
- if(hasyp) {
+ if (hasyp) {
ypkey.data = (u_char *)__yp_token;
ypkey.size = strlen(__yp_token);
ypdata.data = (u_char *)NULL;
ypdata.size = 0;
- if ((dp->put)(dp, &ypkey, &ypdata, R_NOOVERWRITE) == -1)
+ if ((dp->put)(dp, &ypkey, &ypdata, method) == -1)
wr_error(pwd_db_tmp);
}
@@ -296,11 +322,22 @@
}
}
- /* Open the temporary encrypted password database. */
(void)snprintf(pwd_Sdb_tmp, sizeof(pwd_Sdb_tmp), "%s%s.tmp", prefix,
_PATH_SMP_DB);
- edp = dbopen(pwd_Sdb_tmp,
- O_RDWR|O_CREAT|O_EXCL, PERM_SECURE, DB_HASH, &openinfo);
+
+ if (username) {
+ (void)snprintf(pwd_sdb, sizeof(pwd_sdb), "%s/%s", prefix,
+ _PATH_SMP_DB);
+
+ clean = FILE_SECURE;
+ cp(pwd_sdb, pwd_Sdb_tmp, PERM_SECURE);
+ fflag = O_RDWR;
+ } else {
+ fflag = O_RDWR|O_CREAT|O_EXCL;
+ }
+
+ /* Open the temporary encrypted password database. */
+ edp = dbopen(pwd_Sdb_tmp, fflag, PERM_SECURE, DB_HASH, &openinfo);
if (!edp)
error(pwd_Sdb_tmp);
clean = FILE_SECURE;
@@ -308,57 +345,59 @@
rewind(fp);
for (cnt = 1; scan(fp, &pwd, &flags); ++cnt) {
- /* Create secure data. */
- p = buf;
- COMPACT(pwd.pw_name);
- COMPACT(pwd.pw_passwd);
- memmove(p, &pwd.pw_uid, sizeof(int));
- p += sizeof(int);
- memmove(p, &pwd.pw_gid, sizeof(int));
- p += sizeof(int);
- memmove(p, &pwd.pw_change, sizeof(time_t));
- p += sizeof(time_t);
- COMPACT(pwd.pw_class);
- COMPACT(pwd.pw_gecos);
- COMPACT(pwd.pw_dir);
- COMPACT(pwd.pw_shell);
- memmove(p, &pwd.pw_expire, sizeof(time_t));
- p += sizeof(time_t);
- memmove(p, &flags, sizeof(int));
- p += sizeof(int);
- data.size = p - buf;
-
- /* Store secure by name. */
- tbuf[0] = _PW_KEYBYNAME;
- len = strlen(pwd.pw_name);
- memmove(tbuf + 1, pwd.pw_name, len);
- key.size = len + 1;
- if ((edp->put)(edp, &key, &data, R_NOOVERWRITE) == -1)
- wr_error(pwd_Sdb_tmp);
-
- /* Store secure by number. */
- tbuf[0] = _PW_KEYBYNUM;
- memmove(tbuf + 1, &cnt, sizeof(cnt));
- key.size = sizeof(cnt) + 1;
- if ((edp->put)(edp, &key, &data, R_NOOVERWRITE) == -1)
- wr_error(pwd_Sdb_tmp);
-
- /* Store secure by uid. */
- tbuf[0] = _PW_KEYBYUID;
- memmove(tbuf + 1, &pwd.pw_uid, sizeof(pwd.pw_uid));
- key.size = sizeof(pwd.pw_uid) + 1;
- if ((edp->put)(edp, &key, &data, R_NOOVERWRITE) == -1)
- wr_error(pwd_Sdb_tmp);
+ if (!username || (strcmp(username, pwd.pw_name) == 0)) {
+ /* Create secure data. */
+ p = buf;
+ COMPACT(pwd.pw_name);
+ COMPACT(pwd.pw_passwd);
+ memmove(p, &pwd.pw_uid, sizeof(int));
+ p += sizeof(int);
+ memmove(p, &pwd.pw_gid, sizeof(int));
+ p += sizeof(int);
+ memmove(p, &pwd.pw_change, sizeof(time_t));
+ p += sizeof(time_t);
+ COMPACT(pwd.pw_class);
+ COMPACT(pwd.pw_gecos);
+ COMPACT(pwd.pw_dir);
+ COMPACT(pwd.pw_shell);
+ memmove(p, &pwd.pw_expire, sizeof(time_t));
+ p += sizeof(time_t);
+ memmove(p, &flags, sizeof(int));
+ p += sizeof(int);
+ data.size = p - buf;
+
+ /* Store secure by name. */
+ tbuf[0] = _PW_KEYBYNAME;
+ len = strlen(pwd.pw_name);
+ memmove(tbuf + 1, pwd.pw_name, len);
+ key.size = len + 1;
+ if ((edp->put)(edp, &key, &data, method) == -1)
+ wr_error(pwd_Sdb_tmp);
+
+ /* Store secure by number. */
+ tbuf[0] = _PW_KEYBYNUM;
+ memmove(tbuf + 1, &cnt, sizeof(cnt));
+ key.size = sizeof(cnt) + 1;
+ if ((edp->put)(edp, &key, &data, method) == -1)
+ wr_error(pwd_Sdb_tmp);
+
+ /* Store secure by uid. */
+ tbuf[0] = _PW_KEYBYUID;
+ memmove(tbuf + 1, &pwd.pw_uid, sizeof(pwd.pw_uid));
+ key.size = sizeof(pwd.pw_uid) + 1;
+ if ((edp->put)(edp, &key, &data, methoduid) == -1)
+ wr_error(pwd_Sdb_tmp);
+ }
}
/* Store YP token, if needed. */
- if(hasyp) {
+ if (hasyp) {
ypkey.data = (u_char *)__yp_token;
ypkey.size = strlen(__yp_token);
ypdata.data = (u_char *)NULL;
ypdata.size = 0;
- if((edp->put)(edp, &ypkey, &ypdata, R_NOOVERWRITE) == -1)
+ if((edp->put)(edp, &ypkey, &ypdata, method) == -1)
wr_error(pwd_Sdb_tmp);
}
@@ -405,6 +444,61 @@
}
int
+check_user_db(username)
+ char *username;
+{
+ DB *pw_db;
+ DBT data, key;
+ int len;
+ char *p;
+ char buf[MAX(MAXPATHLEN, LINE_MAX * 2)];
+ int methoduid = 0;
+
+ /*
+ * Do some trouble to check if we should store this users
+ * uid. Don't use getpwnam/getpwuid as that interferes
+ * with NIS.
+ */
+ pw_db = dbopen(_PATH_MP_DB, O_RDONLY, 0, DB_HASH, NULL);
+ if (!pw_db)
+ error(_PATH_MP_DB);
+ buf[0] = _PW_KEYBYNAME;
+ len = strlen(username);
+
+ /* Only check that username fits in buffer */
+ memmove(buf + 1, username, MIN(len, sizeof(buf) - 1));
+ key.data = (u_char *)buf;
+ key.size = len + 1;
+ if ((pw_db->get)(pw_db, &key, &data, 0) == 0) {
+ p = (char *)data.data;
+
+ /* jump over pw_name and pw_passwd, to get to pw_uid */
+ while (*p++)
+ ;
+ while (*p++)
+ ;
+
+ buf[0] = _PW_KEYBYUID;
+ memmove(buf + 1, p, sizeof(int));
+ key.data = (u_char *)buf;
+ key.size = sizeof(int) + 1;
+
+ if ((pw_db->get)(pw_db, &key, &data, 0) == 0) {
+ /* First field of data.data holds pw_pwname */
+ if (strcmp(data.data, username))
+ methoduid = R_NOOVERWRITE;
+ } else {
+ methoduid = R_NOOVERWRITE;
+ }
+ } else {
+ methoduid = R_NOOVERWRITE;
+ }
+ if ((pw_db->close)(pw_db))
+ error("close pw_db");
+ return methoduid;
+}
+
+int
scan(fp, pw, flags)
FILE *fp;
struct passwd *pw;
@@ -440,6 +534,37 @@
return (1);
}
+void
+cp(from, to, mode)
+ char *from, *to;
+ mode_t mode;
+{
+ static char buf[MAXBSIZE];
+ int from_fd, rcount, to_fd, wcount;
+
+ if ((from_fd = open(from, O_RDONLY, 0)) < 0)
+ error(from);
+ if ((to_fd = open(to, O_WRONLY|O_CREAT|O_EXCL, mode)) < 0)
+ error(to);
+ while ((rcount = read(from_fd, buf, MAXBSIZE)) > 0) {
+ wcount = write(to_fd, buf, rcount);
+ if (rcount != wcount || wcount == -1) {
+ int sverrno = errno;
+
+ (void)snprintf(buf, sizeof(buf), "%s to %s", from, to);
+ errno = sverrno;
+ error(buf);
+ }
+ }
+ if (rcount < 0) {
+ int sverrno = errno;
+
+ (void)snprintf(buf, sizeof(buf), "%s to %s", from, to);
+ errno = sverrno;
+ error(buf);
+ }
+}
+
void
mv(from, to)
char *from, *to;
@@ -510,6 +635,6 @@
usage()
{
- (void)fprintf(stderr, "usage: pwd_mkdb [-p] [-d directory] file\n");
+ (void)fprintf(stderr, "usage: pwd_mkdb [-p] [-d directory] [-p user] file\n");
exit(1);
}
Index: usr.bin/chpass/chpass.c
--- usr.bin/chpass/chpass.c.orig Mon Feb 15 08:38:04 1999
+++ usr.bin/chpass/chpass.c Mon Apr 12 00:03:50 1999
@@ -82,6 +82,7 @@
void baduser __P((void));
int main __P((int, char **));
void usage __P((void));
+int pw_mkdb_user __P((char *));
int
main(argc, argv)
@@ -279,7 +280,7 @@
pw_copy(pfd, tfd, pw, (op == LOADENTRY) ? NULL : &old_pw);
/* Now finish the passwd file update. */
- if (pw_mkdb() < 0)
+ if (pw_mkdb_user(pw->pw_name) < 0)
pw_error(NULL, 0, 1);
exit(0);
@@ -303,3 +304,37 @@
#endif
exit(1);
}
+
+#include <sys/wait.h>
+
+int
+pw_mkdb_user(username)
+ char *username;
+{
+ int pstat;
+ pid_t pid;
+
+ pid = vfork();
+ if (pid == 0) {
+ if (username)
+ execl(_PATH_PWD_MKDB, "pwd_mkdb", "-p",
+ "-u", username,
+ _PATH_MASTERPASSWD_LOCK, NULL);
+ else
+ execl(_PATH_PWD_MKDB, "pwd_mkdb", "-p",
+ _PATH_MASTERPASSWD_LOCK, NULL);
+ _exit(1);
+ }
+ pid = waitpid(pid, &pstat, 0);
+ if (pid == -1 || !WIFEXITED(pstat) || WEXITSTATUS(pstat) != 0)
+ return(-1);
+ return(0);
+}
+
+#if 0
+int
+pw_mkdb()
+{
+ return pw_mkdb_user(NULL);
+}
+#endif
Index: usr.bin/passwd/local_passwd.c
--- usr.bin/passwd/local_passwd.c.orig Thu Jan 14 00:44:43 1999
+++ usr.bin/passwd/local_passwd.c Mon Apr 12 00:03:58 1999
@@ -60,6 +60,8 @@
static char *getnewpasswd __P((struct passwd *));
+int pw_mkdb_user __P((char *username));
+
static uid_t uid;
char *tempname;
@@ -182,7 +184,41 @@
pw_copy(pfd, tfd, pw, &old_pw);
- if (pw_mkdb() < 0)
+ if (pw_mkdb_user(uname) < 0)
pw_error((char *)NULL, 0, 1);
return (0);
}
+
+#include <sys/wait.h>
+
+int
+pw_mkdb_user(username)
+ char *username;
+{
+ int pstat;
+ pid_t pid;
+
+ pid = vfork();
+ if (pid == 0) {
+ if (username)
+ execl(_PATH_PWD_MKDB, "pwd_mkdb", "-p",
+ "-u", username,
+ _PATH_MASTERPASSWD_LOCK, NULL);
+ else
+ execl(_PATH_PWD_MKDB, "pwd_mkdb", "-p",
+ _PATH_MASTERPASSWD_LOCK, NULL);
+ _exit(1);
+ }
+ pid = waitpid(pid, &pstat, 0);
+ if (pid == -1 || !WIFEXITED(pstat) || WEXITSTATUS(pstat) != 0)
+ return(-1);
+ return(0);
+}
+
+#if 0
+int
+pw_mkdb()
+{
+ return pw_mkdb_user(NULL);
+}
+#endif
>Audit-Trail:
>Unformatted: