JavaScript is required to for searching.
Skip Navigation Links
Exit Print View
ONC+ Developer's Guide     Oracle Solaris 11.1 Information Library
search filter icon
search icon

Document Information

Preface

1.  Introduction to ONC+ Technologies

2.  Introduction to TI-RPC

3.  rpcgen Programming Guide

4.  Programmer's Interface to RPC

5.  Advanced RPC Programming Techniques

poll() on the Server Side

Broadcast RPC

Batching

Authentication

AUTH_SYS Authentication

AUTH_DES Authentication

AUTH_KERB Authentication

Authentication Using RPCSEC_GSS

RPCSEC_GSS API

RPCSEC_GSS Routines

Creating a Context

Changing Values and Destroying a Context

Principal Names

Setting Server Principal Names

Generating Client Principal Names

Freeing Principal Names

Receiving Credentials at the Server

Cookies

Callbacks

Maximum Data Size

Miscellaneous Functions

Associated Files

gsscred Table

/etc/gss/qop and /etc/gss/mech

Using Port Monitors

Using inetd

Using the Listener

Multiple Server Versions

Multiple Client Versions

Using Transient RPC Program Numbers

6.  Porting From TS-RPC to TI-RPC

7.  Multithreaded RPC Programming

8.  Extensions to the Oracle Solaris RPC Library

A.  XDR Technical Note

B.  RPC Protocol and Language Specification

C.  XDR Protocol Specification

D.  RPC Code Examples

E.  portmap Utility

Glossary

Index

Authentication

Just as you can use different transports when creating RPC clients and servers, you can associate different “flavors” of authentication with RPC clients. The authentication subsystem of RPC is open ended. So, RPC can support many flavors of authentication. Appendix B, RPC Protocol and Language Specification further defines the authentication protocols.

Oracle RPC currently supports the authentication flavors shown in the following table.

Table 5-1 Authentication Methods Supported by Oracle RPC

Method
Description
AUTH_NONE
Default. No authentication performed.
AUTH_SYS
An authentication flavor based on the process permissions authentication in the UNIX operating system.
AUTH_SHORT
An alternate flavor of AUTH_SYS used by some servers for efficiency. Client programs using AUTH_SYS authentication can receive AUTH_SHORT response verifiers from some servers. See Appendix B, RPC Protocol and Language Specification for details.
AUTH_DES
An authentication flavor based on DES encryption techniques.
AUTH_KERB
Version 5 Kerberos authentication based on DES framework.

When a caller creates a new RPC client handle as in:

clnt = clnt_create(host, prognum, versnum, nettype);

the appropriate client-creation routine sets the associated authentication handle to:

clnt->cl_auth = authnone_create();

If you create a new instance of authentication, you must destroy it with auth_destroy(clnt->cl_auth). This destruction conserves memory.

On the server side, the RPC package passes a request that has an arbitrary authentication style associated with it to the service-dispatch routine. The request handle passed to a service-dispatch routine contains the structure rq_cred. This structure is opaque, except for one field: the flavor of the authentication credentials.

/*
 * Authentication data
 */
struct opaque_auth {
   enum_t    oa_flavor;        /* style of credentials */
   caddr_t   oa_base;        /* address of more auth stuff */
   u_int     oa_length;        /* not to exceed MAX_AUTH_BYTES */
};

The RPC package guarantees the following structural requirements to the service-dispatch routine:

AUTH_SYS Authentication

The client can use AUTH_SYS style authentication (called AUTH_UNIX in previous releases) by setting clnt–>cl_auth after creating the RPC client handle:

clnt->cl_auth = authsys_create_default();

This setting causes each RPC call associated with clnt to carry with it the following credentials-authentication structure shown in the following example.

Example 5-7 AUTH_SYS Credential Structure

/*
 * AUTH_SYS flavor credentials.
 */
struct authsys_parms {
    u_long aup_time;        /* credentials creation time */
    char *aup_machname;        /* client's host name */
    uid_t aup_uid;            /* client's effective uid */
    gid_t aup_gid;            /* client's current group id */
    u_int aup_len;            /* element length of aup_gids*/
    gid_t *aup_gids;        /* array of groups user is in */
};

