Trusted Solaris Developer's Guide

Chapter 2 Getting Started

This chapter contains short code examples to introduce you to some of the Trusted Solaris programming interfaces. The first section shows how to query the system security configuration, and how to query and set security attribute information for file systems and processes. The second section presents a short overview of Trusted Solaris security mechanisms. The major topics in this chapter are:

System Security Configuration and Attribute Information

System security configuration variables provide system-wide information on the system configuration. Some applications query system variables before taking actions that might be affected by the status of the system's security configuration.

File system security attributes and flags provide security-related information for specified local and mounted file systems. Applications might need to know the status of file system security attributes and flags. For example, an application can query the file system default access control list (ACL) before performing a directory operation, or can find out if a directory is a multilevel directory before creating a new file in it.

Process security attribute flags provide information on the calling process. Applications might need to know the status of a process security attribute flag to, for example, know whether the process was started from an administrative role (trusted path flag set) or by a normal user (trusted path flag not set).

Programming Interfaces

The programming interfaces and code examples to check system security configuration and security attribute information are provided here. Descriptions of the data handled by these calls are in the appropriate chapter. For example, Chapter 4, Labels covers labels and Chapter 3, Privileges covers privileges.

In cases where there is one set of interfaces to access a file using the pathname and another to access a file by the file descriptor, the examples that follow show the pathname only because the syntax is nearly identical.

All examples in this section compile with the -ltsol library.

System Security Configuration

This system call gets information on the system security configuration. Refer to the secconf(2) man page.

long secconf(int name);

File System Security Attributes

These system calls get information on file system security attributes using a path name or file descriptor. Refer to the getfsattr(2) man page.

int getfsattr(char *path, u_long type,
	void *buf_P, int len);
int fgetfsattr(int fd, u_long type, void *buf_P);

File System Security Attribute Flags

These system calls get information on file system security attribute flags using a path name or file descriptor. Refer to the getfattrflag(2) man page.

int fgetfattrflag(const char *path, secflgs_t *flags);
int setfattrflag(const char *path, secflgs_t which,
	secflgs_t flags);
int fsetfattrflag(int fildes, secflgs_t *flags);
int getfattrflag(int fildes, secflgs_t *flags);
int mldgetfattrflag(const char *path, secflgs_t *flags)
int mldsetfattrflag(const char * path, secflgs_t which,
	secflgs_t flags)

Process Security Attribute Flags

These system calls get and set process security attribute flags. Refer to the getpattr(2) man page.

int getpattr(pattr_type_t type, pattr_flag_t *value);
int setpattr(pattr_type_t type, pattr_flag_t value);

Query System Security Configuration

System variables provide information on how the system is configured. The system variables are initialized at system start up, and when there is no entry in system(4), default values are used. An application can query the system variables with the secconf(2) system call. The following variables are defined in /etc/system and have the default values listed:

_TSOL_HIDE_UPGRADED_NAMES - When a directory contains a file or subdirectory that has had its sensitivity label upgraded by a privileged process, this variable determines whether or not those upgraded files or subdirectories can be listed or obtained by system call requests such as getdents(2). Default is off. When off, names of upgraded files and subdirectories are visible when listing directories. When on, names of upgraded files or subdirectories are hidden.

_TSOL_PRIVS_DEBUG - Enable privilege debugging. Default is off. See Trusted Solaris Administrator's Procedures or "Privilege Debugging" for information on how to enable and use privilege debugging.

This code queries the system variables to show their current values.

#include <tsol/secconf.h>

main()
{

long retval;


	retval = secconf(_TSOL_HIDE_UPGRADED_NAMES);
	printf("Hide Names = %d\n", retval);

	retval = secconf(_TSOL_PRIVS_DEBUG);
	printf("Priv Debug = %d\n", retval);
}

The printf statements print the following. A retval of 1 means the variable is on; 0 means off; and -1 means an error has occurred. errno is set only when the input variable is invalid.


