Blame tests/server/torture_server_auth_kbdint.c

Packit Service 31306d
/*
Packit Service 31306d
 * This file is part of the SSH Library
Packit Service 31306d
 *
Packit Service 31306d
 * Copyright (c) 2019 by Red Hat, Inc.
Packit Service 31306d
 *
Packit Service 31306d
 * Author: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
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
#define LIBSSH_STATIC
Packit Service 31306d
Packit Service 31306d
#include <sys/types.h>
Packit Service 31306d
#include <sys/stat.h>
Packit Service 31306d
#include <errno.h>
Packit Service 31306d
#include <pwd.h>
Packit Service 31306d
Packit Service 31306d
#include "torture.h"
Packit Service 31306d
#include "torture_key.h"
Packit Service 31306d
#include "libssh/libssh.h"
Packit Service 31306d
#include "libssh/priv.h"
Packit Service 31306d
#include "libssh/session.h"
Packit Service 31306d
Packit Service 31306d
#include <signal.h>
Packit Service 31306d
#include <sys/wait.h>
Packit Service 31306d
#include <sys/ioctl.h>
Packit Service 31306d
Packit Service 31306d
#include "test_server.h"
Packit Service 31306d
#include "default_cb.h"
Packit Service 31306d
Packit Service 31306d
#define TORTURE_KNOWN_HOSTS_FILE "libssh_torture_knownhosts"
Packit Service 31306d
Packit Service 31306d
enum {
Packit Service 31306d
    SUCCESS,
Packit Service 31306d
    MORE,
Packit Service 31306d
    FAILED
Packit Service 31306d
};
Packit Service 31306d
Packit Service 31306d
struct test_server_st {
Packit Service 31306d
    struct torture_state *state;
Packit Service 31306d
    struct server_state_st *ss;
Packit Service 31306d
};
Packit Service 31306d
Packit Service 31306d
#ifdef WITH_PCAP
Packit Service 31306d
static void set_pcap(struct session_data_st *sdata,
Packit Service 31306d
                     ssh_session session,
Packit Service 31306d
                     char *pcap_file)
Packit Service 31306d
{
Packit Service 31306d
    int rc = 0;
Packit Service 31306d
Packit Service 31306d
    if (sdata == NULL) {
Packit Service 31306d
        return;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (pcap_file == NULL) {
Packit Service 31306d
        return;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    sdata->pcap = ssh_pcap_file_new();
Packit Service 31306d
    if (sdata->pcap == NULL) {
Packit Service 31306d
        return;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    rc = ssh_pcap_file_open(sdata->pcap, pcap_file);
Packit Service 31306d
    if (rc == SSH_ERROR) {
Packit Service 31306d
        fprintf(stderr, "Error opening pcap file\n");
Packit Service 31306d
        ssh_pcap_file_free(sdata->pcap);
Packit Service 31306d
        sdata->pcap = NULL;
Packit Service 31306d
        return;
Packit Service 31306d
    }
Packit Service 31306d
    ssh_set_pcap_file(session, sdata->pcap);
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static void cleanup_pcap(struct session_data_st *sdata)
Packit Service 31306d
{
Packit Service 31306d
    if (sdata == NULL) {
Packit Service 31306d
        return;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (sdata->pcap == NULL) {
Packit Service 31306d
        return;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* Do not free the pcap data context here since its ownership was
Packit Service 31306d
     * transfered to the session object, which will take care of its cleanup.
Packit Service 31306d
     * Morover it is still in use so we can very simply crash by freeing
Packit Service 31306d
     * it here.
Packit Service 31306d
     */
Packit Service 31306d
    sdata->pcap = NULL;