rpc.broadcast defaults to AUTH_SYS authentication.

The following example shows a server, with procedure RUSERPROC_1(), that returns the number of users on the network. As an example of authentication, the server checks AUTH_SYS credentials and does not service requests from callers with a uid of 16.

Example 5-8 Authentication Server

nuser(rqstp, transp)
    struct svc_req *rqstp;
    SVCXPRT *transp;
{
    struct authsys_parms *sys_cred;
    uid_t uid;
    unsigned int nusers;

    /* NULLPROC should never be authenticated */
    if (rqstp->rq_proc == NULLPROC) {
        if (!svc_sendreply( transp, xdr_void, (caddr_t) NULL))
            fprintf(stderr, "can't reply to RPC call\n");
        return;
    }

    /* now get the uid */
    switch(rqstp->rq_cred.oa_flavor) {
        case AUTH_SYS:
            sys_cred = (struct authsys_parms *) rqstp->rq_clntcred;
            uid = sys_cred->aup_uid;
            break;
        default:
            svcerr_weakauth(transp);
            return;
    }
    switch(rqstp->rq_proc) {
        case RUSERSPROC_1:
            /* make sure caller is allowed to call this proc */
            if (uid == 16) {
                svcerr_systemerr(transp);

                return;
            }
            /*
             * Code here to compute the number of users and assign
             * it to the variable nusers
             */
            if (!svc_sendreply( transp, xdr_u_int, &nusers))
                fprintf(stderr, "can't reply to RPC call\n");
            return;
        default:
            svcerr_noproc(transp);
            return;
    }
}

Note the following points about the example:

The last point underscores the relation between the RPC authentication package and the services: RPC deals only with authentication and not with an individual service's access control. The services must establish access-control policies and reflect these policies as return statuses in their protocols.

AUTH_DES Authentication

Use AUTH_DES authentication for programs that require more security than AUTH_SYS provides. AUTH_SYS authentication is easy to defeat. For example, instead of using authsys_create_default(), a program can call authsys_create() and change the RPC authentication handle to give itself any desired user ID and host name.

AUTH_DES authentication requires keyserv() daemons to be running on both the server and client hosts. The NIS naming service must also be running. Users on these hosts need public/secret key pairs assigned by the network administrator in the publickey() database. The users must also have decrypted their secret keys with the keylogin() command. This decryption is normally done by login() unless the login password and secure-RPC password differ.

To use AUTH_DES authentication, a client must set its authentication handle appropriately, as shown in the following example.

cl->cl_auth = authdes_seccreate(servername, 60, server,
                               (char *)NULL);

The first argument is the network name or “net name” of the owner of the server process. Server processes are usually root processes, and you can get their net names with the following call;

char servername[MAXNETNAMELEN];
host2netname(servername, server, (char *)NULL);

servername points to the receiving string and server is the name of the host the server process is running on. If the server process was run by a non-root user, use the call user2netname() as follows:

char servername[MAXNETNAMELEN];
user2netname(servername, serveruid(), (char *)NULL);

serveruid() is the user ID of the server process. The last argument of both functions is the name of the domain that contains the server. NULL means “use the local domain name.”

The second argument of authdes_seccreate() is the lifetime (known also as the “window”) of the client's credential. In this example, a credential expires 60 seconds after the client makes an RPC call. If a program tries to reuse the credential, the server RPC subsystem recognizes that the credential has expired and does not service the request carrying the expired credential. If any program tries to reuse a credential within its lifetime, the process is rejected, because the server RPC subsystem saves credentials it has seen in the near past and does not serve duplicates.

The third argument of authdes_seccreate() is the name of the timehost used to synchronize clocks. AUTH_DES authentication requires that server and client agree on the time. Example 5-8 specifies synchronization with the server. A (char *)NULL says not to synchronize. Use this syntax only when you are sure that the client and server are already synchronized.