Hide Names = 0
Priv Debug = 0

Query File System Security Attributes

File system security attributes fill in absent security attributes on local and mounted file system objects that were not assigned a full set of security attributes by the system administrator or did not acquire them from their creating process. You can get file system security attributes from the vfstab(4) and vfstab_adjunct(4) files, or from the file or directory inode.

Get Attributes from Adjunct File

The vfstab_adjunct(4) file contains remote mount points and their related security information. This file is set up and maintained by the system administrator so that file systems mounted to local workstations from remote workstations have the correct security attributes.

This example retrieves and displays lines from vfstab_adjunct(4). The getvfsaent(3TSOL) routine first reads the top line of the file and with each subsequent call reads the next lines one-by-one. The getvfsaent(3TSOL) routine reads the line for the mount point specified by the input file.


Note -

Be sure to include stdio.h as shown in the example code below.


#include <stdio.h>
#include <tsol/vfstab_adjunct.h>

main()
{
	struct vfsaent *entry;
	char *vfsfile = "/etc/security/tsol/vfstab_adjunct";
	char *file = "/shark/doc";
	int retval;
	FILE *fp;

	fp = fopen(vfsfile, "r");
	if (fp == NULL) {
 		printf("Can't open %s\n", vfsfile);
 		exit(1);
	}

/* Step through file line-by-line. */
	retval = getvfsaent(fp, &entry);
	if (retval == 0) {
 		printf("Mount Point is %s \n Security Info is %s\n",
 		entry->vfsa_fsname, entry->vfsa_attr);
 		free(entry);
	}
	else
		 printf("No entries!\n");

	fseek(fp, 0, 0);

/* Retrieve specific mount point. */
	retval = getvfsafile(fp, &entry, file);
	if (retval == 0) {
		 printf("Mount Point is %s \nSecurity Info is %s\n",
		 entry->vfsa_fsname, entry->vfsa_attr);
		 free(entry);
	}
	else
		 printf("Mount point not found.\n");
	fclose(fp);
}

The printf statements print the following. There is only one entry in this vfstab_adjunct file for the /opt/SUNWspro mount point:


Mount Point is /opt/SUNWspro
Security Info is slabel=[C]:allowed all
Mount Point not found

Get Attributes from inode

The following code gets the CMW label (FSA_LABEL) of file and returns it in buffer.

#include <tsol/fsattr.h>
#include <tsol/label.h>

main()
{
	char *file = "/export";
	char buffer [3*1024], *string = (char *)0;
	int length, retval;

	length = sizeof(buffer);
	retval = getfsattr(file, FSA_LABEL, buffer, length);
	retval = bcltos((bclabel_t *)buffer, &string, 0, VIEW_INTERNAL);
	printf("/export CMW label = %s \n", buffer);
}

The printf statement prints the following:

/export CMW label = [ADMIN_LOW]

Manifest Constant Values

Manifest constant values can be any one of the following:

FSA_ACLCNT - File system access Access Control List (ACL) count.

FSA_ACL - File system access ACL.

FSA_APRIV - File system allowed privilege set.

FSA_FPRIV - File system forced privilege set.

FSA_LABEL - File system CMW label.

FSA_AFLAGS - File system attribute flags as described in "Get and Set File System Security Attribute Flags".

FSA_LBLRNG - File system label range.

FSA_MLDPFX - File system MLD prefix string.

FSA_APSACNT - Number of classes in the process audit preselection mask.

FSA_APSA - Classes in the process audit preselection mask. The process needs the file_audit privilege in its effective set to get this information. See "Privileges and Authorizations" for more information.

Manifest Constant Descriptions

The programming interfaces for accessing CMW labels, file system label ranges, file privileges, and multilevel directories are described briefly in "Trusted Solaris Security Mechanisms" and in more detail in their respective chapters in this guide.

Get and Set File System Security Attribute Flags

