Trusted Solaris Developer's Guide

Chapter 12 Trusted Security Information Exchange Library

The Trusted Security Information Exchange (TSIX) library provides interfaces for managing the security attribute information on a network message from within client and server applications. The TSIX library is based on Berkeley sockets and supports the transport layer interface (TLI).

The security attributes are stored in the data packet header separate from the message so they can be read separately. For example, an application can use the TSIX library to retrieve the security attributes and then test the sensitivity label attribute to determine whether or not the process needs privilege to read the data in the packet.

Security Attributes

By default, messages originating on a Trusted Solaris system acquire the following security attributes from the sending process:

The TSIX library lets you change the user ID, group ID, sensitivity label, process clearance, or privilege attributes before the message is sent.

The TSIX library also lets you retrieve the security attributes on an incoming message. Because a distributed network can have any combination of host types running different Trusted networking protocols, not all protocols support all security attributes. Messages coming from or going to a host type other than a Trusted Solaris host will have very few of the above security attributes.

For example, the audit ID, audit information, and supplementary group ID attributes can only be sent from and received by a host running the TSIX protocol, and when a packet originates on a Solaris host, none of the Solaris security attributes are present when the packet arrives on a Trusted Solaris host.


Note -

The TSIX library can be used in any application written for the Trusted Solaris environment. The TSIX protocol is not required to use the TSIX library.


Default security attributes are assigned to messages arriving on Trusted Solaris hosts from other host types according to settings in the network database files. Security attributes retrieved by TSIX library calls from incoming messages come out of the network database files if they did not arrive with the message. See the Trusted Solaris Administrator's document set for information on host types, their supported security attributes, and network database file defaults.

The sensitivity label of data sent over the network must be within the origination, destination, and next hop destination workstation accreditation ranges. There is no privilege to override this restriction.

Privileged Operations

No privileges are required to read security attributes retrieved from an incoming message. The following sections describe privileges used on outgoing messages.

Replying with Same Sensitivity Label

A server process can receive a message over a multilevel port at any sensitivity label dominated by the server process's clearance. However, the server reply is normally at the sensitivity label of the server process unless the server process has the net_reply_equal privilege in its effective set in which case the reply is sent at the sensitivity label of the last message received. See Chapter 10, Interprocess Communications for a discussion on single-level and multilevel ports.


Note -

Make sure the net_reply_equal privilege is turned off if the receiving process needs to reply at a sensitivity label different from that of the requesting process. See "TCP/IP Server" for an example situation where net_reply_equal must be turned off.


Changing Sensitivity Label

To respond to a single-level client, the server process needs the proc_set_sl privilege in its effective set to change the sensitivity label of its child to be the same as the sensitivity label of the requesting client.

Changing Security Attribute Information

To change the user ID, group ID, sensitivity label, process clearance, or privilege security attribute on an outgoing message or on the communication endpoint for outgoing messages, a process needs the appropriate network privilege in its effective set.

Sensitivity Labels

The sending process can set the sensitivity label for a message or communication endpoint to a new sensitivity label that does not dominate the object's existing sensitivity label if it has the net_downgrade_sl privilege in its effective set. The sending process can set the sensitivity label for a message or communication endpoint to a new sensitivity label that dominates the existing object's sensitivity label it has the net_upgrade_sl privilege in its effective set.

Process Clearance

The sending process needs the net_setclr privilege in its effective set to change the clearance sent with the message.

The system ensures that the clearance always dominates the sensitivity label. There is no privilege to override this restriction.

User and Group IDs

The sending process needs the net_setid privilege in its effective set to change the user or group ID.

Privileges

The sending process needs the net_setpriv privilege in its effective set to specify privileges to be sent with the message. The specified privileges must be in the permitted set of the sending process.

Data Types, Header Files, and Libraries

To use the programming interfaces described in this chapter, you need the following header file.


#include <tsix/t6attrs.h>

The examples in this chapter compile with the following libraries:


-lsocket -lt6 -ltsol

Attribute Structure

The t6attr_t data structure can hold the full set security attributes.

Attribute Enumerations