The fourth argument of authdes_seccreate() points to a DES encryption key to encrypt timestamps and data. If this argument is (char *)NULL, as it is in Example 5-8, a random key is chosen. The ah_key field of the authentication handle contains the key.

The server side is simpler than the client. The following example shows the server in Example 5-8 changed to use AUTH_DES.

Example 5-9 AUTH_DES Server

#include <rpc/rpc.h>
    ...
nuser(rqstp, transp)
    struct svc_req *rqstp;
    SVCXPRT *transp;
{
    struct authdes_cred *des_cred;
    uid_t uid;
    gid_t gid;
    int gidlen;
    gid_t gidlist[10];
 
    /* NULLPROC should never be authenticated */
    if (rqstp->rq_proc == NULLPROC) {
        /* same as before */
    }
    /* now get the uid */
    switch(rqstp->rq_cred.oa_flavor) {
        case AUTH_DES:
            des_cred = (struct authdes_cred *) rqstp->rq_clntcred;
            if (! netname2user( des_cred->adc_fullname.name,
                &uid, &gid, &gidlen, gidlist)) {
                fprintf(stderr, "unknown user: %s\n",
                         des_cred->adc_fullname.name);
                svcerr_systemerr(transp);
                return;
            }
            break;
        default:
            svcerr_weakauth(transp);
            return;
    }
    /* The rest is the same as before */

The routine netname2user() converts a network name, or “net name” of a user, to a local system ID. It also supplies group IDs, which are not used in this example.

AUTH_KERB Authentication

Recent releases of the Oracle Solaris OS include support for most client-side features of Kerberos 5 except klogin. AUTH_KERB is conceptually similar to AUTH_DES. The essential difference is that DES passes a network name and a DES-encrypted session key, while Kerberos passes the encrypted service ticket. This section describes other factors that affect implementation and interoperability.

Kerberos uses the concept of a time window in which its credentials are valid. It does not place restrictions on the clocks of the client or server. Specifically, the window is passed as an argument to authkerb_seccreate(). The window does not change. If a timehost is specified as an argument, the client side gets the time from the timehost and alters its timestamp by the difference in time. Various methods of time synchronization are available. See the kerberos_rpc man page for more information.

Kerberos users are identified by a primary name, instance, and realm. The RPC authentication code ignores the realm and instance, while the Kerberos library code does not. The assumption is that user names are the same between client and server. This enables a server to translate a primary name into user identification information. Two forms of well-known names are used (omitting the realm):

Kerberos uses cipher block chaining (CBC) mode when sending a full name credential, one that includes the ticket and window, and electronic code book (ECB) mode otherwise. CBC and ECB are two methods of DES encryption. The session key is used as the initial input vector for CBC mode. The following notation means that XDR is used on object as a type.

xdr_type(object)

The length in the next code section is the size, in bytes of the credential or verifier, rounded up to 4-byte units. The full name credential and verifier are obtained as follows:

xdr_long(timestamp.seconds)
xdr_long(timestamp.useconds)
xdr_long(window)
xdr_long(window - 1)

After encryption with CBC with input vector equal to the session key, the output is two DES cipher blocks:

CB0
CB1.low
CB1.high

The credential is:

xdr_long(AUTH_KERB)
xdr_long(length)
xdr_enum(AKN_FULLNAME)
xdr_bytes(ticket)
xdr_opaque(CB1.high)

The verifier is:

xdr_long(AUTH_KERB)
xdr_long(length)
xdr_opaque(CB0)
xdr_opaque(CB1.low)

The nickname exchange yields:

xdr_long(timestamp.seconds)
xdr_long(timestamp.useconds)

The nickname is encrypted with ECB to obtain ECB0, and the credential is:

xdr_long(AUTH_KERB)
xdr_long(length)
xdr_enum(AKN_NICKNAME)
xdr_opaque(akc_nickname)

The verifier is:

xdr_long(AUTH_KERB)
xdr_long(length)
xdr_opaque(ECB0)
xdr_opaque(0)