The UNIX and Windows security models are quite different. Interix, as a subsystem of Windows, uses the underlying Windows security model. At the same time, Interix attempts to present the Windows security model in a way that is consistent with UNIX security.
This results in some key differences between the way in which Interix security works and the way in which standard UNIX security works. (For a discussion of someof these differences, see Comparison of Windows and UNIX Architectures in Chapter 2, Windows and UNIX Compared.) This section covers the differencesin the security model and describes how to modify code to operate under Interix.
The key areas that are addressed here are:
User names in Interix
UNIX UIDs and GIDs versus Windows SIDs
The passwd file structure
User and group operation functions
Running programs as other users or groups
User accounting database functions
User names are handled differently in UNIX and Interix. In UNIX, they are lowercase text stored in the passwd file. In Interix, the user names are taken from the account database and can contain information about the domain the accountis in as well as its user name .
It s important to note that Windows places user and group names in the same namespace, while UNIX places them in separate namespaces. What this means is that a UNIX environment might have a user named tools and a group named tools, while a Windows environment would forbid that and require, for example, that the group be named tools_group. Applications should be written in such a waythat user and group names aren t hard-coded; obviously, any code that expects identical user and group names will need to be changed.
From a programming standpoint, functions that use the user or group name in UNIX, such as getpwnam() and getgrnam() , accept a DomainName + UserName pair in Interix. The DomainName part is explained in more detail in the following paragraphs. Any application code that assumes that a user or group name cannot contain a plus sign must be changed. Similarly, applications should be prepared to accept user or group names that are considerably longer than the norm on UNIX systems. (Traditional UNIX systems limit user and group names to eight characters each.)
A domain is a collection of networked Windows-based computers that use a common security database. Most Windows-based computers have access to at least two domains: the network domain, which has a centralized security database; and a local domain, which uses the security database on the local computer. On domain controllers, the network and local domains are the same.
Windows user and group names use the format DomainName + UserName . The pw_name and gr_name members in the Interix passwd and group structuresuse the same format. They can also be passed in the form + UserName or UserName .
Table 10.10 on the next page describes how domain and user names are interpreted.
Name | Description |
---|---|
DomainName + UserName | The group or user name belonging to the specified domain. |
+ UserName | When passed to an Interix function, finds the closest matchingname in the same search order used by Windows. Usually, this is used with well-known names such as +SYSTEM or +Administrator,and the function will find the matching name on the local computer. However, if the name is not found on the local computer, the function will search the primary domain and other trusted domains for that name, returning the first match.When this format is returned from an Interix function, it indicatesa name from the local computer domain. |
UserName | The group or user name in the same domain as the calling process. |
The Interix principal domain is normally the domain to which the system itself belongs. This can be overridden by changing a registry setting (HKEY_LOCAL_MACHINE\Software\Microsoft\Services For Unix\PrincipalDomain). Applications can determine the system s principaldomain through the getpdomain() function.
UNIX systems translate user and group names to integers, UID and GID, respectively. These values are typically 32-bit numbers and are assigned arbitrarily by an administrator. It is possible to reuse UID and GID values, and it is possible for multiple user or group names to correspond to a particular UID or GID. The UID and GID values are taken from distinct spaces ” that is, it is possible for user joes to have UID 556 and group joeteam to have GID 556. There is no guarantee of uniqueness for UID or GID values between separate systems. Two UNIX systems can have different human users each with the same UID of 556.
Windows systems translate user and group names to SIDs, which are large (typically 112-bit) structured values. SIDs are automatically assigned by Windows when users or groups are created. SIDs are guaranteed to be globally unique and can never be reused. There is a one-to-one relationship between a SID and a user or group.SIDs for users and groups come from the same space.
The UNIX APIs expose user and group identities as integers of type UID_t and GID_t, respectively. Interix conforms to this requirement by mapping Windows SIDs to UID and GID values. All systems belonging to the same domain will perform this mapping in the same way. Under normal circumstances, there will be no collisions among mapped UID and GID values ” that is, no two Windows SIDs will be converted to the same UID_t or GID_t.
Because mapped UID and GID values may differ between systems joined to different domains, applications that need to preserve identity information should store user or group names rather than UID or GID values.
The files /etc/passwd and /etc/groups do not exist on an Interix system; therefore, some of the information contained in the structure struct passwd is obtainedin a nonstandard way, such as the following:
pw_gecos
The user information member contains the text from the Description fieldin the Windows user account information.
pw_shell
The user s shell member is always /bin/sh .
Because other applications in both the Interix subsystem and the Win32 subsystem can use the information in the pw_gecos and pw_shell fields, the contents of the pw_gecos member will not necessarily continue to be taken from the Description field found in a Windows user account.
Interix also returns two additional parameters not available on UNIX systems:
The pw_change parameter returns the time until the password must be changed.
The pw_expire parameter returns the time when the user s account expires .
Because the Interix security model is integrated with the Windows security subsystem, Interix does not support all of the user and group functions that manipulate or obtain information from the /etc/passwd , /etc/group , /etc/shadow , or /etc/gshadow files. Table 10.11 summarizes the calls that Interix does not support and recommended replacements .
Function Name | Description | Suggested Interix Replacement |
---|---|---|
endspent | Indicates that the caller expects to do no further shadow password retrieval operations. | Endpwent() |
fgetgrent, | Gets the group file entry. | struct group * getgrent () |
fgetpwent, | Gets the password file entry. | struct passwd *getpwent() |
fgetspent, | Reads from a shadow file stream. | struct passwd *getpwent() |
getgrent_r, | Gets the group file entry. | struct group * getgrent (void) |
getpw | Gets the password file entry from UID. | getpwuid(UID) or getpwnam(*login) |
getpwent_r, | Gets the password file entry. | getpwent, getpwnam, getpwuid |
getspent, | Gets the shadow password file entry. | struct passwd *getpwent() |
getspnam, | Gets the shadow logon name file entry. | getpwnam(*login) |
initgroups | Initializes the supplementary group access list. | getgroups (int gidsetsize, GID_t grouplist[ ]) |
lckpwdf, | Manipulates the shadow password database lock file. | //lckpwdf |
putpwent | Writes a password file entry. | For password change: |
putspent | Writes a shadow password file entry. | For password change: |
setgroups | Sets supplementary group access list Ids. | The list of supplementary groups can be retrieved with getgroups , but it is not possible to build and apply an arbitrary list of supplementary groups. |
setresgid, | Sets real, effective, and saved group ID. | setgid (GID) |
setresgid, | Sets real, effective, and saved group ID. | setregid (rgid, egid) |
setresuid, | Sets real, effective, and saved user ID. | setuid (UID) For more information about changing UID and GID in Interix, see Changing User ID by Using the Interix setuser() Function later in this chapter. |
setresuid, | Sets real, effective, and saved user ID. | setreuid (ruid, euid) |
setspent | Sets the shadow password entry in the database. | Interix does not support a concept of a shadow password file. |
<initgroups.c>
#include <sys/types.h> #include <unistd.h> #include <grp.h> int main() { struct group *ptr_group; GID_t grouplist[100]; int num; num = getgroups (99, grouplist); printf("group\tID:\n---------------\n"); if (num > 0) while(num) { ptr_group = getgrgid(grouplist[num]); printf("%s\t%d\n", ptr_group->gr_name, grouplist[num]); } else printf("num=%d\n", num); exit(0); }
Some programs require access to resources to which the current user has no access. This is solved on UNIX systems by running the program as a specific user or group rather than as the current user or group. UNIX programs can use special permissions on the program s executable file called the setuid and setgid bits.
According to the POSIX standard, a file s permissions include bits to set a UID ( setuid ) and to set a GID ( setgid ). If either or both bits are set on a file and a process executes that file, the process runs with an identity based on the UID or GID of the file, respectively.
When you run a program that has the setuid bit set in the file permissions, it runsas if the file s owner executed it no matter who actually started it. These user and group IDs are called effective user ID and effective group ID .
When an Interix process executes a file that has the setuid or setgid bit set, Interix constructs local security tokens for the process with the privileges assigned to the owner (if setuid is set) and/or group (if setgid is set) of the file. Because these tokens are local, they are not recognized by other computers on the network. Even if the file is owned by a member of the Domain Admins group, the process still does not have trusted access to other computers in the domain by using Windows networking.
For example, a process executes a program file that has its setuid bit set and thatis owned by a member of the Domain Admins group. If that program attempts to change a domain user s password, that attempt fails because the security tokensof the process are local and are not recognized by other systems in the domain.If, however, the program attempts to change a local user s password, the attempt succeeds because the file s owner is a member of the Domain Admins group, which typically belongs to the local computer s Administrators group.
On UNIX systems, the user and/or group owner is often set to root, thereby allowing a nonroot program to run with root privileges. On Interix, the owner should be set to the Local Administrator or to a member of the Domain Admins group.
In summary, UNIX and Interix systems maintain at least two user and group IDs: the effective user ID and effective group ID, and the real user ID and real group ID . Most UNIX systems and Interix also support a saved set user ID and savedset group ID.
Often in programs with the setuid bit set, it is desirable to be able to change the real and effective IDs during execution. For example, programmers might wantto do one of the following in setuid programs:
Change from the initial effective user/group ID to the real user/group ID.
Change from the real user/group ID back to the initial effective user/group ID.
These two actions can be performed by using the UNIX setuid() function. In addition, Interix provides another function named setuser() , which simplifies changing the user ID.
The proprietary Interix setuser() function changes the effective and real UID and GID of the current process to that of the specified user name. All of the security attributes and permissions become those of the specified user name. The current working directory of the process does not change.
– o use setuser() to replace the standard UNIX calls
Add the following include statement to the code:
#include <interix/security.h>
Rewrite the code to use the setuser() function as defined here:
int setuser(char *username , char *password , int flags )
Set the arguments as follows :
The username argument is the name of the user. If the user name is not fully qualified with a domain name (that is, domain + name ), it is not changed.On a system configured for workgroups, specify the domain as NULL:that is, use the string +name for username .
The password argument is the plaintext password for the specified user name.
The flags argument comprises control flags. Possible values for flags are defined in interix/security.h as follows:
SU_COMPLETE changes the real and effective user and group IDs and all security attributes to the default for the specified user.
SU_CHECK verifies that the process can perform a setuser() action by using SU_COMPLETE for the specified user name and password. This is a quick way to verify a password for a user. This action is equivalent to the older Interix call, authenticateuser() .
The setuser() function has the advantage of changing both the UID and the GID with only one function call. However, it has the disadvantage that it is only supportedon Interix.
Performance degradation can occur if a process changes identity to a user who does not have permission to be located in the current working directory. The best solution to this is to call chdir() to a directory known to be permitted for the new identity after the call to setuser() .
Interix provides a set of interfaces used to execute a process as another user. These functions and structures are defined in the header file security.h. They include execl_asuser() , execle_asuser() , execlp_asuser() , execv_asuser() , execve_asuser() , and execvp_asuser() .
All of these functions use a user security structure, struct usersec , to identify another user. The usersec structure is illustrated below:
struct usersec { char * user; char * domain; char * password; int logontype; int logonprovider; };
The domain , user , and password members of the structure have their normal meanings. The logontype and logonprovider members are provided for future development; leave them at the default values of 0.
The six exec*_asuser() functions correspond to the six exec functions: execl() , execle() , execlp() , execv() , execve () , and execvp() . The arguments after the struct usersec member are identical to their exec counterparts.
Interix supports a subset of the routines used to track and manage a user accounting database. Interix does support the following calls: endutxent , getutxent , getutxid , getutxline , pututxline , and setutxent .
Table 10.12 shows user account database functions that are not supported in Interix, and recommended alternatives to them.
Function Name | Description | Suggested Interix Replacement |
---|---|---|
acct | Enables or disables process accounting. | No support or equivalent in Interix. |
endutent | Closes the currently open database. | endutxent |
getutent | Extracts the next entry from a UTMP database. | getutxent |
getutid | Searches forward from the current point in the UTMP database. | getutxid |
getutline | Searches forward from the current point in the UTMP database. | getutxline |
getutmp | Copies the information stored in the members of the UTMPX structure to the corresponding members of the UTMP structure. | No support or equivalent for the UTMP structure in Interix. |
getutmpx | Copies the information stored in the members of the UTMP structure to the corresponding members of the UTMPX structure. | No support or equivalent for the UTMP structure in Interix. |
logwtmp | Appends an entry to the WTMP file. | pututxline |
pututline | Writes the supplied UTMP structure into the UTMP database. | pututxline |
setutent | Resets the input stream to the beginning. | setutxent |
updwtmp | Appends an entry to the WTMP file. | pututxline |
updwtmpx | Writes the contents of the UTMPX structure pointed to by UTMPX to the database. | pututxline |
utmpname | Changes the name of the database file examined to another file. | |
utmpxname | Changes the name of the database file examined from /var/adm/utmpx to any other file, typically /var/adm/wtmpx . |