Blame doc/rpc/design.tex

Packit fd8b60
\documentstyle[fullpage,12pt]{article}
Packit fd8b60
Packit fd8b60
\title{GSS-API Extensions to Sun RPC}
Packit fd8b60
\date{Draft---\today}
Packit fd8b60
\author{Barry Jaspan}
Packit fd8b60
Packit fd8b60
\setlength{\parskip}{.7\baselineskip}
Packit fd8b60
\setlength{\parindent}{0pt}
Packit fd8b60
Packit fd8b60
\makeatletter
Packit fd8b60
\newcount\savecnt\savecnt=0
Packit fd8b60
\def\saveenum#1{\global\savecnt=\csname c@enum#1\endcsname}
Packit fd8b60
\def\restoreenum#1{\csname c@enum#1\endcsname=\savecnt}
Packit fd8b60
\makeatother
Packit fd8b60
Packit fd8b60
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Packit fd8b60
%% Make _ actually generate an _, and allow line-breaking after it.
Packit fd8b60
\let\underscore=\_
Packit fd8b60
\catcode`_=13
Packit fd8b60
\def_{\underscore\penalty75\relax}
Packit fd8b60
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Packit fd8b60
Packit fd8b60
\begin{document}
Packit fd8b60
Packit fd8b60
Packit fd8b60
{\setlength{\parskip}{0pt}\maketitle\tableofcontents}
Packit fd8b60
Packit fd8b60
\section{Introduction}
Packit fd8b60
Packit fd8b60
This document describes the integration of GSS-API authentication and
Packit fd8b60
security with Sun RPC.
Packit fd8b60
Packit fd8b60
\section{Requirements}
Packit fd8b60
Packit fd8b60
The requirements of the GSS-API authentication system for Sun RPC are:
Packit fd8b60
Packit fd8b60
\begin{enumerate}
Packit fd8b60
\item It must provide mutual authentication between RPC clients and
Packit fd8b60
servers.
Packit fd8b60
Packit fd8b60
\item It must provide for integrity checking and encryption of all
Packit fd8b60
procedure arguments and results passed over the network.
Packit fd8b60
\saveenum{i}
Packit fd8b60
\end{enumerate}
Packit fd8b60
Packit fd8b60
The following features are desired, but not mandatory:
Packit fd8b60
Packit fd8b60
\begin{enumerate}
Packit fd8b60
\restoreenum{i}
Packit fd8b60
\item It should provide for integrity checking and encryption of all
Packit fd8b60
``header information'' that specifies the program and procedure being
Packit fd8b60
called.
Packit fd8b60
Packit fd8b60
\item It should obey the Sun RPC protocol so that clients using
Packit fd8b60
it can interoperate with existing servers.  In this case,
Packit fd8b60
``interoperate'' means that existing servers will return an error code
Packit fd8b60
indicating that they do not understand the authentication flavor, but
Packit fd8b60
not that they do not understand the request at all.
Packit fd8b60
Packit fd8b60
\item It should require minimal or no changes to the standard Sun RPC
Packit fd8b60
programming paradigm for either clients or servers so that existing
Packit fd8b60
code can use it with little or no effort.
Packit fd8b60
Packit fd8b60
\item It should operate correctly with all the standard Sun RPC
Packit fd8b60
transport mechansims (e.g. UDP and TCP).
Packit fd8b60
\saveenum{i}
Packit fd8b60
\end{enumerate}
Packit fd8b60
Packit fd8b60
\section{Functional Specification}
Packit fd8b60
Packit fd8b60
This section describes the programmer's interface to the GSS-API
Packit fd8b60
authentication flavor.   Knowledge of standard Sun RPC programming is
Packit fd8b60
assumed.
Packit fd8b60
Packit fd8b60
\subsection{Client Side}
Packit fd8b60
Packit fd8b60
A RPC client can select the GSS-API authentication flavor in the same
Packit fd8b60
way it can select any other authentication flavor, by setting the
Packit fd8b60
cl_auth field of the CLIENT structure to the appropriate value:
Packit fd8b60
Packit fd8b60
\begin{verbatim}
Packit fd8b60
    clnt = clnt_create(server_host, PROG_NUM, PROG_VERS, protocol);
Packit fd8b60
    clnt->cl_auth = auth_gssapi_create(clnt, ...);
Packit fd8b60
\end{verbatim}
Packit fd8b60
Packit fd8b60
There are two functions that create GSS-API authentication flavor
Packit fd8b60
structures for the cl_auth field, auth_gssapi_create and
Packit fd8b60
auth_gssapi_create_default.
Packit fd8b60
Packit fd8b60
\begin{verbatim}
Packit fd8b60
AUTH *auth_gssapi_create(CLIENT         *clnt,
Packit fd8b60
                        OM_uint32       *major_status,
Packit fd8b60
                        OM_uint32       *minor_status,
Packit fd8b60
                        gss_cred_id_t   claimant_cred_handle,
Packit fd8b60
                        gss_name_t      target_name,
Packit fd8b60
                        gss_OID         mech_type,
Packit fd8b60
                        int             req_flags,
Packit fd8b60
                        int             time_req,
Packit fd8b60
                        gss_OID         *actual_mech_type,
Packit fd8b60
                        int             *ret_flags,
Packit fd8b60
                        OM_uint32       *time_rec);
Packit fd8b60
\end{verbatim}
Packit fd8b60
Packit fd8b60
auth_gssapi_create creates a GSS-API authentication structure and
Packit fd8b60
provides most of the flexibility of gss_init_sec_context.  The
Packit fd8b60
arguments have the same interpretation as those of
Packit fd8b60
gss_init_sec_context with the same name, except:
Packit fd8b60
Packit fd8b60
\begin{description}
Packit fd8b60
\item[clnt] The CLIENT structure returned by client_create or one of
Packit fd8b60
its relatives.  It is not modified.
Packit fd8b60
\end{description}
Packit fd8b60
Packit fd8b60
auth_gssapi_create calls gss_init_sec_context as needed, passing each
Packit fd8b60
generated token to and processing each token returned from the RPC
Packit fd8b60
server specified by the RPC handle clnt.  On return, if major_status
Packit fd8b60
is GSS_S_COMPLETE, the context has been established, the returned AUTH
Packit fd8b60
structure is valid, and all of the arguments filled in by
Packit fd8b60
gss_init_sec_context have the correct values.  If major_status is not
Packit fd8b60
GSS_S_COMPLETE then it and minor_status contain error codes that can
Packit fd8b60
be passed to gss_display_status and the returned value is NULL.
Packit fd8b60
Packit fd8b60
\begin{verbatim}
Packit fd8b60
AUTH *auth_gssapi_create_default(CLIENT *clnt, char *service_name);
Packit fd8b60
\end{verbatim}
Packit fd8b60
Packit fd8b60
auth_gssapi_create_default is a shorthand for auth_gssapi_create that
Packit fd8b60
attempts to create a context that provides procedure call and result
Packit fd8b60
integrity, using the default credentials and GSS-API mechanism.
Packit fd8b60
service_name is parsed as a GSS-API ``service'' name and used as the
Packit fd8b60
target name.  The other arguments to auth_gssapi_create are as follows:
Packit fd8b60
Packit fd8b60
\begin{verbatim}
Packit fd8b60
auth_gssapi_create(clnt,
Packit fd8b60
                   &dummy,
Packit fd8b60
                   &dummy,
Packit fd8b60
                   GSS_C_NO_CREDENTIAL,
Packit fd8b60
                   target_name,
Packit fd8b60
                   GSS_C_NULL_OID,
Packit fd8b60
                   GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG,
Packit fd8b60
                   0,
Packit fd8b60
                   NULL,
Packit fd8b60
                   NULL,
Packit fd8b60
                   NULL);
Packit fd8b60
\end{verbatim}
Packit fd8b60
Packit fd8b60
Note that if the underlying default mechanism does not support data
Packit fd8b60
integrity (e.g. the trust mechanism), this function will fail.
Packit fd8b60
Packit fd8b60
The GSS-API major and minor status codes can be interpreted with
Packit fd8b60
auth_gssapi_display_status:
Packit fd8b60
Packit fd8b60
\begin{verbatim}
Packit fd8b60
void auth_gssapi_display_status(char *msg, OM_uint32 major, 
Packit fd8b60
                                OM_uint32 minor); 
Packit fd8b60
\end{verbatim}
Packit fd8b60
Packit fd8b60
All of the error messages associated with the major and minor status
Packit fd8b60
are displated on the standard error output, preceeded by the message
Packit fd8b60
``GSS-API authentication error $<$msg$>$:''.
Packit fd8b60
Packit fd8b60
\subsection{Server Side}
Packit fd8b60
Packit fd8b60
\subsubsection{Service Name Registration}
Packit fd8b60
Packit fd8b60
An application server must register the service name(s) that it will
Packit fd8b60
use for GSS-API connections before any AUTH_GSSAPI requests will
Packit fd8b60
succeed.
Packit fd8b60
Packit fd8b60
\begin{verbatim}
Packit fd8b60
typedef struct _auth_gssapi_name {
Packit fd8b60
     char *name;
Packit fd8b60
     gss_OID type;
Packit fd8b60
} auth_gssapi_name;
Packit fd8b60
Packit fd8b60
bool_t _svcauth_gssapi_set_names(auth_gssapi_name *names, int num);
Packit fd8b60
\end{verbatim}
Packit fd8b60
Packit fd8b60
names is an array of name specifications, each of which consists of a
Packit fd8b60
null-terminated ASCII representation of a name and the GSS-API name
Packit fd8b60
type that should be used to import it with gss_import_name.  The
Packit fd8b60
name type ``gss_nt_service_name'' is recommended.
Packit fd8b60
Packit fd8b60
\subsubsection{Calling Client and Service Identification}
Packit fd8b60
Packit fd8b60
Each application server's dispatch function is passed two arguments,
Packit fd8b60
the transport mechanism (transp) and the RPC service request (rqstp).
Packit fd8b60
If the service request's credential flavor (rq_cred.oa_flavor) is
Packit fd8b60
AUTH_GSSAPI (300001)\footnote{The value 4 was originally used, but
Packit fd8b60
300001 has been officially assigned by the IETF.}, then the call has
Packit fd8b60
been authenticated.  The rq_clntcred field of transp contains the
Packit fd8b60
gss_name_t of the authenticated caller and can be passed to
Packit fd8b60
gss_display_name to obtain a string represtation or gss_compare_name
Packit fd8b60
to compare it with other names.  The rq_svccred field of transp
Packit fd8b60
contains the GSS-API context established with the caller and can be
Packit fd8b60
passed to gss_inquire_context.
Packit fd8b60
Packit fd8b60
\subsubsection{Error Logging}
Packit fd8b60
Packit fd8b60
An application server can register a function to be called when a
Packit fd8b60
failure occurs during GSS-API context establishment with
Packit fd8b60
_svcauth_set_log_badauth_func.
Packit fd8b60
Packit fd8b60
\begin{verbatim}
Packit fd8b60
typedef void (*auth_gssapi_log_badauth_func)(OM_uint32 major,
Packit fd8b60
                                             OM_uint32 minor,
Packit fd8b60
                                             struct sockaddr_in *raddr,
Packit fd8b60
                                             caddr_t data);
Packit fd8b60
   
Packit fd8b60
void _svcauth_set_log_badauth_func(auth_gssapi_log_badauth_func func,
Packit fd8b60
                                   caddr_t data); 
Packit fd8b60
\end{verbatim}
Packit fd8b60
Packit fd8b60
The function func is called each time gss_accept_sec_context fails.
Packit fd8b60
The major and minor arguments indicate the GSS-API major and minor
Packit fd8b60
status codes returned.  The raddr field contains the INET socket that
Packit fd8b60
the request came from, and the data field contains the data argument
Packit fd8b60
of _svcauth_gssapi_set_log_badauth_func.
Packit fd8b60
Packit fd8b60
An application server can register a function to be called when an RPC
Packit fd8b60
request with an invalid verifier arrives with
Packit fd8b60
_svcauth_set_log_badverf_func.
Packit fd8b60
Packit fd8b60
\begin{verbatim}
Packit fd8b60
typedef void (*auth_gssapi_log_badverf_func)(gss_name_t client,
Packit fd8b60
                                             gss_name_t server,
Packit fd8b60
                                             struct svc_req *rqst,
Packit fd8b60
                                             struct rpc_msg *msg,
Packit fd8b60
                                             caddr_t data);
Packit fd8b60
Packit fd8b60
void _svcauth_set_log_badverf_func(auth_gssapi_log_badverf_func func,
Packit fd8b60
                                   caddr_t data); 
Packit fd8b60
\end{verbatim}
Packit fd8b60
Packit fd8b60
The function specified in func is called each time an invalid verifier
Packit fd8b60
is received.  The client and server fields identify the (falsely
Packit fd8b60
claimed) originating client and the server it originally authenticated
Packit fd8b60
to.  The raddr and addrlen fields contain the INET socket that the
Packit fd8b60
request (claims to have) come from, and data contains the data
Packit fd8b60
argument of _svcauth_set_log_badverf_func.
Packit fd8b60
Packit fd8b60
\section{Modifications to Sun RPC}
Packit fd8b60
Packit fd8b60
The Sun RPC extensible authentication mechanism is designed to allow
Packit fd8b60
different authentication systems to be integrated into Sun RPC easily.
Packit fd8b60
Unfortunately, it has two drawbacks.  First, the existing system has a
Packit fd8b60
number of non-general design properties that are intended specifically
Packit fd8b60
for Sun's Secure RPC, and second, the existing system has no concept
Packit fd8b60
of or ability to perform authentication-flavor-specific operations on
Packit fd8b60
function arguments and results passed over the wire.  The first
Packit fd8b60
problem merely makes the system confusing, since a number of features
Packit fd8b60
touted as ``general'' do not make any sense for arbitrary
Packit fd8b60
authentication systems.  The second problem is more substantial, and
Packit fd8b60
can only be corrected by modifications to Sun RPC internals.
Packit fd8b60
Packit fd8b60
The following sections describe the necessary modifications to Sun
Packit fd8b60
RPC.
Packit fd8b60
Packit fd8b60
\subsection{Client Side Authentication, AUTH Structure}
Packit fd8b60
Packit fd8b60
The AUTH structure (figure \ref{fig:auth}) encapsulates the data and
Packit fd8b60
function pointers for an authentication flavor instance.  It has been
Packit fd8b60
changed in two ways.
Packit fd8b60
Packit fd8b60
\begin{figure}[htbp]
Packit fd8b60
\begin{verbatim}
Packit fd8b60
typedef struct {
Packit fd8b60
        struct  opaque_auth     ah_cred;
Packit fd8b60
        struct  opaque_auth     ah_verf;
Packit fd8b60
        union   des_block       ah_key;
Packit fd8b60
        struct auth_ops {
Packit fd8b60
                void    (*ah_nextverf)();
Packit fd8b60
                int     (*ah_marshal)();        /* nextverf & serialize */
Packit fd8b60
                int     (*ah_validate)();       /* validate varifier */
Packit fd8b60
                int     (*ah_refresh)();        /* refresh credentials */
Packit fd8b60
                int     (*ah_wrap)();           /* encode data for wire */
Packit fd8b60
                int     (*ah_unwrap)();         /* decode data from wire */
Packit fd8b60
                void    (*ah_destroy)();        /* destroy this structure */
Packit fd8b60
        } *ah_ops;
Packit fd8b60
        caddr_t ah_private;
Packit fd8b60
} AUTH;
Packit fd8b60
\end{verbatim}
Packit fd8b60
\caption{The AUTH structure, with the new function pointers ah_wrap
Packit fd8b60
and ah_unwrap.}
Packit fd8b60
\label{fig:auth}
Packit fd8b60
\end{figure}
Packit fd8b60
Packit fd8b60
First, the new functions ah_wrap and ah_unwrap prepare function
Packit fd8b60
arguments and results for transmission over the wire.  The
Packit fd8b60
authentication mechanism can use them to sign, encrypt, or perform any
Packit fd8b60
other operation on the data.  Their prototype is:
Packit fd8b60
Packit fd8b60
\begin{verbatim}
Packit fd8b60
bool_t ah_wrap(AUTH *auth, XDR *out_xdrs, xdrproc_t func, caddr_t ptr);
Packit fd8b60
bool_t ah_unwrap(AUTH *auth, XDR *in_xdrs, xdrproc_t func, caddr_t ptr);
Packit fd8b60
\end{verbatim}
Packit fd8b60
Packit fd8b60
ah_wrap encodes function arguments for transmission.  func and ptr are
Packit fd8b60
the XDR procedure and pointer that serialize the arguments, and
Packit fd8b60
out_xdrs is the xdr stream that the encoded arguments should be
Packit fd8b60
written to.  ah_unwrap decodes function arguments received from the
Packit fd8b60
network.  Its arguments are the converse of those to ah_wrap.
Packit fd8b60
Packit fd8b60
It is the responsibility of RPC transport mechanisms to call an
Packit fd8b60
authorization flavor's ah_wrap and ah_unwrap functions when function
Packit fd8b60
arguments or results would normally be written to or read from the
Packit fd8b60
wire.  Authorization flavors that do not need to perform any encoding
Packit fd8b60
or decoding can use the provided function authany_wrap for ah_wrap
Packit fd8b60
and ah_unwrap; it consists of the single statement ``return
Packit fd8b60
(*func)(out_xdrs, ptr)'' (or in_xdrs, as appropriate).
Packit fd8b60
Packit fd8b60
Second, the function ah_refresh has been changed to take the RPC error
Packit fd8b60
message that resulted in its being called as an argument.  This is
Packit fd8b60
necessary since the contents of the error message may dictate how
Packit fd8b60
ah_refresh should go about correcting the authentication failure.
Packit fd8b60
Packit fd8b60
\subsection{Client Side Transport Mechanisms}
Packit fd8b60
Packit fd8b60
Each client side transport mechanism must be modified to call the
Packit fd8b60
ah_wrap and ah_unwrap functions from the cl_auth field of the CLIENT
Packit fd8b60
structure during the call and reply process.  The modification is
Packit fd8b60
fairly simple.  For example, the UDP transport mechanism used to
Packit fd8b60
encode procedure calls like this:
Packit fd8b60
Packit fd8b60
\begin{verbatim}
Packit fd8b60
        if ((! XDR_PUTLONG(xdrs, (long *)&proc)) ||
Packit fd8b60
            (! AUTH_MARSHALL(cl->cl_auth, xdrs)) ||
Packit fd8b60
            (! (*xargs)(xdrs, argsp)))
Packit fd8b60
                return (cu->cu_error.re_status = RPC_CANTENCODEARGS);
Packit fd8b60
\end{verbatim}
Packit fd8b60
Packit fd8b60
The last function call in the conditional serializes the arguments
Packit fd8b60
onto the xdr stream.  This must be replaced with a call to the
Packit fd8b60
appropriate ah_wrap function:
Packit fd8b60
Packit fd8b60
\begin{verbatim}
Packit fd8b60
        if ((! XDR_PUTLONG(xdrs, (long *)&proc)) ||
Packit fd8b60
            (! AUTH_MARSHALL(cl->cl_auth, xdrs)) ||
Packit fd8b60
            (! AUTH_WRAP(cl->cl_auth, xdrs, xargs, argsp)))
Packit fd8b60
                return (cu->cu_error.re_status = RPC_CANTENCODEARGS);
Packit fd8b60
\end{verbatim}
Packit fd8b60
Packit fd8b60
AUTH_WRAP is a macro that takes the four arguments for an ah_wrap
Packit fd8b60
function and extracts and calls the function pointer from the cl_auth
Packit fd8b60
structure with the specified arguments.
Packit fd8b60
Packit fd8b60
Similarly, the transport mechanism must unwrap procedure results.
Packit fd8b60
Again, the UDP mechanism will be instructive.  It used to deserialize
Packit fd8b60
function results like this:
Packit fd8b60
Packit fd8b60
\begin{verbatim}
Packit fd8b60
        reply_msg.acpted_rply.ar_results.where = resultsp;
Packit fd8b60
        reply_msg.acpted_rply.ar_results.proc = xresults;
Packit fd8b60
Packit fd8b60
        ok = xdr_replymsg(&reply_xdrs, &reply_msg);
Packit fd8b60
\end{verbatim}
Packit fd8b60
Packit fd8b60
The problem here is that xdr_replymsg deserializes an entire reply
Packit fd8b60
message, including the results.  Since xresults and resultsp are the
Packit fd8b60
function and pointer to decode the results, they will be automatically
Packit fd8b60
deserialized {\it without} ah_unwrap being invoked.  The simplest
Packit fd8b60
solution (which is also the normal method used by the TCP mechanism)
Packit fd8b60
is to arrange to deserialize the function results explicitly:
Packit fd8b60
Packit fd8b60
\begin{verbatim}
Packit fd8b60
        reply_msg.acpted_rply.ar_results.where = NULL;
Packit fd8b60
        reply_msg.acpted_rply.ar_results.proc = xdr_void;
Packit fd8b60
Packit fd8b60
        if ((! xdr_replymsg(&reply_xdrs, &reply_msg)) ||
Packit fd8b60
            (! AUTH_UNWRAP(cl->cl_auth, reply_xdrs, xresults,
Packit fd8b60
                           resultsp))) {
Packit fd8b60
                return (cu->cu_error.re_status = RPC_CANTENCODEARGS);
Packit fd8b60
        }
Packit fd8b60
\end{verbatim}
Packit fd8b60
Packit fd8b60
Since xdr_void does not read any data from the XDR stream, the
Packit fd8b60
function results are still available when AUTH_UNWRAP is called.  Note
Packit fd8b60
that AUTH_UNWRAP should only be called on {\it successful} calls; if
Packit fd8b60
the reply message status is not RPC_SUCCESS there are no arguments to
Packit fd8b60
read.
Packit fd8b60
Packit fd8b60
Currently, the UDP and TCP transport mechanisms has been
Packit fd8b60
converted.\footnote{The ``raw'' mechanism, for direct connections, has
Packit fd8b60
not been.}
Packit fd8b60
Packit fd8b60
\subsection{Service Side Authentication, SVCAUTH and XPRT}
Packit fd8b60
Packit fd8b60
Standard Sun RPC service-side authentication consists of a single
Packit fd8b60
function per authentication flavor; there is no concept of an AUTH
Packit fd8b60
structure containing function pointers and private data as with the
Packit fd8b60
client side.  Previously, nothing else was necessary, because each
Packit fd8b60
flavor only did a single thing (authenticated individual calls in a
Packit fd8b60
stateless manner).  More functions and state are now required,
Packit fd8b60
however; they are stored in the SVCAUTH structure, see figure
Packit fd8b60
\ref{fig:svcauth}.
Packit fd8b60
Packit fd8b60
\begin{figure}[htbp]
Packit fd8b60
\begin{verbatim}
Packit fd8b60
typedef struct {
Packit fd8b60
     struct svc_auth_ops {
Packit fd8b60
          int   (*svc_ah_wrap)();
Packit fd8b60
          int   (*svc_ah_unwrap)();
Packit fd8b60
     } *svc_ah_ops;
Packit fd8b60
     caddr_t svc_ah_private;
Packit fd8b60
} SVCAUTH;
Packit fd8b60
\end{verbatim}
Packit fd8b60
\caption{The new SVCAUTH structure.}
Packit fd8b60
\label{fig:svcauth}
Packit fd8b60
\end{figure}
Packit fd8b60
Packit fd8b60
There is one SVCAUTH structure per authentication flavor (there is a
Packit fd8b60
default, svc_auth_any, for existing authentication flavors that do not
Packit fd8b60
need the extra functionality).  The svc_ah_wrap and svc_ah_unwrap
Packit fd8b60
perform the same logical function as their client-side counterparts.
Packit fd8b60
Packit fd8b60
Just as with the client side, it is the responsibility of the
Packit fd8b60
transport mechanism to call the svc_ah_wrap and svc_ah_unwrap
Packit fd8b60
functions associated with the authentication flavor associated with
Packit fd8b60
each RPC call at the appropriate time.  Unfortunately, the transport
Packit fd8b60
mechanism code does not have access to the RPC call structure
Packit fd8b60
containing the authenticator flavor because the RPC call structure
Packit fd8b60
itself is not passed as an argument to the necessary functions.  The
Packit fd8b60
present solution is to add another argument to the transport mechanism
Packit fd8b60
structure, xp_auth, that stores the SVCAUTH of the {\it current} call
Packit fd8b60
on that mechanism; see figure \ref{fig:xprt}.  xp_auth is initialized
Packit fd8b60
to svc_auth_any so that existing authentication mechanisms that do not
Packit fd8b60
set the field will still operate correctly.  \footnote{This is not an
Packit fd8b60
great solution, because it forces each transport mechanism to be
Packit fd8b60
single threaded.  The correct solution is to store the SVCAUTH
Packit fd8b60
associated with each RPC call in the RPC call structure; however,
Packit fd8b60
doing so would require changing a lot of code to pass around the RPC
Packit fd8b60
call structure that currently does not do so.  Since other parts of
Packit fd8b60
Sun RPC use the XPRT structure in a non-reentrant way, the present
Packit fd8b60
solution does not make the situation any
Packit fd8b60
worse.}$^{\mbox{,}}$\footnote{A somewhat irrelevant side effect of
Packit fd8b60
adding SVCAUTH to XPRT is that the standard include file
Packit fd8b60
$<$rpc/rpc.h$>$ had to be changed to include $<$rpc/svc_auth$>$ before
Packit fd8b60
$<$rpc/svc.h$>$, whereas they used to be in the opposite order.}
Packit fd8b60
Packit fd8b60
\begin{figure}[htbp]
Packit fd8b60
\begin{verbatim}
Packit fd8b60
typedef struct {
Packit fd8b60
        int             xp_sock;
Packit fd8b60
        u_short         xp_port;         /* associated port number */
Packit fd8b60
        struct xp_ops {
Packit fd8b60
            bool_t      (*xp_recv)();    /* receive incomming requests */
Packit fd8b60
            enum xprt_stat (*xp_stat)(); /* get transport status */
Packit fd8b60
            bool_t      (*xp_getargs)(); /* get arguments */
Packit fd8b60
            bool_t      (*xp_reply)();   /* send reply */
Packit fd8b60
            bool_t      (*xp_freeargs)();/* free mem allocated for args */
Packit fd8b60
            void        (*xp_destroy)(); /* destroy this struct */
Packit fd8b60
        } *xp_ops;
Packit fd8b60
        int             xp_addrlen;      /* length of remote address */
Packit fd8b60
        struct sockaddr_in xp_raddr;     /* remote address */
Packit fd8b60
        struct opaque_auth xp_verf;      /* raw response verifier */
Packit fd8b60
        SVCAUTH         *xp_auth;        /* auth flavor of current req */
Packit fd8b60
        caddr_t         xp_p1;           /* private */
Packit fd8b60
        caddr_t         xp_p2;           /* private */
Packit fd8b60
} SVCXPRT;
Packit fd8b60
\end{verbatim}
Packit fd8b60
\caption{The modified XPRT structure, with the xp_auth field.}
Packit fd8b60
\label{fig:xprt}
Packit fd8b60
\end{figure}
Packit fd8b60
Packit fd8b60
Finally, with the modified XPRT structure carrying around the
Packit fd8b60
authentication flavor structure, the functions that serialize and
Packit fd8b60
deserialize function arguments and results must be modified to use the
Packit fd8b60
svc_ah_wrap and svc_ah_unwrap functions.  Each service-side transport
Packit fd8b60
mechanism has getargs and reply functions that must be modified to use
Packit fd8b60
the SVCAUTH_UNWRAP and SVCAUTH_WRAP macros, respectively, in a manner
Packit fd8b60
completely parallel to the client side.
Packit fd8b60
Packit fd8b60
\subsection{Authenticated Service Identification, svc_req}
Packit fd8b60
Packit fd8b60
Sun RPC provides the authenticated credentials of a client to the
Packit fd8b60
application server via rq_clntcred (``cooked credentials'') field of
Packit fd8b60
the service request (svc_req) structure.  In many authentication
Packit fd8b60
systems, services are also named entities, and there is no reason that
Packit fd8b60
an RPC should be restricted to accepting connections as a single
Packit fd8b60
authenticated service name.  However, access control decisions may be
Packit fd8b60
based on the service name a client authenticated to, so that
Packit fd8b60
information must be available to the application server.
Packit fd8b60
Packit fd8b60
Figure \ref{fig:svc-req} shows the modified service request structure
Packit fd8b60
that contains a single new field, rq_svccred.  Like rq_clntcred, the
Packit fd8b60
authentication flavor is responsible for setting rq_svccred to the
Packit fd8b60
``cooked'' service credentials associated with a given RPC call.
Packit fd8b60
Authentication flavors that do not have the concept of service names
Packit fd8b60
can of course leave this field blank.
Packit fd8b60
Packit fd8b60
\begin{figure}[htbp]
Packit fd8b60
\begin{verbatim}
Packit fd8b60
struct svc_req {
Packit fd8b60
        u_long          rq_prog;        /* service program number */
Packit fd8b60
        u_long          rq_vers;        /* service protocol version */
Packit fd8b60
        u_long          rq_proc;        /* the desired procedure */
Packit fd8b60
        struct opaque_auth rq_cred;     /* raw creds from the wire */
Packit fd8b60
        caddr_t         rq_clntcred;    /* read only cooked client cred */
Packit fd8b60
        caddr_t         rq_svccred;     /* read only cooked svc cred */
Packit fd8b60
        SVCXPRT         *rq_xprt;       /* associated transport */
Packit fd8b60
};
Packit fd8b60
\end{verbatim}
Packit fd8b60
\caption{The modified svc_req structure, with the rq_svccred field.}
Packit fd8b60
\label{fig:svc-req}
Packit fd8b60
\end{figure}
Packit fd8b60
Packit fd8b60
Packit fd8b60
Packit fd8b60
\subsection{Authentication Negotiation, no_dispatch}
Packit fd8b60
Packit fd8b60
In order to avoid having to transmit a full set of authentication
Packit fd8b60
information with every call, the service-side authentication mechanism
Packit fd8b60
must save state between calls.  Establishing that state may require
Packit fd8b60
multiple messages between the client-side and service-side
Packit fd8b60
authentication mechanisms.  The client-side authentication mechanism
Packit fd8b60
can make arbitrary RPC calls to the server simply by requiring the
Packit fd8b60
programmer to specify the CLIENT structure to the authentication
Packit fd8b60
flavor initialization routine.  The service side, however, is more
Packit fd8b60
complex.  In the normal course of events, an RPC call comes in, is
Packit fd8b60
authenticated, and is then dispatched to the appropriate procedure.
Packit fd8b60
For client- and service-side authentication flavors to communicate
Packit fd8b60
independent of the server implemented above the RPC layer, the
Packit fd8b60
service-side flavor must be able to send a reply to the client
Packit fd8b60
directly and {\it prevent} the call from being dispatched.
Packit fd8b60
Packit fd8b60
This is implemented by a simple modification to the _authenticate
Packit fd8b60
routine, which dispatches each RPC call to the appropriate
Packit fd8b60
authentication flavor; see figure \ref{fig:authenticate}.  It takes an
Packit fd8b60
additional argument, no_dispatch, that instructs the mechanism not to
Packit fd8b60
dispatch the RPC call to the specified procedure.
Packit fd8b60
Packit fd8b60
\begin{figure}[htbp]
Packit fd8b60
\begin{verbatim}
Packit fd8b60
                why=_authenticate(&r, &msg, &no_dispatch);
Packit fd8b60
                if (why != AUTH_OK) {
Packit fd8b60
                     svcerr_auth(xprt, why);
Packit fd8b60
                     goto call_done;
Packit fd8b60
                } else if (no_dispatch) {
Packit fd8b60
                     goto call_done;
Packit fd8b60
                }
Packit fd8b60
\end{verbatim}
Packit fd8b60
\caption{A call to the modified _authenticate.}
Packit fd8b60
\label{fig:authenticate}
Packit fd8b60
\end{figure}
Packit fd8b60
Packit fd8b60
If _authenticate sets no_dispatch to true, the call is considered
Packit fd8b60
finished and no procedure dispatch takes place.  Presumably, an
Packit fd8b60
authentication flavor that sets no_dispatch to true also replies to
Packit fd8b60
the RPC call with svc_sendreply.  Authentication flavors that do not
Packit fd8b60
modify no_dispatch implicitly leave it set to false, so the normal
Packit fd8b60
dispatch takes place.
Packit fd8b60
Packit fd8b60
\subsection{Affected Files}
Packit fd8b60
Packit fd8b60
Table \ref{tab:modfiles} lists the files that were
Packit fd8b60
affected for each of the modifications described in previous sections.
Packit fd8b60
Packit fd8b60
\begin{table}[htbp]
Packit fd8b60
\centering
Packit fd8b60
\caption{Files modified for each change to Sun RPC.}
Packit fd8b60
\label{tab:modfiles}
Packit fd8b60
\begin{tabular}{ll}
Packit fd8b60
AUTH structure                  & auth.h \\
Packit fd8b60
                                & auth_none.c \\
Packit fd8b60
                                & auth_exit.c \\
Packit fd8b60
                                & auth_any.c \\
Packit fd8b60
Client Transport Mechanisms     & clnt_udp.c \\
Packit fd8b60
                                & clnt_tcp.c \\
Packit fd8b60
SVCAUTH and XPRT structures     & rpc.h \\
Packit fd8b60
                                & svc.h \\
Packit fd8b60
                                & svc_auth.h \\
Packit fd8b60
                                & svc.c \\
Packit fd8b60
                                & svc_auth.c \\
Packit fd8b60
                                & svc_auth_any.c \\
Packit fd8b60
                                & svc_auth_unix.c \\
Packit fd8b60
Server Transport Mechanisms     & svc_udp.c \\
Packit fd8b60
                                & svc_tcp.c
Packit fd8b60
\end{tabular}
Packit fd8b60
\end{table}
Packit fd8b60
Packit fd8b60
\section{GSS-API Authentication Flavor}
Packit fd8b60
Packit fd8b60
The following sections describe the implementation of the GSS-API
Packit fd8b60
authentication flavor for Sun RPC.
Packit fd8b60
Packit fd8b60
\subsection{Authentication Algorithms}
Packit fd8b60
\label{sec:algorithms}
Packit fd8b60
Packit fd8b60
\subsubsection{Context Initiation}
Packit fd8b60
Packit fd8b60
The client creates a GSS-API context with the server each time it
Packit fd8b60
calls auth_gssapi_create.  The context is created using the standard
Packit fd8b60
gss_init_sec_context and gss_accept_sec_context function calls.  The
Packit fd8b60
generated tokens are passed between the client and server as arguments
Packit fd8b60
and results of normal RPC calls.
Packit fd8b60
Packit fd8b60
The client side, in auth_gssapi_create, performs the following steps
Packit fd8b60
to initiate a context:
Packit fd8b60
Packit fd8b60
\begin{enumerate}
Packit fd8b60
\item\label{item:process-token} The client calls gss_init_sec_context.
Packit fd8b60
On the first such call, no input token is provided; on subsequent
Packit fd8b60
calls, the token received from the server is provided.
Packit fd8b60
Packit fd8b60
\item If gss_init_sec_context produces an output token:
Packit fd8b60
Packit fd8b60
\begin{enumerate}
Packit fd8b60
\item The client transmits the token to the server, identifying itself
Packit fd8b60
with client_handle if it has already been received (see next step).
Packit fd8b60
The return value from the server will contain a client_handle and one
Packit fd8b60
or both of a token and a signed initial sequence number.  
Packit fd8b60
Packit fd8b60
\item If this is the first response from the server, the client_handle
Packit fd8b60
is stored for subsequent calls.  Otherwise, the client_handle should be
Packit fd8b60
the same as returned on the previous call.
Packit fd8b60
Packit fd8b60
\item If the response contains a signed initian sequence number but
Packit fd8b60
the context is not yet established, then the response also contains a
Packit fd8b60
token that will established the context.  The signed initial sequence
Packit fd8b60
number is stored.
Packit fd8b60
Packit fd8b60
\item If the response contains a token, step \ref{item:process-token}
Packit fd8b60
repeated.
Packit fd8b60
\end{enumerate}
Packit fd8b60
Packit fd8b60
\item The signed initial sequence number is verified using the
Packit fd8b60
established context.
Packit fd8b60
\end{enumerate}
Packit fd8b60
Packit fd8b60
The server side, in _svcauth_gssapi, performs the following steps to
Packit fd8b60
initiate a context:
Packit fd8b60
Packit fd8b60
\begin{enumerate}
Packit fd8b60
\item If a call arrives with no client_handle, a new client_handle is
Packit fd8b60
allocated and stored in the database.  Otherwise, the client's
Packit fd8b60
previous state is is looked up in the database.
Packit fd8b60
Packit fd8b60
\item The received token is passed to gss_accept_sec_context.  If an
Packit fd8b60
output token is generated, it is returned to the client.  Note that
Packit fd8b60
since the application server may have registered multiple service
Packit fd8b60
names and there is no way to determine {\it a priori} which service a
Packit fd8b60
token is for, _svcauth_gssapi calls gss_accept_sec_context once for
Packit fd8b60
each registered credential until one of them succeeds.  The code
Packit fd8b60
assumes that GSS_S_FAILURE is the only error that can result from a
Packit fd8b60
credential mismatch, so any other error terminates the loop
Packit fd8b60
immediately.
Packit fd8b60
Packit fd8b60
\item If the context is established, the server signs an initial
Packit fd8b60
sequence number and returns it to the client.
Packit fd8b60
\end{enumerate}
Packit fd8b60
Packit fd8b60
Note that these algorithms require context establishment to be
Packit fd8b60
synchronous.  If gss_init_sec_context returns GSS_S_COMPLETE upon
Packit fd8b60
processing a token, it will either produce a token or not.  If it
Packit fd8b60
does, then gss_accept_sec_context will return GSS_S_COMPLETE when that
Packit fd8b60
token is processed; if it does not, then gss_accept_sec_context
Packit fd8b60
already returned GSS_S_COMPLETE (and presumably returned the token
Packit fd8b60
that caused gss_init_sec_context to return GSS_S_COMPLETE when
Packit fd8b60
processed).  The reverse is also true.
Packit fd8b60
Packit fd8b60
\subsubsection{RPC Calls}
Packit fd8b60
Packit fd8b60
After the GSS-API context is established, both the server and the
Packit fd8b60
client possess a client handle and a corresponding sequence number.
Packit fd8b60
Each call from the client contains the client handle as the
Packit fd8b60
``credential'' so that the server can identify which context to apply
Packit fd8b60
to the call.
Packit fd8b60
Packit fd8b60
Each client call and server response includes a ``verifier'' that
Packit fd8b60
contains the sealed current sequence number.\footnote{In a future
Packit fd8b60
version, the verifier will also contain a signature block for the call
Packit fd8b60
header, including the procedure number called.} The sequence number
Packit fd8b60
prevents replay attacks\footnote{Although some GSS-API mechanisms
Packit fd8b60
provide replay detection themselves, not all of them do; explicitly
Packit fd8b60
including the sequence number in the RPC therefore provides better
Packit fd8b60
end-to-end security}, but by itself it does not prevent splicing
Packit fd8b60
attacks.
Packit fd8b60
Packit fd8b60
Each procedure argument and result block consists of the current
Packit fd8b60
sequence number and the actual serialized argument string, all sealed
Packit fd8b60
with gss_seal.  Combining the sequence number with the argument/result
Packit fd8b60
data prevents splicing attacks.
Packit fd8b60
Packit fd8b60
The sequence number is incremented by one for each RPC call and by one
Packit fd8b60
for each response.  The client and server will both reject messages
Packit fd8b60
that do not contain the expected sequence number.  Packets
Packit fd8b60
retransmitted by the client should use the {\it same} sequence number
Packit fd8b60
as the original packet, since even if the server receives multiple
Packit fd8b60
copies only one will be honored.
Packit fd8b60
Packit fd8b60
\subsection{RPC Call Credential Structure}
Packit fd8b60
Packit fd8b60
Every message transmitted from the client to the server has a
Packit fd8b60
credentials (cb_cred) field of the type auth_gssapi_creds:
Packit fd8b60
Packit fd8b60
\begin{verbatim}
Packit fd8b60
typedef struct _auth_gssapi_creds {
Packit fd8b60
        bool_t       auth_msg;
Packit fd8b60
        gss_buffer_desc client_handle;
Packit fd8b60
};
Packit fd8b60
\end{verbatim}
Packit fd8b60
Packit fd8b60
The auth_msg field indicates whether the message is intended for the
Packit fd8b60
authentication mechanism for the actual server.  Any message whose
Packit fd8b60
auth_msg field is true is processed by the authentication mechanism;
Packit fd8b60
any message whose auth_msg is false is passed to the application
Packit fd8b60
server's dispatch function if authentication succeeds.  All messages
Packit fd8b60
must have an auth_msg of true until the context is established, since
Packit fd8b60
authentication cannot succeed until it is.
Packit fd8b60
Packit fd8b60
The client_handle field contains the client handle obtained from the
Packit fd8b60
first call to the server.  On the first call, this field is empty.
Packit fd8b60
Packit fd8b60
\subsection{GSS-API Authentication Flavor Procedures}
Packit fd8b60
Packit fd8b60
The GSS-API authentication flavor uses standard RPC calls over the
Packit fd8b60
client handle it is provided for the interactions described in
Packit fd8b60
\ref{sec:algorithms}.  All of the following procedures require the
Packit fd8b60
auth_msg field in the credentials to be true; otherwise, the
Packit fd8b60
server-side authentication flavor will simply attempt to authenticate
Packit fd8b60
the caller and pass the call to the application server.  The
Packit fd8b60
server-side authentication flavor uses the no_dispatch variable to
Packit fd8b60
indicate that it has handled the call.
Packit fd8b60
Packit fd8b60
\subsubsection{AUTH_GSSAPI_INIT, AUTH_GSSAPI_CONTINUE_INIT}
Packit fd8b60
Packit fd8b60
Context initiation is performed via AUTH_GSSAPI_INIT and
Packit fd8b60
AUTH_GSSAPI_CONTINUE_INIT.  The former is used to transfer the first
Packit fd8b60
token generated by gss_init_sec_context, when no client handle is
Packit fd8b60
included in the credentials; the latter is used on subsequent calls,
Packit fd8b60
when a client handle is included.
Packit fd8b60
Packit fd8b60
Both procedures take an argument of type auth_gssapi_init_arg and
Packit fd8b60
return results of the type auth_gssapi_init_res.
Packit fd8b60
Packit fd8b60
\begin{verbatim}
Packit fd8b60
typedef struct _auth_gssapi_init_arg {
Packit fd8b60
        u_long       version;
Packit fd8b60
        gss_buffer_desc token;
Packit fd8b60
} auth_gssapi_init_arg;
Packit fd8b60
\end{verbatim}
Packit fd8b60
Packit fd8b60
\begin{description}
Packit fd8b60
\item[version]  Three versions are presently defined.
Packit fd8b60
Packit fd8b60
\begin{description}
Packit fd8b60
\item[1] The original version, as described in this document
Packit fd8b60
Packit fd8b60
\item[2] In earlier versions of Secure there was a bug in the GSS-API
Packit fd8b60
library that affected the contents of accept_sec_context output
Packit fd8b60
tokens.  A client specifies version 2 to indicate that it expects the
Packit fd8b60
correct (fixed) behavior.  If the server indicates AUTH_BADCRED or
Packit fd8b60
AUTH_FAILED it does not understand this version, so the client should
Packit fd8b60
fall back to version 1.
Packit fd8b60
Packit fd8b60
\item[3] Version three indicates that channel bindings are in use.
Packit fd8b60
The client must specify channel bindings with the version, and the
Packit fd8b60
server will as well.  If the server indicates AUTH_BADCRED or
Packit fd8b60
AUTH_FAILED it does not understand this version, so the client should
Packit fd8b60
fall back to version 2 (and cease specifying channel bindings).
Packit fd8b60
Packit fd8b60
\item[4] The previous versions all used the old GSS-API krb5 mechanism
Packit fd8b60
oid; this version uses the new one specified in the RFC.  
Packit fd8b60
\end{description}
Packit fd8b60
Packit fd8b60
\item[token] The token field contains the token generated by
Packit fd8b60
gss_init_sec_context.
Packit fd8b60
\end{description}
Packit fd8b60
Packit fd8b60
\begin{verbatim}
Packit fd8b60
typedef struct _auth_gssapi_init_res {
Packit fd8b60
        u_long       version;
Packit fd8b60
        gss_buffer_desc client_handle;
Packit fd8b60
        gss_buffer_desc token;
Packit fd8b60
        OM_uint32 gss_major, gss_minor;
Packit fd8b60
        gss_buffer_desc signed_isn;
Packit fd8b60
} auth_gssapi_init_res;
Packit fd8b60
\end{verbatim}
Packit fd8b60
Packit fd8b60
\begin{description}
Packit fd8b60
\item[version] There are two versions currently defined.
Packit fd8b60
\begin{description}
Packit fd8b60
\item[1] The original version, as described in this document.  This is
Packit fd8b60
the response version for {\it both} versions 1 and 2.  The Secure 1.1
Packit fd8b60
server will always return this version.
Packit fd8b60
Packit fd8b60
\item[3] Version three indicates that the server specified channel
Packit fd8b60
bindings in response to a call arg version number of three.  The
Packit fd8b60
server must not specify this version unless the client does.
Packit fd8b60
\end{description}
Packit fd8b60
Packit fd8b60
\item[client_handle] The client_handle field contains the client
Packit fd8b60
handle that the client must use in the credentials field in all
Packit fd8b60
subsequent RPC calls.  In response to AUTH_GSSAPI_CONTINUE_INIT, it is
Packit fd8b60
the same client handle that arrived in the credentials.
Packit fd8b60
Packit fd8b60
\item[gss_major, gss_minor] The GSS-API error codes that resulted from
Packit fd8b60
processing the auth_gssapi_init_arg.  If gss_major is GSS_S_COMPLETE,
Packit fd8b60
the argument token was processed successfully.  Otherwise, gss_major
Packit fd8b60
and gss_minor contain the relevant major and minor status codes, and
Packit fd8b60
the context currently being negotiated is no longer valid.
Packit fd8b60
Packit fd8b60
\item[token] In any response that the client is expecting another
Packit fd8b60
token (i.e.: gss_init_sec_context last returned GSS_S_CONTINUE), the
Packit fd8b60
token field contains the output token from gss_accept_sec_context.  If
Packit fd8b60
the client is not expecting a token and this field is not empty, an
Packit fd8b60
error has occurred.
Packit fd8b60
Packit fd8b60
\item[signed_isn]  If the client is not expecting another token (i.e.:
Packit fd8b60
the previous call to gss_init_sec_context yielded a token and returned
Packit fd8b60
GSS_S_COMPLETE) or the supplied token completes the context, the
Packit fd8b60
signed_isn field contains the signed initial sequence number.  The
Packit fd8b60
server expects the first RPC call to have a sequence number one
Packit fd8b60
greater than the initial sequence number (so that the signed_isn block
Packit fd8b60
cannot be replayed).  If the client is expecting another token and the
Packit fd8b60
signed_isn field is not empty, an error has occurred.
Packit fd8b60
\end{description}
Packit fd8b60
Packit fd8b60
\subsubsection{AUTH_GSSAPI_DESTROY}
Packit fd8b60
Packit fd8b60
Context tear-down is performed via AUTH_GSSAPI_DESTROY.  This
Packit fd8b60
procedure takes no arguments and returns no results; it merely informs
Packit fd8b60
the server that the client wishes to destroy the established context.
Packit fd8b60
Packit fd8b60
When a client wishes to tear down an established context between
Packit fd8b60
itself and a server, auth_gssapi_destroy first calls the
Packit fd8b60
AUTH_GSSAPI_DESTROY procedure.  The server authenticates the message
Packit fd8b60
and immediately sends a ``success'' response with no results.  The
Packit fd8b60
client and server then both independently call gss_delete_sec_context
Packit fd8b60
and discard the context-destruction token that is generated.
Packit fd8b60
Packit fd8b60
No RPC error checking is performed by either the client or the server.
Packit fd8b60
The client waits a brief time for a success response from the server,
Packit fd8b60
but if none arrives it destroys the context anyway since presumably
Packit fd8b60
the user is waiting for the application to exit.  The server similar
Packit fd8b60
ignores any RPC errors since it knows that the client will ignore any
Packit fd8b60
errors that are reported.
Packit fd8b60
Packit fd8b60
\subsection{RPC Call Authentication Implementation}
Packit fd8b60
Packit fd8b60
Once the context has been established, all subsequent RPC calls are
Packit fd8b60
authenticated via the verifier described in section
Packit fd8b60
\ref{sec:algorithms}.
Packit fd8b60
Packit fd8b60
auth_gssapi_marshall, invoked via AUTH_MARSHALL while the RPC call is
Packit fd8b60
being created on the client side, serializes the client_handle
Packit fd8b60
obtained during context initiation {\it in plaintext} as the
Packit fd8b60
credentials and serializes the current sequence number, sealed with
Packit fd8b60
gss_seal, as the verifier.
Packit fd8b60
Packit fd8b60
auth_gssapi_wrap, invoked next via AUTH_WRAP, serializes a sealed
Packit fd8b60
token containing both the sequence number of the current call and the
Packit fd8b60
serialized arguments.
Packit fd8b60
Packit fd8b60
_svcauth_gssapi, invoked on the server side by _authenticate, uses the
Packit fd8b60
client_handle contained in the credentials to look up the correct
Packit fd8b60
context and verifies the sequence number provided in the verifier; if
Packit fd8b60
the sequence number is not correct, it declares a potential replay
Packit fd8b60
attack.\footnote{Retransmitted packets will appear as replay attacks,
Packit fd8b60
of course.} The response verifier is set to the serialized sealed
Packit fd8b60
incremented sequence number.
Packit fd8b60
Packit fd8b60
svc_auth_gssapi_unwrap, invoked when either the application server or
Packit fd8b60
_svcauth_gssapi (in response to an AUTH_GSSAPI authentication flavor
Packit fd8b60
message) attempts to read its arguments, deserialzes and unseals the
Packit fd8b60
block containing the current sequence number and serialized arguments.
Packit fd8b60
If the sequence number is incorrect, it declares a splicing attack;
Packit fd8b60
otherwise, it unserializes the arguments into the original structure.
Packit fd8b60
Packit fd8b60
svc_auth_gssapi_wrap, invoked when either the application server or
Packit fd8b60
_svcauth_gssapi attempts to write its response, performs the same
Packit fd8b60
operation as auth_gssapi_wrap.
Packit fd8b60
Packit fd8b60
auth_gssapi_validate, invoked by the client-side RPC mechanism when
Packit fd8b60
an RPC_SUCCESS response is received, verifies that the returned sequence
Packit fd8b60
number is one greater than the previous value sent by
Packit fd8b60
auth_gssapi_marshall.
Packit fd8b60
Packit fd8b60
Finally, auth_gssapi_unwrap, invoked by the client-side RPC mechanism
Packit fd8b60
after auth_gssapi_validate succeeds, performs the same operation as
Packit fd8b60
svc_auth_gssapi_unwrap.
Packit fd8b60
Packit fd8b60
If an RPC request generates an error message (a status of other than
Packit fd8b60
RPC_SUCCESS), auth_gssapi_refresh is called.  If the error status is
Packit fd8b60
AUTH_REJECTEDVERF, then the server rejected the sequence number as
Packit fd8b60
invalid or replayed.  The client guesses that, on some previous call,
Packit fd8b60
the server received a message but the server's response did not make
Packit fd8b60
it back to the client; this could happen if the packet got lost or if
Packit fd8b60
the server was being debugged and the client timed out waiting for it.
Packit fd8b60
As a result, the server is expected a higher sequence number than the
Packit fd8b60
client sent.  auth_gssapi_refresh increments the sequence number and
Packit fd8b60
returns true so that the call will be tried again.  The transport
Packit fd8b60
mechanism will only call auth_gssapi_refresh twice for each RPC
Packit fd8b60
request, so if some other error occurred an infinite loop will not
Packit fd8b60
result; however, it is unlikely the the client and server will be able
Packit fd8b60
to resynchronize after such an event.
Packit fd8b60
Packit fd8b60
\subsection{Client State Information}
Packit fd8b60
Packit fd8b60
The client-side GSS-API authentication flavor maintains an
Packit fd8b60
auth_gssapi_data structure for each authentication instance:
Packit fd8b60
Packit fd8b60
\begin{verbatim}
Packit fd8b60
struct auth_gssapi_data {
Packit fd8b60
     bool_t established;
Packit fd8b60
     CLIENT *clnt;
Packit fd8b60
     gss_ctx_id_t context;
Packit fd8b60
     gss_buffer_desc client_handle;
Packit fd8b60
     u_long seq_num;
Packit fd8b60
     int def_cred;
Packit fd8b60
Packit fd8b60
     /* pre-serialized ah_cred */
Packit fd8b60
     u_char cred_buf[MAX_AUTH_BYTES];
Packit fd8b60
     u_long cred_len;
Packit fd8b60
};
Packit fd8b60
\end{verbatim}
Packit fd8b60
Packit fd8b60
The established field indicates whether the authentication context
Packit fd8b60
between the client and server has been established.  It is set to true
Packit fd8b60
when gss_init_sec_context returns GSS_S_COM\-PLETE.  When this field is
Packit fd8b60
false, the auth_gssapi functions marshall, validate, wrap, and unwrap
Packit fd8b60
mimic the ``no authentication'' flavor since there is no context with
Packit fd8b60
which to perform authentication functions.\footnote{This field is
Packit fd8b60
necessary because, when auth_gssapi_create calls clnt_call to make an
Packit fd8b60
RPC call, it has to have set the client's authentication flavor to
Packit fd8b60
AUTH_GSSAPI; otherwise, the service-side RPC mechanism will not know
Packit fd8b60
to dispatch the call to _svcauth_gssapi.  However, with the client's
Packit fd8b60
authentication flavor set, all of the authentication flavor's
Packit fd8b60
functions will be automatically invoked, even though they are not
Packit fd8b60
ready to operate.}
Packit fd8b60
Packit fd8b60
The clnt field contains the RPC client structure that can be used to
Packit fd8b60
communicate with the GSS-API authentication flavor on the server.
Packit fd8b60
Packit fd8b60
The context field contains the context structure created by
Packit fd8b60
gss_init_sec_context.
Packit fd8b60
Packit fd8b60
The client_handle field contains the client handle used on all RPC
Packit fd8b60
calls except the first one; the handle is obtained as the result of
Packit fd8b60
the first call.
Packit fd8b60
Packit fd8b60
The sequence_number field contains the sequence number that will be
Packit fd8b60
used when transmitting RPC calls to the server and verifying the
Packit fd8b60
server's responses after the context is initialized.
Packit fd8b60
Packit fd8b60
The def_cred field is true if gss_init_sec_context created a default
Packit fd8b60
credential, in which case the authentication mechanism is responsible
Packit fd8b60
for releasing the default credential that gets automatically
Packit fd8b60
allocated.
Packit fd8b60
Packit fd8b60
The cred_buf and cred_len fields contain the pre-serialized
Packit fd8b60
credentials structure used in each call.  This provides a small
Packit fd8b60
performance enhancement since the credentials structure does not
Packit fd8b60
change very often; the same pre-serialized version can be used on
Packit fd8b60
virtually every call.
Packit fd8b60
Packit fd8b60
\subsection{Server State Information}
Packit fd8b60
\label{sec:server-state}
Packit fd8b60
Packit fd8b60
The server-side GSS-API authentication flavor maintains an
Packit fd8b60
svcauth_gssapi_data structure for each established or partially
Packit fd8b60
established context:
Packit fd8b60
Packit fd8b60
\begin{verbatim}
Packit fd8b60
typedef struct _svc_auth_gssapi_data {
Packit fd8b60
     bool_t established;
Packit fd8b60
     gss_ctx_id_t context;
Packit fd8b60
     gss_name_t client_name, server_name;
Packit fd8b60
     gss_cred_id_t server_creds;
Packit fd8b60
Packit fd8b60
     u_long expiration;
Packit fd8b60
     u_long seq_num;
Packit fd8b60
     u_long key;
Packit fd8b60
Packit fd8b60
     SVCAUTH svcauth;
Packit fd8b60
} svc_auth_gssapi_data;
Packit fd8b60
\end{verbatim}
Packit fd8b60
Packit fd8b60
The established field indicates whether the context is fully
Packit fd8b60
established.
Packit fd8b60
Packit fd8b60
The context field contains the context created by
Packit fd8b60
gss_accept_sec_context.
Packit fd8b60
Packit fd8b60
The client_name field contains the client's authenticated name, as
Packit fd8b60
returned by gss_accept_sec_context.  _svcauth_gssapi sets the ``cooked
Packit fd8b60
credentials'' field of the RPC call structure to this value after the
Packit fd8b60
call is authenticated; the application server can use it to perform
Packit fd8b60
authorization.
Packit fd8b60
Packit fd8b60
The server_name field contains the service name that the client
Packit fd8b60
established a context with.  This is useful if the application server
Packit fd8b60
registered more than one service name with the library; it allows the
Packit fd8b60
server to determine which service the client chose.
Packit fd8b60
Packit fd8b60
The server_creds field contains the service credentials that the
Packit fd8b60
client established a context with.  It is used to avoid having to scan
Packit fd8b60
through the server_creds_list multiple times in the case that context
Packit fd8b60
establishment requires more than one round-trip to the server.
Packit fd8b60
Packit fd8b60
The expiration field contains the expiration time of the context, as a
Packit fd8b60
Unix timestamp.  If a context has no expiration (time_rec is
Packit fd8b60
GSS_C_INDEFINITE), the expiration time is set to 24 hours in the
Packit fd8b60
future.  When the structure is created, before the context is
Packit fd8b60
established, the expiration time is initialized to small duration
Packit fd8b60
(currently 5 minutes) so that partially created and abandoned contexts
Packit fd8b60
will be expired quickly.
Packit fd8b60
Packit fd8b60
The seq_num field is the current sequence number for the client.
Packit fd8b60
Packit fd8b60
The key field is the client's key into the hash table (see below).
Packit fd8b60
The client_handle field sent to the client is the key treated as an
Packit fd8b60
arbitrary four-byte string.
Packit fd8b60
Packit fd8b60
The svcauth field is a kludge that allows the svc_auth_gssapi
Packit fd8b60
functions to access the per-client data structure while processing a
Packit fd8b60
call.  One SVCAUTH structure is allocated for each client structure,
Packit fd8b60
and the svc_ah_private field is set to the corresponding client.  The
Packit fd8b60
client's svcauth field is then set to the new SVCAUTH structure, so
Packit fd8b60
that client_data->svcauth->svc_ah_private == client_data.  As each
Packit fd8b60
request is processed, the transport mechanism's xp_auth field is set
Packit fd8b60
to the client's svcauth field; thus, the server-side functions that
Packit fd8b60
dispatch to server-side authentication flavors can access an
Packit fd8b60
appropriate SVCAUTH structure, and the server-side authentication
Packit fd8b60
function that is called can determine the appropriate per-client
Packit fd8b60
structure from the SVCAUTH structure.
Packit fd8b60
Packit fd8b60
The per-client structures are all stored both in a BSD 4.4 db library
Packit fd8b60
hash table and b-tree.  The hash table maps client handles (key
Packit fd8b60
fields) the client structures, and is used to look up client
Packit fd8b60
structures based on the client_handle field of a call's credentials
Packit fd8b60
structure.  The b-tree stores the client structures as keys, sorted by
Packit fd8b60
their expiration time.  Each time _svcauth_gssapi is activated, it
Packit fd8b60
traverses the tree and destroys all client structures that have
Packit fd8b60
expired.
Packit fd8b60
Packit fd8b60
\end{document}