Packit Service 31306d
}
Packit Service 31306d
#endif
Packit Service 31306d
Packit Service 31306d
static int process_stdout(socket_t fd, int revents, void *userdata)
Packit Service 31306d
{
Packit Service 31306d
    char buf[BUF_SIZE];
Packit Service 31306d
    int n = -1;
Packit Service 31306d
    ssh_channel channel = (ssh_channel) userdata;
Packit Service 31306d
Packit Service 31306d
    if (channel != NULL && (revents & POLLIN) != 0) {
Packit Service 31306d
        n = read(fd, buf, BUF_SIZE);
Packit Service 31306d
        if (n > 0) {
Packit Service 31306d
            ssh_channel_write(channel, buf, n);
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    return n;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static int process_stderr(socket_t fd, int revents, void *userdata)
Packit Service 31306d
{
Packit Service 31306d
    char buf[BUF_SIZE];
Packit Service 31306d
    int n = -1;
Packit Service 31306d
    ssh_channel channel = (ssh_channel) userdata;
Packit Service 31306d
Packit Service 31306d
    if (channel != NULL && (revents & POLLIN) != 0) {
Packit Service 31306d
        n = read(fd, buf, BUF_SIZE);
Packit Service 31306d
        if (n > 0) {
Packit Service 31306d
            ssh_channel_write_stderr(channel, buf, n);
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    return n;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static int authenticate_kbdint(ssh_session session,
Packit Service 31306d
                               ssh_message message,
Packit Service 31306d
                               void *userdata)
Packit Service 31306d
{
Packit Service 31306d
    int rc = 0;
Packit Service 31306d
    int count;
Packit Service 31306d
    int *step = NULL;
Packit Service 31306d
    size_t expected_len;
Packit Service 31306d
Packit Service 31306d
    const char instruction[] = "Type the requested data";
Packit Service 31306d
    const char name[] = "Keyboard-Interactive Authentication\n";
Packit Service 31306d
    char initial_echo[] = {1, 0};
Packit Service 31306d
    char retype_echo[] = {0};
Packit Service 31306d
    const char *initial_prompt[2];
Packit Service 31306d
    const char *retype_prompt[1];
Packit Service 31306d
    int cmp;
Packit Service 31306d
Packit Service 31306d
    const char *answer;
Packit Service 31306d
Packit Service 31306d
    struct session_data_st *sdata = (struct session_data_st *)userdata;
Packit Service 31306d
Packit Service 31306d
    initial_prompt[0] = "username: ";
Packit Service 31306d
    initial_prompt[1] = "password: ";
Packit Service 31306d
Packit Service 31306d
    /* Prompt for aditional prompts */
Packit Service 31306d
    retype_prompt[0] = "retype password: ";
Packit Service 31306d
Packit Service 31306d
    if ((session == NULL) || (message == NULL) || (sdata == NULL)) {
Packit Service 31306d
        fprintf(stderr, "Null argument provided\n");
Packit Service 31306d
        goto failed;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (sdata->extra_data == NULL) {
Packit Service 31306d
        goto failed;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    step = (int *)sdata->extra_data;
Packit Service 31306d
Packit Service 31306d
    switch (*step) {
Packit Service 31306d
    case 0:
Packit Service 31306d
        ssh_message_auth_interactive_request(message, name, instruction, 2,
Packit Service 31306d
                initial_prompt, initial_echo);
Packit Service 31306d
        rc = MORE;
Packit Service 31306d
        goto end;
Packit Service 31306d
    case 1:
Packit Service 31306d
        count = ssh_userauth_kbdint_getnanswers(session);
Packit Service 31306d
        if (count != 2) {
Packit Service 31306d
            goto failed;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        if ((sdata->username == NULL) || (sdata->password == NULL)) {
Packit Service 31306d
            goto failed;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        /* Get and compare username */
Packit Service 31306d
        expected_len = strlen(sdata->username);
Packit Service 31306d
        if (expected_len <= 0) {
Packit Service 31306d
            goto failed;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        answer = ssh_userauth_kbdint_getanswer(session, 0);
Packit Service 31306d
        if (answer == NULL) {
Packit Service 31306d
            goto failed;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        cmp = strncmp(answer, sdata->username, expected_len);
Packit Service 31306d
        if (cmp != 0) {
Packit Service 31306d
            goto failed;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        /* Get and compare password */
Packit Service 31306d
        expected_len = strlen(sdata->password);
Packit Service 31306d
        if (expected_len <= 0) {
Packit Service 31306d
            goto failed;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        answer = ssh_userauth_kbdint_getanswer(session, 1);
Packit Service 31306d
        if (answer == NULL) {
Packit Service 31306d
            goto failed;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        cmp = strncmp(answer, sdata->password, expected_len);
Packit Service 31306d
        if (cmp != 0) {
Packit Service 31306d
            goto failed;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        /* Username and password matched. Ask for a retype. */
Packit Service 31306d
        ssh_message_auth_interactive_request(message,
Packit Service 31306d
                                             name,
Packit Service 31306d
                                             instruction,
Packit Service 31306d
                                             1,
Packit Service 31306d
                                             retype_prompt,
Packit Service 31306d
                                             retype_echo);
Packit Service 31306d
Packit Service 31306d
        rc = MORE;
Packit Service 31306d
        goto end;
Packit Service 31306d
    case 2:
Packit Service 31306d
        /* Get and compare password */
Packit Service 31306d
        expected_len = strlen(sdata->password);
Packit Service 31306d
        if (expected_len <= 0) {
Packit Service 31306d
            goto failed;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        answer = ssh_userauth_kbdint_getanswer(session, 0);
Packit Service 31306d
        if (answer == NULL) {
Packit Service 31306d
            goto failed;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        cmp = strncmp(answer, sdata->password, expected_len);
Packit Service 31306d
        if (cmp != 0) {
Packit Service 31306d
            goto failed;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        /* Password was correct, authenticated */
Packit Service 31306d
        rc = SUCCESS;
Packit Service 31306d
        goto end;
Packit Service 31306d
    default:
Packit Service 31306d
        goto failed;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
failed:
Packit Service 31306d
    if (step != NULL) {
Packit Service 31306d
        *step = 0;
Packit Service 31306d
    }
Packit Service 31306d
    return FAILED;
Packit Service 31306d
Packit Service 31306d
end:
Packit Service 31306d
    if (step != NULL) {
Packit Service 31306d
        (*step)++;
Packit Service 31306d
    }
Packit Service 31306d
    return rc;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static int authenticate_callback(ssh_session session,
Packit Service 31306d
                                 ssh_message message,
Packit Service 31306d
                                 void *userdata)
Packit Service 31306d
{
Packit Service 31306d
    struct session_data_st *sdata = (struct session_data_st *)userdata;
Packit Service 31306d
    int rc;
Packit Service 31306d
Packit Service 31306d
    if (sdata == NULL) {
Packit Service 31306d
        fprintf(stderr, "Null userdata\n");
Packit Service 31306d
        goto denied;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (sdata->extra_data == NULL) {
Packit Service 31306d
        sdata->extra_data = (void *)calloc(1, sizeof(int));
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    switch (ssh_message_type(message)) {
Packit Service 31306d
    case SSH_REQUEST_AUTH:
Packit Service 31306d
        switch (ssh_message_subtype(message)) {
Packit Service 31306d
        case SSH_AUTH_METHOD_INTERACTIVE:
Packit Service 31306d
            rc = authenticate_kbdint(session, message, (void *)sdata);
Packit Service 31306d
            if (rc == SUCCESS) {
Packit Service 31306d
                goto accept;
Packit Service 31306d
            }
Packit Service 31306d
            else if (rc == MORE) {
Packit Service 31306d
                goto more;
Packit Service 31306d
            }
Packit Service 31306d
            ssh_message_auth_set_methods(message, SSH_AUTH_METHOD_INTERACTIVE);
Packit Service 31306d
            goto denied;
Packit Service 31306d
        default:
Packit Service 31306d
            ssh_message_auth_set_methods(message, SSH_AUTH_METHOD_INTERACTIVE);
Packit Service 31306d
            goto denied;
Packit Service 31306d
        }
Packit Service 31306d
    default:
Packit Service 31306d
        ssh_message_auth_set_methods(message, SSH_AUTH_METHOD_INTERACTIVE);
Packit Service 31306d
        goto denied;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    ssh_message_free(message);
Packit Service 31306d
Packit Service 31306d
accept:
Packit Service 31306d
    if (sdata) {
Packit Service 31306d
        if (sdata->extra_data) {
Packit Service 31306d
            free(sdata->extra_data);
Packit Service 31306d
            sdata->extra_data = NULL;
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
    ssh_message_auth_reply_success (message, 0);
Packit Service 31306d
more:
Packit Service 31306d
    return 0;
Packit Service 31306d
denied:
Packit Service 31306d
    if (sdata) {
Packit Service 31306d
        if (sdata->extra_data) {
Packit Service 31306d
            free(sdata->extra_data);
Packit Service 31306d
            sdata->extra_data = NULL;
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
    return 1;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static void handle_kbdint_session_cb(ssh_event event,
Packit Service 31306d
                                     ssh_session session,
Packit Service 31306d
                                     struct server_state_st *state)
Packit Service 31306d
{
Packit Service 31306d
    int n;
Packit Service 31306d
    int rc = 0;
Packit Service 31306d
Packit Service 31306d
    /* Structure for storing the pty size. */
Packit Service 31306d
    struct winsize wsize = {
Packit Service 31306d
        .ws_row = 0,
Packit Service 31306d
        .ws_col = 0,
Packit Service 31306d
        .ws_xpixel = 0,
Packit Service 31306d
        .ws_ypixel = 0
Packit Service 31306d
    };
Packit Service 31306d
Packit Service 31306d
    /* Our struct holding information about the channel. */
Packit Service 31306d
    struct channel_data_st cdata = {
Packit Service 31306d
        .pid = 0,
Packit Service 31306d
        .pty_master = -1,
Packit Service 31306d
        .pty_slave = -1,
Packit Service 31306d
        .child_stdin = -1,
Packit Service 31306d
        .child_stdout = -1,
Packit Service 31306d
        .child_stderr = -1,
Packit Service 31306d
        .event = NULL,
Packit Service 31306d
        .winsize = &wsize
Packit Service 31306d
    };
Packit Service 31306d
Packit Service 31306d
    /* Our struct holding information about the session. */
Packit Service 31306d
    struct session_data_st sdata = {
Packit Service 31306d
        .channel = NULL,
Packit Service 31306d
        .auth_attempts = 0,
Packit Service 31306d
        .authenticated = 0,
Packit Service 31306d
        .username = TORTURE_SSH_USER_BOB,
Packit Service 31306d
        .password = TORTURE_SSH_USER_BOB_PASSWORD
Packit Service 31306d
    };
Packit Service 31306d
Packit Service 31306d
    struct ssh_channel_callbacks_struct *channel_cb = NULL;
Packit Service 31306d
    struct ssh_server_callbacks_struct *server_cb = NULL;
Packit Service 31306d
Packit Service 31306d
    if (state == NULL) {
Packit Service 31306d
        fprintf(stderr, "NULL server state provided\n");
Packit Service 31306d
        goto end;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    server_cb = get_default_server_cb();
Packit Service 31306d
    if (server_cb == NULL) {
Packit Service 31306d
        goto end;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    server_cb->userdata = &sdata;
Packit Service 31306d
Packit Service 31306d
    /* This is a macro, it does not return a value */
Packit Service 31306d
    ssh_callbacks_init(server_cb);
Packit Service 31306d
Packit Service 31306d
    rc = ssh_set_server_callbacks(session, server_cb);
Packit Service 31306d
    if (rc) {
Packit Service 31306d
        goto end;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
#ifdef WITH_PCAP
Packit Service 31306d
    set_pcap(&sdata, session, state->pcap_file);
Packit Service 31306d
#endif
Packit Service 31306d
Packit Service 31306d
    rc = ssh_handle_key_exchange(session);
Packit Service 31306d
    if (rc != SSH_OK) {
Packit Service 31306d
        fprintf(stderr, "%s\n", ssh_get_error(session));
Packit Service 31306d
        goto end;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* Set the supported authentication methods */
Packit Service 31306d
    ssh_set_auth_methods(session, SSH_AUTH_METHOD_INTERACTIVE);
Packit Service 31306d
Packit Service 31306d
    ssh_set_message_callback(session, authenticate_callback, &sdata);
Packit Service 31306d
Packit Service 31306d
    rc = ssh_event_add_session(event, session);
Packit Service 31306d
    if (rc != 0) {
Packit Service 31306d
        fprintf(stderr, "Error adding session to event\n");
Packit Service 31306d
        goto end;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    n = 0;
Packit Service 31306d
    while (sdata.authenticated == 0 || sdata.channel == NULL) {
Packit Service 31306d
        /* If the user has used up all attempts, or if he hasn't been able to
Packit Service 31306d
         * authenticate in 10 seconds (n * 100ms), disconnect. */
Packit Service 31306d
        if (sdata.auth_attempts >= state->max_tries || n >= 100) {
Packit Service 31306d
            goto end;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        if (ssh_event_dopoll(event, 100) == SSH_ERROR) {
Packit Service 31306d
            fprintf(stderr, "do_poll error: %s\n", ssh_get_error(session));
Packit Service 31306d
            goto end;
Packit Service 31306d
        }
Packit Service 31306d
        n++;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    channel_cb = get_default_channel_cb();
Packit Service 31306d
    if (channel_cb == NULL) {
Packit Service 31306d
        goto end;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    channel_cb->userdata = &cdata;
Packit Service 31306d
Packit Service 31306d
    ssh_callbacks_init(channel_cb);
Packit Service 31306d
    rc = ssh_set_channel_callbacks(sdata.channel, channel_cb);
Packit Service 31306d
    if (rc != 0) {
Packit Service 31306d
        goto end;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    do {
Packit Service 31306d
        /* Poll the main event which takes care of the session, the channel and
Packit Service 31306d
         * even our child process's stdout/stderr (once it's started). */
Packit Service 31306d
        rc = ssh_event_dopoll(event, -1);
Packit Service 31306d
        if (rc == SSH_ERROR) {
Packit Service 31306d
          ssh_channel_close(sdata.channel);
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        /* If child process's stdout/stderr has been registered with the event,
Packit Service 31306d
         * or the child process hasn't started yet, continue. */
Packit Service 31306d
        if (cdata.event != NULL || cdata.pid == 0) {
Packit Service 31306d
            continue;
Packit Service 31306d
        }
Packit Service 31306d
        /* Executed only once, once the child process starts. */
Packit Service 31306d
        cdata.event = event;
Packit Service 31306d
        /* If stdout valid, add stdout to be monitored by the poll event. */
Packit Service 31306d
        if (cdata.child_stdout != -1) {
Packit Service 31306d
            if (ssh_event_add_fd(event, cdata.child_stdout, POLLIN, process_stdout,
Packit Service 31306d
                                 sdata.channel) != SSH_OK) {
Packit Service 31306d
                fprintf(stderr, "Failed to register stdout to poll context\n");
Packit Service 31306d
                ssh_channel_close(sdata.channel);
Packit Service 31306d
            }
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        /* If stderr valid, add stderr to be monitored by the poll event. */
Packit Service 31306d
        if (cdata.child_stderr != -1){
Packit Service 31306d
            if (ssh_event_add_fd(event, cdata.child_stderr, POLLIN, process_stderr,
Packit Service 31306d
                                 sdata.channel) != SSH_OK) {
Packit Service 31306d
                fprintf(stderr, "Failed to register stderr to poll context\n");
Packit Service 31306d
                ssh_channel_close(sdata.channel);
Packit Service 31306d
            }
Packit Service 31306d
        }
Packit Service 31306d
    } while(ssh_channel_is_open(sdata.channel) &&
Packit Service 31306d
            (cdata.pid == 0 || waitpid(cdata.pid, &rc, WNOHANG) == 0));
Packit Service 31306d
Packit Service 31306d
    close(cdata.pty_master);
Packit Service 31306d
    close(cdata.child_stdin);
Packit Service 31306d
    close(cdata.child_stdout);
Packit Service 31306d
    close(cdata.child_stderr);
Packit Service 31306d
Packit Service 31306d
    /* Remove the descriptors from the polling context, since they are now
Packit Service 31306d
     * closed, they will always trigger during the poll calls. */
Packit Service 31306d
    ssh_event_remove_fd(event, cdata.child_stdout);
Packit Service 31306d
    ssh_event_remove_fd(event, cdata.child_stderr);
Packit Service 31306d
Packit Service 31306d
    /* If the child process exited. */
Packit Service 31306d
    if (kill(cdata.pid, 0) < 0 && WIFEXITED(rc)) {
Packit Service 31306d
        rc = WEXITSTATUS(rc);
Packit Service 31306d
        ssh_channel_request_send_exit_status(sdata.channel, rc);
Packit Service 31306d
    /* If client terminated the channel or the process did not exit nicely,
Packit Service 31306d
     * but only if something has been forked. */
Packit Service 31306d
    } else if (cdata.pid > 0) {
Packit Service 31306d
        kill(cdata.pid, SIGKILL);
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    ssh_channel_send_eof(sdata.channel);
Packit Service 31306d
    ssh_channel_close(sdata.channel);
Packit Service 31306d
Packit Service 31306d
    /* Wait up to 5 seconds for the client to terminate the session. */
Packit Service 31306d
    for (n = 0; n < 50 && (ssh_get_status(session) & SESSION_END) == 0; n++) {
Packit Service 31306d
        ssh_event_dopoll(event, 100);
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
end:
Packit Service 31306d
#ifdef WITH_PCAP
Packit Service 31306d
    cleanup_pcap(&sdata);
Packit Service 31306d
#endif
Packit Service 31306d
    if (channel_cb != NULL) {
Packit Service 31306d
        free(channel_cb);
Packit Service 31306d
    }
Packit Service 31306d
    if (server_cb != NULL) {
Packit Service 31306d
        free(server_cb);
Packit Service 31306d
    }
Packit Service 31306d
    return;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static int setup_kbdint_server(void **state)
Packit Service 31306d
{
Packit Service 31306d
    struct torture_state *s;
Packit Service 31306d
    struct server_state_st *ss;
Packit Service 31306d
    struct test_server_st *tss;
Packit Service 31306d
Packit Service 31306d
    char rsa_hostkey[1024] = {0};
Packit Service 31306d
Packit Service 31306d
    char sshd_path[1024];
Packit Service 31306d
Packit Service 31306d
    int rc;
Packit Service 31306d
Packit Service 31306d
    char pid_str[1024];
Packit Service 31306d
Packit Service 31306d
    pid_t pid;
Packit Service 31306d
Packit Service 31306d
    assert_non_null(state);
Packit Service 31306d
Packit Service 31306d
    tss = (struct test_server_st*)calloc(1, sizeof(struct test_server_st));
Packit Service 31306d
    assert_non_null(tss);
Packit Service 31306d
Packit Service 31306d
    torture_setup_socket_dir((void **)&s);
Packit Service 31306d
    assert_non_null(s->socket_dir);
Packit Service 31306d
Packit Service 31306d
    /* Set the default interface for the server */
Packit Service 31306d
    setenv("SOCKET_WRAPPER_DEFAULT_IFACE", "10", 1);
Packit Service 31306d
    setenv("PAM_WRAPPER", "1", 1);
Packit Service 31306d
Packit Service 31306d
    snprintf(sshd_path,
Packit Service 31306d
             sizeof(sshd_path),
Packit Service 31306d
             "%s/sshd",
Packit Service 31306d
             s->socket_dir);
Packit Service 31306d
Packit Service 31306d
    rc = mkdir(sshd_path, 0755);
Packit Service 31306d
    assert_return_code(rc, errno);
Packit Service 31306d
Packit Service 31306d
    snprintf(rsa_hostkey,
Packit Service 31306d
             sizeof(rsa_hostkey),
Packit Service 31306d
             "%s/sshd/ssh_host_rsa_key",
Packit Service 31306d
             s->socket_dir);
Packit Service 31306d
    torture_write_file(rsa_hostkey,
Packit Service 31306d
                       torture_get_openssh_testkey(SSH_KEYTYPE_RSA, 0));
Packit Service 31306d
Packit Service 31306d
    /* Create the server state */
Packit Service 31306d
    ss = (struct server_state_st *)calloc(1, sizeof(struct server_state_st));
Packit Service 31306d
    assert_non_null(ss);
Packit Service 31306d
Packit Service 31306d
    ss->address = strdup("127.0.0.10");
Packit Service 31306d
    assert_non_null(ss->address);
Packit Service 31306d
Packit Service 31306d
    ss->port = 22;
Packit Service 31306d
Packit Service 31306d
    ss->host_key = strdup(rsa_hostkey);
Packit Service 31306d
    assert_non_null(rsa_hostkey);
Packit Service 31306d
Packit Service 31306d
    ss->verbosity = torture_libssh_verbosity();
Packit Service 31306d
Packit Service 31306d
#ifdef WITH_PCAP
Packit Service 31306d
    ss->with_pcap = 1;
Packit Service 31306d
    ss->pcap_file = strdup(s->pcap_file);
Packit Service 31306d
    assert_non_null(ss->pcap_file);
Packit Service 31306d
#endif
Packit Service 31306d
Packit Service 31306d
    ss->max_tries = 3;
Packit Service 31306d
    ss->error = 0;
Packit Service 31306d
Packit Service 31306d
    /* Set the session handling function */
Packit Service 31306d
    ss->handle_session = handle_kbdint_session_cb;
Packit Service 31306d
    assert_non_null(ss->handle_session);
Packit Service 31306d
Packit Service 31306d
    /* Start the server */
Packit Service 31306d
    pid = fork_run_server(ss);
Packit Service 31306d
    if (pid < 0) {
Packit Service 31306d
        fail();
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    snprintf(pid_str, sizeof(pid_str), "%d", pid);
Packit Service 31306d
Packit Service 31306d
    torture_write_file(s->srv_pidfile, (const char *)pid_str);
Packit Service 31306d
Packit Service 31306d
    setenv("SOCKET_WRAPPER_DEFAULT_IFACE", "21", 1);
Packit Service 31306d
    unsetenv("PAM_WRAPPER");
Packit Service 31306d
Packit Service 31306d
    /* Wait 200ms */
Packit Service 31306d
    usleep(200 * 1000);
Packit Service 31306d
Packit Service 31306d
    tss->state = s;
Packit Service 31306d
    tss->ss = ss;
Packit Service 31306d
Packit Service 31306d
    *state = tss;
Packit Service 31306d
Packit Service 31306d
    return 0;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static int teardown_kbdint_server(void **state)
Packit Service 31306d
{
Packit Service 31306d
    struct torture_state *s;
Packit Service 31306d
    struct server_state_st *ss;
Packit Service 31306d
    struct test_server_st *tss;
Packit Service 31306d
Packit Service 31306d
    tss = *state;
Packit Service 31306d
    assert_non_null(tss);
Packit Service 31306d
Packit Service 31306d
    s = tss->state;
Packit Service 31306d
    assert_non_null(s);
Packit Service 31306d
Packit Service 31306d
    ss = tss->ss;
Packit Service 31306d
    assert_non_null(ss);
Packit Service 31306d
Packit Service 31306d
    /* This function can be reused */
Packit Service 31306d
    torture_teardown_sshd_server((void **)&s);
Packit Service 31306d
Packit Service 31306d
    free_server_state(tss->ss);
Packit Service 31306d
    SAFE_FREE(tss->ss);
Packit Service 31306d
    SAFE_FREE(tss);
Packit Service 31306d
Packit Service 31306d
    return 0;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static int session_setup(void **state)
Packit Service 31306d
{
Packit Service 31306d
    struct test_server_st *tss = *state;
Packit Service 31306d
    struct torture_state *s;
Packit Service 31306d
    int verbosity = torture_libssh_verbosity();
Packit Service 31306d
    struct passwd *pwd;
Packit Service 31306d
    bool b = false;
Packit Service 31306d
    int rc;
Packit Service 31306d
Packit Service 31306d
    assert_non_null(tss);
Packit Service 31306d
Packit Service 31306d
    s = tss->state;
Packit Service 31306d
    assert_non_null(s);
Packit Service 31306d
Packit Service 31306d
    pwd = getpwnam("bob");
Packit Service 31306d
    assert_non_null(pwd);
Packit Service 31306d
Packit Service 31306d
    rc = setuid(pwd->pw_uid);
Packit Service 31306d
    assert_return_code(rc, errno);
Packit Service 31306d
Packit Service 31306d
    s->ssh.session = ssh_new();
Packit Service 31306d
    assert_non_null(s->ssh.session);
Packit Service 31306d
Packit Service 31306d
    rc = ssh_options_set(s->ssh.session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
Packit Service 31306d
    assert_ssh_return_code(s->ssh.session, rc);
Packit Service 31306d
    rc = ssh_options_set(s->ssh.session, SSH_OPTIONS_HOST, TORTURE_SSH_SERVER);
Packit Service 31306d
    assert_ssh_return_code(s->ssh.session, rc);
Packit Service 31306d
    /* Make sure no other configuration options from system will get used */
Packit Service 31306d
    rc = ssh_options_set(s->ssh.session, SSH_OPTIONS_PROCESS_CONFIG, &b);
Packit Service 31306d
    assert_ssh_return_code(s->ssh.session, rc);
Packit Service 31306d
Packit Service 31306d
    return 0;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static int session_teardown(void **state)
Packit Service 31306d
{
Packit Service 31306d
    struct test_server_st *tss = *state;
Packit Service 31306d
    struct torture_state *s;
Packit Service 31306d
Packit Service 31306d
    assert_non_null(tss);
Packit Service 31306d
Packit Service 31306d
    s = tss->state;
Packit Service 31306d
    assert_non_null(s);
Packit Service 31306d
Packit Service 31306d
    ssh_disconnect(s->ssh.session);
Packit Service 31306d
    ssh_free(s->ssh.session);
Packit Service 31306d
Packit Service 31306d
    return 0;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static void torture_server_auth_kbdint(void **state)
Packit Service 31306d
{
Packit Service 31306d
    struct test_server_st *tss = *state;
Packit Service 31306d
    struct torture_state *s;
Packit Service 31306d
    ssh_session session;
Packit Service 31306d
    int rc;
Packit Service 31306d
Packit Service 31306d
    assert_non_null(tss);
Packit Service 31306d
Packit Service 31306d
    s = tss->state;
Packit Service 31306d
    assert_non_null(s);
Packit Service 31306d
Packit Service 31306d
    session = s->ssh.session;
Packit Service 31306d
    assert_non_null(session);
Packit Service 31306d
Packit Service 31306d
    rc = ssh_options_set(session, SSH_OPTIONS_USER, TORTURE_SSH_USER_BOB);
Packit Service 31306d
    assert_ssh_return_code(session, rc);
Packit Service 31306d
Packit Service 31306d
    rc = ssh_connect(session);
Packit Service 31306d
    assert_ssh_return_code(session, rc);
Packit Service 31306d
Packit Service 31306d
    rc = ssh_userauth_none(session,NULL);
Packit Service 31306d
    /* This request should return a SSH_REQUEST_DENIED error */
Packit Service 31306d
    if (rc == SSH_ERROR) {
Packit Service 31306d
        assert_int_equal(ssh_get_error_code(session), SSH_REQUEST_DENIED);
Packit Service 31306d
    }
Packit Service 31306d
    rc = ssh_userauth_list(session, NULL);
Packit Service 31306d
    assert_true(rc & SSH_AUTH_METHOD_INTERACTIVE);
Packit Service 31306d
Packit Service 31306d
    rc = ssh_userauth_kbdint(session, NULL, NULL);
Packit Service 31306d
    assert_int_equal(rc, SSH_AUTH_INFO);
Packit Service 31306d
    assert_int_equal(ssh_userauth_kbdint_getnprompts(session), 2);
Packit Service 31306d
Packit Service 31306d
    /* Reply the first 2 prompts using the username and password */
Packit Service 31306d
    rc = ssh_userauth_kbdint_setanswer(session, 0,
Packit Service 31306d
            TORTURE_SSH_USER_BOB);
Packit Service 31306d
    assert_false(rc < 0);
Packit Service 31306d
Packit Service 31306d
    rc = ssh_userauth_kbdint_setanswer(session, 1,
Packit Service 31306d
            TORTURE_SSH_USER_BOB_PASSWORD);
Packit Service 31306d
    assert_false(rc < 0);
Packit Service 31306d
Packit Service 31306d
    /* Resend the password */
Packit Service 31306d
    rc = ssh_userauth_kbdint(session, NULL, NULL);
Packit Service 31306d
    assert_int_equal(rc, SSH_AUTH_INFO);
Packit Service 31306d
    assert_int_equal(ssh_userauth_kbdint_getnprompts(session), 1);
Packit Service 31306d
Packit Service 31306d
    rc = ssh_userauth_kbdint_setanswer(session, 0,
Packit Service 31306d
            TORTURE_SSH_USER_BOB_PASSWORD);
Packit Service 31306d
    assert_false(rc < 0);
Packit Service 31306d
Packit Service 31306d
    rc = ssh_userauth_kbdint(session, NULL, NULL);
Packit Service 31306d
Packit Service 31306d
    /* Sometimes, SSH server send an empty query at the end of exchange */
Packit Service 31306d
    if(rc == SSH_AUTH_INFO) {
Packit Service 31306d
        assert_int_equal(ssh_userauth_kbdint_getnprompts(session), 0);
Packit Service 31306d
        rc = ssh_userauth_kbdint(session, NULL, NULL);
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    assert_int_equal(rc, SSH_AUTH_SUCCESS);
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
int torture_run_tests(void)
Packit Service 31306d
{
Packit Service 31306d
    int rc;
Packit Service 31306d
    struct CMUnitTest tests[] = {
Packit Service 31306d
        cmocka_unit_test_setup_teardown(torture_server_auth_kbdint,
Packit Service 31306d
                                        session_setup,
Packit Service 31306d
                                        session_teardown),
Packit Service 31306d
    };
Packit Service 31306d
Packit Service 31306d
    ssh_init();
Packit Service 31306d
Packit Service 31306d
    torture_filter_tests(tests);
Packit Service 31306d
    rc = cmocka_run_group_tests(tests,
Packit Service 31306d
            setup_kbdint_server,
Packit Service 31306d
            teardown_kbdint_server);
Packit Service 31306d
Packit Service 31306d
    ssh_finalize();
Packit Service 31306d
Packit Service 31306d
    return rc;
Packit Service 31306d
}