diff --git a/lib/libutil/passwd.c b/lib/libutil/passwd.c index 867e77ddc708..c439dd5daef1 100644 --- a/lib/libutil/passwd.c +++ b/lib/libutil/passwd.c @@ -1,4 +1,4 @@ -/* $NetBSD: passwd.c,v 1.45 2006/12/20 16:47:13 christos Exp $ */ +/* $NetBSD: passwd.c,v 1.46 2008/12/21 17:54:43 christos Exp $ */ /* * Copyright (c) 1987, 1993, 1994, 1995 @@ -31,7 +31,7 @@ #include #if defined(LIBC_SCCS) && !defined(lint) -__RCSID("$NetBSD: passwd.c,v 1.45 2006/12/20 16:47:13 christos Exp $"); +__RCSID("$NetBSD: passwd.c,v 1.46 2008/12/21 17:54:43 christos Exp $"); #endif /* LIBC_SCCS and not lint */ #include @@ -59,7 +59,7 @@ __RCSID("$NetBSD: passwd.c,v 1.45 2006/12/20 16:47:13 christos Exp $"); 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_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); @@ -290,7 +290,8 @@ pw_prompt(void) } /* for use in pw_copy(). Compare a pw entry to a pw struct. */ -static int +/* returns a character string labelling the miscompared field or 0 */ +static const char * pw_equal(char *buf, struct passwd *pw) { struct passwd buf_pw; @@ -303,16 +304,26 @@ pw_equal(char *buf, struct passwd *pw) 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); + 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 @@ -365,6 +376,7 @@ pw_copyx(int ffd, int tfd, struct passwd *pw, struct passwd *old_pw, } for (done = 0; fgets(buf, (int)sizeof(buf), from);) { + const char *neq; if (!strchr(buf, '\n')) { snprintf(errbuf, errbufsz, "%s: line too long", mpwd); (void)fclose(from); @@ -402,9 +414,15 @@ pw_copyx(int ffd, int tfd, struct passwd *pw, struct passwd *old_pw, continue; } *p = ':'; - if (old_pw && !pw_equal(buf, old_pw)) { - snprintf(errbuf, errbufsz, "%s: entry inconsistent", - mpwd); + if (old_pw && (neq = pw_equal(buf, old_pw)) != NULL) { + if (strcmp(neq, "corrupt line") == 0) + (void)snprintf(errbuf, errbufsz, + "%s: entry %s corrupted", mpwd, + pw->pw_name); + else + (void)snprintf(errbuf, errbufsz, + "%s: entry %s inconsistent %s", + mpwd, pw->pw_name, neq); (void)fclose(from); (void)fclose(to); return (0);