The t6attr_id_t structure contains enumerated constants that represent the full set of security attribute values. Variables of type t6attr_t are initialized with these constants. Most of the constants have a fixed size in bytes as shown below; however, T6_GROUPS, has a variable size that reflects the actual size of its value.

Enumerated Constant 

Description 

Data Type 

Size in Bytes 

T6_SL

Sensitivity label 

bslabel_t 

36 

T6_SESSION_ID

Network session ID 

sid_t 

T6_CLEARANCE

Clearance 

bclear_t 

36 

T6_PRIVILEGES

Effective privileges 

priv_set_t 

16 

T6_AUDIT_ID

Audit ID 

au_id_t 

T6_PID

Process ID 

pid_t 

T6_AUDIT_INFO

Additional audit info 

auditinfo_t 

24 

T6_UID

Effective User ID 

uid_t 

T6_GID

Effective Group ID 

gid_t 

T6_GROUPS

Supplementary Group IDs 

gid_t 

Variable 

T6_PROC_ATTR

Process Attribute Flags 

pattr_t 

Attribute Mask

The t6mask_t data structure represents the set of security attributes of current interest. A variable of type t6mask_t is initialized by assigning the following enumerated values.

T6M_SL

Sensitivity label 

T6M_SESSION_ID

Network session ID 

T6M_CLEARANCE

Clearance 

T6M_PRIVILEGES

Effective privilege set 

T6M_AUDIT_ID

Audit ID 

T6M_PID

Process ID 

T6M_AUDIT_INFO

Terminal ID and preselection masks 

T6M_UID

Effective User ID 

T6M_GID

Effective Group ID 

T6M_GROUPS

Supplementary Group IDs 

T6M_NO_ATTRS

No attributes 

T6M_ALL_ATTRS

All attributes 

Programming Interface Declarations

These network library routines handle security attributes on messages sent to and received from a Trusted Solaris host.

Get Attribute Masks

These routines create an attribute mask of system supported security attributes, attributes of the space allocated in the attribute structure, and attributes present in an attribute structure. You can use these routines instead of assigning t6mask_t enumerated values to a mask variable.

t6mask_t t6supported_attrs(void);
t6mask_t t6allocated_attrs(t6attr_t t6ctl);
t6mask_t t6present_attrs(t6attr_t t6ctl);

Allocate and Free Space

The t6alloc_blk(3NSL) routine creates a security attribute structure with enough space allocated for the security attributes specified in new_attrs. The t6free_blk(3NSL) routine frees the space allocated for the security attribute structure t6ctl.

t6attr_t t6alloc_blk(t6mask_t mask);
void t6free_blk(t6attr_t t6ctl);

Send and Receive Data

The t6sendto(3NSL) routine sends security attributes with a message. The t6recvfrom(3NSL) routine receives a message and its security attributes. When t6new_attr(3NSL) is on, t6recvfrom(3NSL) receives security attributes only when the attributes in new_attrs have changed.


Note -

These routines are specific to sockets. For Transport Layer Interface (TLI), use t6last_attr(3NSL) in place of t6recvfrom(3NSL) and t6new_attr(3NSL); and t6set_endpt_default(3NSL) in place of t6sendto(3NSL).


ssize_t t6sendto(int sock,
	const char *msg,
	size_t len,
	int flags,
	const struct sockaddr *name,
	socklen_t namelen,
	const t6attr_t handle);

ssize_t t6recvfrom(int sock,
	void *buffer,
	size_t len,
	int flags,
	struct sockaddr *name,
	Psocklen_t namelenp,
	t6attr_t handle,
	t6mask_t *new_mask);

int t6new_attr(int fd, t6cmd_t cmd);

Get and Set Security Attributes

The t6get_attr(3NSL) routine gets the attribute in attr_type from the security attribute structure t6ctl. The return value should be cast to the correct type as described in "Attribute Enumerations".

The t6set_attr(3NSL) routine sets the attribute in attr_type with the value specified in attr in the security attribute structure t6ctl.

void *t6get_attr(t6attr_id_t attr_type,
	const t6attr_t t6ctl);

