= Implement thread-safe versions of the getpwent(3) and getgrent(3)

family of functions using the new nsdispatch(3) core.  Remove
  arbitrary size limits when using the thread-safe versions.

= Re-implement the traditional getpwent(3)/getgrent(3) functions on
  top of the thread-safe versions.

= Update the on-disk format of the hashed version of the passwd(5)
  databases to allow for versioned entries.  The legacy version is
  `3'.  (Don't ask.)

= Add support for version `4' entries in the passwd(5) database.
  Entries in this format are identical to version 3 entries except
  that all integers are stored as 32-bit integers in network byte
  order (big endian).

= pwd_mkdb is updated to generate both version 3 and version 4
  entries.

Sponsored by:	DARPA, Network Associates Laboratories
This commit is contained in:
Jacques Vidrine 2003-04-17 14:15:26 +00:00
parent 46d9306383
commit 05f98035ee
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=113596
7 changed files with 2949 additions and 1751 deletions

View File

@ -52,6 +52,11 @@ typedef __gid_t gid_t;
#define _GID_T_DECLARED
#endif
#ifndef _SIZE_T_DECLARED
typedef __size_t size_t;
#define _SIZE_T_DECLARED
#endif
struct group {
char *gr_name; /* group name */
char *gr_passwd; /* group password */
@ -70,15 +75,17 @@ struct group *getgrnam(const char *);
const char *group_from_gid(gid_t, int);
#endif
#if __BSD_VISIBLE || __POSIX_VISIBLE >= 200112 || __XSI_VISIBLE
/* XXX IEEE Std 1003.1, 2003 specifies `void setgrent(void)' */
int setgrent(void);
int getgrgid_r(gid_t, struct group *, char *, size_t,
struct group **);
int getgrnam_r(const char *, struct group *, char *, size_t,
struct group **);
#endif
#if __BSD_VISIBLE
void setgrfile(const char *);
int getgrent_r(struct group *, char *, size_t, struct group **);
int setgroupent(int);
#endif
/*
* XXX missing getgrgid_r(), getgrnam_r().
*/
__END_DECLS
#endif /* !_GRP_H_ */

View File

@ -60,6 +60,11 @@ typedef __uid_t uid_t;
#define _UID_T_DECLARED
#endif
#ifndef _SIZE_T_DECLARED
typedef __size_t size_t;
#define _SIZE_T_DECLARED
#endif
#define _PATH_PWD "/etc"
#define _PATH_PASSWD "/etc/passwd"
#define _PASSWD "passwd"
@ -73,11 +78,17 @@ typedef __uid_t uid_t;
#define _PATH_PWD_MKDB "/usr/sbin/pwd_mkdb"
#define _PW_KEYBYNAME '1' /* stored by name */
#define _PW_KEYBYNUM '2' /* stored by entry in the "file" */
#define _PW_KEYBYUID '3' /* stored by uid */
#define _PW_KEYYPENABLED '4' /* YP is enabled */
#define _PW_KEYYPBYNUM '5' /* special +@netgroup entries */
#define _PWD_VERSION_KEY "\xFF" "VERSION"
#define _PWD_CURRENT_VERSION '\x04'
#define _PW_VERSION_MASK '0xF0'
#define _PW_VERSION(x) ((unsigned char)((x)<<4))
#define _PW_KEYBYNAME '\x01' /* stored by name */
#define _PW_KEYBYNUM '\x02' /* stored by entry in the "file" */
#define _PW_KEYBYUID '\x03' /* stored by uid */
#define _PW_KEYYPENABLED '\x04' /* YP is enabled */
#define _PW_KEYYPBYNUM '\x05' /* special +@netgroup entries */
#define _PASSWORD_EFMT1 '_' /* extended encryption format */
@ -110,6 +121,9 @@ struct passwd {
#define _PWF_SHELL _PWF(8)
#define _PWF_EXPIRE _PWF(9)
/* XXX These flags are bogus. With nsswitch, there are many
* possible sources and they cannot be represented in a small integer.
*/
#define _PWF_SOURCE 0x3000
#define _PWF_FILES 0x1000
#define _PWF_NIS 0x2000
@ -123,12 +137,14 @@ struct passwd *getpwuid(uid_t);
void endpwent(void);
struct passwd *getpwent(void);
void setpwent(void);
/*
* XXX missing getpwnam_r() and getpwuid_r().
*/
int getpwnam_r(const char *, struct passwd *, char *, size_t,
struct passwd **);
int getpwuid_r(uid_t, struct passwd *, char *, size_t,
struct passwd **);
#endif
#if __BSD_VISIBLE
int getpwent_r(struct passwd *, char *, size_t, struct passwd **);
int setpassent(int);
const char *user_from_uid(uid_t, int);
#endif

View File

@ -32,15 +32,17 @@
.\" From: @(#)getgrent.3 8.2 (Berkeley) 4/19/94
.\" $FreeBSD$
.\"
.Dd September 29, 1994
.Dd April 16, 2003
.Dt GETGRENT 3
.Os
.Sh NAME
.Nm getgrent ,
.Nm getgrent_r ,
.Nm getgrnam ,
.Nm getgrnam_r ,
.Nm getgrgid ,
.Nm getgrgid_r ,
.Nm setgroupent ,
.\" .Nm setgrfile ,
.Nm setgrent ,
.Nm endgrent
.Nd group database operations
@ -50,14 +52,18 @@
.In grp.h
.Ft struct group *
.Fn getgrent void
.Ft int
.Fn getgrent_r "struct group *grp" "char *buffer" "size_t bufsize" "struct group **result"
.Ft struct group *
.Fn getgrnam "const char *name"
.Ft int
.Fn getgrnam_r "const char *name" "struct group *grp" "char *buffer" "size_t bufsize" "struct group **result"
.Ft struct group *
.Fn getgrgid "gid_t gid"
.Ft int
.Fn getgrgid_r "gid_t gid" "struct group *grp" "char *buffer" "size_t bufsize" "struct group **result"
.Ft int
.Fn setgroupent "int stayopen"
.\" .Ft void
.\" .Fn setgrfile "const char *name"
.Ft int
.Fn setgrent void
.Ft void
@ -99,7 +105,36 @@ function
sequentially reads the group database and is intended for programs
that wish to step through the complete list of groups.
.Pp
All three routines will open the group file for reading, if necessary.
The functions
.Fn getgrent_r ,
.Fn getgrnam_r ,
and
.Fn getgrgid_r
are thread-safe versions of
.Fn getgrent ,
.Fn getgrnam ,
and
.Fn getgrgid ,
respectively.
The caller must provide storage for the results of the search in
the
.Fa grp ,
.Fa buffer ,
.Fa bufsize ,
and
.Fa result
arguments.
When these functions are successful, the
.Fa grp
argument will be filled-in, and a pointer to that argument will be
stored in
.Fa result .
If an entry is not found or an error occurs,
.Fa result
will be set to
.Dv NULL .
.Pp
These functions will open the group file for reading, if necessary.
.Pp
The
.Fn setgroupent
@ -130,8 +165,25 @@ The functions
.Fn getgrnam ,
and
.Fn getgrgid ,
return a pointer to the group entry if successful; if end-of-file
is reached or an error occurs a null pointer is returned.
return a pointer to a group structure on success or
.Dv NULL
if the entry is not found or if an error occurs.
In the latter case,
.Va errno
will be set.
The functions
.Fn getgrent_r ,
.Fn getgrnam_r ,
and
.Fn getgrgid_r
return 0 if no error occurred, or an error number to indicate failure.
It is not an error if a matching entry is not found.
(Thus, if
.Fa result
is set to
.Dv NULL
and the return value is 0, no matching entry exists.)
.Pp
The functions
.Fn setgroupent
and
@ -169,6 +221,30 @@ and
.Fn setgroupent
appeared in
.Bx 4.3 Reno .
The functions
.Fn getgrent_r ,
.Fn getgrnam_r ,
and
.Fn getgrgid_r
appeared in
.Fx 5.1 .
.Sh STANDARDS
The
.Fn getgrent ,
.Fn getgrnam ,
.Fn getgrnam_r ,
.Fn getgrgid ,
.Fn getgrgid_r
and
.Fn endgrent
functions conform to
.St -p1003.1-96 .
The
.Fn setgrent
function differs from that standard in that its return type is
.Vt int
rather than
.Vt void .
.Sh COMPATIBILITY
The historic function
.Fn setgrfile ,
@ -190,6 +266,7 @@ will modify the same object.
.Pp
The functions
.Fn getgrent ,
.Fn getgrent_r ,
.Fn endgrent ,
.Fn setgroupent ,
and
@ -198,7 +275,9 @@ are fairly useless in a networked environment and should be
avoided, if possible.
The
.Fn getgrent
function
makes no attempt to suppress duplicate information if multiple
and
.Fn getgrent_r
functions
make no attempt to suppress duplicate information if multiple
sources are specified in
.Xr nsswitch.conf 5 .

File diff suppressed because it is too large Load Diff

View File

@ -32,13 +32,16 @@
.\" From: @(#)getpwent.3 8.2 (Berkeley) 12/11/93
.\" $FreeBSD$
.\"
.Dd September 20, 1994
.Dd April 16, 2003
.Dt GETPWENT 3
.Os
.Sh NAME
.Nm getpwent ,
.Nm getpwent_r ,
.Nm getpwnam ,
.Nm getpwnam_r ,
.Nm getpwuid ,
.Nm getpwuid_r ,
.Nm setpassent ,
.Nm setpwent ,
.Nm endpwent
@ -50,11 +53,17 @@
.In pwd.h
.Ft struct passwd *
.Fn getpwent void
.Ft int
.Fn getpwent_r "struct passwd *pwd" "char *buffer" "size_t bufsize" "struct passwd **result"
.Ft struct passwd *
.Fn getpwnam "const char *login"
.Ft int
.Fn getpwnam_r "const char *name" "struct passwd *pwd" "char *buffer" "size_t bufsize" "struct passwd **result"
.Ft struct passwd *
.Fn getpwuid "uid_t uid"
.Ft int
.Fn getpwuid_r "uid_t uid" "struct passwd *pwd" "char *buffer" "size_t bufsize" "struct passwd **result"
.Ft int
.Fn setpassent "int stayopen"
.Ft void
.Fn setpwent void
@ -100,6 +109,35 @@ function
sequentially reads the password database and is intended for programs
that wish to process the complete list of users.
.Pp
The functions
.Fn getpwent_r ,
.Fn getpwnam_r ,
and
.Fn getpwuid_r
are thread-safe versions of
.Fn getpwent ,
.Fn getpwnam ,
and
.Fn getpwuid ,
respectively.
The caller must provide storage for the results of the search in
the
.Fa pwd ,
.Fa buffer ,
.Fa bufsize ,
and
.Fa result
arguments.
When these functions are successful, the
.Fa pwd
argument will be filled-in, and a pointer to that argument will be
stored in
.Fa result .
If an entry is not found or an error occurs,
.Fa result
will be set to
.Dv NULL .
.Pp
The
.Fn setpassent
function
@ -142,9 +180,26 @@ The functions
.Fn getpwent ,
.Fn getpwnam ,
and
.Fn getpwuid ,
.Fn getpwuid
return a valid pointer to a passwd structure on success
and a null pointer if end-of-file is reached or an error occurs.
or
.Dv NULL
if the entry is not found or if an error occurs.
In the latter case,
.Va errno
will be set.
The functions
.Fn getpwent_r ,
.Fn getpwnam_r ,
and
.Fn getpwuid_r
return 0 if no error occurred, or an error number to indicate failure.
It is not an error if a matching entry is not found. (Thus, if
.Fa result
is
.Dv NULL
and the return value is 0, no matching entry exists.)
.Pp
The
.Fn setpassent
function returns 0 on failure and 1 on success.
@ -154,6 +209,23 @@ and
.Fn setpwent
functions
have no return value.
.Sh ERRORS
These routines may fail for any of the errors specified in
.Xr open 2 ,
.Xr dbopen 2 ,
.Xr socket 2 ,
and
.Xr connect 2 ,
in addition to the following:
.Bl -tag -width Er
.It Bq Er ERANGE
The buffer specified by the
.Fa buffer
and
.Fa bufsize
arguments was insufficiently sized to store the result.
The caller should retry with a larger buffer.
.El
.Sh FILES
.Bl -tag -width /etc/master.passwd -compact
.It Pa /etc/pwd.db
@ -187,6 +259,25 @@ The
.Fn setpassent
function appeared in
.Bx 4.3 Reno .
The
.Fn getpwent_r ,
.Fn getpwnam_r ,
and
.Fn getpwuid_r
functions appeared in
.Fx 5.1 .
.Sh STANDARDS
The
.Fn getpwent ,
.Fn getpwnam ,
.Fn getpwnam_r ,
.Fn getpwuid ,
.Fn getpwuid_r ,
.Fn setpwent ,
and
.Fn endpwent
functions conform to
.St -p1003.1-96 .
.Sh COMPATIBILITY
The historic function
.Xr setpwfile 3 ,
@ -206,6 +297,7 @@ will modify the same object.
.Pp
The functions
.Fn getpwent ,
.Fn getpwent_r ,
.Fn endpwent ,
.Fn setpassent ,
and
@ -214,7 +306,9 @@ are fairly useless in a networked environment and should be
avoided, if possible.
The
.Fn getpwent
function
makes no attempt to suppress duplicate information if multiple
and
.Fn getpwent_r
functions
make no attempt to suppress duplicate information if multiple
sources are specified in
.Xr nsswitch.conf 5 .

File diff suppressed because it is too large Load Diff

View File

@ -47,6 +47,7 @@ static const char rcsid[] =
#include <sys/param.h>
#include <sys/stat.h>
#include <arpa/inet.h>
#include <db.h>
#include <err.h>
@ -66,6 +67,8 @@ static const char rcsid[] =
#define SECURE 2
#define PERM_INSECURE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
#define PERM_SECURE (S_IRUSR|S_IWUSR)
#define LEGACY_VERSION _PW_VERSION(3)
#define CURRENT_VERSION _PW_VERSION(4)
HASHINFO openinfo = {
4096, /* bsize */
@ -94,6 +97,8 @@ static void usage(void);
int
main(int argc, char *argv[])
{
static char verskey[] = _PWD_VERSION_KEY;
char version = _PWD_CURRENT_VERSION;
DB *dp, *sdp, *pw_db;
DBT data, sdata, key;
FILE *fp, *oldfp;
@ -101,6 +106,7 @@ main(int argc, char *argv[])
int ch, cnt, ypcnt, makeold, tfd, yp_enabled = 0;
unsigned int len;
int32_t pw_change, pw_expire;
uint32_t store;
const char *t;
char *p;
char buf[MAX(MAXPATHLEN, LINE_MAX * 2)], tbuf[1024];
@ -223,7 +229,7 @@ main(int argc, char *argv[])
pw_db = dbopen(_PATH_MP_DB, O_RDONLY, 0, DB_HASH, NULL);
if (!pw_db)
error(_MP_DB);
buf[0] = _PW_KEYBYNAME;
buf[0] = _PW_KEYBYNAME | CURRENT_VERSION;
len = strlen(username);
/* Only check that username fits in buffer */
@ -239,7 +245,7 @@ main(int argc, char *argv[])
while (*p++)
;
buf[0] = _PW_KEYBYUID;
buf[0] = _PW_KEYBYUID | CURRENT_VERSION;
memmove(buf + 1, p, sizeof(int));
key.data = (u_char *)buf;
key.size = sizeof(int) + 1;
@ -304,6 +310,19 @@ main(int argc, char *argv[])
* original file prepended by the _PW_KEYBYNUM character. (The special
* characters are prepended to ensure that the keys do not collide.)
*/
/* In order to transition this file into a machine-independent
* form, we have to change the format of entries. However, since
* older binaries will still expect the old MD format entries, we
* create * those as usual and use versioned tags for the new entries.
*/
key.data = verskey;
key.size = sizeof(verskey)-1;
data.data = &version;
data.size = 1;
if ((dp->put)(dp, &key, &data, 0) == -1)
error("put");
if ((dp->put)(sdp, &key, &data, 0) == -1)
error("put");
ypcnt = 1;
data.data = (u_char *)buf;
sdata.data = (u_char *)sbuf;
@ -315,6 +334,9 @@ main(int argc, char *argv[])
if (is_comment)
--cnt;
#define COMPACT(e) t = e; while ((*p++ = *t++));
#define SCALAR(e) store = htonl((uint32_t)(e)); \
memmove(p, &store, sizeof(store)); \
p += sizeof(store);
if (!is_comment &&
(!username || (strcmp(username, pwd.pw_name) == 0))) {
pw_change = pwd.pw_change;
@ -323,6 +345,97 @@ main(int argc, char *argv[])
p = buf;
COMPACT(pwd.pw_name);
COMPACT("*");
SCALAR(pwd.pw_uid);
SCALAR(pwd.pw_gid);
SCALAR(pwd.pw_change);
COMPACT(pwd.pw_class);
COMPACT(pwd.pw_gecos);
COMPACT(pwd.pw_dir);
COMPACT(pwd.pw_shell);
SCALAR(pwd.pw_expire);
SCALAR(pwd.pw_fields);
data.size = p - buf;
/* Create secure data. */
p = sbuf;
COMPACT(pwd.pw_name);
COMPACT(pwd.pw_passwd);
SCALAR(pwd.pw_uid);
SCALAR(pwd.pw_gid);
SCALAR(pwd.pw_change);
COMPACT(pwd.pw_class);
COMPACT(pwd.pw_gecos);
COMPACT(pwd.pw_dir);
COMPACT(pwd.pw_shell);
SCALAR(pwd.pw_expire);
SCALAR(pwd.pw_fields);
sdata.size = p - sbuf;
/* Store insecure by name. */
tbuf[0] = _PW_KEYBYNAME | CURRENT_VERSION;
len = strlen(pwd.pw_name);
memmove(tbuf + 1, pwd.pw_name, len);
key.size = len + 1;
if ((dp->put)(dp, &key, &data, method) == -1)
error("put");
/* Store insecure by number. */
tbuf[0] = _PW_KEYBYNUM | CURRENT_VERSION;
store = htonl(cnt);
memmove(tbuf + 1, &store, sizeof(store));
key.size = sizeof(store) + 1;
if ((dp->put)(dp, &key, &data, method) == -1)
error("put");
/* Store insecure by uid. */
tbuf[0] = _PW_KEYBYUID | CURRENT_VERSION;
store = htonl(pwd.pw_uid);
memmove(tbuf + 1, &store, sizeof(store));
key.size = sizeof(store) + 1;
if ((dp->put)(dp, &key, &data, methoduid) == -1)
error("put");
/* Store secure by name. */
tbuf[0] = _PW_KEYBYNAME | CURRENT_VERSION;
len = strlen(pwd.pw_name);
memmove(tbuf + 1, pwd.pw_name, len);
key.size = len + 1;
if ((sdp->put)(sdp, &key, &sdata, method) == -1)
error("put");
/* Store secure by number. */
tbuf[0] = _PW_KEYBYNUM | CURRENT_VERSION;
store = htonl(cnt);
memmove(tbuf + 1, &store, sizeof(store));
key.size = sizeof(store) + 1;
if ((sdp->put)(sdp, &key, &sdata, method) == -1)
error("put");
/* Store secure by uid. */
tbuf[0] = _PW_KEYBYUID | CURRENT_VERSION;
store = htonl(pwd.pw_uid);
memmove(tbuf + 1, &store, sizeof(store));
key.size = sizeof(store) + 1;
if ((sdp->put)(sdp, &key, &sdata, methoduid) == -1)
error("put");
/* Store insecure and secure special plus and special minus */
if (pwd.pw_name[0] == '+' || pwd.pw_name[0] == '-') {
tbuf[0] = _PW_KEYYPBYNUM | CURRENT_VERSION;
store = htonl(ypcnt);
memmove(tbuf + 1, &store, sizeof(store));
ypcnt++;
key.size = sizeof(store) + 1;
if ((dp->put)(dp, &key, &data, method) == -1)
error("put");
if ((sdp->put)(sdp, &key, &sdata, method) == -1)
error("put");
}
/* Create insecure data. (legacy version) */
p = buf;
COMPACT(pwd.pw_name);
COMPACT("*");
memmove(p, &pwd.pw_uid, sizeof(pwd.pw_uid));
p += sizeof(int);
memmove(p, &pwd.pw_gid, sizeof(pwd.pw_gid));
@ -339,7 +452,7 @@ main(int argc, char *argv[])
p += sizeof pwd.pw_fields;
data.size = p - buf;
/* Create secure data. */
/* Create secure data. (legacy version) */
p = sbuf;
COMPACT(pwd.pw_name);
COMPACT(pwd.pw_passwd);
@ -360,7 +473,7 @@ main(int argc, char *argv[])
sdata.size = p - sbuf;
/* Store insecure by name. */
tbuf[0] = _PW_KEYBYNAME;
tbuf[0] = _PW_KEYBYNAME | LEGACY_VERSION;
len = strlen(pwd.pw_name);
memmove(tbuf + 1, pwd.pw_name, len);
key.size = len + 1;
@ -368,21 +481,21 @@ main(int argc, char *argv[])
error("put");
/* Store insecure by number. */
tbuf[0] = _PW_KEYBYNUM;
tbuf[0] = _PW_KEYBYNUM | LEGACY_VERSION;
memmove(tbuf + 1, &cnt, sizeof(cnt));
key.size = sizeof(cnt) + 1;
if ((dp->put)(dp, &key, &data, method) == -1)
error("put");
/* Store insecure by uid. */
tbuf[0] = _PW_KEYBYUID;
tbuf[0] = _PW_KEYBYUID | LEGACY_VERSION;
memmove(tbuf + 1, &pwd.pw_uid, sizeof(pwd.pw_uid));
key.size = sizeof(pwd.pw_uid) + 1;
if ((dp->put)(dp, &key, &data, methoduid) == -1)
error("put");
/* Store secure by name. */
tbuf[0] = _PW_KEYBYNAME;
tbuf[0] = _PW_KEYBYNAME | LEGACY_VERSION;
len = strlen(pwd.pw_name);
memmove(tbuf + 1, pwd.pw_name, len);
key.size = len + 1;
@ -390,14 +503,14 @@ main(int argc, char *argv[])
error("put");
/* Store secure by number. */
tbuf[0] = _PW_KEYBYNUM;
tbuf[0] = _PW_KEYBYNUM | LEGACY_VERSION;
memmove(tbuf + 1, &cnt, sizeof(cnt));
key.size = sizeof(cnt) + 1;
if ((sdp->put)(sdp, &key, &sdata, method) == -1)
error("put");
/* Store secure by uid. */
tbuf[0] = _PW_KEYBYUID;
tbuf[0] = _PW_KEYBYUID | LEGACY_VERSION;
memmove(tbuf + 1, &pwd.pw_uid, sizeof(pwd.pw_uid));
key.size = sizeof(pwd.pw_uid) + 1;
if ((sdp->put)(sdp, &key, &sdata, methoduid) == -1)
@ -405,7 +518,7 @@ main(int argc, char *argv[])
/* Store insecure and secure special plus and special minus */
if (pwd.pw_name[0] == '+' || pwd.pw_name[0] == '-') {
tbuf[0] = _PW_KEYYPBYNUM;
tbuf[0] = _PW_KEYYPBYNUM | LEGACY_VERSION;
memmove(tbuf + 1, &ypcnt, sizeof(cnt));
ypcnt++;
key.size = sizeof(cnt) + 1;
@ -437,7 +550,7 @@ main(int argc, char *argv[])
if (yp_enabled) {
buf[0] = yp_enabled + 2;
data.size = 1;
tbuf[0] = _PW_KEYYPENABLED;
tbuf[0] = _PW_KEYYPENABLED | LEGACY_VERSION;
key.size = 1;
if ((dp->put)(dp, &key, &data, method) == -1)
error("put");