Blame src/mechglue/gpp_init_sec_context.c

Packit Service 9f2c4a
/* Copyright (C) 2012 the GSS-PROXY contributors, see COPYING for license */
Packit Service 9f2c4a
Packit Service 9f2c4a
#include "gss_plugin.h"
Packit Service 9f2c4a
Packit Service 9f2c4a
static OM_uint32 init_ctx_local(OM_uint32 *minor_status,
Packit Service 9f2c4a
                                struct gpp_cred_handle *cred_handle,
Packit Service 9f2c4a
                                struct gpp_context_handle *ctx_handle,
Packit Service 9f2c4a
                                struct gpp_name_handle *name,
Packit Service 9f2c4a
                                gss_OID mech_type,
Packit Service 9f2c4a
                                OM_uint32 req_flags,
Packit Service 9f2c4a
                                OM_uint32 time_req,
Packit Service 9f2c4a
                                gss_channel_bindings_t input_cb,
Packit Service 9f2c4a
                                gss_buffer_t input_token,
Packit Service 9f2c4a
                                gss_OID *actual_mech_type,
Packit Service 9f2c4a
                                gss_buffer_t output_token,
Packit Service 9f2c4a
                                OM_uint32 *ret_flags,
Packit Service 9f2c4a
                                OM_uint32 *time_rec)