int t6set_attr(t6attr_id_t attr_type,
	const void *attr,
	t6attr_t t6ctl);

Examine Security Attributes

The t6peek_attr(3NSL) routine examines the security attributes in attr_ptr on the next byte of data to be received, and the t6last_attr(3NSL) routine examines the security attributes on the last byte of data received.

int t6peek_attr(int fd, t6attr_t attr_ptr, t6mask_t *new_attrs);

int t6last_attr(int fd, t6attr_t attr_ptr, t6mask_t *new_attrs);

Get the Size of One Security Attribute

The t6size_attr(3NSL) routine gets the size in bytes of the value for the security attribute specified in attr_type in the security attribute structure t6ctl.

size_t t6size_attr(t6attr_id_t attr_type, const t6attr_t t6ctl);

Copy and Duplicate Security Attributes

These routines make a copy of attr_src. Refer to the t6copy_blk(3NSL) and t6dup_blk(3NSL) man pages.

int t6copy_blk(const t6attr_t attr_src, t6attr_t attr_dest);
t6attr_t t6dup_blk(const t6attr_t attr_src);

Compare Security Attributes

This routine compares one security attribute structure to another. Refer to the t6cmp_blk(3NSL) man page.

int t6cmp_blk(t6attr_t t6ctl1, t6attr_t t6ctl2);

Clear Security Attributes

This routine clears the attributes specified in mask from t6ctl. Refer to the t6clear_blk(3NSL) man page.

void t6clear_blk(t6mask_t mask, t6attr_t t6ctl);

Get and Set Endpoint Attributes

The t6set_endpt_default(3NSL) routine sets the security attribute values in attr indicated by mask on the communication endpoint. The t6get_endpt_mask(3NSL) routine sets the endpoint mask only.

The t6get_endpt_default(3NSL) routine gets the security attribute values in attr indicated by mask from the communication endpoint. The t6get_endpt_mask(3NSL) routine gets the endpoint mask only.

int t6get_endpt_default(int fd,
	t6mask_t *mask,
	t6attr_t attr);

int t6set_endpt_mask(int fd,
	t6mask_t mask);

int t6set_endpt_default(int fd,
	t6mask_t mask,
	const t6attr_t attr_ptr);

int t6get_endpt_mask(int fd,
	t6mask_t *mask);

Turn Extended Security Operations On and Off

This routine turns the extended security operations on and off for compatibility with other vendors. The operations are on by default. When off, messages can be sent and received as long as the communications are with the mandatory and discretionary access controls of the system. Refer to the t6ext_attr(3NSL) man page.

int t6ext_attr(int fd, t6cmd_t cmd);

Getting and Setting Security Attributes

These examples show how to set up a security attribute structure and masks to specify security attributes on outgoing data. The first example sets new security attributes on the message, and the second example sets new security attributes on the communication endpoint.

Security Attributes on Messages

This example sets up new sensitivity label and clearance attribute values to send with msg. This is done by doing the following:

Because the process sending msg is at Confidential, it needs the net_setclr and net_upgrade_sl privileges in its effective set to change the clearance and sensitivity label. The new sensitivity label and clearance override the sensitivity label and clearance msg received from its sending process. The code comments indicate where privilege bracketing as described in Chapter 3, Privileges should take place.

#include <tsix/t6attrs.h>
#include <label.h>
main()
{
	int retval, sock, error;
	t6attr_t sendattrs;
	t6mask_t sendmask;
	char *msg = "Hello World!";
	bslabel_t senslabel;
	bclear_t clearance;
	struct sockaddr_in sin;

/* Initialize a mask with the sensitivity label and */
/* process clearance security attribute fields */
	sendmask = T6M_SL | T6M_CLEARANCE;
/* Allocate space for two security attribute structures */
/* using the masks so only the space needed is allocated */
	sendattrs = t6alloc_blk(sendmask);
/* Initialize senslabel and clearance to Top Secret */
	stobsl("TOP SECRET", &senslabel;, NEW_LABEL, &error;);
	stobclear("TOP SECRET", &clearance;, NEW_LABEL, &error;);
/* Set attribute values for the security attribute fields */
/* to be sent with the message */
	retval = t6set_attr(T6_SL, &senslabel;, sendattrs);
	printf("Retval1 = %d\n", retval);
	retval = t6set_attr(T6_CLEARANCE, &clearance;, sendattrs);
	printf("Retval2 = %d\n", retval);
/* Set up socket communications */
/* ... */
/* Send changed security attributes with the message */
/* Turn net_setclr and net_upgrade_sl on in the effective set */
	retval = t6sendto(sock, msg, sizeof(msg), 0, (struct sockaddr *) &sin;,
		sizeof(sin), &sendattrs;);
/* Turn off the net_setclr and net_upgrade_sl privileges */
	printf("Retval3 = %d\n bytes", retval);
}

