From d0d2e5a2ff8fc83a49115cb11e84212a801c9476 Mon Sep 17 00:00:00 2001 From: millert <> Date: Tue, 20 Apr 2004 23:20:07 +0000 Subject: [PATCH] Change pw_copy(3) to take a 3rd arguement, the existing passwd entry. This allows an application to only update a password entry if it is in the state it expects. Additionally, if the old passwd struct is specified the new one may have a different pw_name field since matching is done on the original. Adapted from FreeBSD. --- src/lib/libutil/passwd.c | 37 +++++++++++++++++++++++++++++------ src/lib/libutil/pw_init.3 | 19 ++++++++++++++---- src/lib/libutil/shlib_version | 2 +- src/lib/libutil/util.h | 4 ++-- 4 files changed, 49 insertions(+), 13 deletions(-) diff --git a/src/lib/libutil/passwd.c b/src/lib/libutil/passwd.c index 33b900db..69d6cdc1 100644 --- a/src/lib/libutil/passwd.c +++ b/src/lib/libutil/passwd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: passwd.c,v 1.42 2003/06/26 16:34:42 deraadt Exp $ */ +/* $OpenBSD: passwd.c,v 1.43 2004/04/20 23:20:07 millert Exp $ */ /* * Copyright (c) 1987, 1993, 1994, 1995 @@ -30,7 +30,7 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static const char rcsid[] = "$OpenBSD: passwd.c,v 1.42 2003/06/26 16:34:42 deraadt Exp $"; +static const char rcsid[] = "$OpenBSD: passwd.c,v 1.43 2004/04/20 23:20:07 millert Exp $"; #endif /* LIBC_SCCS and not lint */ #include @@ -422,12 +422,27 @@ pw_prompt(void) pw_error(NULL, 0, 0); } +static int +pw_equal(const struct passwd *pw1, const struct passwd *pw2) +{ + return (strcmp(pw1->pw_name, pw2->pw_name) == 0 && + pw1->pw_uid == pw2->pw_uid && + pw1->pw_gid == pw2->pw_gid && + strcmp(pw1->pw_class, pw2->pw_class) == 0 && + pw1->pw_change == pw2->pw_change && + pw1->pw_expire == pw2->pw_expire && + strcmp(pw1->pw_gecos, pw2->pw_gecos) == 0 && + strcmp(pw1->pw_dir, pw2->pw_dir) == 0 && + strcmp(pw1->pw_shell, pw2->pw_shell) == 0); +} + void -pw_copy(int ffd, int tfd, struct passwd *pw) +pw_copy(int ffd, int tfd, const struct passwd *pw, const struct passwd *opw) { + struct passwd tpw; FILE *from, *to; int done; - char *p, buf[8192]; + char *p, *ep, buf[8192]; char *master = pw_file(_PATH_MASTERPASSWD); if (!master) @@ -438,7 +453,7 @@ pw_copy(int ffd, int tfd, struct passwd *pw) pw_error(pw_lck ? pw_lck : NULL, pw_lck ? 1 : 0, 1); for (done = 0; fgets(buf, sizeof(buf), from);) { - if (!strchr(buf, '\n')) { + if ((ep = strchr(buf, '\n')) == NULL) { warnx("%s: line too long", master); pw_error(NULL, 0, 1); } @@ -453,13 +468,23 @@ pw_copy(int ffd, int tfd, struct passwd *pw) pw_error(NULL, 0, 1); } *p = '\0'; - if (strcmp(buf, pw->pw_name)) { + if (strcmp(buf, opw ? opw->pw_name : pw->pw_name)) { *p = ':'; (void)fprintf(to, "%s", buf); if (ferror(to)) goto err; continue; } + if (opw != NULL) { + *p = ':'; + *ep = '\0'; + if (!pw_scan(buf, &tpw, NULL)) + pw_error(NULL, 0, 1); + if (!pw_equal(&tpw, opw)) { + warnx("%s: inconsistent entry", master); + pw_error(NULL, 0, 1); + } + } (void)fprintf(to, "%s:%s:%u:%u:%s:%d:%d:%s:%s:%s\n", pw->pw_name, pw->pw_passwd, (u_int)pw->pw_uid, (u_int)pw->pw_gid, pw->pw_class, pw->pw_change, diff --git a/src/lib/libutil/pw_init.3 b/src/lib/libutil/pw_init.3 index 2cff0f3a..49daeb04 100644 --- a/src/lib/libutil/pw_init.3 +++ b/src/lib/libutil/pw_init.3 @@ -1,4 +1,4 @@ -.\" $OpenBSD: pw_init.3,v 1.7 2003/06/02 20:18:42 millert Exp $ +.\" $OpenBSD: pw_init.3,v 1.8 2004/04/20 23:20:07 millert Exp $ .\" .\" Copyright (c) 1995 .\" The Regents of the University of California. All rights reserved. @@ -58,7 +58,7 @@ .Ft void .Fn pw_prompt .Ft void -.Fn pw_copy "int ffd" "int tfd" "struct passwd *pw" +.Fn pw_copy "int ffd" "int tfd" "const struct passwd *pw" "const struct passwd *opw" .Ft int .Fn pw_scan "char *bp" "struct passwd *pw" "int *flags" .Ft void @@ -125,9 +125,20 @@ function reads a passwd file from .Fa ffd and writes it to .Fa tfd , -updating the entry corresponding to pw->pw_name with the information -in +updating the entry corresponding to pw-\*(Gtpw_name +with the information in .Fa pw . +If +.Fa opw +is not NULL, opw-\*(Gtpw_name will be used for matching instead. +Additionally, if the existing entry does not match +.Fa opw , +the operation is aborted. +The use of +.Fa opw +allows the caller to change the user name in an entry as well as +guarantee that the entry being replaced has not changed in the +meantime. .Pp The .Fn pw_scan diff --git a/src/lib/libutil/shlib_version b/src/lib/libutil/shlib_version index 1c5d96eb..c10074d5 100644 --- a/src/lib/libutil/shlib_version +++ b/src/lib/libutil/shlib_version @@ -1,2 +1,2 @@ -major=9 +major=10 minor=0 diff --git a/src/lib/libutil/util.h b/src/lib/libutil/util.h index 6f8b9b40..d3fc11fc 100644 --- a/src/lib/libutil/util.h +++ b/src/lib/libutil/util.h @@ -1,4 +1,4 @@ -/* $OpenBSD: util.h,v 1.24 2003/06/02 20:18:42 millert Exp $ */ +/* $OpenBSD: util.h,v 1.25 2004/04/20 23:20:07 millert Exp $ */ /* $NetBSD: util.h,v 1.2 1996/05/16 07:00:22 thorpej Exp $ */ /*- @@ -97,7 +97,7 @@ int pw_abort(void); void pw_init(void); void pw_edit(int, const char *); void pw_prompt(void); -void pw_copy(int, int, struct passwd *); +void pw_copy(int, int, const struct passwd *, const struct passwd *); void pw_getconf(char *, size_t, const char *, const char *); int pw_scan(char *, struct passwd *, int *); void pw_error(const char *, int, int);