Chapter Eight Question Two

Linux Programming Interface by Michael Kerrisk

Question

Implement getpwnam() using setpwent(), getpwent(), and endpwent().

Implementation


/**
 * Chapter Eight Question Two Linux Progamming Interface - Michael Kerrisk
 *
 * Implement getpwnam() using setpwent(), getpwent(), and endpwent().
 *
 * Notes: about the sys calls above.
 *
 * getpwent() function returns a pointer to a structure containing the broken-out fields of a record from the password
 * database (e.g. the local password file /etc/passwd, NIS and LDAP). The first time getpwent() is called, it
 * returns the first entry; thereafter, it returns successive entries.
 *
 * setpwent() function rewinds to the beginning of the password database
 *
 * endpwent() is used to close the password database after all processing has been performed
 */
#include <stdio.h>
#include <errno.h>
#include <pwd.h>
#include <string.h>

/*
 * For Reference:
 *
 * The passwd struct represents the return from the getwpwnam system call in which we are implementing.
 * The following fields are self explanatory with the exception of the pw_gecos and pw_passwd.
 *
 * 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
 * };
 *
 * pw_gecos field derives its name from early UNIX implementations, where this field contained information that
 * was  used for communicating with a machine running the General Electric Comprehensive Operating System
 * (GECOS).  Although this usage has long since become obsolete, the field name has survived and the field
 * is used for recoding information about the user.
 *
 * Note on pw_passwd: this field contains valid information only if password shadowing is not enabled. The simplest
 * way to programmatically determine whether password shadowing is enabled is to follow a successful getpwnam call with
 * a call to getspnam() to see if it returns a shadow password record for the same username.
 */


/**
 * Gets the current user and reads the passwd file and returns a pointer to a passwd structure.
 *
 * @param name the user name to look up
 * @return pointer to the passwd structure
 */
struct passwd *learningGetpwnam(const char *name) {
    if (name == NULL)
        return 0;

    /*
     * Reset the pointer to which the pw entrance is set do this every time this method is called to avoid being in
     * the middle of the file
     */
    setpwent();

    /*
     * Iterate through the entire password file one at a time by calling getpwent() and check to see if the pointer
     * pw_name field matches the char pointer that was passed in vai the call.
     */
    do {
        /*
         * The getpwent() function returns a pointer to a passwd structure, or NULL if there are no more entries or an
         * error occurs. If an error occurs, errno is set appropriately. If one wants to check errno after the call,
         * it should be set to zero before the call.
         */
        struct passwd *userInformation = getpwent();

        if (userInformation == NULL || errno != 0) {
            // Close the pw file and return NULL
            endpwent();
            return NULL;
        }

        // Make sure the two strings are equal if they are we found it the passwd struct
        if (0 == strcmp(userInformation->pw_name, name)) {
            endpwent();
            return userInformation;
        }
    } while (1);

    // If it gets here return null (should never get here)
    return NULL;
}

int main() {
    fprintf(stdout, "Chapter Eight Question Two: implement getpwnam().\n");
    struct passwd *mikeInformation = getpwnam("mtrottie");

    if (mikeInformation != NULL) {
        fprintf(stdout, "Name      : %s\n", mikeInformation->pw_name);
        fprintf(stdout, "UID       : %ld\n", (long) mikeInformation->pw_uid);
        fprintf(stdout, "User Dir  : %s\n", mikeInformation->pw_dir);
        fprintf(stdout, "GECOS     : %s\n", mikeInformation->pw_gecos);
        fprintf(stdout, "Passwd    : %s\n", mikeInformation->pw_passwd);
        fprintf(stdout, "Shell     : %s\n", mikeInformation->pw_shell);
        fprintf(stdout, "Group     : %ld\n", (long) mikeInformation->pw_gid);
    } else {
        fprintf(stderr, "%s", strerror(errno));
        return -1;
    }

    return 0;
}