The printf statements print the following:


Retval1 = 0
Retval2 = 0
Retval3 = 4 bytes

Security Attributes on Communication Endpoints

The first part of this example sets only the sensitivity label security attribute specified in sendattrs on the communication endpoint by using a different mask (endptmask) with sendattrs. This way, when privileged process sends a message over the communication endpoint using a form of transmission other than the t6sendto(3NSL) routine, or using the t6sendto(3NSL) routine with an attribute set that does not specify the sensitivity label, the sensitivity label is picked up from the communication endpoint. Because the process setting security attributes on the communication endpoint is running at Secret, it needs the net_upgrade_sl privilege in its effective set. The code comments indicate where privilege bracketing as described in Chapter 3, Privileges should take place.

The next statements change the mask on the communication endpoint to sendmask, retrieve the endpoint mask and put it in getmask, allocate getattrs to hold a clearance, and get the binary clearance from the communication endpoint defaults and store it in getattrs.

Security attributes on the communication endpoint override the attributes acquired from the sending process. The security attributes on the message override the attributes from the communication endpoint.

#include <tsix/t6attrs.h>
include <tsol/label.h>
#include <tsol/priv.h>
main()
{ t6mask_t sendmask, endptmask, getmask;
	int fd, sock, retval;
	t6attr_t sendattrs, getattrs;
	sendmask = T6M_SL | T6M_CLEARANCE;
	sendattrs = t6alloc_blk(sendmask);


	if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
		perror("socket");
		exit(1);
	}
/* Initialize a mask with the sensitivity label field */
	endptmask = T6M_SL;
/* Set the attribute in sendattrs indicated by the mask */
/* Turn net_upgrade_sl on in the effective set */
	set_effective_priv(PRIV_ON, 1, PRIV_NET_UPGRADE_SL);

	retval = t6set_endpt_default(sock, endptmask, &sendattrs;);

	set_effective_priv(PRIV_OFF, 1, PRIV_NET_UPGRADE_SL);
	printf("t6set_endpt_default return val: %d\n", retval);
/* Turn off the net_upgrade_sl privilege */
/* Change the endpoint mask to a different mask */

	retval = t6set_endpt_mask(sock, sendmask);

	printf("t6set_endpt_mask return val: %d\n", retval);
/* Get the current endpoint mask */

	retval = t6get_endpt_mask(sock, &getmask;);

	printf("t6get_endpt_mask return val: %d\n", retval);
/* Get the default clearance on the endpoint */

	getmask = T6M_CLEARANCE;
	getattrs = t6alloc_blk(getmask);
	retval = t6get_endpt_default(sock, &getmask;, getattrs);

	printf("t6get_endpt_default return val: %d\n", retval);
}

Receiving and Retrieving Security Attributes

This example receives a message with security attributes and retrieves the security attribute information.

#include <tsix/t6attrs.h>
#include <tsol/label.h>
main()
{
	char buf[512];
	int retval, len = sizeof(buf), sock;
	t6mask_t recvmask;
	t6attr_t recvattrs;
	bslabel_t *senslabel;
	bclear_t *clearance;
	struct sockaddr_in sin;
	t6mask_t rcv_mask;

/* Initialize a mask with all security attribute fields */
	recvmask = T6M_ALL_ATTRS;
	recvattrs = t6alloc_blk(recvmask);
/* Code to set up socket communications */
/* ... */
/* Receive security attributes on the message */
	retval = t6recvfrom(sock, buf, len, 0,(struct sockaddr *) &sin;,
		sizeof (sin), recvattrs, &rcv_mask;);
/* Retrieve security attribute Values */
	senslabel = (bslabel_t *)t6get_attr(T6_SL, recvattrs);
	clearance = (bclear_t *)t6get_attr(T6_CLEARANCE, recvattrs);
}

