gss_init_sec_context() and gss_accept_sec_context() both output a token and either create or modify a security context. There are some additional outputs: actual_mech_type, ret_flags, and time_rec for gss_init_sec_context(), and src_name, mech_type, ret_flags, time_rec, and delegated_cred_handle for gss_accept_sec_context(). RFC 2744 sections 5.1 and 5.19 define some rules for how these parameters should be set when GSS_S_CONTINUE_NEEDED is returned.
Although the mechglue initializes most output parameters, it does not do so for ret_flags and time_rec. This is a separate bug, which impacts the following SPNEGO misbehaviors; if SPNEGO does not set these output parameters, the caller's value will remain unchanged.
The current SPNEGO implementation has the following bugs related to the additional output parameters:
* gss_init_sec_context() only sets ret_flags if the underlying mech is called and returns GSS_S_COMPLETE, or if SPNEGO itself will return GSS_S_COMPLETE. gss_accept_sec_context() initializes ret_flags to 0, and only sets ret_flags to another value if the underlying mech is called and returns GSS_S_COMPLETE; ret_flags could remain as 0 on SPNEGO's final return from gss_accept_sec_context(), if the MIC exchange forces an extra round trip.
* gss_init_sec_context() and gss_accept_sec_context() do not filter out PROT_READY from ret_flags as required by RFC 4178.
* gss_init_sec_context() and gss_accept_sec_context() pass time_rec directly to the underlying mech. gss_accept_sec_context() initializes time_rec to 0 but gss_init_sec_context() does not. Neither function will set time_rec to a meaningful value if the underlying mech is not called on the final SPNEGO call due to the MIC exchange. Note that time_rec is relative to the current time; if SPNEGO records time_rec from the underlying mech at one step and reports it to the caller at a later step, the time differential between steps could render that value inaccurate. SPNEGO could either adjust the value by the differential, or call gss_context_time() on the underlying context.
* gss_accept_sec_context() initializes mech_type to GSS_C_NO_OID and passes it directly to the underlying mech. If the underlying mech is not called on the final step, mech_type will remain as GSS_C_NO_OID.
* gss_accept_sec_context() initializes delegated_cred_handle to GSS_C_NO_CREDENTIAL and passes it directly to the underlying mech. SPNEGO could report a delegated cred to the caller too early (before the MIC exchange) and not on the final call.
* gss_accept_sec_context() could leak a value of src_name (recorded as sc->internal_name) if the underlying mech reports it twice. RFC 2744 doesn't explicitly prohibit this, although it seems like it should be unusual.