int authenticate_gss_client_step()

in src/kerberosgss.c [234:347]


int authenticate_gss_client_step(
    gss_client_state* state, const char* challenge, struct gss_channel_bindings_struct* channel_bindings
) {
    OM_uint32 maj_stat;
    OM_uint32 min_stat;
    gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
    gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
    int ret = AUTH_GSS_CONTINUE;
    
    // Always clear out the old response
    if (state->response != NULL) {
        free(state->response);
        state->response = NULL;
    }
    
    // If there is a challenge (data from the server) we need to give it to GSS
    if (challenge && *challenge) {
        size_t len;
        input_token.value = base64_decode(challenge, &len);
        if (input_token.value == NULL)
        {
            PyErr_NoMemory();
            ret = AUTH_GSS_ERROR;
            goto end;
        }
        input_token.length = len;
    }
    
    // Do GSSAPI step
    Py_BEGIN_ALLOW_THREADS
    maj_stat = gss_init_sec_context(
        &min_stat,
        state->client_creds,
        &state->context,
        state->server_name,
        state->mech_oid,
        (OM_uint32)state->gss_flags,
        0,
        channel_bindings,
        &input_token,
        NULL,
        &output_token,
        NULL,
        NULL
    );
    Py_END_ALLOW_THREADS
    
    if ((maj_stat != GSS_S_COMPLETE) && (maj_stat != GSS_S_CONTINUE_NEEDED)) {
        set_gss_error(maj_stat, min_stat);
        ret = AUTH_GSS_ERROR;
        goto end;
    }
    
    ret = (maj_stat == GSS_S_COMPLETE) ? AUTH_GSS_COMPLETE : AUTH_GSS_CONTINUE;
    // Grab the client response to send back to the server
    if (output_token.length) {
        state->response = base64_encode((const unsigned char *)output_token.value, output_token.length);
        if (state->response == NULL) {
            PyErr_NoMemory();
            ret = AUTH_GSS_ERROR;
            goto end;
        }
        maj_stat = gss_release_buffer(&min_stat, &output_token);
    }
    
    // Try to get the user name if we have completed all GSS operations
    if (ret == AUTH_GSS_COMPLETE) {
        gss_name_t gssuser = GSS_C_NO_NAME;
        maj_stat = gss_inquire_context(&min_stat, state->context, &gssuser, NULL, NULL, NULL,  NULL, NULL, NULL);
        if (GSS_ERROR(maj_stat)) {
            set_gss_error(maj_stat, min_stat);
            ret = AUTH_GSS_ERROR;
            goto end;
        }
        
        gss_buffer_desc name_token;
        name_token.length = 0;
        maj_stat = gss_display_name(&min_stat, gssuser, &name_token, NULL);
        if (GSS_ERROR(maj_stat)) {
            if (name_token.value) {
                gss_release_buffer(&min_stat, &name_token);
            }
            gss_release_name(&min_stat, &gssuser);
            
            set_gss_error(maj_stat, min_stat);
            ret = AUTH_GSS_ERROR;
            goto end;
        } else {
            if (state->username != NULL) {                                                                                                    
                free(state->username);                                                                                                        
                state->username = NULL;                                                                                                       
            }                                                                                                                                 
            state->username = (char *)malloc(name_token.length + 1);
            if (state->username == NULL) {
                PyErr_NoMemory();
                ret = AUTH_GSS_ERROR;
                goto end;
            }
            strncpy(state->username, (char*) name_token.value, name_token.length);
            state->username[name_token.length] = 0;
            gss_release_buffer(&min_stat, &name_token);
            gss_release_name(&min_stat, &gssuser);
        }
    }

end:
    if (output_token.value) {
        gss_release_buffer(&min_stat, &output_token);
    }
    if (input_token.value) {
        free(input_token.value);
    }
    return ret;
}