The next example creates newmask with no attributes specified, calls the t6new_attr(3NSL) routine with a value of T6_ON, and calls the t6recvfrom(3NSL) routine with newmask. This combination tells the t6recvfrom() routine to get the security attribute information with the message only when one or more security attributes are different from the set of security attributes on the last message received. The t6recvfrom() call returns the full set of security attributes requested; not just the changed security attributes. When security attributes change, the newmask value becomes non-zero so you check this value to find out when to look for new security attributes.

#include <tsix/t6attrs.h>
#include <tsol/label.h>

main()
{
	char buf[512];
	int retval, len = sizeof(buf), sock;
	t6mask_t newmask;
	t6attr_t recvattrs;

/* Code to set up socket communications */
/* ... */

/* Create mask to look for change in the sensitivity label */
	newmask = T6M_NO_ATTRS;

/* Turn on new attributes and test for sensitivity label */
	retval = t6new_attr(sock, T6_ON) > 0;
	retval = t6recvfrom(sock, buf, len, 0, 0, 0, recvattrs, &newmask);

	if(newmask > 0)
		{/* Process security attribute information */}
}

Examining Attributes

You can retrieve the security attributes for either the next byte of data to be read or the last byte of data read. This example uses the sensitivity label mask to peek at the sensitivity label of the next byte of data and look up the sensitivity label on the last byte of data.

#include <tsix/t6attrs.h>
#include <tsol/label.h>

main()
{
	char buf[512]
	int retval, sock;
	int len = sizeof(buf);
	t6mask_t recvmask;
	t6attr_t recvattrs;

	recvmask = T6M_SL;
	recvattrs = t6alloc_blk(recvmask);

/* Code to set up socket communications */
/* ... */

/* Peek at sensitivity label on next byte of data */
	 retval = t6peek_attr(sock, recvattrs, &recvmask);

/* Look up sensitivity label on last byte of data */
	 retval = t6last_attr(sock, recvattrs, &recvmask);
}

Getting Attribute Size

The t6size_attr(3NSL) return value contains the size in bytes of the specified attribute if the call was successful and -1 otherwise. This example gets the size of the clearance attribute in sendattrs.

#include <tsix/t6attrs.h>
#include <tsol/label.h>

main()
{
	size_t size;
	t6attr_t sendattrs;

	size = t6size_attr(T6_CLEARANCE, sendattrs);
	printf("Clearance size = %d\n", size);
}

The printf(1)statement prints the following fixed size for clearances:


Clearance size = 36

Copying and Duplicating Attribute Structures

The TSIX library provides routines for copying and duplicating an attribute structure. They both do the same thing using different parameter lists. Use the one that meets your application requirements. This example shows the two ways to copy the security attributes in sendattrs to recvattrs.

#include <tsix/t6attrs.h>
#include <tsol/label.h>

main()
{
	size_t size;
	t6attr_t sendattrs, recvattrs;
	t6mask_t sendmask, recvmask;

	recvmask = T6M_SL;
	recvattrs = t6alloc_blk(recvmask);
	sendmask = T6M_CLEARANCE;
	sendattrs = t6alloc_blk(sendmask);

/* Copy the attributes in sendattrs to recvattrs */
	t6copy_blk(sendattrs, recvattrs);

/* Duplicate the attributes in sendattrs to recvattrs */
	recvattrs = t6dup_blk(sendattrs);
}

Compare Attribute Structures

This example compares the sendattrs with recvattrs for equality.

#include <tsix/t6attrs.h>
#include <tsol/label.h>

