An example demonstrating how privilege interfaces are used in a privileged application is also provided.
The major data types that are used by the privilege interfaces are:
priv_t priv_id = PRIV_FILE_DAC_WRITE;
Privilege set type – Privilege sets are represented by the priv_set_t data structure. Use one of the privilege manipulation functions shown in Table 2-1 to initialize variables of type priv_set_t.
Privilege operation type – The type of operation to be performed on a file or process privilege set is represented by the priv_op_t type definition. Not all operations are valid for every type of privilege set. Read the privilege set descriptions in Programming with Privileges for details.
PRIV_SET – Set the privileges in the specified file or process privilege set to the privileges asserted in the priv_set_t structure. If the structure is initialized to empty, PRIV_SET sets the privilege set to none.
Table 2-1 Interfaces for Using Privileges
int setppriv(priv_op_t op, priv_ptype_t which, \ const priv_set_t *set);
op represents the privilege operation that is to be performed. The op parameter has one of three possible values:
PRIV_ON – Adds the privileges that are specified by the set variable to the set type that is specified by which
PRIV_OFF – Removes the privileges that are specified by the set variable from the set type that is specified by which
PRIV_SET – Uses the privileges that are specified by the set variable to replace privileges in the set type that is specified by which
which specifies the type of privilege set to be changed, as follows:
set specifies the privileges to be used in the change operation.
In addition, a convenience function is provided: priv_set().
priv_set_t *priv_str_to_set(const char *buf, const char *set, \ const char **endptr);
priv_str_to_set() takes a string of privilege names that are specified in buf. priv_str_to_set() returns a set of privilege values that can be combined with one of the four privilege sets. **endptr can be used to debug parsing errors. Note that the following keywords can be included in buf:
“all” indicates all defined privileges. “all,!priv_name,...” enables you to specify all privileges except the indicated privileges.
Note - Constructions that use “priv_set, “!priv_name,...” subtract the specified privilege from the specified set of privileges. Do not use “!priv_name,...” without first specifying a set because with no privilege set to subtract from, the construction subtracts the specified privileges from an empty set of privileges and effectively indicates no privileges.
“none” indicates no privileges.
“basic” indicates the set of privileges that are required to perform operations that are traditionally granted to all users on login to a standard UNIX operating system.
This section compares how privileges are bracketed using the superuser model and the least privilege model.
Example 2-1 Superuser Privilege Bracketing Example
/* Program start */ uid = getuid(); seteuid(uid); /* Privilege bracketing */ seteuid(0); /* Code requiring superuser capability */ ... /* End of code requiring superuser capability */ seteuid(uid); ... /* Give up superuser ability permanently */ setreuid(uid,uid);
The program is setuid 0.
The permitted and effective sets are initially set to all privileges as a result of setuid 0.
The inheritable set is initially set to the basic privileges.
The limit set is initially set to all privileges.
An explanation of the example follows the code listing.
Note - The source code for this example is also available through the Sun download center. See http://www.sun.com/download/products.xml?id=41912db5.
Example 2-2 Least Privilege Bracketing Example
1 #include <priv.h> 2 /* Always use the basic set. The Basic set might grow in future 3 * releases and potentially retrict actions that are currently 4 * unrestricted */ 5 priv_set_t *temp = priv_str_to_set("basic", ",", NULL); 6 /* PRIV_FILE_DAC_READ is needed in this example */ 7 (void) priv_addset(temp, PRIV_FILE_DAC_READ); 8 /* PRIV_PROC_EXEC is no longer needed after program starts */ 9 (void) priv_delset(temp, PRIV_PROC_EXEC); 10 /* Compute the set of privileges that are never needed */ 11 priv_inverse(temp); 12 /* Remove the set of unneeded privs from Permitted (and by 13 * implication from Effective) */ 14 (void) setppriv(PRIV_OFF, PRIV_PERMITTED, temp); 15 /* Remove unneeded priv set from Limit to be safe */ 16 (void) setppriv(PRIV_OFF, PRIV_LIMIT, temp); 17 /* Done with temp */ 18 priv_freeset(temp); 19 /* Now get rid of the euid that brought us extra privs */ 20 (void) seteuid(getuid()); 21 /* Toggle PRIV_FILE_DAC_READ off while it is unneeded */ 22 priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_FILE_DAC_READ, NULL); 23 /* Toggle PRIV_FILE_DAC_READ on when special privilege is needed*/ 24 priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_FILE_DAC_READ, NULL); 25 fd = open("/some/retricted/file", O_RDONLY); 26 /* Toggle PRIV_FILE_DAC_READ off after it has been used */ 27 priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_FILE_DAC_READ, NULL); 28 /* Remove PRIV_FILE_DAC_READ when it is no longer needed */ 29 priv_set(PRIV_OFF, PRIV_ALLSETS, PRIV_FILE_DAC_READ, NULL);
The program defines a variable that is named temp. The temp variable determines the set of privileges that are not needed by this program. Initially in line 5, temp is defined to contain the set of basic privileges. In line 7, the file_dac_read privilege is added to temp. The proc_exec privilege is necessary to exec(1) new processes, which is not permitted in this program. Therefore, proc_exec is removed from temp in line 9 so that the exec(1) command cannot execute new processes.
At this point, temp contains only those privileges that are needed by the program, that is, the basic set plus file_dac_read minus proc_exec. In line 11, the priv_inverse() function computes the inverse of temp and resets the value of temp to the inverse. The inverse is the result of subtracting the specified set, temp in this case, from the set of all possible privileges. As a result of line 11, temp now contains those privileges that are never needed by the program. In line 14, the unneeded privileges that are defined by temp are subtracted from the permitted set. This removal effectively removes the privileges from the effective set as well. In line 16, the unneeded privileges are removed from the limit set. In line 18, the temp variable is freed, since temp is no longer needed.
This program is aware of privileges. Accordingly, the program does not use setuid and can reset the effective UID to the user's real UID in line 20.
The file_dac_read privilege is turned off in line 22 through removal from the effective set. In a real program, other activities would take place before file_dac_read is needed. In this sample program, file_dac_read is needed for to read a file in line 25. Accordingly, file_dac_read is turned on in line 24. Immediately after the file is read, file_dac_read is again removed from the effective set. When all files have been read, file_dac_read is removed for good by turning off file_dac_read in all privilege sets.
The following table shows the transition of the privilege sets as the program progresses. The line numbers are indicated.
Table 2-2 Privilege Set Transition