Subject: lib/18150: "passwd: /etc/master.passwd: entry inconsistent" not helpful
To: None <gnats-bugs@gnats.netbsd.org>
From: John F. Woods <jfw@jfwhome.funhouse.com>
List: netbsd-bugs
Date: 09/02/2002 12:27:12
>Number: 18150
>Category: lib
>Synopsis: "passwd: /etc/master.passwd: entry inconsistent" not helpful
>Confidential: no
>Severity: non-critical
>Priority: medium
>Responsible: lib-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Mon Sep 02 09:28:00 PDT 2002
>Closed-Date:
>Last-Modified:
>Originator: John F. Woods
>Release: NetBSD 1.6F
>Organization:
Misanthropes-R-Us
>Environment:
System: NetBSD jfwhome.funhouse.com 1.6F NetBSD 1.6F (JFW) #6: Sun Aug 18 12:28:13 EDT 2002 jfw@jfwhome.funhouse.com:/usr/src/sys/arch/i386/compile/JFW i386
Architecture: i386
Machine: i386
>Description:
Attempting to change a user's passwd, I was rewarded with the unhelpful
error messages
passwd: /etc/master.passwd: entry inconsistent
passwd: /etc/master.passwd: unchanged
This does not tell which entry is inconsistent, nor does it tell what is
consistent. After inserting some debug code (cleaned up and offered as a
fix below), I discovered that I had apparently sometime changed the group ID
of the entry I wanted to change without having updated the pwd database.
It would be much better if passwd could issue an error message indicating
which entry and what field was inconsistent, and I offer the code to do so
below.
>How-To-Repeat:
1. Edit master.passwd manually to change a gid for some user.
2. Run "passwd" to change that user's passwd.
3. Pretend you did step 1 so long ago that you do not remember it, and
figure out what is wrong.
>Fix:
The following results in a somewhat more useful error message.
*** passwd.c.orig Mon Sep 2 09:55:50 2002
--- passwd.c Mon Sep 2 12:10:17 2002
***************
*** 62,68 ****
static const char *pw_filename(const char *filename);
static void pw_cont(int sig);
! static int pw_equal(char *buf, struct passwd *old_pw);
static const char *pw_default(const char *option);
static int read_line(FILE *fp, char *line, int max);
static void trim_whitespace(char *line);
--- 62,68 ----
static const char *pw_filename(const char *filename);
static void pw_cont(int sig);
! static const char * pw_equal(char *buf, struct passwd *old_pw);
static const char *pw_default(const char *option);
static int read_line(FILE *fp, char *line, int max);
static void trim_whitespace(char *line);
***************
*** 296,302 ****
}
/* 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;
--- 296,303 ----
}
/* for use in pw_copy(). Compare a pw entry to a pw struct. */
! /* returns a character string labelling the miscompared field or 0 */
! static const char *
pw_equal(char *buf, struct passwd *pw)
{
struct passwd buf_pw;
***************
*** 309,324 ****
if (buf[len-1] == '\n')
buf[len-1] = '\0';
if (!pw_scan(buf, &buf_pw, NULL))
! return 0;
! return !strcmp(pw->pw_name, buf_pw.pw_name)
! && pw->pw_uid == buf_pw.pw_uid
! && pw->pw_gid == buf_pw.pw_gid
! && !strcmp(pw->pw_class, buf_pw.pw_class)
! && (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)
! && !strcmp(pw->pw_dir, buf_pw.pw_dir)
! && !strcmp(pw->pw_shell, buf_pw.pw_shell);
}
void
--- 310,335 ----
if (buf[len-1] == '\n')
buf[len-1] = '\0';
if (!pw_scan(buf, &buf_pw, NULL))
! return "corrupt line";
! if (strcmp(pw->pw_name, buf_pw.pw_name) != 0)
! return "name";
! if (pw->pw_uid != buf_pw.pw_uid)
! return "uid";
! if (pw->pw_gid != buf_pw.pw_gid)
! return "gid";
! if (strcmp( pw->pw_class, buf_pw.pw_class) != 0)
! return "class";
! if (pw->pw_change != buf_pw.pw_change)
! return "change";
! if (pw->pw_expire != buf_pw.pw_expire)
! return "expire";
! if (strcmp( pw->pw_gecos, buf_pw.pw_gecos) != 0)
! return "gecos";
! if (strcmp( pw->pw_dir, buf_pw.pw_dir) != 0)
! return "dir";
! if (strcmp( pw->pw_shell, buf_pw.pw_shell) != 0)
! return "shell";
! return (char *)0;
}
void
***************
*** 345,350 ****
--- 356,362 ----
pw_error(mpwdl, 1, 1);
for (done = 0; fgets(buf, sizeof(buf), from);) {
+ const char *neq;
if (!strchr(buf, '\n')) {
warnx("%s: line too long", mpwd);
pw_error(NULL, 0, 1);
***************
*** 368,375 ****
continue;
}
*p = ':';
! if (old_pw && !pw_equal(buf, old_pw)) {
! warnx("%s: entry inconsistent", mpwd);
pw_error(NULL, 0, 1);
}
(void)fprintf(to, "%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s\n",
--- 380,392 ----
continue;
}
*p = ':';
! if (old_pw && (neq = pw_equal(buf, old_pw))) {
! if (strcmp(neq,"corrupt line")==0)
! warnx("%s: entry %s corrupted", mpwd,
! pw->pw_name);
! else
! warnx("%s: entry %s inconsistent %s",
! mpwd, pw->pw_name, neq);
pw_error(NULL, 0, 1);
}
(void)fprintf(to, "%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s\n",
>Release-Note:
>Audit-Trail:
>Unformatted: