Subject: Re: pwd_mkdb
To: Takahiro Kambe <taca@sky.yamashina.kyoto.jp>
From: Perry E. Metzger <perry@piermont.com>
List: current-users
Date: 04/12/1999 11:45:53
you should send-pr this patch so it is not lost!

Takahiro Kambe <taca@sky.yamashina.kyoto.jp> writes:

> [1  <text/plain; us-ascii (7bit)>]
> Good evening.
> 
> In message <19990408182918.A8407@pyy.jmp.fi>
> 	on Thu, 8 Apr 1999 18:29:19 +0300,
> 	Jukka Marin <jmarin@pyy.jmp.fi> wrote:
> > > > > I think "-u" option is valuable to implement.
> > > > 
> > > > Is there any hope of seeing the -u option in the near future?
> > > O.K., I'll try to implement it this weekend.  :-)
> I've called from my boss, and must go to the office today.  :-(
> So I don't have much time, I made "-u" option for pwd_mkdb(8), mainly
> borrow codes from FreeBSD version.
> 
> > Great!  I looked into pwd_mkdb.c and the db(3) man page, but I'd rather
> > leave it to someone who knows what he/she is doing... ;-)
> > 
> > Please let me know when a patch is available and I'll try it out right
> > away (a patch for NetBSD 1.3.3 would be the best for me).
> Though I attach the patch, this isn't test verfy much.  Please don't use 
> this on production systems.
> 
> Some note:
> 
> In this patch, pw_mkdb_user() is added into passwd and chpass.  This
> functionality should be in libutil(3), lib/libutil/passwd.c.  It might
> be simple that adding an argument to pw_mkdb(), but it breaks binary
> ompatibitity.  So, I add newly pw_mkdb_user().
> 
> Thanks in adivese.
> 
> P.S.
> I want to change the subject when talking about 1.5 release.  :-)
> 
> --
> Takahiro Kambe <taca@sky.yamashina.kyoto.jp>
> 
> [2 diff <text/plain; us-ascii (7bit)>]
> 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