summaryrefslogtreecommitdiff
path: root/lib/libutil/passwd.c
diff options
context:
space:
mode:
authorTodd C. Miller <millert@cvs.openbsd.org>2004-04-20 23:20:08 +0000
committerTodd C. Miller <millert@cvs.openbsd.org>2004-04-20 23:20:08 +0000
commita4ccbe5bc7e8df106f798254306616fb80e6922f (patch)
tree36e883584f5995d21c4c37300e1a7dbfc63b492b /lib/libutil/passwd.c
parent5d3813f3f73ea1f5cd7b4684048b1db3b5cb6adc (diff)
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.
Diffstat (limited to 'lib/libutil/passwd.c')
-rw-r--r--lib/libutil/passwd.c37
1 files changed, 31 insertions, 6 deletions
diff --git a/lib/libutil/passwd.c b/lib/libutil/passwd.c
index 33b900db5c0..69d6cdc1dcd 100644
--- a/lib/libutil/passwd.c
+++ b/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 <sys/types.h>
@@ -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,