Blame src/gssapi.c

Packit Service 31306d
/*
Packit Service 31306d
 * This file is part of the SSH Library
Packit Service 31306d
 *
Packit Service 31306d
 * Copyright (c) 2013 by Aris Adamantiadis <aris@badcode.be>
Packit Service 31306d
 *
Packit Service 31306d
 * The SSH Library is free software; you can redistribute it and/or modify
Packit Service 31306d
 * it under the terms of the GNU Lesser General Public License as published by
Packit Service 31306d
 * the Free Software Foundation; either version 2.1 of the License, or (at your
Packit Service 31306d
 * option) any later version.
Packit Service 31306d
 *
Packit Service 31306d
 * The SSH Library is distributed in the hope that it will be useful, but
Packit Service 31306d
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
Packit Service 31306d
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
Packit Service 31306d
 * License for more details.
Packit Service 31306d
 *
Packit Service 31306d
 * You should have received a copy of the GNU Lesser General Public License
Packit Service 31306d
 * along with the SSH Library; see the file COPYING.  If not, write to
Packit Service 31306d
 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
Packit Service 31306d
 * MA 02111-1307, USA.
Packit Service 31306d
 */
Packit Service 31306d
Packit Service 31306d
#include "config.h"
Packit Service 31306d
Packit Service 31306d
#include <stdio.h>
Packit Service 31306d
#include <stdlib.h>
Packit Service 31306d
#ifdef HAVE_UNISTD_H
Packit Service 31306d
#include <unistd.h>
Packit Service 31306d
#endif
Packit Service 31306d
Packit Service 31306d
#include <gssapi/gssapi.h>
Packit Service 31306d
Packit Service 31306d
#include <libssh/gssapi.h>
Packit Service 31306d
#include <libssh/libssh.h>
Packit Service 31306d
#include <libssh/ssh2.h>
Packit Service 31306d
#include <libssh/buffer.h>
Packit Service 31306d
#include <libssh/crypto.h>
Packit Service 31306d
#include <libssh/callbacks.h>
Packit Service 31306d
#include <libssh/string.h>
Packit Service 31306d
#include <libssh/server.h>
Packit Service 31306d
Packit Service 31306d
/** current state of an GSSAPI authentication */
Packit Service 31306d
enum ssh_gssapi_state_e {
Packit Service 31306d
    SSH_GSSAPI_STATE_NONE, /* no status */
Packit Service 31306d
    SSH_GSSAPI_STATE_RCV_TOKEN, /* Expecting a token */
Packit Service 31306d
    SSH_GSSAPI_STATE_RCV_MIC, /* Expecting a MIC */
Packit Service 31306d
};
Packit Service 31306d
Packit Service 31306d
struct ssh_gssapi_struct{
Packit Service 31306d
    enum ssh_gssapi_state_e state; /* current state */
Packit Service 31306d
    struct gss_OID_desc_struct mech; /* mechanism being elected for auth */
Packit Service 31306d
    gss_cred_id_t server_creds; /* credentials of server */
Packit Service 31306d
    gss_cred_id_t client_creds; /* creds delegated by the client */
Packit Service 31306d
    gss_ctx_id_t ctx; /* the authentication context */
Packit Service 31306d
    gss_name_t client_name; /* Identity of the client */
Packit Service 31306d
    char *user; /* username of client */
Packit Service 31306d
    char *canonic_user; /* canonic form of the client's username */
Packit Service 31306d
    char *service; /* name of the service */
Packit Service 31306d
    struct {
Packit Service 31306d
        gss_name_t server_name; /* identity of server */
Packit Service 31306d
        OM_uint32 flags; /* flags used for init context */
Packit Service 31306d
        gss_OID oid; /* mech being used for authentication */
Packit Service 31306d
        gss_cred_id_t creds; /* creds used to initialize context */
Packit Service 31306d
        gss_cred_id_t client_deleg_creds; /* delegated creds (const, not freeable) */
Packit Service 31306d
    } client;
Packit Service 31306d
};
Packit Service 31306d
Packit Service 31306d
Packit Service 31306d
/** @internal
Packit Service 31306d
 * @initializes a gssapi context for authentication
Packit Service 31306d
 */
