diff options
-rw-r--r-- | chpass/chpass.c | 49 | ||||
-rw-r--r-- | chpass/pw_copy.c | 36 | ||||
-rw-r--r-- | chpass/pw_copy.h | 4 |
3 files changed, 64 insertions, 25 deletions
diff --git a/chpass/chpass.c b/chpass/chpass.c index f10a9d6..86955f6 100644 --- a/chpass/chpass.c +++ b/chpass/chpass.c @@ -83,7 +83,7 @@ main(argc, argv) char **argv; { enum { NEWSH, LOADENTRY, EDITENTRY, NEWPW, NEWEXP } op; - struct passwd *pw = NULL, lpw; + struct passwd *pw = NULL, lpw, old_pw; char *username = NULL; int ch, pfd, tfd; char *arg = NULL; @@ -160,7 +160,7 @@ main(argc, argv) uid = getuid(); - if (op == EDITENTRY || op == NEWSH || op == NEWPW || op == NEWEXP) + if (op == EDITENTRY || op == NEWSH || op == NEWPW || op == NEWEXP) { switch(argc) { #ifdef YP case 0: @@ -186,6 +186,12 @@ main(argc, argv) default: usage(); } + + /* Make a copy for later verification */ + old_pw = *pw; + old_pw.pw_gecos = strdup(old_pw.pw_gecos); + } + if (op == NEWSH) { /* protect p_shell -- it thinks NULL is /bin/sh */ if (!arg[0]) @@ -222,31 +228,31 @@ main(argc, argv) /* * The temporary file/file descriptor usage is a little tricky here. - * 1: We start off with two fd's, one for the master password - * file (used to lock everything), and one for a temporary file. + * 1: Create a temporary file called tempname, get descriptor tfd. * 2: Display() gets an fp for the temporary file, and copies the * user's information into it. It then gives the temporary file * to the user and closes the fp, closing the underlying fd. * 3: The user edits the temporary file some number of times. - * 4: Verify() gets an fp for the temporary file, and verifies the - * contents. It can't use an fp derived from the step #2 fd, - * because the user's editor may have created a new instance of - * the file. Once the file is verified, its contents are stored - * in a password structure. The verify routine closes the fp, - * closing the underlying fd. - * 5: Delete the temporary file. - * 6: Get a new temporary file/fd. Pw_copy() gets an fp for it - * file and copies the master password file into it, replacing - * the user record with a new one. We can't use the first - * temporary file for this because it was owned by the user. - * Pw_copy() closes its fp, flushing the data and closing the - * underlying file descriptor. We can't close the master - * password fp, or we'd lose the lock. - * 7: Call pw_mkdb() (which renames the temporary file) and exit. + * The results are stored in pw by edit(). + * 4: Delete the temporary file. + * 5: Make a new temporary file, descriptor tfd. + * 6: Get a descriptor for the master.passwd file, pfd, and + * lock master.passwd. + * 7: Pw_copy() gets descriptors for master.passwd and the + * temporary file and copies the master password file into it, + * replacing the modified user's record with a new one. We can't + * use the first temporary file for this because it was owned + * by the user. Pass the new and old user info. Check the + * entry for our user has not been changed by someone else by + * while the user was editing by comparing the old info to + * the entry freshly read from master.passwd. Pw_copy() closes + * its fp, flushing the data and closing the underlying file + * descriptor. We can't close the master password fp, or we'd + * lose the lock. + * 8: Call pw_mkdb() (which renames the temporary file) and exit. * The exit closes the master passwd fp/fd. */ pw_init(); - pfd = pw_lock(); tfd = pw_tmp(); if (op == EDITENTRY) { @@ -262,7 +268,8 @@ main(argc, argv) (void)unlink(tempname); } else { #endif /* YP */ - pw_copy(pfd, tfd, pw); + pfd = pw_lock(); + pw_copy(pfd, tfd, pw, (op == LOADENTRY) ? NULL : &old_pw); if (!pw_mkdb(username)) pw_error((char *)NULL, 0, 1); diff --git a/chpass/pw_copy.c b/chpass/pw_copy.c index d475757..2e86dc3 100644 --- a/chpass/pw_copy.c +++ b/chpass/pw_copy.c @@ -48,15 +48,41 @@ static const char sccsid[] = "@(#)pw_copy.c 8.4 (Berkeley) 4/2/94"; #include <string.h> #include <unistd.h> +#include <pw_scan.h> #include <pw_util.h> + #include "pw_copy.h" extern char *tempname; +/* for use in pw_copy(). Compare a pw entry to a pw struct. */ +static int +pw_equal(char *buf, struct passwd *pw) +{ + struct passwd buf_pw; + int len; + + len = strlen (buf); + if (buf[len-1] == '\n') + buf[len-1] = '\0'; + if (!__pw_scan(buf, &buf_pw, _PWSCAN_MASTER)) + return 0; + return (strcmp(pw->pw_name, buf_pw.pw_name) == 0 + && pw->pw_uid == buf_pw.pw_uid + && pw->pw_gid == buf_pw.pw_gid + && strcmp(pw->pw_class, buf_pw.pw_class) == 0 + && (long)pw->pw_change == (long)buf_pw.pw_change + && (long)pw->pw_expire == (long)buf_pw.pw_expire + && strcmp(pw->pw_gecos, buf_pw.pw_gecos) == 0 + && strcmp(pw->pw_dir, buf_pw.pw_dir) == 0 + && strcmp(pw->pw_shell, buf_pw.pw_shell) == 0); +} + + void -pw_copy(ffd, tfd, pw) +pw_copy(ffd, tfd, pw, old_pw) int ffd, tfd; - struct passwd *pw; + struct passwd *pw, *old_pw; { FILE *from, *to; int done; @@ -108,6 +134,12 @@ pw_copy(ffd, tfd, pw) goto err; continue; } + *p = ':'; + if (old_pw && !pw_equal(buf, old_pw)) { + warnx("%s: entry for %s has changed", + _PATH_MASTERPASSWD, pw->pw_name); + pw_error(NULL, 0, 1); + } (void)fprintf(to, "%s:%s:%s:%s:%s:%s:%s:%s:%s:%s\n", pw->pw_name, pw->pw_passwd, pw->pw_fields & _PWF_UID ? uidstr : "", diff --git a/chpass/pw_copy.h b/chpass/pw_copy.h index 4ef68c5..20f3bcc 100644 --- a/chpass/pw_copy.h +++ b/chpass/pw_copy.h @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)pw_copy.h 8.1 (Berkeley) 4/2/94 + * $FreeBSD$ */ -void pw_copy __P((int, int, struct passwd *)); +void pw_copy __P((int, int, struct passwd *, struct passwd *)); |