Trusted Solaris Developer's Guide

Chapter 13 Remote Procedure Calls

The Trusted Solaris remote procedure call (RPC) mechanism is built on Berkeley internet sockets and the Trusted Security Information Exchange (TSIX) library, and supports Transport Layer Interface (TLI). Trusted Solaris modifications to RPC enable a server process to receive security attribute information on incoming client requests, and change security attribute information on an outgoing response to a client. Chapter 12, Trusted Security Information Exchange Library describes the privileges required to change security attribute information on messages.

In addition, mappings have been extended to include sensitivity labels to separate and protect mappings according to their sensitivity label.

Mapping

Mapping is a relationship maintained by the RPC binder service between an ordered triple (program number, version number, and network ID) and a service address on a machine serviced by the RPC binder. The current set of mappings represents the available registered RPC services on a host. The Trusted Solaris environment supports single-level mapping and multilevel mapping.

Single-Level Mapping

A single-level mapping is a mapping the RPC binder service advertises only to clients that have the same sensitivity label as the server that created the mapping.

Multilevel Mapping

A multilevel mapping (MLM) is a mapping the RPC binder service advertises to all clients regardless of their sensitivity label. A multilevel mapping is created when a server has the net_mac_read privilege in its effective set when it makes the RPC library call to register the service with the RPC binder service.

Multilevel Ports

A multilevel port is created when a server has the net_mac_read privilege in its effective set when it makes the RPC library call to create the port. See "Multilevel Ports" in Chapter 10, Interprocess Communications for a discussion of multilevel ports.

Security Attributes

The server handle for RPC library calls is a pointer to an SVCXPRT data structure, and the client handle for RPC library calls is a pointer to a CLIENT data structure. In the Trusted Solaris environment, both structures have additional fields that point to security attribute information.

The security attributes pointed to by the server and client handles are based on the TSIX library. See Chapter 12, Trusted Security Information Exchange Library for information on the library routines and privileges required to change security attributes.


Note -

The caller must free all memory blocks allocated for security attribute pointers.


Servers

The following security attribute fields of the SVCXPRT structure can be accessed directly by the server process:


t6attr_t xp_tsol_incoming_attrsp
t6attr_t xp_tsol_outgoing_attrsp
t6mask_t xp_tsol_incoming_new_attrs

A server can receive one or more security attributes of incoming client requests by using t6alloc_blk(3NSL) to allocate an opaque structure with space for the security attributes and setting xp_tsol_incoming_attrsp field in the SVCXPRT structure to point to the security attribute structure.

A privileged server can set security attributes on a request to the server by using t6alloc_blk(3NSL) to allocate an opaque structure with space for the security attributes and setting xp_tsol_outgoing_attrsp field in the SVCXPRT to point to the security attribute structure. The RPC library routines pick up the attributes and send them as the attributes for the response.

A server can examine the security attributes on the next and last bytes of data by using the xp_tsol_incoming_new_attrs field in the SVCXPRT structure to point to specific incoming attributes to be examined.

Clients

The following security attribute fields of the CLIENT structure can be accessed directly by the client process:


t6attr_t cl_tsol_incoming_attrsp
t6attr_t cl_tsol_outgoing_attrsp

A client can receive one or more security attributes of incoming server responses by using t6alloc_blk(3NSL) to allocate an opaque structure with space for the attributes and setting cl_tsol_incoming_attrsp field in the CLIENT structure to point to the security attribute structure.

A privileged client can set security attributes on a request to the server by using t6alloc_blk(3NSL) to allocate an opaque structure with space for the security attributes and setting xp_tsol_outgoing_attrsp field in the CLIENT structure to point to the security attribute structure. The RPC library routines pick up the attributes and send them as the attributes for the response.

Header Files and Libraries

The following header file is necessary to use the RPC programming interfaces.


#include <rpc/rpc.h>

The examples in this chapter compile with the following libraries:


-DTSOL -lt6 -lnsl -lsocket -ltsol

Programming Interfaces

The Trusted Solaris environment introduces the rpcb_getallmaps() routine in the rpcbind() interface. This section lists the RPC man pages that have information specific to the Trusted Solaris environment added.

Client-Server Application

This is a simple client-server application to show how security attributes are sent and received with RPC library routines. Command line arguments supply the server name and a user ID, and the server process retrieves the user ID sent by the client, multiplies the input by 2, and sends the result to the client. To run the programs, compile them with the libraries listed in "Header Files and Libraries".

Header File

The following header file rpc_test.h is required for the example application to compile.

#include <rpc/rpc.h>
#include <rpc/types.h>
#define RPC_TEST_PROG ((u_long)1234567890)
#define RPC_TEST_VERS ((u_long)1)
#define RPC_TEST_DOUBLE1 ((u_long)1)
#define RPC_TEST_EXIT1 ((u_long)2)

Client Program

This part of the client program accepts command line inputs and creates a client handle.

#include <stdio.h>
#include <stdlib.h>
#include <rpc/rpc.h>
#include <netdb.h>
#include <tsix/t6attrs.h>
#include "rpc_test.h"

