The other half of context establishment is context acceptance, which is done through the gss_accept_sec_context() function. In a typical scenario, a server accepts a context initiated (with gss_init_sec_context()) by a client.
gss_accept_sec_context() takes as its main input an input token sent by the initiator. It returns a context handle as well as an output token to be returned to the initiator. Before gss_accept_sec_context() can be called, however, the server should acquire credentials for the service requested by the client. The server acquires these credentials with the gss_acquire_cred() function. Alternatively, the server can bypass acquiring credentials explicitly and instead specify the default credential (indicated by GSS_C_NO_CREDENTIAL) when calling gss_accept_sec_context().
The credential handle returned by gss_acquire_cred(), or
GSS_C_NO_CREDENTIAL to indicate the default credential, for the cred_handle argument.
GSS_C_NO_CONTEXT for the context_handle argument, to indicate an initial null context. Note that since gss_init_sec_context() is usually called in a loop, subsequent calls should pass the context handle returned by previous calls.
The context token received from the client for the input_token argument.
The full set of gss_accept_sec_context() arguments is described in the following paragraphs.
Security context establishment may require several “handshakes”; that is, the initiator and acceptor may have to send more than one piece of context information before the context is fully established. Therefore, for portability, context acceptance should always be done as part of a loop that checks whether the context has been fully established. If it hasn't, gss_accept_sec_context() returns a major-status code of GSS_C_CONTINUE_NEEDED. Thus a loop should use the value returned by gss_accept_sec_context() to test whether to continue the acceptance loop.
The context acceptor returns context information to the context initiator in the form of the output token returned by gss_accept_sec_context(). Subsequently, the acceptor can receive further information from the initiator as an input token, which is then passed as an argument to subsequent calls of gss_accept_sec_context(). When gss_accept_sec_context() has no more tokens to send to the initiator, it returns an output token with a length of zero. Therefore, in addition to checking for the return status of gss_accept_sec_context(), the loop should check the output token's length to see if a further token must be sent. Before the loop begins, the output token's length should be initialized to zero, either by setting
the output token to
GSS_C_NO_BUFFER or by setting the structure's length field to a value of zero.
This is what such a loop might look like, highly generalized:
context = GSS_C_NO_CONTEXT output token = GSS_C_NO_BUFFER do receive an input token from the initiator call gss_accept_sec_context(context, cred handle, input token, output token, other args...) if (there's an output token to send to the initiator) send the output token to the initiator release the output token if (there's a GSS-API error) delete the context until the context is complete
Naturally, a real loop will be more complete, doing much more extensive error-checking. See Accepting a Context (listing in server_establish_context()) for a real example of such a context-acceptance loop. Additionally, the gss_accept_sec_context() man page gives a somewhat less generic example than this.
Again, the GSS-API does not send or receive tokens; these must be handled by the application. Examples of token-transferring functions are found in send_token() and recv_token().
Here is a synopsis of gss_accept_sec_context(). For more information, see the gss_accept_sec_context(3GSS) man page.
OM_uint32 gss_accept_sec_context ( OM_uint32 *minor_status, gss_ctx_id_t *context_handle, const gss_cred_id_t acceptor_cred_handle, const gss_buffer_t input_token_buffer, const gss_channel_bindings_t input_chan_bindings, const gss_name_t *src_name, gss_OID *mech_type, gss_buffer_t output_token, OM_uint32 *ret_flags, OM_uint32 *time_req, gss_cred_id_t *delegated_cred_handle)
The status code returned by the underlying mechanism.
The context handle to return to the initiator. This argument should be set to
GSS_C_NO_CONTEXT before the loop begins.
The handle for the credentials acquired by the acceptor, typically through gss_acquire_cred()). Can be initialized to
GSS_C_NO_CREDENTIAL to indicate a default credential to use. If no default credential is defined, the function returns GSS_C_NO_CRED.
(Note: if gss_acquire_cred() was passed
GSS_C_NO_NAME as a principal name, it produces a credential that will cause gss_accept_sec_context() to treat it as a default credential.)
Token received from the context initiator.
Specific peer-to-peer channel identification information connected with the security context. See Channel Bindings for more information about channel bindings. Set to
GSS_C_NO_CHANNEL_BINDINGS if you don't want to use channel bindings.
The name of the initiating principal; for example, nfs@machinename. If you don't care, set to NULL.
The security mechanism used. Set to NULL if you don't care which mechanism is used.
The token to send to the initiator. Should be initialized to
GSS_C_NO_BUFFER before the function is called (or its length field set to zero). If the length is zero, no token needs to be sent.
if (ret_flags & GSS_C_CONF_FLAG) confidentiality = TRUE;
Indicates the initiator's credentials may be delegated via the delegated_cred_handle argument. See Delegation.
Indicates that mutual authentication is available. See Mutual Authentication.
Indicates that detection of repeated messages is available. See Out-of-Sequence Detection and Replay Detection.
Indicates that detection of out-of-sequence messages is available. See Out-of-Sequence Detection and Replay Detection.
If true, confidentiality service is allowed for transferred messages; that is, that messages can be encrypted. If confidentiality is not allowed, then only data-origin authentication and integrity services can be applied (this last only if GSS_C_INTEG_FLAG is not returned as false).
If true, the integrity service can be applied to messages; that is, that messages can be stamped with a MIC to ensure their validity.
Indicates that the context initiator will be anonymous. See Anonymous Authentication.
Sometimes context establishment can take several passes, and sometimes the client can send enough information on the initial passes to allow the acceptor to process context-related data, even though the context is incomplete. In those circumstances the acceptor needs to know in which way, if any, the information has been protected.
If true, GSS_C_PROT_READY_FLAG indicates that the protection services indicated by the GSS_C_CONF_FLAG and GSS_C_INTEG_FLAG flags are available. The acceptor can therefore call the appropriate data–reception functions, gss_unwrap() or gss_verify_mic(), with these services in mind.
(Additionally, as with the context initiator, the acceptor can use these flags in buffering any data it might want to send to the initiator, transmitting it when the context is fully established.)
If GSS_C_PROT_READY_FLAG is false, then the acceptor cannot make any assumptions about data protection, and must wait until the context is complete (that is, when gss_accept_sec_context() returns GSS_S_COMPLETE).
Earlier versions of the GSS-API did not support the GSS_C_PROT_READY_FLAG argument, so developers wanting to maximize portability should determine which per-message services are available by looking at the GSS_C_CONF_FLAG and GSS_C_INTEG_FLAG flags after a context has been successfully established.
If true, this context can be exported. For more information on importing and exporting contexts, see Context Export and Import.
Number of seconds for which the context will remain valid. Specify NULL if you're not interested in this value.
The credential handle for credentials received from the context initiator, that is, the client's credentials. Valid only if the initiator has requested that the acceptor act as a proxy: that is, if the ret_flags argument resolves to GSS_C_DELEG_FLAG. See Delegation for more about delegation.
gss_accept_sec_context() returns GSS_S_COMPLETE if it completes successfully. If the context is not complete, it returns GSS_S_CONTINUE_NEEDED. If there are errors, it returns error codes; for more information, see the gss_accept_sec_context(3GSS) man page.