Sun Microsystems, Inc.
spacerspacer
spacer www.sun.com docs.sun.com |
spacer
black dot
 
 
5.  Advanced RPC Programming Techniques Authentication Using RPCSEC_GSS Creating a Context  Previous   Contents   Next 
   
 

Changing Values and Destroying a Context

After a context has been set, the application might need to change QOP and service values for individual data units being transmitted. For example, if you want a program to encrypt a password but not a login name, you can use rpc_gss_set_defaults().


Example 5-11 rpc_gss_set_defaults ()

rpc_gss_set_defaults(clnt->clnt_auth, rpc_gss_svc_privacy, qop);

. . .

In this case, the security service is set to privacy. See "Creating a Context". qop is a pointer to a string naming the new QOP.

Contexts are destroyed in the usual way, with auth_destroy().

For more information on changing service and QOP, see the rpc_gss_set_defaults(3NSL) man page.

Principal Names

You need both a client and a server principal name to establish and maintain a security context.

  • A server's principal name is always specified as a NULL-terminated ASCII string of the form service@host. One example is nfs@eng.acme.com.

    When a client creates a security context, it specifies the server principal name in this format. See "Creating a Context". Similarly, when a server needs to set the name of a principal it represents, it uses rpc_gss_set_svc_name(). This function takes a principal name in this format as an argument.

  • The principal name of a client, as received by a server, takes the form of an rpc_gss_principal_t structure: a counted, opaque byte string determined by the mechanism being used. This structure is described in the rpcsec_gss(3NSL) man page.

Setting Server Principal Names

A server needs to be told the names of the principals it represents when it starts up. A server can act as more than one principal. rpc_gss_set_svc_name() sets the name of the principals, as shown in the following code example.


Example 5-12 rpc_gss_set_svc_name()

char *principal, *mechanism;
u_int req_time;

principal = "nfs@eng.acme.com";
mechanism = "kerberos_v5";
req_time = 10000;		/* time for which credential should be valid */

rpc_gss_set_svc_name(principal, mechanism, req_time, SERV_PROG, SERV_VERS);

Kerberos ignores the req_time parameter. Other authentication systems might use it.

For more information, see the rpc_gss_set_svc_name(3NSL) man page.

Generating Client Principal Names

Servers need to be able to operate on a client's principal name. For example, you might need to compare a client's principal name to an access control list, or look up a UNIX credential for that client, if such a credential exists. Such principal names are kept in the form of a rpc_gss_principal_t structure pointer. See the rpcsec_gss(3NSL) man page for more on rpc_gss_principal_t. If a server is to compare a principal name it has received with the name of a known entity, the server needs to be able to generate a principal name in that form.

The rpc_gss_get_principal_name() call takes as input several parameters that uniquely identify an individual on a network, and generates a principal name as a rpc_gss_principal_t structure pointer, as shown in the following code example.


Example 5-13 rpc_gss_get_principal_name()

rpc_gss_principal_t *principal;
rpc_gss_get_principal_name(principal, mechanism, name, node, domain);
. . .

The arguments to rpc_gss_get_principal_name() are:

  • principal is a pointer to the rpc_gss_principal_t structure to be set.

  • mechanism is the security mechanism being used. The principal name being generated is mechanism dependent.

  • name is an individual or service name, such as joeh or nfs, or even the name of a user-defined application.

  • node might be, for example, a UNIX machine name.

  • domain might be, for example, a DNS, NIS, or NIS+ domain name, or a Kerberos realm.

Each security mechanism requires different identifying parameters. For example, Kerberos V5 requires a user name and, only optionally, qualified node and domain names, which in Kerberos terms are host and realm names.

For more information, see the rpc_gss_get_principal_name(3NSL) man page.

Freeing Principal Names

Use the free() library call to free principal names.

Receiving Credentials at the Server

A server must be able to fetch the credentials of a client. The rpc_gss_getcred() function, shown in Example 5-14, enables the server to retrieve either UNIX credentials or RPCSEC_GSS credentials, or both. The function has two arguments that are set if the function is successful. One is a pointer to an rpc_gss_ucred_t structure, which contains the caller's UNIX credentials, if such exist:

typedef struct {
    uid_t   uid;          /* user ID */
    gid_t   gid;          /* group ID */
    short   gidlen; 
    git_t   *gidlist;     /* list of groups */
} rpc_gss_ucred_t;

The other argument is a pointer to a rpc_gss_raw_cred_t structure, which looks like this:
typedef struct {
	u_int  version;              /*RPCSEC_GS program version *mechanism;
          	char          *qop;
	rpc_gss_principal_t client_principal;  /* client principal name */
	char                   *svc_principal; /*server principal name */
	rpc_gss_service_t	  service;        /* privacy, integrity enum */
} rpc_gss_rawcred_t;

Because rpc_gss_rawcred_t contains both the client and server principal names, rpc_gss_getcred() can return them both. See "Generating Client Principal Names" for a description of the rpc_gss_principal_t structure and how it is created.

The following example is a simple server-side dispatch procedure, in which the server gets the credentials for the caller. The procedure gets the caller's UNIX credentials and then verifies the user's identity, using the mechanism, QOP, and service type found in the rpc_gss_rcred_t argument.


Example 5-14 Getting Credentials

static void server_prog(struct svc_req *rqstp, SVCXPRT *xprt)
{
		rpc_gss_ucred_t *ucred;
		rpc_gss_rawcred_t *rcred;
 
		if (rqst->rq_proq == NULLPROC) {
			svc_sendreply(xprt, xdr_void, NULL);
			return;
		}
		/*
		 * authenticate all other requests */
		 */
 
		switch (rqstp->rq_cred.oa_flavor) {
		case RPCSEC_GSS:
			/*
			 * get credential information
			 */
			rpc_gss_getcred(rqstp, &rcred, &ucred, NULL);
			/*
			* verify that the user is allowed to access
			* using received security parameters by
			* peeking into my config file
			*/
			if (!authenticate_user(ucred->uid, rcred->mechanism,
				rcred->qop, rcred->service)) {
				svcerr_weakauth(xprt);
				return;
			}
			break; 	/* allow the user in */
		default:
			svcerr_weakauth(xprt);
			return;
		} /* end switch */
 
		switch (rqstp->rq_proq) {
		case SERV_PROC1:
			. . .
		}
 
		/* usual request processing; send response ... */
 
		return;
 
}

 
 
 
  Previous   Contents   Next