This example sets the public attribute flag on a regular directory and gets the MLD flag of a multi-level directory. The process needs the file_owner and file_audit privileges for this example to work. Use setfpriv(1) to set the privileges as follows. The file_setpriv privilege is required with setfpriv(1) so this command must be executed from the profile shell with this privilege.


phoenix% setfpriv -s -a file_owner,file_audit executable
#include <tsol/secflgs.h>
main()
{
	secflgs_t value;
	char *file = "/opt/SUNWspro"; /* Not MLD */
	char *file1 = "/export/home/zelda"; /* MLD */
	int retval;

	retval = setfattrflag(file, FAF_PUBLIC, FAF_PUBLIC);
	retval = getfattrflag(file, &value);
	printf("Public Attribute Flag = %d\n", value);

	retval = mldgetfattrflag(file1, &value);
	printf("MLD Attribute Flag = %d\n", value);
}

The printf statements print the following where 1 equals True and 0 equals false.


Public Attribute Flag = 0
MLD Attribute Flag = 1

FAF_MLD - Directory is a multi-level directory. FAF_MLD may be set without privilege if the directory is empty, the effective user ID of the process matches the directory owner, and the process has mandatory write access.

FAF_SLD - Directory is a single-level directory. This flag cannot be set programmatically.

If an adorned pathname is passed to getfattrflag(1), FAF_MLD is returned if the directory is an MLD. If an unadorned pathname is passed and if the directory is an MLD, FAF_SLD is returned.

If an adorned pathname is passed to mldgetfattrflag(2), FAF_SLD is returned if the directory is an MLD. If an unadorned pathname is passed and if the directory is an MLD, FAF_MLD is returned.

Adorned names are described in Chapter 7, Multilevel Directories.

FAF_PUBLIC - File or directory is public. Audit records are not generated for read operations on public files and directories even when the read operations are part of a preselected audit class. This applies to the following read operations: access(2), fstatvfs(2), lstat(2), open(2) (read only), pathconf(2), readlink(2), stat(2), and statvfs(2).


Note -

If the AUE_MAC or AUE_UPRIV audit pseudo events are in a preselected audit class, an audit record for those events is always generated regardless of the public attribute flag setting. See Trusted Solaris Audit Administration for more information on these pseudo audit events.


The process needs the file_audit and file_owner privileges in its effective set to get or set the public attribute flag for a file or directory. See "Privileges and Authorizations" for more information. This flag can also be administratively set as described in Trusted Solaris Administrator's Procedures.

FAF_ALL - The directory is a public MLD.

Get and Set Process Security Attribute Flags

Use getpattr(2) to query the attribute flags of the calling process.

#include <tsol/pattr.h>

main()
{
	int retval;
	pattr_flag_t value;

	retval = getpattr(PAF_TRUSTED_PATH, &value);
	printf("Trusted Path Value = %d\n", value);

	retval = getpattr(PAF_PRIV_DBG, &value);
	printf("Priv Debug value = %d\n", value);

	retval = getpattr(PAF_TOKMAPPER, &value);
	printf("Trusted Network Value = %d\n", value);

	retval = getpattr(PAF_DISKLESS_BOOT, &value);
	printf("Diskless Boot Value = %d\n", value);

	retval = getpattr(PAF_SELAGNT, &value);
	printf("Bypass Selection Agent Value = %d\n", value);

	retval = getpattr(PAF_PRINT_SYSTEM, &value);
	printf("Print System Value = %d\n", value);

	retval = getpattr(PAF_LABEL_VIEW, &value);
	printf("Label View Value = %d\n", value);

	retval = getpattr(PAF_LABEL_XLATE, &value);
	printf("Label Translate Value = %x\n", value);

	retval = getpattr(PAF_AUTOMOUNT, &value);
	printf("Automounter Value = %x\n", value);
}

The printf statements print the following where a value of 0 means the flag is off, and a value of 1 means it is on. The label translation value is 0 when off and a hexadecimal value representing the label translation flags when on. See "Manifest Constant Values" for a description of the process attribute flags.