Packit Service 9f2c4a
{
Packit Service 9f2c4a
    OM_uint32 maj, min;
Packit Service 9f2c4a
Packit Service 9f2c4a
    if (name->remote && !name->local) {
Packit Service 9f2c4a
        maj = gpp_name_to_local(&min, name->remote,
Packit Service 9f2c4a
                                mech_type, &name->local);
Packit Service 9f2c4a
        if (maj) {
Packit Service 9f2c4a
            goto done;
Packit Service 9f2c4a
        }
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    maj = gss_init_sec_context(&min,
Packit Service 9f2c4a
                               cred_handle->local,
Packit Service 9f2c4a
                               &ctx_handle->local,
Packit Service 9f2c4a
                               name->local,
Packit Service 9f2c4a
                               gpp_special_mech(mech_type),
Packit Service 9f2c4a
                               req_flags,
Packit Service 9f2c4a
                               time_req,
Packit Service 9f2c4a
                               input_cb,
Packit Service 9f2c4a
                               input_token,
Packit Service 9f2c4a
                               actual_mech_type,
Packit Service 9f2c4a
                               output_token,
Packit Service 9f2c4a
                               ret_flags,
Packit Service 9f2c4a
                               time_rec);
Packit Service 9f2c4a
Packit Service 9f2c4a
done:
Packit Service 9f2c4a
    *minor_status = min;
Packit Service 9f2c4a
    return maj;
Packit Service 9f2c4a
}
Packit Service 9f2c4a
Packit Service 9f2c4a
OM_uint32 gssi_init_sec_context(OM_uint32 *minor_status,
Packit Service 9f2c4a
                                gss_cred_id_t claimant_cred_handle,
Packit Service 9f2c4a
                                gss_ctx_id_t *context_handle,
Packit Service 9f2c4a
                                gss_name_t target_name,
Packit Service 9f2c4a
                                gss_OID mech_type,
Packit Service 9f2c4a
                                OM_uint32 req_flags,
Packit Service 9f2c4a
                                OM_uint32 time_req,
Packit Service 9f2c4a
                                gss_channel_bindings_t input_cb,
Packit Service 9f2c4a
                                gss_buffer_t input_token,
Packit Service 9f2c4a
                                gss_OID *actual_mech_type,
Packit Service 9f2c4a
                                gss_buffer_t output_token,
Packit Service 9f2c4a
                                OM_uint32 *ret_flags,
Packit Service 9f2c4a
                                OM_uint32 *time_rec)
Packit Service 9f2c4a
{
Packit Service 9f2c4a
    enum gpp_behavior behavior = GPP_UNINITIALIZED;
Packit Service 9f2c4a
    struct gpp_context_handle *ctx_handle = NULL;
Packit Service 9f2c4a
    struct gpp_cred_handle *cred_handle = NULL;
Packit Service 9f2c4a
    gssx_cred *out_cred = NULL;
Packit Service 9f2c4a
    struct gpp_name_handle *name;
Packit Service 9f2c4a
    OM_uint32 tmaj, tmin;
Packit Service 9f2c4a
    OM_uint32 maj, min;
Packit Service 9f2c4a
Packit Service 9f2c4a
    GSSI_TRACE();
Packit Service 9f2c4a
Packit Service 9f2c4a
    *minor_status = 0;
Packit Service 9f2c4a
Packit Service 9f2c4a
    if (target_name == GSS_C_NO_NAME) {
Packit Service 9f2c4a
        return GSS_S_CALL_INACCESSIBLE_READ;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    if (mech_type == GSS_C_NO_OID || gpp_is_special_oid(mech_type)) {
Packit Service 9f2c4a
        return GSS_S_BAD_MECH;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    tmaj = GSS_S_COMPLETE;
Packit Service 9f2c4a
    tmin = 0;
Packit Service 9f2c4a
Packit Service 9f2c4a
    if (*context_handle) {
Packit Service 9f2c4a
        ctx_handle = (struct gpp_context_handle *)*context_handle;
Packit Service 9f2c4a
        if (ctx_handle->local) {
Packit Service 9f2c4a
            /* ok this means a previous call decided to use the local mech,
Packit Service 9f2c4a
             * so let's just re-enter the mechglue here and keep at it */
Packit Service 9f2c4a
            behavior = GPP_LOCAL_ONLY;
Packit Service 9f2c4a
        }
Packit Service 9f2c4a
    } else {
Packit Service 9f2c4a
        ctx_handle = calloc(1, sizeof(struct gpp_context_handle));
Packit Service 9f2c4a
        if (!ctx_handle) {
Packit Service 9f2c4a
            maj = GSS_S_FAILURE;
Packit Service 9f2c4a
            min = ENOMEM;
Packit Service 9f2c4a
            goto done;
Packit Service 9f2c4a
        }
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    if (claimant_cred_handle != GSS_C_NO_CREDENTIAL) {
Packit Service 9f2c4a
        cred_handle = (struct gpp_cred_handle *)claimant_cred_handle;
Packit Service 9f2c4a
        if (cred_handle->local) {
Packit Service 9f2c4a
            /* ok this means a previous call decided to short circuit to the
Packit Service 9f2c4a
             * local mech, so let's just re-enter the mechglue here, as we
Packit Service 9f2c4a
             * have no way to export creds yet. */
Packit Service 9f2c4a
            behavior = GPP_LOCAL_ONLY;
Packit Service 9f2c4a
        } else if (behavior == GPP_LOCAL_ONLY) {
Packit Service 9f2c4a
            maj = GSS_S_DEFECTIVE_CREDENTIAL;
Packit Service 9f2c4a
            min = 0;
Packit Service 9f2c4a
            goto done;
Packit Service 9f2c4a
        }
Packit Service 9f2c4a
    } else {
Packit Service 9f2c4a
        maj = gpp_cred_handle_init(&min, true, NULL, &cred_handle);
Packit Service 9f2c4a
        if (maj) {
Packit Service 9f2c4a
            goto done;
Packit Service 9f2c4a
        }
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    name = (struct gpp_name_handle *)target_name;
Packit Service 9f2c4a
    if (behavior == GPP_UNINITIALIZED) {
Packit Service 9f2c4a
        behavior = gpp_get_behavior();
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    /* See if we should try local first */
Packit Service 9f2c4a
    if (behavior == GPP_LOCAL_ONLY || behavior == GPP_LOCAL_FIRST) {
Packit Service 9f2c4a
Packit Service 9f2c4a
        maj = init_ctx_local(&min, cred_handle, ctx_handle, name,
Packit Service 9f2c4a
                              mech_type, req_flags, time_req, input_cb,
Packit Service 9f2c4a
                              input_token, actual_mech_type, output_token,
Packit Service 9f2c4a
                              ret_flags, time_rec);
Packit Service 9f2c4a
Packit Service 9f2c4a
        if (maj == GSS_S_COMPLETE || maj == GSS_S_CONTINUE_NEEDED ||
Packit Service 9f2c4a
            behavior == GPP_LOCAL_ONLY) {
Packit Service 9f2c4a
            goto done;
Packit Service 9f2c4a
        }
Packit Service 9f2c4a
Packit Service 9f2c4a
        /* not successful, save actual local error if remote fallback fails */
Packit Service 9f2c4a
        tmaj = maj;
Packit Service 9f2c4a
        tmin = min;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    /* Then try with remote */
Packit Service 9f2c4a
    if (behavior != GPP_LOCAL_ONLY) {
Packit Service 9f2c4a
        if (name->local && !name->remote) {
Packit Service 9f2c4a
            maj = gpp_local_to_name(&min, name->local, &name->remote);
Packit Service 9f2c4a
            if (maj) {
Packit Service 9f2c4a
                goto done;
Packit Service 9f2c4a
            }
Packit Service 9f2c4a
        }
Packit Service 9f2c4a
Packit Service 9f2c4a
        if (!cred_handle->remote) {
Packit Service 9f2c4a
            /* we ignore failures here */
Packit Service 9f2c4a
            (void)gppint_get_def_creds(&min, GPP_REMOTE_ONLY, NULL,
Packit Service 9f2c4a
                                       GSS_C_INITIATE, &cred_handle);
Packit Service 9f2c4a
        }
Packit Service 9f2c4a
Packit Service 9f2c4a
        maj = gpm_init_sec_context(&min,
Packit Service 9f2c4a
                                   cred_handle->remote,
Packit Service 9f2c4a
                                   &ctx_handle->remote,
Packit Service 9f2c4a
                                   name->remote,
Packit Service 9f2c4a
                                   mech_type,
Packit Service 9f2c4a
                                   req_flags,
Packit Service 9f2c4a
                                   time_req,
Packit Service 9f2c4a
                                   input_cb,
Packit Service 9f2c4a
                                   input_token,
Packit Service 9f2c4a
                                   actual_mech_type,
Packit Service 9f2c4a
                                   output_token,
Packit Service 9f2c4a
                                   ret_flags,
Packit Service 9f2c4a
                                   time_rec,
Packit Service 9f2c4a
                                   &out_cred);
Packit Service 9f2c4a
        if (maj == GSS_S_COMPLETE || maj == GSS_S_CONTINUE_NEEDED) {
Packit Service 9f2c4a
            if (out_cred) {
Packit Service 9f2c4a
                xdr_free((xdrproc_t)xdr_gssx_cred,
Packit Service 9f2c4a
                         (char *)cred_handle->remote);
Packit Service 9f2c4a
                free(cred_handle->remote);
Packit Service 9f2c4a
                cred_handle->remote = out_cred;
Packit Service 9f2c4a
                out_cred = NULL;
Packit Service 9f2c4a
                /* failuire is not fatal */
Packit Service 9f2c4a
                (void)gpp_store_remote_creds(&tmin,
Packit Service 9f2c4a
                                             cred_handle->default_creds,
Packit Service 9f2c4a
                                             &cred_handle->store,
Packit Service 9f2c4a
                                             cred_handle->remote);
Packit Service 9f2c4a
            }
Packit Service 9f2c4a
            goto done;
Packit Service 9f2c4a
        }
Packit Service 9f2c4a
Packit Service 9f2c4a
        if (behavior == GPP_REMOTE_FIRST) {
Packit Service 9f2c4a
            /* So remote failed, but we can fallback to local, try that */
Packit Service 9f2c4a
            maj = init_ctx_local(&min, cred_handle, ctx_handle, name,
Packit Service 9f2c4a
                                 mech_type, req_flags, time_req, input_cb,
Packit Service 9f2c4a
                                 input_token, actual_mech_type, output_token,
Packit Service 9f2c4a
                                 ret_flags, time_rec);
Packit Service 9f2c4a
        }
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
done:
Packit Service 9f2c4a
    if (maj != GSS_S_COMPLETE &&
Packit Service 9f2c4a
        maj != GSS_S_CONTINUE_NEEDED &&
Packit Service 9f2c4a
        tmaj != GSS_S_COMPLETE) {
Packit Service 9f2c4a
        maj = tmaj;
Packit Service 9f2c4a
        min = tmin;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
    if (maj != GSS_S_COMPLETE && maj != GSS_S_CONTINUE_NEEDED) {
Packit Service 9f2c4a
        if (ctx_handle &&
Packit Service 9f2c4a
            ctx_handle->local == GSS_C_NO_CONTEXT &&
Packit Service 9f2c4a
            ctx_handle->remote == NULL) {
Packit Service 9f2c4a
            free(ctx_handle);
Packit Service 9f2c4a
            ctx_handle = NULL;
Packit Service 9f2c4a
        }
Packit Service 9f2c4a
        *minor_status = gpp_map_error(min);
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
    /* always replace the provided context handle to avoid
Packit Service 9f2c4a
     * dangling pointers when a context has been passed in */
Packit Service 9f2c4a
    *context_handle = (gss_ctx_id_t)ctx_handle;
Packit Service 9f2c4a
Packit Service 9f2c4a
    if (claimant_cred_handle == GSS_C_NO_CREDENTIAL) {
Packit Service 9f2c4a
        free(cred_handle);
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
    return maj;
Packit Service 9f2c4a
}