A UNIX system requires numerous data files for normal operation: the password file /etc/passwd and the group file /etc/group are two files that are frequently used by various programs.

1 Password File

The UNIX System’s password file contains the fields shown in Figure 6.1. These fields are contained in a passwd structure that is defined in <pwd.h>.

Historically, the password file has been stored in /etc/passwd and has been an ASCII file. Each line contains the fields described in Figure 6.1, separated by colons. For example, four lines from the /etc/passwd file on Linux could be:

  • There is usually an entry with the user name root. This entry has a user ID of 0 (the superuser).
  • The encrypted password field contains a single character as a placeholder.
  • Some fields in a password file entry can be empty. If the encrypted password field is empty, it usually means that the user does not have a password. (This is not recommended.)
  • The shell field contains the name of the executable program to be used as the login shell for the user.
  • The nobody user name can be used to allow people to log in to a system, but with a user ID (65534) and group ID (65534) that provide no privileges.

POSIX.1 defines two functions to fetch entries from the password file. These functions allow us to look up an entry given a user’s login name or numerical user ID.

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

The getpwuid function is used by the ls program to map the numerical user ID contained in an i-node into a user’s login name. The getpwnam function is used by the login program when we enter our login name.

These two POSIX.1 functions are fine if we want to look up either a login name or a user ID, but some programs need to go through the entire password file. Three functions can be used for this purpose: getpwent, setpwent, and endpwent.

2 Shadow Passwords

The encrypted password is a copy of the user’s password that has been put through a one-way encryption algorithm. Because this algorithm is one-way, we can’t guess the original password from the encrypted version.

Linux store the encrypted password in another file, often called the shadow password file. Minimally, this file has to contain the user name and the encrypted password. Other information relating to the password is also stored here.

3 Group File

The UNIX System’s group file contains the fields shown in Figure 6.4. These fields are contained in a group structure that is defined in <grp.h>.
.

The field gr_mem is an array of pointers to the user names that belong to this group. This array is terminated by a null pointer.

We can look up either a group name or a numerical group ID with the following two functions.

1
2
struct group *getgrgid(gid_t gid);
struct group *getgrnam(const char *name);

If we want to search the entire group file, we need some additional functions.

1
2
3
struct group *getgrent(void);
void setgrent(void);
void endgrent(void);

4 Supplementary Group IDs

Not only did we belong to the group corresponding to the group ID in our password file entry, but we could also belong to as many as 16 additional groups. The file access permission checks were modified so that in addition to comparing the the file’s group ID to the process effective group ID, it was also compared to all the supplementary group IDs.
The advantage of using supplementary group IDs is that we no longer have to change groups explicitly. It is common to belong to multiple groups (i.e., participate in multiple projects) at the same time.

Three functions are provided to fetch and set the supplementary group IDs.

1
2
3
int getgroups(int gidsetsize, gid_t grouplist[]);
int setgroups(int ngroups, const gid_t grouplist[]);
int initgroups(const char *username, gid_t basegid);

5 Other Data Files

We’ve discussed only two of the system’s data files so far: the password file and the group file. Numerous other files are used by UNIX systems in normal day-to-day operation.

Figure 6.6 shows some of these routines, which are common to UNIX systems. In this figure, we show the functions for the password files and group file, which we discussed earlier in this chapter, and some of the networking functions. There are get, set, and end functions for all the data files in this figure.

6 Login Accounting

Two data files provided with most UNIX systems are the utmp file, which keeps track of all the users currently logged in, and the wtmp file, which keeps track of all logins and logouts.

7 System Identification

POSIX.1 defines the uname function to return information on the current host and operating system.

1
int uname(struct utsname *name);

gethostname function only return the name of the host.

8 Time and Date Routines

The time function returns the current time and date.

1
time_t time(time_t *calptr);

The real-time extensions to POSIX.1 added support for multiple system clocks.A clock is identified by the clockid_t type. Standard values are summarized in Figure 6.8.

The clock_gettime function can be used to get the time of the specified clock. The time is returned in a timespec structure which expresses time values in terms of seconds and nanoseconds.

1
int clock_gettime(clockid_t clock_id, struct timespec *tsp);

When the clock ID is set to CLOCK_REALTIME, the clock_gettime function provides similar functionality to the time function, except with clock_gettime, we might be able to get a higher-resolution time value if the system supports it.

Once we have the integer value that counts the number of seconds since the Epoch, we normally call a function to convert it to a broken-down time structure, and then call another function to generate a human-readable time and date. Figure 6.9 shows the relationships between the various time functions. (The three functions in this figure that are shown with dashed lines—localtime, mktime, and strftime—are all affected by the TZ environment variable. The dotted lines show how the calendar time is obtained from time-related structures.)

The two functions localtime and gmtime convert a calendar time into what’s called a broken-down time, a tm structure.

1
2
3
4
5
6
7
8
9
10
11
struct tm {      /* a broken-down time */
int tm_sec; /* seconds after the minute: [0 - 60] */
int tm_min; /* minutes after the hour: [0 - 59] */
int tm_hour; /* hours after midnight: [0 - 23] */
int tm_mday; /* day of the month: [1 - 31] */
int tm_mon; /* months since January: [0 - 11] */
int tm_year; /* years since 1900 */
int tm_wday; /* days since Sunday: [0 - 6] */
int tm_yday; /* days since January 1: [0 - 365] */
int tm_isdst; /* daylight saving time flag: <0, 0, >0 */
};

The difference between localtime and gmtime is that the first converts the calendar time to the local time, taking into account the local time zone and daylight saving time flag, whereas the latter converts the calendar time into a broken-down time expressed as UTC.

The function mktime takes a broken-down time, expressed as a local time, and converts it into a time_t value.

The strftime function is a printf-like function for time values. It is complicated by the multitude of arguments available to customize the string it produces.

We mentioned that the three functions in Figure 6.9 with dashed lines were affected by the TZ environment variable:localtime,mktime,and strftime. If defined,the value of this environment variable is used by these functions instead of the default time zone. If the variable is defined to be a null string, such as TZ=, then UTC is normally used.