Topic : Accessing User Information
Author : LUPG
Page : 1 Next >>
Go to page :


Accessing User Information On A Unix System


Table Of Contents:
Preface
Accessing Info About User Accounts
Structure Of The /etc/passwd File
Getting A Given User's Info
Enumerating All User Accounts  
Writing A User Authentication Function
The (Non-Standard) Handling Of Shadow Passwords
Association Of Extra Groups For Users
Structure Of The /etc/group File
Listing The Users In A Given Group
Enumerating (almost) All Groups
Groups In /etc/group Vs. Groups In /etc/passwd
Determining User Info At Run-Time
Which User Is My Process Running As?  
Which Groups Is My Process Associated With?
The Sick Case Of Set-User-ID (suid) Programs
Who Is Currently Logged On?
Who Has Been Using My System Lately?
References To Other System Databases




Preface
One type of information that many programs require, is user information. This includes finding out the home directory of a given user, finding the list of groups a user belongs to, finding out who is logged on the system at a given time and so on.

Most Unix systems keep this data in a set of files spread across the system. In order to allow programs to access this data in a portable manner, some system functions (or API - Application Programming Interface) and data structures are defined, and documented in different manual pages. This tutorial is an attempt at collecting the information that is common across most Unix systems into one location, and at giving a few examples of using this information.

You will note one great problem with these APIs - they are exclusively read-only. You can use them in order to read user information, but not to write out anything (i.e. create new data, update existing data or delete existing data). This makes these APIs useless for writing a program that allows (for example) creation of new users, addition of groups for a user and so on. Some hints will be supplied here as to how these tasks could be accomplished, but should be taken as time-bombs - do NOT rely only on this information if you are trying to write such programs, as you might find your system's data corrupt, your list of users erased, or something similar - DO THIS AT YOUR VERY OWN RISK. Now that we have made this point clear, we can get started.




Accessing Info About User Accounts
The most basic info one would want to know about user accounts is - what user accounts exist on a system? or, is a given user name valid on this system? This information is traditionally kept in the file named "/etc/passwd", and on current Unix systems, in other files as well.




Structure Of The /etc/passwd File
The "/etc/passwd" file contains one line (or record) per user account, and may NOT contain any comments. Each line is made of a set of fields, separated by a colon (':') character. An example of such an line would be:

root:UQstWvHV002G1:0:0:root:/root:/bin/tcsh

This example shows a "root" (or superuser) account's entry. Most fields serve the same purpose on all Unix systems, and would be as follows:
User Name
The name used to identify this account in all human-readable printouts, as well as when the user tries to log on to the system.
Password
The encrypted password of the user (see the manual page of "crypt" for more information on password encryption). on many systems, this field may also serve as a marker that the password is kept elsewhere - see discussion of shadow passwords below.
User ID
The numeric ID of the given user on the system - this number is used internally by the system instead of the user name, mostly because numbers occupy a fixed size in binary format (usually 2 or 4 bytes), and are much faster to handle, to use as keys in search tables, etc.
User's Group ID
The numeric ID of a group this user belongs to. Every user belongs to at least one group on the system. Additional groups may be specified for a user using the /etc/group file.
GECOS field
This field is a general-purpose field in which a comment about this user may be kept. This will often contain the name of the account holder. Some systems use this to store the phone number, address and office room number of the account holder. The contents of this field are never crucial for the account's proper operation (on a non-modified system).
Home Directory
Full path to the home directory of this user. This will be used by the login program to place this user in this directory when logged on, for example.
Shell.
The default shell this user will use. This shell is launched for the user when logging on to the system.

The "/etc/passwd" file is readable for all users on the system, but writable only to its owner - root. This means that users cannot directly change the contents of this file - instead, there are specialized programs that allow a user to change her password, default shell and GECOS field. See the manual page for the "passwd" command for more info on these programs.




Getting A Given User's Info
The first API we will introduce is the function for fetching the "/etc/passwd" entry of a given user. There are two functions for doing that - getpwnam() and getpwuid().

getpwnam is used to fetch a "/etc/passwd" record of a user, given his user name. The function will return a pointer to a struct passwd, or NULL, if the user does not exist on the system. This structure is defined as follows:

struct passwd {
    char    *pw_name;       /* user name */
    char    *pw_passwd;     /* user password */
    uid_t   pw_uid;         /* user id */
    gid_t   pw_gid;         /* group id */
    char    *pw_gecos;      /* real name */
    char    *pw_dir;        /* home directory */
    char    *pw_shell;      /* shell program */
};


Here is an example of using this function:

#include <pwd.h> /* defines 'struct passwd', and getpwnam(). */
#include <sys/types.h> /* defines 'uid_t', etc.              */

/* lets print some information about our root account. */
struct passwd* user_info = getpwnam("root");

/* make sure the root account exists. */
if (!user_info) {
    printf("What?? no root account? this system is broken....\n");
}
else { /* information found - lets print it out. */
    printf("Information for user 'root':\n");
    printf("  User ID: %d\n", user_info->pw_uid);
    printf("  Group ID: %d\n", user_info->pw_gid);
    printf("  Home Directory: '%s'\n", user_info->pw_dir);
    printf("  Default Shell: '%s'\n", user_info->pw_shell);
}





Just like we used the getpwnam() function, we may also use the getpwuid() function, supplying it the UID of the given user. For example, we know that the "root" account always has the UID of '0', so doing the above can be done by:




/* get the info of user with ID '0'. */
struct passwd* user_info = getpwuid(0);
/* continue like in the previous case.... */
if (!user_info) {
    printf("What?? no root account? this system is broken....\n");
}
else {
   .
   .
}





One important note about these two functions: The structure they return is allocated in static memory. This means that the same structure will be re-filled with new information after each call to the same function, erasing any data it returned in a previous call. If you need to get info about two users and have it stored in memory, you should copy the structure returned from the first call, and store it in a struct passwd you allocated (as a local variable, or using malloc()). Here is an example:


/* this function copies one passwd struct into another. */
void
copy_passwd(struct passwd* from_pw, struct passwd* to_pw)
{
    /* "string" fields need to be pre-allocated first. */
    /* copy the user name field. */
    to_pw->pw_user = (char*)malloc(strlen(from_pw->pw_user)+1);
    if (!to_pw->pw_user) { /* out of memory?? */
        fprintf(stderr, "copy_passwd: out of memory\n");
        exit(1);
    }
    strcpy(to_pw->pw_user, from_pw->pw_user);
    /* copy the passwd field. */
    to_pw->pw_passwd = (char*)malloc(strlen(from_pw->pw_passwd)+1);
    if (!to_pw->pw_passwd) { /* out of memory?? */
        fprintf(stderr, "copy_passwd: out of memory\n");
        exit(1);
    }


Page : 1 Next >>