Retrieving User and Group Information

In this section, we look at library functions that permit us to retrieve individual records from the password, shadow password, and group files, and to scan all of the records in each of these files.

The getpwnam() and getpwuid() functions retrieve records from the password file.

#include <pwd.h>

struct passwd *getpwnam(const char *name);
struct passwd *getpwuid(uid_t uid);

Note

Both return a pointer on success, or NULL on error; see main text for description of the “not found” case

Given a login name in name, the getpwnam() function returns a pointer to a structure of the following type, containing the corresponding information from the password record:

struct passwd {
    char *pw_name;      /* Login name (username) */
    char *pw_passwd;    /* Encrypted password */
    uid_t pw_uid;       /* User ID */
    gid_t pw_gid;       /* Group ID */
    char *pw_gecos;     /* Comment (user information) */
    char *pw_dir;       /* Initial working (home) directory */
    char *pw_shell;     /* Login shell */
};

The pw_gecos and pw_passwd fields of the passwd structure are not defined in SUSv3, but are available on all UNIX implementations. The pw_passwd field contains valid information only if password shadowing is not enabled. (Programmatically, the simplest way to determine whether password shadowing is enabled is to follow a successful getpwnam() call with a call to getspnam(), described shortly, to see if it returns a shadow password record for the same username.) Some other implementations provide additional, nonstandard fields in this structure.

The getpwuid() function returns exactly the same information as getpwnam(), but does a lookup using the numeric user ID supplied in the argument uid.

Both getpwnam() and getpwuid() return a pointer to a statically allocated structure. This structure is overwritten on each call to either of these functions (or to the getpwent() function described below).

According to SUSv3, if a matching passwd record can’t be found, then getpwnam() and getpwuid() should return NULL and leave errno unchanged. This means that we should be able to distinguish the error and the “not found” cases using code such as the following:

struct passwd *pwd;

errno = 0;
pwd = getpwnam(name);
if (pwd == NULL) {
    if (errno == 0)
        /* Not found */;
    else
        /* Error */;
 }

However, a number of UNIX implementations don’t conform to SUSv3 on this point. If a matching passwd record is not found, then these functions return NULL and set errno to a nonzero value, such as ENOENT or ESRCH. Before version 2.7, glibc produced the error ENOENT for this case, but since version 2.7, glibc conforms to the SUSv3 requirements. This variation across implementations arises in part because POSIX.1-1990 did not require these functions to set errno on error and allowed them to set errno for the “not found” case. The upshot of all of this is that it isn’t really possible to portably distinguish the error and “not found” cases when using these functions.

One common use of the functions that we have already described in this section is to convert symbolic user and group names into numeric IDs and vice versa. Example 8-1 demonstrates these conversions, in the form of four functions: userNameFromId(), userIdFromName(), groupNameFromId(), and groupIdFromName(). As a convenience to the caller, userIdFromName() and groupIdFromName() also allow the name argument to be a (purely) numeric string; in that case, the string is converted directly to a number and returned to the caller. We employ these functions in some example programs later in this book.

The following functions are used to retrieve individual records from the shadow password file and to scan all records in that file.

#include <shadow.h>

struct spwd *getspnam(const char *name);

Note

Returns pointer on success, or NULL on not found or error

struct spwd *getspent(void);

Note

Returns pointer on success, or NULL on end of stream or error

void setspent(void);
void endspent(void);

We won’t describe these functions in detail, since their operation is similar to the corresponding password file functions. (These functions aren’t specified in SUSv3, and aren’t present on all UNIX implementations.)

The getspnam() and getspent() functions return pointers to a structure of type spwd. This structure has the following form:

struct spwd {
    char *sp_namp;          /* Login name (username) */
    char *sp_pwdp;          /* Encrypted password */

    /* Remaining fields support "password aging", an optional
       feature that forces users to regularly change their
       passwords, so that even if an attacker manages to obtain
       a password, it will eventually cease to be usable. */

    long sp_lstchg;         /* Time of last password change
                               (days since 1 Jan 1970) */
    long sp_min;            /* Min. number of days between password changes */
    long sp_max;            /* Max. number of days before change required */
    long sp_warn;           /* Number of days beforehand that user is
                               warned of upcoming password expiration */
    long sp_inact;          /* Number of days after expiration that account
                               is considered inactive and locked */
    long sp_expire;         /* Date when account expires
                               (days since 1 Jan 1970) */
    unsigned long sp_flag;  /* Reserved for future use */
};

We demonstrate the use of getspnam() in Example 8-2.