Trusted Path Value = 0
Priv Debug Value = 0
Trusted Network Value = 0
Diskless Boot value = 0
Bypass Selection Agent Value = 0
Print System Value = 0
Label View Value = 1
Label Translate Value = 1
Automounter Value = 1

Manifest Constant Values

PAF_TRUSTED_PATH: The trusted path flag is set for all administrative roles. Any process started from an administrative role has this flag set to 1. All other processes have this flag set to 0. This flag can be queried and cleared, but not set.

PAF_PRIV_DEBUG: The privilege debug flag is set to 1 when the process is started in privilege debugging mode. This flag can be queried by any process, but set only by a trusted path process. Enabling and using privilege debugging mode is described in Trusted Solaris Administrator's Procedures and "Privilege Debugging" in Appendix A, Programmer's Reference.

PAF_NO_TOKMAP: The trusted computing base network flag is set to 1 only on trusted computing base applications that send packets without security attributes to workstations that expect packets with security attributes.

PAF_DISKLESS_BOOT: The diskless boot flag supports diskless boot servers. When this flag is set to 1, the security attribute information in network packet headers is not sent.

PAF_SELAGNT: The selection agent flag when set to 1 permits a process to bypass the Selection Manager when moving data from one window to another. See "Moving Data Between Windows" for more information.

PAF_PRINT_SYSTEM: The print system flag when set to 1 identifies a client process as a member of the printing subsystem.

PAF_LABEL_VIEW: When a user or role starts a process, this flag is set according to the label view specification in the label_encodings file or user label view setting in the /etc/security/tsol/tsoluser file. The label view applies to how the ADMIN_HIGH and ADMIN_LOW administrative labels are viewed in the system by users. The setting in the tsoluser file (if one exists) takes precedence over the setting in the label_encodings file.

A value of zero indicates the external view is in use and a value of 1 indicates the internal view is in use. Regardless of the value of this flag, a text to binary label translation can request the text string output for an administrative label to use the internal or external name. See Chapter 5, Label Code Examples in "Binary to Text Label Translation Routines" for details.

PAF_LABEL_XLATE: The label translation flag when set to 1 indicates the flags= keyword option is in use in the label_encodings(4) file. This optional flag setting specifies which of 15 flags are associated with the word using this optional flag. Flags are not used by the system, but can be used by applications specifically written to use them to do such things as define certain words that appear only in printer banner labels (not in normal labels), or to define certain words that appear only in labels embedded in formal message traffic. This flag can be queried and set by a trusted path process only.

Trusted Solaris Security Mechanisms

This section provides short examples of the Trusted Solaris security mechanisms to give you an idea of how they are used. Every example in this section has a corresponding chapter, and the interface declarations can be found in the chapters. All examples compile with the -ltsol library, and in some cases, other libraries are also needed as noted with the example.

Privileges and Authorizations

Privileges let a process perform security-related tasks normally prohibited by the system security policy. Authorizations let a user perform privileged tasks not allowed to all users. Every authorization maps to a privileged task. Always check a user's authorizations before allowing a privileged task to take place.


Caution - Caution -

The development, testing, and debugging of privileged applications should always be on an isolated development machine to prevent bugs and incomplete code from compromising security policy on the main system.


Privileges distribute security-related powers so a process has enough power to perform a task and no more. Likewise, authorizations distribute security-related powers so each user or role has enough power to perform a task and no more.

The system administrator assigns authorizations to users and roles through an execution profile. The chkauth(3TSOL) routine accepts a valid user name and authorization as parameters and returns true if the authorization is assigned to that user. During development, privileges can be assigned to the executable file and/or inherited from the user's or role's executable profile at run time.

To know if a program performs tasks that require privilege and user authorization checks, ask these questions:

This example checks the process permitted set for the file_downgrade_sl privilege, and the user authorization solaris.label.file.downgrade for user ID zelda before performing a task that involves downgrading the sensitivity label on a file. If the privilege is in the permitted set and if zelda has the authorization, the code turns the file_downgrade_sl privilege on in the effective set (makes the privilege effective) and performs the task. When the task completes, file_downgrade_sl is turned off (is no longer effective).

The example compiles with the following libraries:


-lsecdb -lnsl -lcmd -ltsol

Note -

The permitted set contains the privileges the process can potentially use during execution, and the effective set contains the privileges the process is actually using at a given time. Turning effective privileges on and off is called privilege bracketing and is discussed in Chapter 3, Privileges.


#include <tsol/priv.h>
#include <tsol/auth.h>

main()
{
	char *zelda = "zelda";
	priv_set_t priv_set;

/* Retrieve the permitted privilege set */
	getppriv(PRIV_PERMITTED, &priv_set);

	if(PRIV_ISASSERT(&priv_set, PRIV_FILE_DOWNGRADE_SL) &&
		chkauthattr(solaris.label.file.downgrade, zelda)) {
		set_effective_priv(PRIV_ON, 1, PRIV_FILE_DOWNGRADE_SL);
		/* Downgrade sensitivity label on file*/
		set_effective_priv(PRIV_OFF, 1, PRIV_FILE_DOWNGRADE_SL);
	}
	else {/* Raise Errors */}
}

CMW Labels and Clearances

When a process writes to a file with a higher sensitivity label or changes the CMW label of an object, the system checks that the file sensitivity label dominates the process sensitivity label and the process clearance dominates the file sensitivity label. If your application writes to files at different sensitivity labels, you might want to perform these checks in the code to catch errors or to turn privileges on in the effective set as needed.

This code performs the following tasks:

Chapter 4, Labels and Chapter 6, Process Clearance describe the programming interfaces for translating a binary label or clearance to text so they can be handled like a string.

#include <tsol/label.h>
main()
{
	int retval, retvalclearance, retvalsens;
	bclabel_t filecmwlabel, processcmwlabel;
	bslabel_t filesenslabel, processsenslabel;
	bclear_t processclearance;
	char *file = "/export/home/labelfile";

/* Get CMW label of file */
	retval = getcmwlabel(file, &filecmwlabel);

/* Get Process CMW label */
	retval = getcmwplabel(&processcmwlabel);

/* Get sensitivity label portion of CMW labels */
	getcsl(&filesenslabel, &filecmwlabel);
	getcsl(&processsenslabel, &processcmwlabel);

/* Get process clearance */
	retval = getclearance(&processclearance);

/* See if process label dominates file label (retvalclearance > 0) */
	retvalclearance = bldominates(&processsenslabel, &filesenslabel);

/* See if process clearance dominates file label (retvalsens > 0) */
	retvalsens = bldominates(&processclearance, &filesenslabel);

/* Test results */
	if(retvalclearance && retvalsens > 0)
		{ /* Change file CMW label or write-up to file */}
	else if (retvalclearance == 0)
		{ /* Turn on error message or make appropriate privilege
		     effective */}
	else if (retvalsens == 0)
		{ /* Turn on error message or make appropriate privilege
		     effective*/}
}

Multilevel Directories

Multilevel directories (MLDs) enable an application to run at different sensitivity labels and access data in the single-level directory (SLD) at the sensitivity label at which its process was launched. This example shows how to get the name for the Confidential SLD in the zelda MLD by translating a text string to binary with stobsl(3TSOL) and passing the binary label to getsldname(1). The /export/home/zelda MLD is at ADMIN_LOW and the process is running at Confidential. The process needs no privileges because it has mandatory read access to the MLD and the process sensitivity label dominates the SLD sensitivity label.

#include <tsol/mld.h>

char *file = "/export/home/zelda";
char buffer[3*1024];
bslabel_t senslabel;
int length, flags, retval, error;

