Blame tests/pkd/pkd_daemon.c

Packit Service 31306d
/*
Packit Service 31306d
 * pkd_daemon.c -- a sample public-key testing daemon using libssh
Packit Service 31306d
 *
Packit Service 31306d
 * Uses public key authentication to establish an exec channel and
Packit Service 31306d
 * echo back payloads to the user.
Packit Service 31306d
 *
Packit Service 31306d
 * (c) 2014 Jon Simons
Packit Service 31306d
 */
Packit Service 31306d
Packit Service 31306d
#include "config.h"
Packit Service 31306d
Packit Service 31306d
#include <errno.h>
Packit Service 31306d
#include <netinet/in.h>
Packit Service 31306d
#include <pthread.h>
Packit Service 31306d
#include <signal.h>
Packit Service 31306d
#include <stdarg.h>
Packit Service 31306d
#include <stdio.h>
Packit Service 31306d
#include <stdlib.h>
Packit Service 31306d
#include <sys/types.h>
Packit Service 31306d
#include <sys/socket.h>
Packit Service 31306d
Packit Service 31306d
#include <libssh/callbacks.h>
Packit Service 31306d
#include <libssh/libssh.h>
Packit Service 31306d
#include <libssh/server.h>
Packit Service 31306d
#include <libssh/kex.h>
Packit Service 31306d
Packit Service 31306d
#include "torture.h" // for ssh_fips_mode()
Packit Service 31306d
#include "pkd_daemon.h"
Packit Service 31306d
Packit Service 31306d
#include <setjmp.h> // for cmocka
Packit Service 31306d
#include <cmocka.h>
Packit Service 31306d
Packit Service 31306d
static int pkdout_enabled;
Packit Service 31306d
static int pkderr_enabled;
Packit Service 31306d
Packit Service 31306d
static void pkdout(const char *fmt, ...) PRINTF_ATTRIBUTE(1, 2);
Packit Service 31306d
static void pkderr(const char *fmt, ...) PRINTF_ATTRIBUTE(1, 2);
Packit Service 31306d
Packit Service 31306d
static void pkdout(const char *fmt, ...) {
Packit Service 31306d
    va_list vargs;
Packit Service 31306d
    if (pkdout_enabled) {
Packit Service 31306d
        va_start(vargs, fmt);
Packit Service 31306d
        vfprintf(stdout, fmt, vargs);
Packit Service 31306d
        va_end(vargs);
Packit Service 31306d
    }
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static void pkderr(const char *fmt, ...) {
Packit Service 31306d
    va_list vargs;
Packit Service 31306d
    if (pkderr_enabled) {
Packit Service 31306d
        va_start(vargs, fmt);
Packit Service 31306d
        vfprintf(stderr, fmt, vargs);
Packit Service 31306d
        va_end(vargs);
Packit Service 31306d
    }
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/*
Packit Service 31306d
 * pkd state: only one thread can run pkd at a time ---------------------
Packit Service 31306d
 */
Packit Service 31306d
Packit Service 31306d
static struct {
Packit Service 31306d
    int rc;
Packit Service 31306d
    pthread_t tid;
Packit Service 31306d
    int keep_going;
Packit Service 31306d
    volatile int pkd_ready;
Packit Service 31306d
} ctx;
Packit Service 31306d
Packit Service 31306d
static struct {
Packit Service 31306d
    int server_fd;
Packit Service 31306d
    int req_exec_received;
Packit Service 31306d
    int close_received;
Packit Service 31306d
    int eof_received;
Packit Service 31306d
} pkd_state;
Packit Service 31306d
Packit Service 31306d
static void pkd_sighandler(int signum) {
Packit Service 31306d
    (void) signum;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static int pkd_init_libssh(void)
Packit Service 31306d
{
Packit Service 31306d
    int rc = ssh_threads_set_callbacks(ssh_threads_get_pthread());
Packit Service 31306d
    return (rc == SSH_OK) ? 0 : 1;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static int pkd_init_server_fd(short port) {
Packit Service 31306d
    int rc = 0;
Packit Service 31306d
    int yes = 1;
Packit Service 31306d
    struct sockaddr_in addr;
Packit Service 31306d
Packit Service 31306d
    int server_fd = socket(PF_INET, SOCK_STREAM, 0);
Packit Service 31306d
    if (server_fd < 0) {
Packit Service 31306d
        rc = -1;
Packit Service 31306d
        goto out;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    rc = setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
Packit Service 31306d
    if (rc != 0) {
Packit Service 31306d
        goto outclose;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    memset(&addr, 0x0, sizeof(addr));
Packit Service 31306d
    addr.sin_family = AF_INET;
Packit Service 31306d
    addr.sin_port = htons(port);
Packit Service 31306d
    addr.sin_addr.s_addr = INADDR_ANY;
Packit Service 31306d
    rc = bind(server_fd, (struct sockaddr *)&addr, sizeof(addr));
Packit Service 31306d
    if (rc != 0) {
Packit Service 31306d
        goto outclose;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    rc = listen(server_fd, 128);
Packit Service 31306d
    if (rc == 0) {
Packit Service 31306d
        goto out;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
outclose:
Packit Service 31306d
    close(server_fd);
Packit Service 31306d
    server_fd = -1;
Packit Service 31306d
out:
Packit Service 31306d
    pkd_state.server_fd = server_fd;
Packit Service 31306d
    return rc;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static int pkd_accept_fd(void)
Packit Service 31306d
{
Packit Service 31306d
    int fd = -1;
Packit Service 31306d
    struct sockaddr_in addr;
Packit Service 31306d
    socklen_t len = sizeof(addr);
Packit Service 31306d
Packit Service 31306d
    do {
Packit Service 31306d
        fd = accept(pkd_state.server_fd, (struct sockaddr *) &addr, &len;;
Packit Service 31306d
    } while ((ctx.keep_going != 0) && (fd < 0) && (errno == EINTR));
Packit Service 31306d
Packit Service 31306d
    return fd;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static void pkd_eof(ssh_session session,
Packit Service 31306d
                    ssh_channel channel,
Packit Service 31306d
                    void *userdata) {
Packit Service 31306d
    (void) session;
Packit Service 31306d
    (void) channel;
Packit Service 31306d
    (void) userdata;
Packit Service 31306d
    pkdout("pkd_eof\n");
Packit Service 31306d
    pkd_state.eof_received = 1;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static void pkd_chan_close(ssh_session session,
Packit Service 31306d
                           ssh_channel channel,
Packit Service 31306d
                           void *userdata) {
Packit Service 31306d
    (void) session;
Packit Service 31306d
    (void) channel;
Packit Service 31306d
    (void) userdata;
Packit Service 31306d
    pkdout("pkd_chan_close\n");
Packit Service 31306d
    pkd_state.close_received = 1;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static int pkd_req_exec(ssh_session s,
Packit Service 31306d
                        ssh_channel c,
Packit Service 31306d
                        const char *cmd,
Packit Service 31306d
                        void *userdata) {
Packit Service 31306d
    (void) s;
Packit Service 31306d
    (void) c;
Packit Service 31306d
    (void) cmd;
Packit Service 31306d
    (void) userdata;
Packit Service 31306d
    /* assumes pubkey authentication has already succeeded */
Packit Service 31306d
    pkdout("pkd_req_exec\n");
Packit Service 31306d
    pkd_state.req_exec_received = 1;
Packit Service 31306d
    return 0;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/* assumes there is only ever a single channel */
Packit Service 31306d
static struct ssh_channel_callbacks_struct pkd_channel_cb = {
Packit Service 31306d
    .channel_eof_function = pkd_eof,
Packit Service 31306d
    .channel_close_function = pkd_chan_close,
Packit Service 31306d
    .channel_exec_request_function = pkd_req_exec,
Packit Service 31306d
};
Packit Service 31306d
Packit Service 31306d
static int pkd_auth_pubkey_cb(ssh_session s,
Packit Service 31306d
                              const char *user,
Packit Service 31306d
                              ssh_key key,
Packit Service 31306d
                              char state,
Packit Service 31306d
                              void *userdata) {
Packit Service 31306d
    (void) s;
Packit Service 31306d
    (void) user;
Packit Service 31306d
    (void) key;
Packit Service 31306d
    (void) state;
Packit Service 31306d
    (void) userdata;
Packit Service 31306d
    pkdout("pkd_auth_pubkey_cb keytype %s, state: %d\n",
Packit Service 31306d
           ssh_key_type_to_char(ssh_key_type(key)), state);
Packit Service 31306d
    if ((state == SSH_PUBLICKEY_STATE_NONE) ||
Packit Service 31306d
        (state == SSH_PUBLICKEY_STATE_VALID)) {
Packit Service 31306d
        return SSH_AUTH_SUCCESS;
Packit Service 31306d
    }
Packit Service 31306d
    return SSH_AUTH_DENIED;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static int pkd_service_request_cb(ssh_session session,
Packit Service 31306d
                                  const char *service,
Packit Service 31306d
                                  void *userdata) {
Packit Service 31306d
    (void) session;
Packit Service 31306d
    (void) userdata;
Packit Service 31306d
    pkdout("pkd_service_request_cb: %s\n", service);
Packit Service 31306d
    return (0 == (strcmp(service, "ssh-userauth"))) ? 0 : -1;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static ssh_channel pkd_channel_openreq_cb(ssh_session s,
Packit Service 31306d
                                          void *userdata) {
Packit Service 31306d
    ssh_channel c = NULL;
Packit Service 31306d
    ssh_channel *out = (ssh_channel *) userdata;
Packit Service 31306d
Packit Service 31306d
    /* assumes pubkey authentication has already succeeded */
Packit Service 31306d
    pkdout("pkd_channel_openreq_cb\n");
Packit Service 31306d
Packit Service 31306d
    c = ssh_channel_new(s);
Packit Service 31306d
    if (c == NULL) {
Packit Service 31306d
        pkderr("ssh_channel_new: %s\n", ssh_get_error(s));
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    ssh_callbacks_init(&pkd_channel_cb);
Packit Service 31306d
    pkd_channel_cb.userdata = userdata;
Packit Service 31306d
    if (ssh_set_channel_callbacks(c, &pkd_channel_cb) != SSH_OK) {
Packit Service 31306d
        pkderr("ssh_set_channel_callbacks: %s\n", ssh_get_error(s));
Packit Service 31306d
        ssh_channel_free(c);
Packit Service 31306d
        c = NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    *out = c;
Packit Service 31306d
Packit Service 31306d
    return c;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static struct ssh_server_callbacks_struct pkd_server_cb = {
Packit Service 31306d
    .auth_pubkey_function = pkd_auth_pubkey_cb,
Packit Service 31306d
    .service_request_function = pkd_service_request_cb,
Packit Service 31306d
    .channel_open_request_session_function = pkd_channel_openreq_cb,
Packit Service 31306d
};
Packit Service 31306d
Packit Service 31306d
static int pkd_exec_hello(int fd, struct pkd_daemon_args *args)
Packit Service 31306d
{
Packit Service 31306d
    int rc = -1;
Packit Service 31306d
    ssh_bind b = NULL;
Packit Service 31306d
    ssh_session s = NULL;
Packit Service 31306d
    ssh_event e = NULL;
Packit Service 31306d
    ssh_channel c = NULL;
Packit Service 31306d
    enum ssh_bind_options_e opts = -1;
Packit Service 31306d
Packit Service 31306d
    int level = args->opts.libssh_log_level;
Packit Service 31306d
    enum pkd_hostkey_type_e type = args->type;
Packit Service 31306d
    const char *hostkeypath = args->hostkeypath;
Packit Service 31306d
    const char *default_kex = NULL;
Packit Service 31306d
    char *all_kex = NULL;
Packit Service 31306d
    size_t kex_len = 0;
Packit Service 31306d
    const char *all_ciphers = NULL;
Packit Service 31306d
    const uint64_t rekey_data_limit = args->rekey_data_limit;
Packit Service 31306d
    bool process_config = false;
Packit Service 31306d
Packit Service 31306d
    pkd_state.eof_received = 0;
Packit Service 31306d
    pkd_state.close_received  = 0;
Packit Service 31306d
    pkd_state.req_exec_received = 0;
Packit Service 31306d
Packit Service 31306d
    b = ssh_bind_new();
Packit Service 31306d
    if (b == NULL) {
Packit Service 31306d
        pkderr("ssh_bind_new\n");
Packit Service 31306d
        goto outclose;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (type == PKD_RSA) {
Packit Service 31306d
        opts = SSH_BIND_OPTIONS_RSAKEY;
Packit Service 31306d
    } else if (type == PKD_ED25519) {
Packit Service 31306d
        opts = SSH_BIND_OPTIONS_HOSTKEY;
Packit Service 31306d
#ifdef HAVE_DSA
Packit Service 31306d
    } else if (type == PKD_DSA) {
Packit Service 31306d
        opts = SSH_BIND_OPTIONS_DSAKEY;
Packit Service 31306d
#endif
Packit Service 31306d
    } else if (type == PKD_ECDSA) {
Packit Service 31306d
        opts = SSH_BIND_OPTIONS_ECDSAKEY;
Packit Service 31306d
    } else {
Packit Service 31306d
        pkderr("unknown hostkey type: %d\n", type);
Packit Service 31306d
        rc = -1;
Packit Service 31306d
        goto outclose;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    rc = ssh_bind_options_set(b, opts, hostkeypath);
Packit Service 31306d
    if (rc != 0) {
Packit Service 31306d
        pkderr("ssh_bind_options_set: %s\n", ssh_get_error(b));
Packit Service 31306d
        goto outclose;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    rc = ssh_bind_options_set(b, SSH_BIND_OPTIONS_LOG_VERBOSITY, &level);
Packit Service 31306d
    if (rc != 0) {
Packit Service 31306d
        pkderr("ssh_bind_options_set log verbosity: %s\n", ssh_get_error(b));
Packit Service 31306d
        goto outclose;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    rc = ssh_bind_options_set(b, SSH_BIND_OPTIONS_PROCESS_CONFIG,
Packit Service 31306d
                              &process_config);
Packit Service 31306d
    if (rc != 0) {
Packit Service 31306d
        pkderr("ssh_bind_options_set process config: %s\n", ssh_get_error(b));
Packit Service 31306d
        goto outclose;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (!ssh_fips_mode()) {
Packit Service 31306d
        /* Add methods not enabled by default */
Packit Service 31306d
#define GEX_SHA1 "diffie-hellman-group-exchange-sha1"
Packit Service 31306d
        default_kex = ssh_kex_get_default_methods(SSH_KEX);
Packit Service 31306d
        kex_len = strlen(default_kex) + strlen(GEX_SHA1) + 2;
Packit Service 31306d
        all_kex = malloc(kex_len);
Packit Service 31306d
        if (all_kex == NULL) {
Packit Service 31306d
            pkderr("Failed to alloc more memory.\n");
Packit Service 31306d
            goto outclose;
Packit Service 31306d
        }
Packit Service 31306d
        snprintf(all_kex, kex_len, "%s," GEX_SHA1, default_kex);
Packit Service 31306d
        rc = ssh_bind_options_set(b, SSH_BIND_OPTIONS_KEY_EXCHANGE, all_kex);
Packit Service 31306d
        free(all_kex);
Packit Service 31306d
        if (rc != 0) {
Packit Service 31306d
            pkderr("ssh_bind_options_set kex methods: %s\n", ssh_get_error(b));
Packit Service 31306d
            goto outclose;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        /* Enable all supported ciphers */
Packit Service 31306d
        all_ciphers = ssh_kex_get_supported_method(SSH_CRYPT_C_S);
Packit Service 31306d
        rc = ssh_bind_options_set(b, SSH_BIND_OPTIONS_CIPHERS_C_S, all_ciphers);
Packit Service 31306d
        if (rc != 0) {
Packit Service 31306d
            pkderr("ssh_bind_options_set Ciphers C-S: %s\n", ssh_get_error(b));
Packit Service 31306d
            goto outclose;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        all_ciphers = ssh_kex_get_supported_method(SSH_CRYPT_S_C);
Packit Service 31306d
        rc = ssh_bind_options_set(b, SSH_BIND_OPTIONS_CIPHERS_S_C, all_ciphers);
Packit Service 31306d
        if (rc != 0) {
Packit Service 31306d
            pkderr("ssh_bind_options_set Ciphers S-C: %s\n", ssh_get_error(b));
Packit Service 31306d
            goto outclose;
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    s = ssh_new();
Packit Service 31306d
    if (s == NULL) {
Packit Service 31306d
        pkderr("ssh_new\n");
Packit Service 31306d
        goto outclose;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    rc = ssh_options_set(s, SSH_OPTIONS_REKEY_DATA, &rekey_data_limit);
Packit Service 31306d
    if (rc != 0) {
Packit Service 31306d
        pkderr("ssh_options_set rekey data: %s\n", ssh_get_error(s));
Packit Service 31306d
        goto outclose;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /*
Packit Service 31306d
     * ssh_bind_accept loads host key as side-effect.  If this
Packit Service 31306d
     * succeeds, the given 'fd' will be closed upon 'ssh_free(s)'.
Packit Service 31306d
     */
Packit Service 31306d
    rc = ssh_bind_accept_fd(b, s, fd);
Packit Service 31306d
    if (rc != SSH_OK) {
Packit Service 31306d
        pkderr("ssh_bind_accept_fd: %s\n", ssh_get_error(b));
Packit Service 31306d
        goto outclose;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* accept only publickey-based auth */
Packit Service 31306d
    ssh_set_auth_methods(s, SSH_AUTH_METHOD_PUBLICKEY);
Packit Service 31306d
Packit Service 31306d
    /* initialize callbacks */
Packit Service 31306d
    ssh_callbacks_init(&pkd_server_cb);
Packit Service 31306d
    pkd_server_cb.userdata = &c;
Packit Service 31306d
    rc = ssh_set_server_callbacks(s, &pkd_server_cb);
Packit Service 31306d
    if (rc != SSH_OK) {
Packit Service 31306d
        pkderr("ssh_set_server_callbacks: %s\n", ssh_get_error(s));
Packit Service 31306d
        goto out;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* first do key exchange */
Packit Service 31306d
    rc = ssh_handle_key_exchange(s);
Packit Service 31306d
    if (rc != SSH_OK) {
Packit Service 31306d
        pkderr("ssh_handle_key_exchange: %s\n", ssh_get_error(s));
Packit Service 31306d
        goto out;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* setup and pump event to carry out exec channel */
Packit Service 31306d
    e = ssh_event_new();
Packit Service 31306d
    if (e == NULL) {
Packit Service 31306d
        pkderr("ssh_event_new\n");
Packit Service 31306d
        goto out;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    rc = ssh_event_add_session(e, s);
Packit Service 31306d
    if (rc != SSH_OK) {
Packit Service 31306d
        pkderr("ssh_event_add_session\n");
Packit Service 31306d
        goto out;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* poll until exec channel established */
Packit Service 31306d
    while ((ctx.keep_going != 0) &&
Packit Service 31306d
           (rc != SSH_ERROR) && (pkd_state.req_exec_received == 0)) {
Packit Service 31306d
        rc = ssh_event_dopoll(e, -1 /* infinite timeout */);
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (rc == SSH_ERROR) {
Packit Service 31306d
        pkderr("ssh_event_dopoll\n");
Packit Service 31306d
        goto out;
Packit Service 31306d
    } else if (c == NULL) {
Packit Service 31306d
        pkderr("poll loop exited but exec channel not ready\n");
Packit Service 31306d
        rc = -1;
Packit Service 31306d
        goto out;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    rc = ssh_channel_write(c, args->payload.buf, args->payload.len);
Packit Service 31306d
    if (rc != (int)args->payload.len) {
Packit Service 31306d
        pkderr("ssh_channel_write partial (%d != %zd)\n", rc, args->payload.len);
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    rc = ssh_channel_request_send_exit_status(c, 0);
Packit Service 31306d
    if (rc != SSH_OK) {
Packit Service 31306d
        pkderr("ssh_channel_request_send_exit_status: %s\n",
Packit Service 31306d
                        ssh_get_error(s));
Packit Service 31306d
        goto out;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    rc = ssh_channel_send_eof(c);
Packit Service 31306d
    if (rc != SSH_OK) {
Packit Service 31306d
        pkderr("ssh_channel_send_eof: %s\n", ssh_get_error(s));
Packit Service 31306d
        goto out;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    rc = ssh_channel_close(c);
Packit Service 31306d
    if (rc != SSH_OK) {
Packit Service 31306d
        pkderr("ssh_channel_close: %s\n", ssh_get_error(s));
Packit Service 31306d
        goto out;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    while ((ctx.keep_going != 0) &&
Packit Service 31306d
           (pkd_state.eof_received == 0) &&
Packit Service 31306d
           (pkd_state.close_received == 0)) {
Packit Service 31306d
        rc = ssh_event_dopoll(e, 1000 /* milliseconds */);
Packit Service 31306d
        if (rc == SSH_ERROR) {
Packit Service 31306d
            /* log, but don't consider this fatal */
Packit Service 31306d
            pkdout("ssh_event_dopoll for eof + close: %s\n", ssh_get_error(s));
Packit Service 31306d
            rc = 0;
Packit Service 31306d
            break;
Packit Service 31306d
        } else {
Packit Service 31306d
            rc = 0;
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    while ((ctx.keep_going != 0) &&
Packit Service 31306d
           (ssh_is_connected(s))) {
Packit Service 31306d
        rc = ssh_event_dopoll(e, 1000 /* milliseconds */);
Packit Service 31306d
        if (rc == SSH_ERROR) {
Packit Service 31306d
            /* log, but don't consider this fatal */
Packit Service 31306d
            pkdout("ssh_event_dopoll for session connection: %s\n", ssh_get_error(s));
Packit Service 31306d
            rc = 0;
Packit Service 31306d
            break;
Packit Service 31306d
        } else {
Packit Service 31306d
            rc = 0;
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
    goto out;
Packit Service 31306d
Packit Service 31306d
outclose:
Packit Service 31306d
    close(fd);
Packit Service 31306d
out:
Packit Service 31306d
    if (c != NULL) {
Packit Service 31306d
        ssh_channel_free(c);
Packit Service 31306d
    }
Packit Service 31306d
    if (e != NULL) {
Packit Service 31306d
        ssh_event_remove_session(e, s);
Packit Service 31306d
        ssh_event_free(e);
Packit Service 31306d
    }
Packit Service 31306d
    if (s != NULL) {
Packit Service 31306d
        ssh_disconnect(s);
Packit Service 31306d
        ssh_free(s);
Packit Service 31306d
    }
Packit Service 31306d
    if (b != NULL) {
Packit Service 31306d
        ssh_bind_free(b);
Packit Service 31306d
    }
Packit Service 31306d
    return rc;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/*
Packit Service 31306d
 * main loop ------------------------------------------------------------
Packit Service 31306d
 */
Packit Service 31306d
Packit Service 31306d
static void *pkd_main(void *args) {
Packit Service 31306d
    int rc = -1;
Packit Service 31306d
    struct pkd_daemon_args *a = (struct pkd_daemon_args *) args;
Packit Service 31306d
Packit Service 31306d
    struct sigaction act = { .sa_handler = pkd_sighandler, };
Packit Service 31306d
Packit Service 31306d
    pkd_state.server_fd = -1;
Packit Service 31306d
    pkd_state.req_exec_received = 0;
Packit Service 31306d
    pkd_state.close_received = 0;
Packit Service 31306d
    pkd_state.eof_received = 0;
Packit Service 31306d
Packit Service 31306d
    /* SIGUSR1 is used to interrupt 'pkd_accept_fd'. */
Packit Service 31306d
    rc = sigaction(SIGUSR1, &act, NULL);
Packit Service 31306d
    if (rc != 0) {
Packit Service 31306d
        pkderr("sigaction: %d\n", rc);
Packit Service 31306d
        goto out;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* Ignore SIGPIPE */
Packit Service 31306d
    signal(SIGPIPE, SIG_IGN);
Packit Service 31306d
Packit Service 31306d
    rc = pkd_init_libssh();
Packit Service 31306d
    if (rc != 0) {
Packit Service 31306d
        pkderr("pkd_init_libssh: %d\n", rc);
Packit Service 31306d
        goto out;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    rc = pkd_init_server_fd(1234);
Packit Service 31306d
    if (rc != 0) {
Packit Service 31306d
        pkderr("pkd_init_server_fd: %d\n", rc);
Packit Service 31306d
        goto out;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    ctx.pkd_ready = 1;
Packit Service 31306d
Packit Service 31306d
    while (ctx.keep_going != 0) {
Packit Service 31306d
        int fd = pkd_accept_fd();
Packit Service 31306d
        if (fd < 0) {
Packit Service 31306d
            if (ctx.keep_going != 0) {
Packit Service 31306d
                pkderr("pkd_accept_fd");
Packit Service 31306d
                rc = -1;
Packit Service 31306d
            } else {
Packit Service 31306d
                rc = 0;
Packit Service 31306d
            }
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        rc = pkd_exec_hello(fd, a);
Packit Service 31306d
        if (rc != 0) {
Packit Service 31306d
            pkderr("pkd_exec_hello: %d\n", rc);
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (pkd_state.server_fd != -1) {
Packit Service 31306d
        close(pkd_state.server_fd);
Packit Service 31306d
    }
Packit Service 31306d
    pkd_state.server_fd = -1;
Packit Service 31306d
out:
Packit Service 31306d
    ctx.rc = rc;
Packit Service 31306d
Packit Service 31306d
    return NULL;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/*
Packit Service 31306d
 * pkd start and stop used by setup/teardown test scaffolding -----------
Packit Service 31306d
 */
Packit Service 31306d
Packit Service 31306d
int pkd_start(struct pkd_daemon_args *args) {
Packit Service 31306d
    int rc = 0;
Packit Service 31306d
Packit Service 31306d
    pkdout_enabled = args->opts.log_stdout;
Packit Service 31306d
    pkderr_enabled = args->opts.log_stderr;
Packit Service 31306d
Packit Service 31306d
    /* Initialize the pkd context. */
Packit Service 31306d
    ctx.rc = -1;
Packit Service 31306d
    ctx.keep_going = 1;
Packit Service 31306d
    ctx.pkd_ready = 0;
Packit Service 31306d
    rc = pthread_create(&ctx.tid, NULL, &pkd_main, args);
Packit Service 31306d
    assert_int_equal(rc, 0);
Packit Service 31306d
Packit Service 31306d
    /* Busy-spin until pkd thread is ready. */
Packit Service 31306d
    while (ctx.pkd_ready == 0);
Packit Service 31306d
Packit Service 31306d
    return rc;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
void pkd_stop(struct pkd_result *out) {
Packit Service 31306d
    int rc = 0;
Packit Service 31306d
Packit Service 31306d
    ctx.keep_going = 0;
Packit Service 31306d
    close(pkd_state.server_fd);
Packit Service 31306d
Packit Service 31306d
    rc = pthread_kill(ctx.tid, SIGUSR1);
Packit Service 31306d
    assert_int_equal(rc, 0);
Packit Service 31306d
Packit Service 31306d
    rc = pthread_join(ctx.tid, NULL);
Packit Service 31306d
    assert_int_equal(rc, 0);
Packit Service 31306d
Packit Service 31306d
    assert_non_null(out);
Packit Service 31306d
    out->ok = (ctx.rc == 0);
Packit Service 31306d
Packit Service 31306d
    return;
Packit Service 31306d
}