extern int
main(int argc, char *argv[])
{
	struct timeval time_out;
	CLIENT *handlep;
	enum clnt_stat stat;
	int input, output;
	uid_t uid;
	if (argc < 2 || argc > 3) {
		fprintf(stderr,
			"Usage: simple_rpc_clnt_test HOSTNAME [UID]\n");
		exit(1);
	}

	handlep = clnt_create(argv[1], RPC_TEST_PROG,
		RPC_TEST_VERS, "udp");
		if (handlep == (CLIENT *) NULL) {
			fprintf(stderr, "Couldn't create client%s.\n",
				clnt_spcreateerror(""));
		exit(1);
	}

This part of the client program sets the client handle to point to the space allocated for the user ID to be input from the command line, sets the user ID value, sends the value to the server process, and waits for the server response. The client prints out the server response before it exits.

The client program needs the net_setid privilege in its effective set to send a changed outgoing user ID. The code comments indicate where privilege bracketing should occur.

	if (argc == 3) {
		handlep->cl_tsol_outgoing_attrsp = t6alloc_blk(T6M_UID);
		if (handlep->cl_tsol_outgoing_attrsp == NULL) {
			fprintf(stderr, "Can't create attr buffer\n");
			exit(1);
		}

		printf ("Sending UID %s\n", argv[2]);
		uid = atoi(argv[2]);
		if (t6set_attr(T6_UID, &uid,
			handlep->cl_tsol_outgoing_attrsp) != 0) {
			fprintf(stderr, "Error returned by t6set_attr.\n");
			exit(1);
		}
	}
	time_out.tv_sec = 30;
	time_out.tv_usec = 0;
	input = 3;

/* Turn net_uid on in the effective set */
	stat = clnt_call(handlep, RPC_TEST_DOUBLE1, xdr_int,
		(caddr_t) &input, xdr_int, (caddr_t) &output, time_out);
	if (stat != RPC_SUCCESS) {
		fprintf(stderr, "Call failed. %s.\n",
			clnt_sperror(handlep, ""));
			exit(1);
	}
/* Turn off the net_uid privilege */

	printf("Response received: %d\n", output);
	(void) clnt_destroy(handlep);

	return (0);
}

Server Program

The server program sets the server handle to point to the space allocated space for all security attributes.

#include <stdio.h>
#include <stdlib.h>
#include <rpc/rpc.h>
#include <tsix/t6attrs.h>
#include "rpc_test.h"
static void proc_1(struct svc_req *rqstp, SVCXPRT *transp);
extern int
main(int argc, char *argv[])
{
	SVCXPRT *handlep;
	struct netconfig *netconfigp;
	netconfigp = getnetconfigent("udp");
	if (netconfigp == NULL) {
		fprintf(stderr, "Cannot find netconfig entry for udp.\n");
		exit(1);
	}

	handlep = svc_tp_create(proc_1, RPC_TEST_PROG,
		RPC_TEST_VERS, netconfigp);

	if (handlep == NULL) {
		fprintf(stderr, "Cannot create service.\n");
		exit(1);
	}
	freenetconfigent(netconfigp);
	handlep->xp_tsol_incoming_attrsp = t6alloc_blk(T6M_ALL_ATTRS);
	if (handlep->xp_tsol_incoming_attrsp == NULL) {
		fprintf(stderr, "Can't create attr buffer\n");
		exit(1);
	}
	svc_run();
	return (0);
}

Remote Procedure

The remote procedure receives the user ID from command line arguments, and multiplies the input by 2, sends the result to the client and prints the response before exiting.

static void
proc_1(struct svc_req *rqstp, SVCXPRT *handlep)
{
	int input;
	int result;
	uid_t *uidp;

	switch(rqstp->rq_proc) {
	case NULLPROC:
			svc_sendreply(handlep, xdr_void, NULL);
			break;
	case RPC_TEST_DOUBLE1:
			if (!svc_getargs(handlep, xdr_int, (caddr_t) &input)) {
				fprintf(stderr, "Error from svc_getargs\n");
				svcerr_systemerr(handlep);
			}
			uidp = (uid_t *) t6get_attr(T6_UID,
				handlep->xp_tsol_incoming_attrsp);
			if (uidp == NULL)
				fprintf(stderr, "Error from t6get_attr.\n");
			else printf("Client's UID is %d\n", *uidp);
			result = 2 * input;
			if (!svc_sendreply(handlep, xdr_int, (caddr_t) &result)) {
				fprintf(stderr, "Error from sendreply\n");
				svcerr_systemerr(handlep);
			}
			svc_freeargs(handlep, xdr_int, (caddr_t) &input);
			break;

	default:
			fprintf(stderr, "Call to unexpected procedure number %d\n",
				rqstp->rq_proc);
		svcerr_noproc(handlep);
		break;
	}
}

Running the Simple Application

The client process takes the server host name and a user ID as input parameters and prints that it is sending the specified user ID:


owl%  phoenix
phoenix% owl 2570
Sending UID 2570

The server retrieves the user ID and prints it out as follows:


Client's UID is 2570

The client process prints the server response and then exits:


Response received: 6
phoenix%