main()
{
	int retval;
	t6attr_t sendattrs, recvattrs;
	t6mask_t sendmask, recvmask;

	recvmask = T6M_SL;
	recvattrs = t6alloc_blk(recvmask);
	sendmask = T6M_SESSION_ID;
	sendattrs = t6alloc_blk(sendmask);

	retval = t6cmp_blk(sendattrs, recvattrs);
	printf("Does sendattrs = recvattrs? %d\n", retval);
}

The printf statement prints the following where 0 means the structures are equal and any non-zero value means they are not.


Does sendattrs = recvattrs? 5

Clear Attribute Structure

This example clears the session ID attribute value from recvattrs. Space is still allocated in the attribute structure, but the attribute values are NULL.

#include <tsix/t6attrs.h>
#include <tsol/label.h>

main()
{
	t6attr_t recvattrs;
	t6mask_t recvmask, clrmask;

	recvmask = T6M_ALL_ATTRS; recvattrs = t6alloc_blk(recvmask);
	clrmask = T6M_SESSION_ID;
	t6clear_blk(clrmask, recvattrs);
}

Creating Attribute Masks

This example shows three ways to create an attribute mask in addition to instantiating a mask structure and or'ing the desired enumerated fields.

#include <tsix/t6attrs.h>
#include <tsol/label.h>

main()
{
	t6mask_t suppmask, allocmask, presentmask;
	t6mask_t getmask, recvmask;
	t6attr_t attrs, getattrs, recvattrs;

	recvmask = T6M_ALL_ATTRS; recvattrs = t6alloc_blk(recvmask);
	getmask = T6M_CLEARANCE; getattrs = t6alloc_blk(getmask);

/* Get mask of system-supported attributes */
	suppmask = t6supported_attrs();

/* Get mask of attributes for which space is */
/* allocated in rcvattrs (T6M_ALL_ATTRS)*/
	allocmask = t6allocated_attrs(rcvattrs);

/* Get mask of attributes present in getattrs */
	presentmask = t6present_attrs(getattrs);
}

Free Space

At the end of a program, free all space allocated for variables of type t6attr_t.

t6free_blk(sendattrs);
t6free_blk(recvattrs);
t6free_blk(getattrs)
t6free_blk(attrs);

Client-Server Application

This section presents a short client-server application using Berkeley sockets and the TSIX library to transfer data and security attribute information across the network. The communication path is connection-oriented using the internet domain (TCP/IP). The server is a concurrent process that supplies information about upcoming meetings at different sensitivity levels. To get the service, the client connects to the server and requests the information for a specified sensitivity level.

TCP/IP Server

The server process uses the net_mac_read privilege to bind to a multilevel port to serve single-level clients at different sensitivity levels. Chapter 10, Interprocess Communications describes multilevel and single-level ports.

The msg_array structure contains meeting information at Confidential, Secret, Top Secret, and NULL. To respond to a single-level client, the server process needs the proc_set_sl privilege in its effective set to change the sensitivity label of its child to be the same as the client.

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>

#include <tsol/label.h>
#include <tsix/t6attrs.h>

struct msg {
	char *sl;
	bslabel_t *bsl;
	char *msg;
} msg_array[] = {
	{"CONFIDENTIAL", NULL, "Staff Meeting at 1:00 pm, Rm 200"},
	{"SECRET", NULL, "Manager Meeting at 10:00 am, Rm 303"},
	{"TOP SECRET", NULL, "Exective Meeting at 3:00 pm, Rm 902"},
	{NULL, NULL, NULL};
};

This first part of the main program sets the process clearance to ADMIN_HIGH so the child process can set its sensitivity label to the sensitivity label of the requesting client. The proc_setclr privilege is needed for this task.

The code comments indicate where privilege bracketing as described in Chapter 3, Privileges should take place. With privilege bracketing, the net_reply_equal privilege should be off so the server can reply to the client at the sensitivity label specified by the msg_array data and not the sensitivity label of the requesting client. The code comments show at what point the net_repy_equal privilege must be off for the example to work.

