This chapter discusses the following topics:
In order to allow adding new fields to the current for getting and setting authentication information without violating binary compatibility, a new series of interfaces has been added to enhanced security. Take for example the user profile:
struct pr_passwd { struct pr_field ufld; struct pr_flag uflg; struct pr_field sfld; struct pr_flag sflg; };
Any new field in pr_field changes the offsets to uflg, sfld, and sflg (even if you add to the end). Because the offsets are known and compiled into calling applications, this breaks binary compatibility.
Additions to (at least) pr_passwd are expected as new features are added.
Several of the security routines are being replaced in the Digital UNIX Version 4.0 release. Table 18-1 lists the affected interfaces and the replacements.
Obsolete Interface | Replacement Interface |
getprpwnam() | getespwnam() |
putprpwnam() | putespwnam() |
getprpwent() | getespwent() |
getprpwuid() | getespwuid() |
getprtcent() | getestcent() |
getprtcnam() | getestcnam() |
putprtcnam() | putestcnam() |
getdvagnam() | getesdvnam() |
getdvagent() | getesdvent() |
copydvagent() | copyesdvent() |
putdvagnam() | putesdvnam() |
getprdfent() | getesdfent() |
getprdfnam() | getesdfnam() |
putprdfnam() | putesdfnam() |
getprfient() | getesfient() |
getprfinam() | getesfinam() |
putprfinam() | putesfinam() |
read_pw_fields() | [escap_parse_fields(espw_parse, ...)] |
store_pw_fields() | [escap_print_fields(espw_parse, ...)] |
read_tc_fields() | [escap_parse_fields(estc_parse, ...)] |
store_tc_fields() | [escap_print_fields(estc_parse, ...)] |
time_lock() | time_lock_es() |
get_seed() | get_seed_es() |
auth_for_terminal() | auth_for_terminal_es() |
locked_out() | locked_out_es() |
The following new APIs are added in the Digital UNIX Version 4.0 release:
copyespwent() copyestcent() copyesfient() copyesdfent() escap_parse_fields() escap_print_fields() escap_cmp_fields() escap_copy_fields() escap_size_data() get_num_crypts() get_crypt_name()
Table 18-2 lists the data structures changed in the Digital UNIX Version 4.0 release.
Obsolete Structures | Replacement Structures |
pr_field | espw_field |
pr_flag | espw_flag |
pr_passwd | es_passwd |
t_field | estc_field |
t_flag | estc_flag |
pr_term | es_term |
dev_field | esdev_field |
dev_flag | esdev_flag |
dev_asg | esdev_asg |
f_field | esfi_field |
f_flag | esfi_flag |
pr_file | es_file |
system_default_fields | es_default_fields |
system_default_flags | es_default_flags |
pr_default | es_default |
The obsolete routines with the old names and calling sequences are currently supported. These obsolete routines were rewritten to be layered on top of the new interfaces, so that the routines (putprpwnam for example) do not lose new fields, but will instead refetch the affected record, and propagate changes to the new-format interface, thereby preserving new fields.
Statically-compiled programs using the obsolete interfaces will lose or destroy the new fields if they are allowed to write data.
The new libsecurity library with the new extended routines needs to be compiled ahead of the application. New programs should use the new getes*() and putes*() routines.
Digital UNIX preserves all traditional UNIX process user and group identities. Additionally, it provides the per-process audit ID (AUID), which is unique to Digital UNIX. The AUID is similar in principle to the real user ID, except that it remains unchanged even in cases where the real user ID changes. The audit ID is associated with all audit records and establishes the user identity even in those cases where the real and effective user IDs have been changed from their values at login.
The audit ID can be set only once in a line of process descendants, regardless of any process privileges. The audit ID is set at login to the authenticated user (the same as the real and effective user IDs) and is inherited from parent to child when a process forks using the fork() system call.
Programs that are created from startup scripts or that are created as a result of respawn entries in the inittab file are created with an unset audit ID. Such programs are normally authentication programs (getty/login sequences, window managers, trusted path managers) that set the AUID based on the user that authenticates through that interface.
Programs started through startup scripts typically receive requests for service on behalf of users and spawn a process to service that request. Such programs typically set the audit ID in the child service process based on the requesting process's effective identity.
The getluid() and setluid() system calls read and set the audit ID. See their reference pages for details.
The Digital UNIX operating system provides several library routines for managing user and group identities. For example, the set_auth_parameters() routine, usually called at the beginning of a program's main() routine, stores the initial user and group IDs that can later be queried or tested by the other routines.
Several of the routines for querying the authentication database require the program to have previously called set_auth_parameters() before changing any of the user or group IDs, or the command arguments (argc and argv).
See the identity(3) reference page for more information.
Whenever a daemon performs an operation at the request of a user program (the client), it acts in one of two ways:
In the latter case, the daemon needs to establish a set of security attributes. The preferred technique is to fork a process, set the identities and privileges, and then either perform the actions directly or execute a program to perform them.
Although the protected password database is intended mainly for Digital UNIX programs, your programs may need to use the fields described in the following list. (These fields are also described in the getespwent(3) and prpasswd(4) reference pages, the prot.h include file, and the administrative part of this document.)
These correspond to the user name and ID in /etc/passwd.
This is the real encrypted password. The system supports a longer password length than the traditional UNIX limit of 8 characters. The system encrypts the password in 8 character segments. Each cycle of encryption provides an 11-character value plus the initial 2-character salt string. Thus, the length of the encrypted password is the number of segments times 11 plus 2 ((11 * n) + 2).
For example, a plain text password of 1 to 8 characters encodes to 13 characters. A plain text password of 9 to 16 characters encodes to 24 characters and a plain text password of 17 to 24 characters encodes to 35 characters.
See the crypt(3) reference page for more information.
Indicates whether the authentication profile is valid. If not valid, login sessions are not allowed. Once retired, an account should never again be reused.
The process priority assigned to programs of the user login session using setpriority().
This mask and its control flags, in conjunction with the system audit mask, designate the events audited during the login session. The login program assigns a mask to the user's login shell. Audit masks and the control flags are inherited across exec() and fork() calls. See Chapter 19 and the auditmask(8) reference page for more information.
The following parameters describe the login password and its generation:
This is sometimes called the ``null password option'' and controls attempts to set a null password. Most administrators do not allow this option.
This field is formated like the UUCP systems file. (The systems file describes when a remote system can be contacted for file transfer.) It determines the valid times for a user to login.
Expressed as a canonical UNIX time (in seconds since 1970).
The terminal name is a cross-reference to the device assignment and terminal control databases.
This value is used to compute whether the terminal is locked due to too many unsuccessful attempts.
This value is the user-specific limit for the number of unsuccessful attempts allowed until the account locks.
Whether or not the administrator has locked the account. A locked profile cannot be used for login or other services. Only an explicit request from the system administrator should unlock an authentication profile, and only programs that handle such requests should reset the locked field.
A common programming error is to assume that the lock indicates all lock conditions. This indicator only shows the status of the administrative lock. An account may also be locked due to a password lifetime expiration or exceeding the number of unsuccessful attempts allowed for the account.
Your program can assume that the user name and ID in the protected password database is maintained by the system to have a corresponding entry in the /etc/passwd file.
The program named myexpire in Example 18-1 prints the user's password expiration time as defined in the protected password database. This program is part of the authentication protected subsystem and runs in the set group ID (SGID) mode, setting the GID to auth.
include <sys/types.h> include <stdio.h> include <sys/security.h> include <prot.h>
main (argc, argv) int argc; char *argv[]; { struct es_passwd *acct; time_t expire_time; time_t expire_date;
/*--- Standard initialization ---*/
set_auth_parameters(argc, argv); initprivs();
/*--- fetch account information using audit ID ---*/
if ((acct = getespwuid(getluid())) == NULL) errmsg("Internal error");
/*-- test if personal or system default applies and print --*/
if (acct->uflg->fg_expire) expire_time = acct->ufld->fd_expire; else if (acct->sflg->fg_expire) expire_time = acct->sfld->fd_expire; else { audit_db_error(acct); /* audit (externally defined) */ errmsg("No user-specific or system default \ expiration time."); }
if (!acct->ufld->fg_schange) { audit_db_error(acct); /* audit (externally defined) */ errmsg("Account does not have successful change time"); }
expire_date = acct->ufld->fd_schange + expire_time;
if (acct->uflg->fg_psw_chg_reqd && \ acct->ufld->fd_psw_chg_reqd) \ expire_date = time((time_t *) NULL);
audit_action(acct->ufld->fd_name, expire_date); exit(0); }
Note
The protected password database files are accessible only to processes in the auth group. Programs that need to read the protected password database files must set the group ID to auth (see the setgid(2) reference page). To write this information you must set the UID to 0 or a user ID and have a group ID of auth.
Digital UNIX has been designed so that trusted programs can authenticate their users without specifically asking for passwords. Digital UNIX explicitly uses the audit ID for this purpose. Additional password handling is usually not necessary and difficult to handle securely. Appendix D provides an example of a program for password checking.