summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chpass/chpass.c49
-rw-r--r--chpass/pw_copy.c36
-rw-r--r--chpass/pw_copy.h4
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 *));