Packit Service 31306d
static int ssh_gssapi_init(ssh_session session){
Packit Service 31306d
    if (session->gssapi != NULL)
Packit Service 31306d
        return SSH_OK;
Packit Service 31306d
    session->gssapi = malloc(sizeof(struct ssh_gssapi_struct));
Packit Service 31306d
    if(!session->gssapi){
Packit Service 31306d
        ssh_set_error_oom(session);
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
    ZERO_STRUCTP(session->gssapi);
Packit Service 31306d
    session->gssapi->server_creds = GSS_C_NO_CREDENTIAL;
Packit Service 31306d
    session->gssapi->client_creds = GSS_C_NO_CREDENTIAL;
Packit Service 31306d
    session->gssapi->ctx = GSS_C_NO_CONTEXT;
Packit Service 31306d
    session->gssapi->state = SSH_GSSAPI_STATE_NONE;
Packit Service 31306d
    return SSH_OK;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/** @internal
Packit Service 31306d
 * @frees a gssapi context
Packit Service 31306d
 */
Packit Service 31306d
static void ssh_gssapi_free(ssh_session session){
Packit Service 31306d
    OM_uint32 min;
Packit Service 31306d
    if (session->gssapi == NULL)
Packit Service 31306d
        return;
Packit Service 31306d
    SAFE_FREE(session->gssapi->user);
Packit Service 31306d
    SAFE_FREE(session->gssapi->mech.elements);
Packit Service 31306d
    gss_release_cred(&min,&session->gssapi->server_creds);
Packit Service 31306d
    if (session->gssapi->client.creds !=
Packit Service 31306d
                    session->gssapi->client.client_deleg_creds) {
Packit Service 31306d
        gss_release_cred(&min, &session->gssapi->client.creds);
Packit Service 31306d
    }
Packit Service 31306d
    SAFE_FREE(session->gssapi);
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_token){
Packit Service 31306d
#ifdef WITH_SERVER
Packit Service 31306d
    if(session->server)
Packit Service 31306d
        return ssh_packet_userauth_gssapi_token_server(session, type, packet, user);
Packit Service 31306d
#endif
Packit Service 31306d
    return ssh_packet_userauth_gssapi_token_client(session, type, packet, user);
Packit Service 31306d
}
Packit Service 31306d
#ifdef WITH_SERVER
Packit Service 31306d
Packit Service 31306d
/** @internal
Packit Service 31306d
 * @brief sends a SSH_MSG_USERAUTH_GSSAPI_RESPONSE packet
Packit Service 31306d
 * @param[in] oid the OID that was selected for authentication
Packit Service 31306d
 */
Packit Service 31306d
static int ssh_gssapi_send_response(ssh_session session, ssh_string oid){
Packit Service 31306d
    if (ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_GSSAPI_RESPONSE) < 0 ||
Packit Service 31306d
            ssh_buffer_add_ssh_string(session->out_buffer,oid) < 0) {
Packit Service 31306d
        ssh_set_error_oom(session);
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
    session->auth.state = SSH_AUTH_STATE_GSSAPI_TOKEN;
Packit Service 31306d
Packit Service 31306d
    ssh_packet_send(session);
Packit Service 31306d
    SSH_LOG(SSH_LOG_PACKET,
Packit Service 31306d
            "Sent SSH_MSG_USERAUTH_GSSAPI_RESPONSE");
Packit Service 31306d
    return SSH_OK;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
#endif /* WITH_SERVER */
Packit Service 31306d
Packit Service 31306d
static void ssh_gssapi_log_error(int verb,
Packit Service 31306d
                                 const char *msg,
Packit Service 31306d
                                 int maj_stat,
Packit Service 31306d
                                 int min_stat)
Packit Service 31306d
{
Packit Service 31306d
    gss_buffer_desc msg_maj = {
Packit Service 31306d
        .length = 0,
Packit Service 31306d
    };
Packit Service 31306d
    gss_buffer_desc msg_min = {
Packit Service 31306d
        .length = 0,
Packit Service 31306d
    };
Packit Service 31306d
    OM_uint32 dummy_maj, dummy_min;
Packit Service 31306d
    OM_uint32 message_context = 0;
Packit Service 31306d
Packit Service 31306d
    dummy_maj = gss_display_status(&dummy_min,
Packit Service 31306d
                                   maj_stat,
Packit Service 31306d
                                   GSS_C_GSS_CODE,
Packit Service 31306d
                                   GSS_C_NO_OID,
Packit Service 31306d
                                   &message_context,
Packit Service 31306d
                                   &msg_maj);
Packit Service 31306d
    if (dummy_maj != 0) {
Packit Service 31306d
        goto out;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    dummy_maj = gss_display_status(&dummy_min,
Packit Service 31306d
                                   min_stat,
Packit Service 31306d
                                   GSS_C_MECH_CODE,
Packit Service 31306d
                                   GSS_C_NO_OID,
Packit Service 31306d
                                   &message_context,
Packit Service 31306d
                                   &msg_min);
Packit Service 31306d
    if (dummy_maj != 0) {
Packit Service 31306d
        goto out;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    SSH_LOG(verb,
Packit Service 31306d
            "GSSAPI(%s): %s - %s",
Packit Service 31306d
            msg,
Packit Service 31306d
            (const char *)msg_maj.value,
Packit Service 31306d
            (const char *)msg_min.value);
Packit Service 31306d
Packit Service 31306d
out:
Packit Service 31306d
    if (msg_maj.value) {
Packit Service 31306d
        gss_release_buffer(&dummy_min, &msg_maj);
Packit Service 31306d
    }
Packit Service 31306d
    if (msg_min.value) {
Packit Service 31306d
        gss_release_buffer(&dummy_min, &msg_min);
Packit Service 31306d
    }
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
#ifdef WITH_SERVER
Packit Service 31306d
Packit Service 31306d
/** @internal
Packit Service 31306d
 * @brief handles an user authentication using GSSAPI
Packit Service 31306d
 */
Packit Service 31306d
int ssh_gssapi_handle_userauth(ssh_session session, const char *user, uint32_t n_oid, ssh_string *oids){
Packit Service 31306d
    char service_name[]="host";
Packit Service 31306d
    gss_buffer_desc name_buf;
Packit Service 31306d
    gss_name_t server_name; /* local server fqdn */
Packit Service 31306d
    OM_uint32 maj_stat, min_stat;
Packit Service 31306d
    size_t i;
Packit Service 31306d
    char *ptr;
Packit Service 31306d
    gss_OID_set supported; /* oids supported by server */
Packit Service 31306d
    gss_OID_set both_supported; /* oids supported by both client and server */
Packit Service 31306d
    gss_OID_set selected; /* oid selected for authentication */
Packit Service 31306d
    int present=0;
Packit Service 31306d
    size_t oid_count=0;
Packit Service 31306d
    struct gss_OID_desc_struct oid;
Packit Service 31306d
    int rc;
Packit Service 31306d
Packit Service 31306d
    if (ssh_callbacks_exists(session->server_callbacks, gssapi_select_oid_function)){
Packit Service 31306d
        ssh_string oid_s = session->server_callbacks->gssapi_select_oid_function(session,
Packit Service 31306d
                user, n_oid, oids,
Packit Service 31306d
                session->server_callbacks->userdata);
Packit Service 31306d
        if (oid_s != NULL){
Packit Service 31306d
            if (ssh_gssapi_init(session) == SSH_ERROR)
Packit Service 31306d
                return SSH_ERROR;
Packit Service 31306d
            session->gssapi->state = SSH_GSSAPI_STATE_RCV_TOKEN;
Packit Service 31306d
            rc = ssh_gssapi_send_response(session, oid_s);
Packit Service 31306d
            SSH_STRING_FREE(oid_s);
Packit Service 31306d
            return rc;
Packit Service 31306d
        } else {
Packit Service 31306d
            return ssh_auth_reply_default(session,0);
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
    gss_create_empty_oid_set(&min_stat, &both_supported);
Packit Service 31306d
Packit Service 31306d
    maj_stat = gss_indicate_mechs(&min_stat, &supported);
Packit Service 31306d
    if (maj_stat != GSS_S_COMPLETE) {
Packit Service 31306d
        SSH_LOG(SSH_LOG_WARNING, "indicate mecks %d, %d", maj_stat, min_stat);
Packit Service 31306d
        ssh_gssapi_log_error(SSH_LOG_WARNING,
Packit Service 31306d
                             "indicate mechs",
Packit Service 31306d
                             maj_stat,
Packit Service 31306d
                             min_stat);
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    for (i=0; i < supported->count; ++i){
Packit Service 31306d
        ptr = ssh_get_hexa(supported->elements[i].elements, supported->elements[i].length);
Packit Service 31306d
        SSH_LOG(SSH_LOG_DEBUG, "Supported mech %zu: %s", i, ptr);
Packit Service 31306d
        free(ptr);
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    for (i=0 ; i< n_oid ; ++i){
Packit Service 31306d
        unsigned char *oid_s = (unsigned char *) ssh_string_data(oids[i]);
Packit Service 31306d
        size_t len = ssh_string_len(oids[i]);
Packit Service 31306d
Packit Service 31306d
        if (oid_s == NULL) {
Packit Service 31306d
            continue;
Packit Service 31306d
        }
Packit Service 31306d
        if(len < 2 || oid_s[0] != SSH_OID_TAG || ((size_t)oid_s[1]) != len - 2){
Packit Service 31306d
            SSH_LOG(SSH_LOG_WARNING,"GSSAPI: received invalid OID");
Packit Service 31306d
            continue;
Packit Service 31306d
        }
Packit Service 31306d
        oid.elements = &oid_s[2];
Packit Service 31306d
        oid.length = len - 2;
Packit Service 31306d
        gss_test_oid_set_member(&min_stat,&oid,supported,&present);
Packit Service 31306d
        if(present){
Packit Service 31306d
            gss_add_oid_set_member(&min_stat,&oid,&both_supported);
Packit Service 31306d
            oid_count++;
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
    gss_release_oid_set(&min_stat, &supported);
Packit Service 31306d
    if (oid_count == 0){
Packit Service 31306d
        SSH_LOG(SSH_LOG_PROTOCOL,"GSSAPI: no OID match");
Packit Service 31306d
        ssh_auth_reply_default(session, 0);
Packit Service 31306d
        gss_release_oid_set(&min_stat, &both_supported);
Packit Service 31306d
        return SSH_OK;
Packit Service 31306d
    }
Packit Service 31306d
    /* from now we have room for context */
Packit Service 31306d
    if (ssh_gssapi_init(session) == SSH_ERROR)
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
Packit Service 31306d
    name_buf.value = service_name;
Packit Service 31306d
    name_buf.length = strlen(name_buf.value) + 1;
Packit Service 31306d
    maj_stat = gss_import_name(&min_stat, &name_buf,
Packit Service 31306d
            (gss_OID) GSS_C_NT_HOSTBASED_SERVICE, &server_name);
Packit Service 31306d
    if (maj_stat != GSS_S_COMPLETE) {
Packit Service 31306d
        SSH_LOG(SSH_LOG_WARNING, "importing name %d, %d", maj_stat, min_stat);
Packit Service 31306d
        ssh_gssapi_log_error(SSH_LOG_WARNING,
Packit Service 31306d
                             "importing name",
Packit Service 31306d
                             maj_stat,
Packit Service 31306d
                             min_stat);
Packit Service 31306d
        return -1;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    maj_stat = gss_acquire_cred(&min_stat, server_name, 0,
Packit Service 31306d
            both_supported, GSS_C_ACCEPT,
Packit Service 31306d
            &session->gssapi->server_creds, &selected, NULL);
Packit Service 31306d
    gss_release_name(&min_stat, &server_name);
Packit Service 31306d
    gss_release_oid_set(&min_stat, &both_supported);
Packit Service 31306d
Packit Service 31306d
    if (maj_stat != GSS_S_COMPLETE) {
Packit Service 31306d
        SSH_LOG(SSH_LOG_WARNING, "error acquiring credentials %d, %d", maj_stat, min_stat);
Packit Service 31306d
        ssh_gssapi_log_error(SSH_LOG_WARNING,
Packit Service 31306d
                             "acquiring creds",
Packit Service 31306d
                             maj_stat,
Packit Service 31306d
                             min_stat);
Packit Service 31306d
        ssh_auth_reply_default(session,0);
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    SSH_LOG(SSH_LOG_PROTOCOL, "acquiring credentials %d, %d", maj_stat, min_stat);
Packit Service 31306d
Packit Service 31306d
    /* finding which OID from client we selected */
Packit Service 31306d
    for (i=0 ; i< n_oid ; ++i){
Packit Service 31306d
        unsigned char *oid_s = (unsigned char *) ssh_string_data(oids[i]);
Packit Service 31306d
        size_t len = ssh_string_len(oids[i]);
Packit Service 31306d
Packit Service 31306d
        if (oid_s == NULL) {
Packit Service 31306d
            continue;
Packit Service 31306d
        }
Packit Service 31306d
        if(len < 2 || oid_s[0] != SSH_OID_TAG || ((size_t)oid_s[1]) != len - 2){
Packit Service 31306d
            SSH_LOG(SSH_LOG_WARNING,"GSSAPI: received invalid OID");
Packit Service 31306d
            continue;
Packit Service 31306d
        }
Packit Service 31306d
        oid.elements = &oid_s[2];
Packit Service 31306d
        oid.length = len - 2;
Packit Service 31306d
        gss_test_oid_set_member(&min_stat,&oid,selected,&present);
Packit Service 31306d
        if(present){
Packit Service 31306d
            SSH_LOG(SSH_LOG_PACKET, "Selected oid %zu", i);
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
    session->gssapi->mech.length = oid.length;
Packit Service 31306d
    session->gssapi->mech.elements = malloc(oid.length);
Packit Service 31306d
    if (session->gssapi->mech.elements == NULL){
Packit Service 31306d
        ssh_set_error_oom(session);
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
    memcpy(session->gssapi->mech.elements, oid.elements, oid.length);
Packit Service 31306d
    gss_release_oid_set(&min_stat, &selected);
Packit Service 31306d
    session->gssapi->user = strdup(user);
Packit Service 31306d
    session->gssapi->service = service_name;
Packit Service 31306d
    session->gssapi->state = SSH_GSSAPI_STATE_RCV_TOKEN;
Packit Service 31306d
    return ssh_gssapi_send_response(session, oids[i]);
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static char *ssh_gssapi_name_to_char(gss_name_t name){
Packit Service 31306d
    gss_buffer_desc buffer;
Packit Service 31306d
    OM_uint32 maj_stat, min_stat;
Packit Service 31306d
    char *ptr;
Packit Service 31306d
    maj_stat = gss_display_name(&min_stat, name, &buffer, NULL);
Packit Service 31306d
    ssh_gssapi_log_error(SSH_LOG_WARNING,
Packit Service 31306d
                         "converting name",
Packit Service 31306d
                         maj_stat,
Packit Service 31306d
                         min_stat);
Packit Service 31306d
    ptr = malloc(buffer.length + 1);
Packit Service 31306d
    if (ptr == NULL) {
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
    memcpy(ptr, buffer.value, buffer.length);
Packit Service 31306d
    ptr[buffer.length] = '\0';
Packit Service 31306d
    gss_release_buffer(&min_stat, &buffer);
Packit Service 31306d
    return ptr;
Packit Service 31306d
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_token_server){
Packit Service 31306d
    ssh_string token;
Packit Service 31306d
    char *hexa;
Packit Service 31306d
    OM_uint32 maj_stat, min_stat;
Packit Service 31306d
    gss_buffer_desc input_token, output_token = GSS_C_EMPTY_BUFFER;
Packit Service 31306d
    gss_name_t client_name = GSS_C_NO_NAME;
Packit Service 31306d
    OM_uint32 ret_flags=0;
Packit Service 31306d
    gss_channel_bindings_t input_bindings=GSS_C_NO_CHANNEL_BINDINGS;
Packit Service 31306d
    int rc;
Packit Service 31306d
Packit Service 31306d
    (void)user;
Packit Service 31306d
    (void)type;
Packit Service 31306d
Packit Service 31306d
    SSH_LOG(SSH_LOG_PACKET,"Received SSH_MSG_USERAUTH_GSSAPI_TOKEN");
Packit Service 31306d
    if (!session->gssapi || session->gssapi->state != SSH_GSSAPI_STATE_RCV_TOKEN){
Packit Service 31306d
        ssh_set_error(session, SSH_FATAL, "Received SSH_MSG_USERAUTH_GSSAPI_TOKEN in invalid state");
Packit Service 31306d
        return SSH_PACKET_USED;
Packit Service 31306d
    }
Packit Service 31306d
    token = ssh_buffer_get_ssh_string(packet);
Packit Service 31306d
Packit Service 31306d
    if (token == NULL){
Packit Service 31306d
        ssh_set_error(session, SSH_REQUEST_DENIED, "ssh_packet_userauth_gssapi_token: invalid packet");
Packit Service 31306d
        return SSH_PACKET_USED;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (ssh_callbacks_exists(session->server_callbacks, gssapi_accept_sec_ctx_function)){
Packit Service 31306d
        ssh_string out_token=NULL;
Packit Service 31306d
        rc = session->server_callbacks->gssapi_accept_sec_ctx_function(session,
Packit Service 31306d
                token, &out_token, session->server_callbacks->userdata);
Packit Service 31306d
        if (rc == SSH_ERROR){
Packit Service 31306d
            ssh_auth_reply_default(session, 0);
Packit Service 31306d
            ssh_gssapi_free(session);
Packit Service 31306d
            session->gssapi=NULL;
Packit Service 31306d
            return SSH_PACKET_USED;
Packit Service 31306d
        }
Packit Service 31306d
        if (ssh_string_len(out_token) != 0){
Packit Service 31306d
            rc = ssh_buffer_pack(session->out_buffer,
Packit Service 31306d
                                 "bS",
Packit Service 31306d
                                 SSH2_MSG_USERAUTH_GSSAPI_TOKEN,
Packit Service 31306d
                                 out_token);
Packit Service 31306d
            if (rc != SSH_OK) {
Packit Service 31306d
                ssh_set_error_oom(session);
Packit Service 31306d
                return SSH_PACKET_USED;
Packit Service 31306d
            }
Packit Service 31306d
            ssh_packet_send(session);
Packit Service 31306d
            SSH_STRING_FREE(out_token);
Packit Service 31306d
        } else {
Packit Service 31306d
            session->gssapi->state = SSH_GSSAPI_STATE_RCV_MIC;
Packit Service 31306d
        }
Packit Service 31306d
        return SSH_PACKET_USED;
Packit Service 31306d
    }
Packit Service 31306d
    hexa = ssh_get_hexa(ssh_string_data(token),ssh_string_len(token));
Packit Service 31306d
    SSH_LOG(SSH_LOG_PACKET, "GSSAPI Token : %s",hexa);
Packit Service 31306d
    SAFE_FREE(hexa);
Packit Service 31306d
    input_token.length = ssh_string_len(token);
Packit Service 31306d
    input_token.value = ssh_string_data(token);
Packit Service 31306d
Packit Service 31306d
    maj_stat = gss_accept_sec_context(&min_stat, &session->gssapi->ctx, session->gssapi->server_creds,
Packit Service 31306d
            &input_token, input_bindings, &client_name, NULL /*mech_oid*/, &output_token, &ret_flags,
Packit Service 31306d
            NULL /*time*/, &session->gssapi->client_creds);
Packit Service 31306d
    ssh_gssapi_log_error(SSH_LOG_PROTOCOL,
Packit Service 31306d
                         "accepting token",
Packit Service 31306d
                         maj_stat,
Packit Service 31306d
                         min_stat);
Packit Service 31306d
    SSH_STRING_FREE(token);
Packit Service 31306d
    if (client_name != GSS_C_NO_NAME){
Packit Service 31306d
        session->gssapi->client_name = client_name;
Packit Service 31306d
        session->gssapi->canonic_user = ssh_gssapi_name_to_char(client_name);
Packit Service 31306d
    }
Packit Service 31306d
    if (GSS_ERROR(maj_stat)){
Packit Service 31306d
        ssh_gssapi_log_error(SSH_LOG_WARNING,
Packit Service 31306d
                             "Gssapi error",
Packit Service 31306d
                             maj_stat,
Packit Service 31306d
                             min_stat);
Packit Service 31306d
        ssh_auth_reply_default(session,0);
Packit Service 31306d
        ssh_gssapi_free(session);
Packit Service 31306d
        session->gssapi=NULL;
Packit Service 31306d
        return SSH_PACKET_USED;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (output_token.length != 0){
Packit Service 31306d
        hexa = ssh_get_hexa(output_token.value, output_token.length);
Packit Service 31306d
        SSH_LOG(SSH_LOG_PACKET, "GSSAPI: sending token %s",hexa);
Packit Service 31306d
        SAFE_FREE(hexa);
Packit Service 31306d
        ssh_buffer_pack(session->out_buffer,
Packit Service 31306d
                        "bdP",
Packit Service 31306d
                        SSH2_MSG_USERAUTH_GSSAPI_TOKEN,
Packit Service 31306d
                        output_token.length,
Packit Service 31306d
                        (size_t)output_token.length, output_token.value);
Packit Service 31306d
        ssh_packet_send(session);
Packit Service 31306d
    }
Packit Service 31306d
    if(maj_stat == GSS_S_COMPLETE){
Packit Service 31306d
        session->gssapi->state = SSH_GSSAPI_STATE_RCV_MIC;
Packit Service 31306d
    }
Packit Service 31306d
    return SSH_PACKET_USED;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
#endif /* WITH_SERVER */
Packit Service 31306d
Packit Service 31306d
static ssh_buffer ssh_gssapi_build_mic(ssh_session session)
Packit Service 31306d
{
Packit Service 31306d
    struct ssh_crypto_struct *crypto = NULL;
Packit Service 31306d
    ssh_buffer mic_buffer = NULL;
Packit Service 31306d
    int rc;
Packit Service 31306d
Packit Service 31306d
    crypto = ssh_packet_get_current_crypto(session, SSH_DIRECTION_BOTH);
Packit Service 31306d
    if (crypto == NULL) {
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    mic_buffer = ssh_buffer_new();
Packit Service 31306d
    if (mic_buffer == NULL) {
Packit Service 31306d
        ssh_set_error_oom(session);
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    rc = ssh_buffer_pack(mic_buffer,
Packit Service 31306d
                         "dPbsss",
Packit Service 31306d
                         crypto->digest_len,
Packit Service 31306d
                         (size_t)crypto->digest_len, crypto->session_id,
Packit Service 31306d
                         SSH2_MSG_USERAUTH_REQUEST,
Packit Service 31306d
                         session->gssapi->user,
Packit Service 31306d
                         "ssh-connection",
Packit Service 31306d
                         "gssapi-with-mic");
Packit Service 31306d
    if (rc != SSH_OK) {
Packit Service 31306d
        ssh_set_error_oom(session);
Packit Service 31306d
        SSH_BUFFER_FREE(mic_buffer);
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    return mic_buffer;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
#ifdef WITH_SERVER
Packit Service 31306d
Packit Service 31306d
SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_mic)
Packit Service 31306d
{
Packit Service 31306d
    ssh_string mic_token;
Packit Service 31306d
    OM_uint32 maj_stat, min_stat;
Packit Service 31306d
    gss_buffer_desc mic_buf = GSS_C_EMPTY_BUFFER;
Packit Service 31306d
    gss_buffer_desc mic_token_buf = GSS_C_EMPTY_BUFFER;
Packit Service 31306d
    ssh_buffer mic_buffer = NULL;
Packit Service 31306d
Packit Service 31306d
    (void)user;
Packit Service 31306d
    (void)type;
Packit Service 31306d
Packit Service 31306d
    SSH_LOG(SSH_LOG_PACKET,"Received SSH_MSG_USERAUTH_GSSAPI_MIC");
Packit Service 31306d
    mic_token = ssh_buffer_get_ssh_string(packet);
Packit Service 31306d
    if (mic_token == NULL) {
Packit Service 31306d
        ssh_set_error(session, SSH_FATAL, "Missing MIC in packet");
Packit Service 31306d
        goto error;
Packit Service 31306d
    }
Packit Service 31306d
    if (session->gssapi == NULL
Packit Service 31306d
        || session->gssapi->state != SSH_GSSAPI_STATE_RCV_MIC) {
Packit Service 31306d
        ssh_set_error(session, SSH_FATAL, "Received SSH_MSG_USERAUTH_GSSAPI_MIC in invalid state");
Packit Service 31306d
        goto error;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    mic_buffer = ssh_gssapi_build_mic(session);
Packit Service 31306d
    if (mic_buffer == NULL) {
Packit Service 31306d
        ssh_set_error_oom(session);
Packit Service 31306d
        goto error;
Packit Service 31306d
    }
Packit Service 31306d
    if (ssh_callbacks_exists(session->server_callbacks, gssapi_verify_mic_function)){
Packit Service 31306d
        int rc = session->server_callbacks->gssapi_verify_mic_function(session, mic_token,
Packit Service 31306d
                ssh_buffer_get(mic_buffer), ssh_buffer_get_len(mic_buffer),
Packit Service 31306d
                session->server_callbacks->userdata);
Packit Service 31306d
        if (rc != SSH_OK) {
Packit Service 31306d
            goto error;
Packit Service 31306d
        }
Packit Service 31306d
    } else {
Packit Service 31306d
        mic_buf.length = ssh_buffer_get_len(mic_buffer);
Packit Service 31306d
        mic_buf.value = ssh_buffer_get(mic_buffer);
Packit Service 31306d
        mic_token_buf.length = ssh_string_len(mic_token);
Packit Service 31306d
        mic_token_buf.value = ssh_string_data(mic_token);
Packit Service 31306d
Packit Service 31306d
        maj_stat = gss_verify_mic(&min_stat, session->gssapi->ctx, &mic_buf, &mic_token_buf, NULL);
Packit Service 31306d
        ssh_gssapi_log_error(SSH_LOG_PROTOCOL,
Packit Service 31306d
                             "verifying MIC",
Packit Service 31306d
                             maj_stat,
Packit Service 31306d
                             min_stat);
Packit Service 31306d
        if (maj_stat == GSS_S_DEFECTIVE_TOKEN || GSS_ERROR(maj_stat)) {
Packit Service 31306d
            goto error;
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (ssh_callbacks_exists(session->server_callbacks, auth_gssapi_mic_function)){
Packit Service 31306d
        switch(session->server_callbacks->auth_gssapi_mic_function(session,
Packit Service 31306d
                    session->gssapi->user, session->gssapi->canonic_user,
Packit Service 31306d
                    session->server_callbacks->userdata)){
Packit Service 31306d
            case SSH_AUTH_SUCCESS:
Packit Service 31306d
                ssh_auth_reply_success(session, 0);
Packit Service 31306d
                break;
Packit Service 31306d
            case SSH_AUTH_PARTIAL:
Packit Service 31306d
                ssh_auth_reply_success(session, 1);
Packit Service 31306d
                break;
Packit Service 31306d
            default:
Packit Service 31306d
                ssh_auth_reply_default(session, 0);
Packit Service 31306d
                break;
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    goto end;
Packit Service 31306d
Packit Service 31306d
error:
Packit Service 31306d
    ssh_auth_reply_default(session,0);
Packit Service 31306d
Packit Service 31306d
end:
Packit Service 31306d
    ssh_gssapi_free(session);
Packit Service 31306d
    if (mic_buffer != NULL) {
Packit Service 31306d
        SSH_BUFFER_FREE(mic_buffer);
Packit Service 31306d
    }
Packit Service 31306d
    if (mic_token != NULL) {
Packit Service 31306d
        SSH_STRING_FREE(mic_token);
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    return SSH_PACKET_USED;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/** @brief returns the client credentials of the connected client.
Packit Service 31306d
 * If the client has given a forwardable token, the SSH server will
Packit Service 31306d
 * retrieve it.
Packit Service 31306d
 * @returns gssapi credentials handle.
Packit Service 31306d
 * @returns NULL if no forwardable token is available.
Packit Service 31306d
 */
Packit Service 31306d
ssh_gssapi_creds ssh_gssapi_get_creds(ssh_session session){
Packit Service 31306d
    if (!session || !session->gssapi || session->gssapi->client_creds == GSS_C_NO_CREDENTIAL)
Packit Service 31306d
        return NULL;
Packit Service 31306d
    return (ssh_gssapi_creds)session->gssapi->client_creds;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
#endif /* SERVER */
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @brief Set the forwadable ticket to be given to the server for authentication.
Packit Service 31306d
 * Unlike ssh_gssapi_get_creds() this is called on the client side of an ssh
Packit Service 31306d
 * connection.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in] creds gssapi credentials handle.
Packit Service 31306d
 */
Packit Service 31306d
void ssh_gssapi_set_creds(ssh_session session, const ssh_gssapi_creds creds)
Packit Service 31306d
{
Packit Service 31306d
    if (session == NULL) {
Packit Service 31306d
        return;
Packit Service 31306d
    }
Packit Service 31306d
    if (session->gssapi == NULL) {
Packit Service 31306d
        ssh_gssapi_init(session);
Packit Service 31306d
        if (session->gssapi == NULL) {
Packit Service 31306d
            return;
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    session->gssapi->client.client_deleg_creds = (gss_cred_id_t)creds;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static int ssh_gssapi_send_auth_mic(ssh_session session, ssh_string *oid_set, int n_oid){
Packit Service 31306d
    int rc;
Packit Service 31306d
    int i;
Packit Service 31306d
Packit Service 31306d
    rc = ssh_buffer_pack(session->out_buffer,
Packit Service 31306d
                         "bsssd",
Packit Service 31306d
                         SSH2_MSG_USERAUTH_REQUEST,
Packit Service 31306d
                         session->opts.username,
Packit Service 31306d
                         "ssh-connection",
Packit Service 31306d
                         "gssapi-with-mic",
Packit Service 31306d
                         n_oid);
Packit Service 31306d
Packit Service 31306d
    if (rc != SSH_OK) {
Packit Service 31306d
        ssh_set_error_oom(session);
Packit Service 31306d
        goto fail;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    for (i=0; i
Packit Service 31306d
        rc = ssh_buffer_add_ssh_string(session->out_buffer, oid_set[i]);
Packit Service 31306d
        if (rc < 0) {
Packit Service 31306d
            goto fail;
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    session->auth.state = SSH_AUTH_STATE_GSSAPI_REQUEST_SENT;
Packit Service 31306d
    return ssh_packet_send(session);
Packit Service 31306d
fail:
Packit Service 31306d
    ssh_buffer_reinit(session->out_buffer);
Packit Service 31306d
    return SSH_ERROR;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/** @brief returns the OIDs of the mechs that have usable credentials
Packit Service 31306d
 */
Packit Service 31306d
static int ssh_gssapi_match(ssh_session session, gss_OID_set *valid_oids)
Packit Service 31306d
{
Packit Service 31306d
    OM_uint32 maj_stat, min_stat, lifetime;
Packit Service 31306d
    gss_OID_set actual_mechs;
Packit Service 31306d
    gss_buffer_desc namebuf;
Packit Service 31306d
    gss_name_t client_id = GSS_C_NO_NAME;
Packit Service 31306d
    gss_OID oid;
Packit Service 31306d
    unsigned int i;
Packit Service 31306d
    char *ptr;
Packit Service 31306d
    int ret;
Packit Service 31306d
Packit Service 31306d
    if (session->gssapi->client.client_deleg_creds == NULL) {
Packit Service 31306d
        if (session->opts.gss_client_identity != NULL) {
Packit Service 31306d
            namebuf.value = (void *)session->opts.gss_client_identity;
Packit Service 31306d
            namebuf.length = strlen(session->opts.gss_client_identity);
Packit Service 31306d
Packit Service 31306d
            maj_stat = gss_import_name(&min_stat, &namebuf,
Packit Service 31306d
                                       GSS_C_NT_USER_NAME, &client_id);
Packit Service 31306d
            if (GSS_ERROR(maj_stat)) {
Packit Service 31306d
                ret = SSH_ERROR;
Packit Service 31306d
                goto end;
Packit Service 31306d
            }
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        maj_stat = gss_acquire_cred(&min_stat, client_id, GSS_C_INDEFINITE,
Packit Service 31306d
                                    GSS_C_NO_OID_SET, GSS_C_INITIATE,
Packit Service 31306d
                                    &session->gssapi->client.creds,
Packit Service 31306d
                                    &actual_mechs, NULL);
Packit Service 31306d
        if (GSS_ERROR(maj_stat)) {
Packit Service 31306d
            ret = SSH_ERROR;
Packit Service 31306d
            goto end;
Packit Service 31306d
        }
Packit Service 31306d
    } else {
Packit Service 31306d
        session->gssapi->client.creds =
Packit Service 31306d
                                    session->gssapi->client.client_deleg_creds;
Packit Service 31306d
Packit Service 31306d
        maj_stat = gss_inquire_cred(&min_stat, session->gssapi->client.creds,
Packit Service 31306d
                                    &client_id, NULL, NULL, &actual_mechs);
Packit Service 31306d
        if (GSS_ERROR(maj_stat)) {
Packit Service 31306d
            ret = SSH_ERROR;
Packit Service 31306d
            goto end;
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    gss_create_empty_oid_set(&min_stat, valid_oids);
Packit Service 31306d
Packit Service 31306d
    /* double check each single cred */
Packit Service 31306d
    for (i = 0; i < actual_mechs->count; i++) {
Packit Service 31306d
        /* check lifetime is not 0 or skip */
Packit Service 31306d
        lifetime = 0;
Packit Service 31306d
        oid = &actual_mechs->elements[i];
Packit Service 31306d
        maj_stat = gss_inquire_cred_by_mech(&min_stat,
Packit Service 31306d
                                            session->gssapi->client.creds,
Packit Service 31306d
                                            oid, NULL, &lifetime, NULL, NULL);
Packit Service 31306d
        if (maj_stat == GSS_S_COMPLETE && lifetime > 0) {
Packit Service 31306d
            gss_add_oid_set_member(&min_stat, oid, valid_oids);
Packit Service 31306d
            ptr = ssh_get_hexa(oid->elements, oid->length);
Packit Service 31306d
            SSH_LOG(SSH_LOG_DEBUG, "GSSAPI valid oid %d : %s", i, ptr);
Packit Service 31306d
            SAFE_FREE(ptr);
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    ret = SSH_OK;
Packit Service 31306d
Packit Service 31306d
end:
Packit Service 31306d
    gss_release_name(&min_stat, &client_id);
Packit Service 31306d
    return ret;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @brief launches a gssapi-with-mic auth request
Packit Service 31306d
 * @returns SSH_AUTH_ERROR:   A serious error happened\n
Packit Service 31306d
 *          SSH_AUTH_DENIED:  Authentication failed : use another method\n
Packit Service 31306d
 *          SSH_AUTH_AGAIN:   In nonblocking mode, you've got to call this again
Packit Service 31306d
 *                            later.
Packit Service 31306d
 */
Packit Service 31306d
int ssh_gssapi_auth_mic(ssh_session session){
Packit Service 31306d
    size_t i;
Packit Service 31306d
    gss_OID_set selected; /* oid selected for authentication */
Packit Service 31306d
    ssh_string *oids = NULL;
Packit Service 31306d
    int rc;
Packit Service 31306d
    size_t n_oids = 0;
Packit Service 31306d
    OM_uint32 maj_stat, min_stat;
Packit Service 31306d
    char name_buf[256] = {0};
Packit Service 31306d
    gss_buffer_desc hostname;
Packit Service 31306d
    const char *gss_host = session->opts.host;
Packit Service 31306d
Packit Service 31306d
    rc = ssh_gssapi_init(session);
Packit Service 31306d
    if (rc == SSH_ERROR) {
Packit Service 31306d
        return SSH_AUTH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (session->opts.gss_server_identity != NULL) {
Packit Service 31306d
        gss_host = session->opts.gss_server_identity;
Packit Service 31306d
    }
Packit Service 31306d
    /* import target host name */
Packit Service 31306d
    snprintf(name_buf, sizeof(name_buf), "host@%s", gss_host);
Packit Service 31306d
Packit Service 31306d
    hostname.value = name_buf;
Packit Service 31306d
    hostname.length = strlen(name_buf) + 1;
Packit Service 31306d
    maj_stat = gss_import_name(&min_stat, &hostname,
Packit Service 31306d
                               (gss_OID)GSS_C_NT_HOSTBASED_SERVICE,
Packit Service 31306d
                               &session->gssapi->client.server_name);
Packit Service 31306d
    if (maj_stat != GSS_S_COMPLETE) {
Packit Service 31306d
        SSH_LOG(SSH_LOG_WARNING, "importing name %d, %d", maj_stat, min_stat);
Packit Service 31306d
        ssh_gssapi_log_error(SSH_LOG_WARNING,
Packit Service 31306d
                             "importing name",
Packit Service 31306d
                             maj_stat,
Packit Service 31306d
                             min_stat);
Packit Service 31306d
        return SSH_AUTH_DENIED;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* copy username */
Packit Service 31306d
    session->gssapi->user = strdup(session->opts.username);
Packit Service 31306d
    if (session->gssapi->user == NULL) {
Packit Service 31306d
        ssh_set_error_oom(session);
Packit Service 31306d
        return SSH_AUTH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    SSH_LOG(SSH_LOG_PROTOCOL, "Authenticating with gssapi to host %s with user %s",
Packit Service 31306d
            session->opts.host, session->gssapi->user);
Packit Service 31306d
    rc = ssh_gssapi_match(session, &selected);
Packit Service 31306d
    if (rc == SSH_ERROR) {
Packit Service 31306d
        return SSH_AUTH_DENIED;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    n_oids = selected->count;
Packit Service 31306d
    SSH_LOG(SSH_LOG_PROTOCOL, "Sending %zu oids", n_oids);
Packit Service 31306d
Packit Service 31306d
    oids = calloc(n_oids, sizeof(ssh_string));
Packit Service 31306d
    if (oids == NULL) {
Packit Service 31306d
        ssh_set_error_oom(session);
Packit Service 31306d
        return SSH_AUTH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    for (i=0; i
Packit Service 31306d
        oids[i] = ssh_string_new(selected->elements[i].length + 2);
Packit Service 31306d
        if (oids[i] == NULL) {
Packit Service 31306d
            ssh_set_error_oom(session);
Packit Service 31306d
            rc = SSH_ERROR;
Packit Service 31306d
            goto out;
Packit Service 31306d
        }
Packit Service 31306d
        ((unsigned char *)oids[i]->data)[0] = SSH_OID_TAG;
Packit Service 31306d
        ((unsigned char *)oids[i]->data)[1] = selected->elements[i].length;
Packit Service 31306d
        memcpy((unsigned char *)oids[i]->data + 2, selected->elements[i].elements,
Packit Service 31306d
                selected->elements[i].length);
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    rc = ssh_gssapi_send_auth_mic(session, oids, n_oids);
Packit Service 31306d
Packit Service 31306d
out:
Packit Service 31306d
    for (i = 0; i < n_oids; i++) {
Packit Service 31306d
        SSH_STRING_FREE(oids[i]);
Packit Service 31306d
    }
Packit Service 31306d
    free(oids);
Packit Service 31306d
    if (rc != SSH_ERROR) {
Packit Service 31306d
        return SSH_AUTH_AGAIN;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    return SSH_AUTH_ERROR;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static gss_OID ssh_gssapi_oid_from_string(ssh_string oid_s)
Packit Service 31306d
{
Packit Service 31306d
    gss_OID ret = NULL;
Packit Service 31306d
    unsigned char *data = ssh_string_data(oid_s);
Packit Service 31306d
    size_t len = ssh_string_len(oid_s);
Packit Service 31306d
Packit Service 31306d
    if (data == NULL) {
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (len > 256 || len <= 2) {
Packit Service 31306d
        SAFE_FREE(ret);
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (data[0] != SSH_OID_TAG || data[1] != len - 2) {
Packit Service 31306d
        SAFE_FREE(ret);
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    ret = malloc(sizeof(gss_OID_desc));
Packit Service 31306d
    if (ret == NULL) {
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    ret->elements = malloc(len - 2);
Packit Service 31306d
    if (ret->elements == NULL) {
Packit Service 31306d
        SAFE_FREE(ret);
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
    memcpy(ret->elements, &data[2], len-2);
Packit Service 31306d
    ret->length = len-2;
Packit Service 31306d
Packit Service 31306d
    return ret;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_response){
Packit Service 31306d
    ssh_string oid_s;
Packit Service 31306d
    gss_uint32 maj_stat, min_stat;
Packit Service 31306d
    gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
Packit Service 31306d
    gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
Packit Service 31306d
    char *hexa;
Packit Service 31306d
    (void)type;
Packit Service 31306d
    (void)user;
Packit Service 31306d
Packit Service 31306d
    SSH_LOG(SSH_LOG_PACKET, "Received SSH_USERAUTH_GSSAPI_RESPONSE");
Packit Service 31306d
    if (session->auth.state != SSH_AUTH_STATE_GSSAPI_REQUEST_SENT){
Packit Service 31306d
        ssh_set_error(session, SSH_FATAL, "Invalid state in ssh_packet_userauth_gssapi_response");
Packit Service 31306d
        goto error;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    oid_s = ssh_buffer_get_ssh_string(packet);
Packit Service 31306d
    if (!oid_s){
Packit Service 31306d
        ssh_set_error(session, SSH_FATAL, "Missing OID");
Packit Service 31306d
        goto error;
Packit Service 31306d
    }
Packit Service 31306d
    session->gssapi->client.oid = ssh_gssapi_oid_from_string(oid_s);
Packit Service 31306d
    SSH_STRING_FREE(oid_s);
Packit Service 31306d
    if (!session->gssapi->client.oid) {
Packit Service 31306d
        ssh_set_error(session, SSH_FATAL, "Invalid OID");
Packit Service 31306d
        goto error;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    session->gssapi->client.flags = GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG;
Packit Service 31306d
    if (session->opts.gss_delegate_creds) {
Packit Service 31306d
        session->gssapi->client.flags |= GSS_C_DELEG_FLAG;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* prepare the first TOKEN response */
Packit Service 31306d
    maj_stat = gss_init_sec_context(&min_stat,
Packit Service 31306d
                                    session->gssapi->client.creds,
Packit Service 31306d
                                    &session->gssapi->ctx,
Packit Service 31306d
                                    session->gssapi->client.server_name,
Packit Service 31306d
                                    session->gssapi->client.oid,
Packit Service 31306d
                                    session->gssapi->client.flags,
Packit Service 31306d
                                    0, NULL, &input_token, NULL,
Packit Service 31306d
                                    &output_token, NULL, NULL);
Packit Service 31306d
    if(GSS_ERROR(maj_stat)){
Packit Service 31306d
        ssh_gssapi_log_error(SSH_LOG_WARNING,
Packit Service 31306d
                             "Initializing gssapi context",
Packit Service 31306d
                             maj_stat,
Packit Service 31306d
                             min_stat);
Packit Service 31306d
        goto error;
Packit Service 31306d
    }
Packit Service 31306d
    if (output_token.length != 0){
Packit Service 31306d
        hexa = ssh_get_hexa(output_token.value, output_token.length);
Packit Service 31306d
        SSH_LOG(SSH_LOG_PACKET, "GSSAPI: sending token %s", hexa);
Packit Service 31306d
        SAFE_FREE(hexa);
Packit Service 31306d
        ssh_buffer_pack(session->out_buffer,
Packit Service 31306d
                        "bdP",
Packit Service 31306d
                        SSH2_MSG_USERAUTH_GSSAPI_TOKEN,
Packit Service 31306d
                        output_token.length,
Packit Service 31306d
                        (size_t)output_token.length, output_token.value);
Packit Service 31306d
        ssh_packet_send(session);
Packit Service 31306d
        session->auth.state = SSH_AUTH_STATE_GSSAPI_TOKEN;
Packit Service 31306d
    }
Packit Service 31306d
    return SSH_PACKET_USED;
Packit Service 31306d
Packit Service 31306d
error:
Packit Service 31306d
    session->auth.state = SSH_AUTH_STATE_ERROR;
Packit Service 31306d
    ssh_gssapi_free(session);
Packit Service 31306d
    session->gssapi = NULL;
Packit Service 31306d
    return SSH_PACKET_USED;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static int ssh_gssapi_send_mic(ssh_session session){
Packit Service 31306d
    OM_uint32 maj_stat, min_stat;
Packit Service 31306d
    gss_buffer_desc mic_buf = GSS_C_EMPTY_BUFFER;
Packit Service 31306d
    gss_buffer_desc mic_token_buf = GSS_C_EMPTY_BUFFER;
Packit Service 31306d
    ssh_buffer mic_buffer;
Packit Service 31306d
    int rc;
Packit Service 31306d
Packit Service 31306d
    SSH_LOG(SSH_LOG_PACKET,"Sending SSH_MSG_USERAUTH_GSSAPI_MIC");
Packit Service 31306d
Packit Service 31306d
    mic_buffer = ssh_gssapi_build_mic(session);
Packit Service 31306d
    if (mic_buffer == NULL) {
Packit Service 31306d
        ssh_set_error_oom(session);
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
    mic_buf.length = ssh_buffer_get_len(mic_buffer);
Packit Service 31306d
    mic_buf.value = ssh_buffer_get(mic_buffer);
Packit Service 31306d
Packit Service 31306d
    maj_stat = gss_get_mic(&min_stat,session->gssapi->ctx, GSS_C_QOP_DEFAULT,
Packit Service 31306d
                           &mic_buf, &mic_token_buf);
Packit Service 31306d
    if (GSS_ERROR(maj_stat)){
Packit Service 31306d
        SSH_BUFFER_FREE(mic_buffer);
Packit Service 31306d
        ssh_gssapi_log_error(SSH_LOG_PROTOCOL,
Packit Service 31306d
                             "generating MIC",
Packit Service 31306d
                             maj_stat,
Packit Service 31306d
                             min_stat);
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    rc = ssh_buffer_pack(session->out_buffer,
Packit Service 31306d
                         "bdP",
Packit Service 31306d
                         SSH2_MSG_USERAUTH_GSSAPI_MIC,
Packit Service 31306d
                         mic_token_buf.length,
Packit Service 31306d
                         (size_t)mic_token_buf.length, mic_token_buf.value);
Packit Service 31306d
    if (rc != SSH_OK) {
Packit Service 31306d
        SSH_BUFFER_FREE(mic_buffer);
Packit Service 31306d
        ssh_set_error_oom(session);
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    return ssh_packet_send(session);
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_token_client){
Packit Service 31306d
    ssh_string token;
Packit Service 31306d
    char *hexa;
Packit Service 31306d
    OM_uint32 maj_stat, min_stat;
Packit Service 31306d
    gss_buffer_desc input_token, output_token = GSS_C_EMPTY_BUFFER;
Packit Service 31306d
    (void)user;
Packit Service 31306d
    (void)type;
Packit Service 31306d
Packit Service 31306d
    SSH_LOG(SSH_LOG_PACKET,"Received SSH_MSG_USERAUTH_GSSAPI_TOKEN");
Packit Service 31306d
    if (!session->gssapi || session->auth.state != SSH_AUTH_STATE_GSSAPI_TOKEN) {
Packit Service 31306d
        ssh_set_error(session, SSH_FATAL,
Packit Service 31306d
                      "Received SSH_MSG_USERAUTH_GSSAPI_TOKEN in invalid state");
Packit Service 31306d
        goto error;
Packit Service 31306d
    }
Packit Service 31306d
    token = ssh_buffer_get_ssh_string(packet);
Packit Service 31306d
Packit Service 31306d
    if (token == NULL){
Packit Service 31306d
        ssh_set_error(session, SSH_REQUEST_DENIED,
Packit Service 31306d
                      "ssh_packet_userauth_gssapi_token: invalid packet");
Packit Service 31306d
        goto error;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    hexa = ssh_get_hexa(ssh_string_data(token),ssh_string_len(token));
Packit Service 31306d
    SSH_LOG(SSH_LOG_PACKET, "GSSAPI Token : %s",hexa);
Packit Service 31306d
    SAFE_FREE(hexa);
Packit Service 31306d
    input_token.length = ssh_string_len(token);
Packit Service 31306d
    input_token.value = ssh_string_data(token);
Packit Service 31306d
    maj_stat = gss_init_sec_context(&min_stat,
Packit Service 31306d
                                    session->gssapi->client.creds,
Packit Service 31306d
                                    &session->gssapi->ctx,
Packit Service 31306d
                                    session->gssapi->client.server_name,
Packit Service 31306d
                                    session->gssapi->client.oid,
Packit Service 31306d
                                    session->gssapi->client.flags,
Packit Service 31306d
                                    0, NULL, &input_token, NULL,
Packit Service 31306d
                                    &output_token, NULL, NULL);
Packit Service 31306d
Packit Service 31306d
    ssh_gssapi_log_error(SSH_LOG_PROTOCOL,
Packit Service 31306d
                         "accepting token",
Packit Service 31306d
                         maj_stat,
Packit Service 31306d
                         min_stat);
Packit Service 31306d
    SSH_STRING_FREE(token);
Packit Service 31306d
    if (GSS_ERROR(maj_stat)){
Packit Service 31306d
        ssh_gssapi_log_error(SSH_LOG_PROTOCOL,
Packit Service 31306d
                             "Gssapi error",
Packit Service 31306d
                             maj_stat,
Packit Service 31306d
                             min_stat);
Packit Service 31306d
        goto error;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (output_token.length != 0) {
Packit Service 31306d
        hexa = ssh_get_hexa(output_token.value, output_token.length);
Packit Service 31306d
        SSH_LOG(SSH_LOG_PACKET, "GSSAPI: sending token %s",hexa);
Packit Service 31306d
        SAFE_FREE(hexa);
Packit Service 31306d
        ssh_buffer_pack(session->out_buffer,
Packit Service 31306d
                        "bdP",
Packit Service 31306d
                        SSH2_MSG_USERAUTH_GSSAPI_TOKEN,
Packit Service 31306d
                        output_token.length,
Packit Service 31306d
                        (size_t)output_token.length, output_token.value);
Packit Service 31306d
        ssh_packet_send(session);
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (maj_stat == GSS_S_COMPLETE) {
Packit Service 31306d
        ssh_gssapi_send_mic(session);
Packit Service 31306d
        session->auth.state = SSH_AUTH_STATE_GSSAPI_MIC_SENT;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    return SSH_PACKET_USED;
Packit Service 31306d
Packit Service 31306d
error:
Packit Service 31306d
    session->auth.state = SSH_AUTH_STATE_ERROR;
Packit Service 31306d
    ssh_gssapi_free(session);
Packit Service 31306d
    session->gssapi = NULL;
Packit Service 31306d
    return SSH_PACKET_USED;
Packit Service 31306d
}