main(int argc, char **argv)
{
	int fd, newfd, chpid, index, error;
	struct sockaddr_in serv_addr;
	bclear_t clearance;

	if (argc != 2) {
		printf("Usage: %s host\n", argv[0]);
		exit(1);
	}
	printf("PID = %ld\n", getpid());

	/* Set the process clearance to ADMIN_HIGH
	/* Turn the proc_setclr privilege on in the effective set */

	bclearhigh(&clearance);
	if (setclearance(&clearance) != 0) {
		perror("setclearance");
		exit(1);
	}
	/* Turn the proc_setclr privilege off */

This next main program segment creates binary sensitivity label from the data in msg_array. The binary labels are used later with the TSIX library routines.

	/* Obtain binary labels for run time efficiency */

	index = 0;
	while (msg_array[index].sl != NULL) {
		if ((msg_array[index].bsl =
			(bslabel_t *) malloc(sizeof (bslabel_t))) == NULL) {
			printf("No memory");
			exit (1);
		}
		if (stobsl(msg_array[index].sl, msg_array[index].bsl,
			NEW_LABEL, &error) != 1) {
			printf("converting SL %s failed\n",
			msg_array[index].sl);
			exit(1);
		}
		index++;
	}

This next main program segment sets up endpoint communications by creating a socket, binding it to a name, and listening on the socket for client requests. The code comments indicate where privilege bracketing as described in Chapter 3, Privileges should take place.

	if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
		perror("socket");
		exit(1);
	}
	memset(&serv_addr, 0, sizeof (serv_addr));
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	serv_addr.sin_port = htons(10000);

/* Turn net_mac_read on in the effective set */
	if (bind(fd, (struct sockaddr *) &serv_addr,
		sizeof (serv_addr)) < 0) {
		perror("bind");
		exit(1);
	}
/* Turn the net_mac_read privilege off */

	listen(fd, 5);