main()
{
/* Get the Confidential SLD name */
	retval = stobsl("CONFIDENTIAL", &senslabel, NEW_LABEL, &error);
	length = sizeof(buffer);
	retval = getsldname(file, &senslabel, buffer, length);
	printf("SLD Name = %s\n", buffer);
}

The printf statement prints the name of the SLD at ADMIN_LOW. See Chapter 7, Multilevel Directories for the meaning of the SLD name.


SLD Name = .SLD.2

Note -

You can get file attribute information for an MLD or symbolic link that is an MLD with the mldstat(3TSOL) and mldlstat(3TSOL) system calls. See also the stat(2) man page and Chapter 7, Multilevel Directories.


Application Auditing

An application can log its own third-party audit events with the auditwrite(3TSOL) library routine. This example creates a user audit record in one call to auditwrite(). The audit event logged is AUE_su with the text "successful login at console". Normally, auditwrite() logs application-level audit events. This example logs a Trusted Solaris user event to show how the routine is used. Chapter 8, Application Auditing shows third-party audit events.

The process executing this program needs the proc_audit_tcb privilege in its effective set because AUE_su is a Trusted Computing Base (TCB) audit event. The code comments indicate where privilege bracketing as described in Chapter 3, Privileges should take place. The aw_strerror(3TSOL) routine converts auditwrite error messages (aw_errno) to strings. The parameters passed to auditwrite() are as follows:

#include <bsm/auditwrite.h>
#include <types.h>
#include <unistd.h>

main()
{
	char *aw_string;
	int retval, errno;

/* Turn proc_audit_tcb on in the effective set */
	retval = auditwrite( AW_EVENT, "AUE_su", AW_TEXT,
		"Successful login at console", AW_WRITE, AW_END);
/* Turn the proc_audit_tcb privilege off */

	aw_string = aw_strerror(aw_errno);
	printf("Retval = %d AW_ERROR = %s ERRNO = %d\n", retval,
		aw_string, errno);
}

To run the program and view the audit record, do the following:

  1. Assume an administrative role, open a terminal at ADMIN_HIGH, and execute the following command where lo is the class to which AUE_su belongs and pid is the process ID of the terminal.

    #auditconfig -setpmask pid lo

  2. Assume an administrative role, open a second viewing terminal at ADMIN_HIGH, and use praudit(1M) to read the not_terminated (most recent and not yet closed) audit log file by typing the command and options shown:


    Note -

    This syntax works when there is only one *not_terminated* file. If there are others, delete the older ones before executing this command.



    phoenix% tail -0f *not_terminated* | praudit
    
  3. Compile and run the code from the first terminal window.

    These libraries are needed for the example to successfully compile. -lbsm -lnsl -lintl -lsocket -ltsol

    The process needs the proc_audit_tcb privilege for this example to work. Use setfpriv(1) to set the privileges as follows. The file_setpriv privilege is required with setfpriv(1)so this command must be executed from the profile shell with this privilege. phoenix% setfpriv -s -a proc_audit_tcb executable

    The printf statement prints the following in the first terminal window:

    Retval = 0, AW_ERROR = No error, ERRNO = 0

    The viewing window shows the following audit record:


    header, 129,2,su,,Wed Jun 26 14:50:19 1996, +698 msec
    text, Successful login at console
    subject,zelda,zelda,staff,zelda,staff,1050,853,24,7 phoenix
    slabel,Confidential
    return,success,0

    The audit record consists of a sequence of tokens. Each line starts with a token followed by the token value. In the example, the tokens for audit event AUE_su are header, text, subject, slabel, and return; and the token values are the information following the tokens until the next token is encountered. Trusted Solaris Audit Administration describes the tokens in detail.

User and Rights Profile Databases

The information in the user_attr(4), prof_attr(4), and exec_attr(4) databases is accessible through library routines (see getuserattr(3SECDB), getprofattr(3SECDB), and getexecattr(3SECDB). User information is put into the databases by the system administrator through the Users Tool set in the Solaris Management Console.