From c125d4a078b7a032c543d05536e21ae7b33c4c75 Mon Sep 17 00:00:00 2001 From: ian Date: Thu, 26 Jul 2018 18:34:38 +0000 Subject: [PATCH] Make pw_scan(3) more compatible with getpwent(3) et. al. when processing data from /etc/passwd rather than /etc/master.passwd. The libc getpwent(3) and related functions automatically read master.passwd when run by root, or passwd when run by a non-root user. When run by non- root, getpwent() copes with the missing data by setting the corresponding fields in the passwd struct to known values (zeroes for numbers, or a pointer to an empty string for literals). When libutil's pw_scan(3) was used to parse a line without the root-accessible data, it was leaving garbage in the corresponding fields. These changes rename the static pw_init() function used by getpwent() and friends to __pw_initpwd(), and move it into pw_scan.c so that common init code can be shared between libc and libutil. pw_scan(3) now calls __pw_initpwd() before __pw_scan(), just like the getpwent() family does, so that reading an arbitrary passwd file in either format and parsing it with pw_scan(3) returns the same results as getpwent(3) would. This also adds a new pw_initpwd(3) function to libutil, so that code which creates passwd structs from scratch in some manner that doesn't involve pw_scan() can initialize the struct to the values expected by lots of existing code, which doesn't expect to encounter NULL pointers or garbage values in some fields. --- lib/libc/gen/Symbol.map | 1 + lib/libc/gen/getpwent.c | 27 ++++----------------------- lib/libc/gen/pw_scan.c | 16 ++++++++++++++++ lib/libc/gen/pw_scan.h | 1 + lib/libutil/libutil.h | 1 + lib/libutil/pw_util.3 | 18 ++++++++++++++++-- lib/libutil/pw_util.c | 11 ++++++++++- 7 files changed, 49 insertions(+), 26 deletions(-) diff --git a/lib/libc/gen/Symbol.map b/lib/libc/gen/Symbol.map index ea2419488b6a..40cdc9312c4d 100644 --- a/lib/libc/gen/Symbol.map +++ b/lib/libc/gen/Symbol.map @@ -510,6 +510,7 @@ FBSDprivate_1.0 { __opendir2; __pause; _pause; + __pw_initpwd; /* Used by (at least) libutil */ __pw_scan; /* Used by (at least) libutil */ __raise; _raise; diff --git a/lib/libc/gen/getpwent.c b/lib/libc/gen/getpwent.c index 0797ece86a93..5c944801d767 100644 --- a/lib/libc/gen/getpwent.c +++ b/lib/libc/gen/getpwent.c @@ -96,8 +96,6 @@ int __pw_match_entry(const char *, size_t, enum nss_lookup_type, const char *, uid_t); int __pw_parse_entry(char *, size_t, struct passwd *, int, int *errnop); -static void pwd_init(struct passwd *); - union key { const char *name; uid_t uid; @@ -527,7 +525,7 @@ getpwent_r(struct passwd *pwd, char *buffer, size_t bufsize, }; int rv, ret_errno; - pwd_init(pwd); + __pw_initpwd(pwd); ret_errno = 0; *result = NULL; rv = _nsdispatch(result, dtab, NSDB_PASSWD, "getpwent_r", defaultsrc, @@ -566,7 +564,7 @@ getpwnam_r(const char *name, struct passwd *pwd, char *buffer, size_t bufsize, }; int rv, ret_errno; - pwd_init(pwd); + __pw_initpwd(pwd); ret_errno = 0; *result = NULL; rv = _nsdispatch(result, dtab, NSDB_PASSWD, "getpwnam_r", defaultsrc, @@ -605,7 +603,7 @@ getpwuid_r(uid_t uid, struct passwd *pwd, char *buffer, size_t bufsize, }; int rv, ret_errno; - pwd_init(pwd); + __pw_initpwd(pwd); ret_errno = 0; *result = NULL; rv = _nsdispatch(result, dtab, NSDB_PASSWD, "getpwuid_r", defaultsrc, @@ -617,23 +615,6 @@ getpwuid_r(uid_t uid, struct passwd *pwd, char *buffer, size_t bufsize, } -static void -pwd_init(struct passwd *pwd) -{ - static char nul[] = ""; - - memset(pwd, 0, sizeof(*pwd)); - pwd->pw_uid = (uid_t)-1; /* Considered least likely to lead to */ - pwd->pw_gid = (gid_t)-1; /* a security issue. */ - pwd->pw_name = nul; - pwd->pw_passwd = nul; - pwd->pw_class = nul; - pwd->pw_gecos = nul; - pwd->pw_dir = nul; - pwd->pw_shell = nul; -} - - static struct passwd pwd; static char *pwd_storage; static size_t pwd_storage_size; @@ -1614,7 +1595,7 @@ compat_redispatch(struct compat_state *st, enum nss_lookup_type how, for (i = 0; i < (int)(nitems(dtab) - 1); i++) dtab[i].mdata = (void *)lookup_how; more: - pwd_init(pwd); + __pw_initpwd(pwd); switch (lookup_how) { case nss_lt_all: rv = _nsdispatch(&discard, dtab, NSDB_PASSWD_COMPAT, diff --git a/lib/libc/gen/pw_scan.c b/lib/libc/gen/pw_scan.c index a7dbdf2cb5b9..619092d3d4bc 100644 --- a/lib/libc/gen/pw_scan.c +++ b/lib/libc/gen/pw_scan.c @@ -65,6 +65,22 @@ __FBSDID("$FreeBSD$"); */ static int pw_big_ids_warning = 0; +void +__pw_initpwd(struct passwd *pwd) +{ + static char nul[] = ""; + + memset(pwd, 0, sizeof(*pwd)); + pwd->pw_uid = (uid_t)-1; /* Considered least likely to lead to */ + pwd->pw_gid = (gid_t)-1; /* a security issue. */ + pwd->pw_name = nul; + pwd->pw_passwd = nul; + pwd->pw_class = nul; + pwd->pw_gecos = nul; + pwd->pw_dir = nul; + pwd->pw_shell = nul; +} + int __pw_scan(char *bp, struct passwd *pw, int flags) { diff --git a/lib/libc/gen/pw_scan.h b/lib/libc/gen/pw_scan.h index 44ff8185bc9e..b56703677ac0 100644 --- a/lib/libc/gen/pw_scan.h +++ b/lib/libc/gen/pw_scan.h @@ -35,4 +35,5 @@ #define _PWSCAN_MASTER 0x01 #define _PWSCAN_WARN 0x02 +extern void __pw_initpwd(struct passwd *); extern int __pw_scan(char *, struct passwd *, int); diff --git a/lib/libutil/libutil.h b/lib/libutil/libutil.h index c79eaac5a5fa..2ac5e975a2d7 100644 --- a/lib/libutil/libutil.h +++ b/lib/libutil/libutil.h @@ -155,6 +155,7 @@ int pw_edit(int _notsetuid); int pw_equal(const struct passwd *_pw1, const struct passwd *_pw2); void pw_fini(void); int pw_init(const char *_dir, const char *_master); +void pw_initpwd(struct passwd *_pw); char *pw_make(const struct passwd *_pw); char *pw_make_v7(const struct passwd *_pw); int pw_mkdb(const char *_user); diff --git a/lib/libutil/pw_util.3 b/lib/libutil/pw_util.3 index 901135e02b94..ad5dcaaeccc3 100644 --- a/lib/libutil/pw_util.3 +++ b/lib/libutil/pw_util.3 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd July 02, 2015 +.Dd July 26, 2018 .Dt PW_UTIL 3 .Os .Sh NAME @@ -59,6 +59,8 @@ .Fn pw_fini "void" .Ft int .Fn pw_init "const char *dir" const char *master" +.Ft void +.Fn pw_initpwd "struct passwd *pw" .Ft "char *" .Fn pw_make "const struct passwd *pw" .Ft "char *" @@ -179,7 +181,7 @@ if any. .Pp The .Fn pw_init -initialize the static variable representing the path a password file. +initializes the static variable representing the path to a password file. .Fa dir is the directory where the password file is located. If set to @@ -194,6 +196,18 @@ it will default to .Pa master.passwd .Pp The +.Fn pw_initpwd +function initializes the +.Vt passwd +struct to canonical values. +The entire structure is zeroed, then +.Va pw_uid +and +.Va pw_gid +are set to -1, and all string pointers are set to point at +an internally-defined zero-length string. +.Pp +The .Fn pw_make function creates a properly formatted .Bx diff --git a/lib/libutil/pw_util.c b/lib/libutil/pw_util.c index 112b6d8af45a..1659c97a7fcd 100644 --- a/lib/libutil/pw_util.c +++ b/lib/libutil/pw_util.c @@ -652,8 +652,16 @@ pw_dup(const struct passwd *pw) #include "pw_scan.h" /* - * Wrapper around an internal libc function + * Wrapper around some internal libc functions. */ + +void +pw_initpwd(struct passwd *pw) +{ + + __pw_initpwd(pw); +} + struct passwd * pw_scan(const char *line, int flags) { @@ -662,6 +670,7 @@ pw_scan(const char *line, int flags) if ((bp = strdup(line)) == NULL) return (NULL); + __pw_initpwd(&pw); if (!__pw_scan(bp, &pw, flags)) { free(bp); return (NULL);