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.
This commit is contained in:
ian 2018-07-26 18:34:38 +00:00
parent 669a205547
commit c125d4a078
7 changed files with 49 additions and 26 deletions

View File

@ -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;

View File

@ -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,

View File

@ -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)
{

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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);