The while loop accepts client connections on the socket and forks a process to handle each client request. The forked process prepares structures to receive the incoming message and its sensitivity label, and to set the sensitivity label portion of the process CMW label to the incoming sensitivity label. It also allocates handle_in with enough space to receive the sensitivity label on the incoming message, allocates handle_out with enough space to send a sensitivity label with the outgoing message, and receives the message and security attribute information with the t6recvfrom(3NSL) routine.

	while (1) {
		if ((newfd = accept(fd, NULL, 0)) < 0) {
			perror("accept");
			exit(1);
		}
		printf("Request Received\n");
		if ((chpid = fork()) < 0) {
			perror("fork");
			exit(1);
		} else if (chpid == 0) {        /* child process */
			t6attr_t handle_in;
			t6attr_t handle_out;
			t6mask_t mask_in = T6M_SL;
			int client_index = 0;
			bslabel_t *bsl;
			bclabel_t bcmwlabel;
			char buf[256];
			int index, buflen = 256;
			t6mask_t new_mask = T6M_NO_ATTRS;
			char *string = (char *) 0;
			char any;

			close(fd);
			printf("child PID = %ld\n", getpid());

/* Process client request */
			if ((handle_in = t6alloc_blk(mask_in)) == NULL) {
				printf("t6attr_alloc: no memory");
				exit(1);
			}
			if (t6recvfrom(newfd, buf, buflen, 0, 0, 0,
				handle_in, &new_mask) < 0) {
				perror("t6recvfrom");
				exit(1);
			}

The last main program segment extracts the sensitivity label received, sets the sensitivity label of the process to that of the client, and sends the reply to the client. The code comments indicate where privilege bracketing as described in Chapter 3, Privileges should take place.

	/* Get sensitivity label */
		if ((bsl = (bslabel_t *) t6get_attr(T6_SL,
				handle_in)) == NULL) {
				printf("t6get_attr: no SL available");
				exit(1);
		}
		if (bsltos(bsl, &string, 0, LONG_WORDS) < 0) {
				perror("bsltos");
				exit(1);
		}
		printf("Requestor's SL = %s\n", string);

	/* Set the sensitivity label of the child process to */
	/* that of the client */
		if (getcmwplabel(&bcmwlabel) != 0) {
				perror("getcmwplabel");
				exit(1);
		}
		setcsl(&bcmwlabel, bsl);

	/* Turn proc_set_sl on in the effective set */
		if (setcmwplabel(&bcmwlabel, SETCL_SL) < 0) {
				perror("setcmwplabel");
				exit (1);
		}
	/* Turn the proc_set_sl privilege off */

	/*
	 * Retreive the msg_array entry that matches the sensitivity
	 * label of the client.
	 */
		while (msg_array[client_index].sl != NULL) {
			if (blequal(bsl, msg_array[client_index].bsl)
			break;
			client_index++;
		}
		if (msg_array[client_index].sl == NULL) {
			perror("No message for the client's SL");
			exit (1);
		}
		send(new_fd, msg_array[client_index].msg,
			strlen(msg_array[client_index].msg));

		exit (0);

TCP/IP Client

To request the service, the client program connects to the server, sends a request, and waits for the meeting message. If the connection is closed before a message is received, the client exits because there is no meeting at its sensitivity label. If a message is received, the client uses t6recvfrom(3NSL) to obtain the message. Code to process the information is not shown in the example.

This first part of the program sets up data structures for the client request and server response.

#include <stdio.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <tsol/label.h>
#include <tsix/t6attrs.h>

char *clnt_req = "Request Meeting Info";

main(int argc, char **argv)
{
	int sock, retval;
	char buf[256];
	int buflen = 256;
	int num;
	struct sockaddr_in serv_addr;
	struct hostent *hostent;
	bslabel_t *bsl;
	t6mask_t new_mask, sl_mask = T6M_SL;
	t6attr_t handle;
	char    *string = (char *)0;

This next main program segment processes the command-line argc and argv inputs to get the host name and port number of the server and establishes a connection.

	if (argc != 2) {
		printf("Usage: %s host\n", argv[0]);
		exit (1);
	}
	if ((hostent = gethostbyname(argv[1])) == NULL) {
		perror("gethostbyname");
		exit(1);
	}

	memset((void *) &serv_addr, 0, sizeof (serv_addr));
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_port = htons(10000);
	memcpy((void *) &serv_addr.sin_addr,
		(void *) hostent->h_addr_list[0], hostent->h_length);

	if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
		perror("socket");
		exit(1);
	}
	if (connect(sock, (struct sockaddr *)&serv_addr,
		sizeof (serv_addr)) < 0) {
		perror("connect");
		exit(1);
	}
	printf("Connected\n");
	if ((handle = t6alloc_blk(sl_mask)) == NULL) {
		printf("t6attr_alloc: no memory");
		exit(1);
	}

This next main program segment sends the request to the server. The request is sent at the sensitivity label at which the client process is executing. When the server processes the request, it sends back meeting information for the sensitivity label at which the request is made only. The t6recvfrom(3NSL) routine receives the meeting information.

/* Send a request to server */
	write(sock, clnt_req, strlen(clnt_req));

	if ((num = t6recvfrom(sock, buf, buflen, 0, 0, 0, handle,
		&new_mask)) < 0) {
		perror("t6recvfrom");
		exit (1);
	} else if (num == 0) {
		printf("Connection closed, nothing matches.\n");
		exit(0);
	} else
		printf("Received Reply\n");

	retval = bsltos(bsl, &string, 0, LONG_WORDS);
	printf("Retval = %d, Sensitivity label = %s\n", retval, string);
	printf("Message = %s\n", buf);
}

Running the Programs

The server process starts and waits for a client request.


phoenix% serverProgram phoenix
PID = 655

When the client process is started at Confidential, the printf statements in the client print the following. The sensitivity label of the server does not matter because it is a multilevel connection.


phoenix% clientProgram phoenix
Received Reply
Message = Staff Meeting at 1:00 pm, Rm 200

The server process prints the following after fulfilling the client request:


Request Received
child PID = 657
Requestor's SL = C
Attributes List (alloc_mask = 0x00000040, attr_mask = 0x00000040):
child: exiting

In the following example, the client process is instead started at Secret.


phoenix% clientProgram phoenix
Received Reply
Message = Manager Meeting at 10:00 am, Rm 303

The server process prints the following after fulfilling the client request:


Request Received
child PID = 661
Requestor's SL = S
Attributes List (alloc_mask = 0x00000040, attr_mask = 0x00000040):
child: exiting