Blame examples/sshd_direct-tcpip.c

Packit 6c0a39
/* This is a sample implementation of a libssh based SSH server */
Packit 6c0a39
/*
Packit 6c0a39
Copyright 2003-2009 Aris Adamantiadis
Packit 6c0a39
Copyright 2018 T. Wimmer
Packit 6c0a39
Packit 6c0a39
This file is part of the SSH Library
Packit 6c0a39
Packit 6c0a39
You are free to copy this file, modify it in any way, consider it being public
Packit 6c0a39
domain. This does not apply to the rest of the library though, but it is
Packit 6c0a39
allowed to cut-and-paste working code from this file to any license of
Packit 6c0a39
program.
Packit 6c0a39
The goal is to show the API in action. It's not a reference on how terminal
Packit 6c0a39
clients must be made or how a client should react.
Packit 6c0a39
*/
Packit 6c0a39
Packit 6c0a39
/*
Packit 6c0a39
 Example:
Packit 6c0a39
  ./sshd_direct-tcpip -v -p 2022 -d serverkey.dsa -r serverkey.rsa 127.0.0.1
Packit 6c0a39
*/
Packit 6c0a39
Packit 6c0a39
#include "config.h"
Packit 6c0a39
Packit 6c0a39
#include <libssh/libssh.h>
Packit 6c0a39
#include <libssh/server.h>
Packit 6c0a39
#include <libssh/callbacks.h>
Packit 6c0a39
#include <libssh/channels.h>
Packit 6c0a39
Packit 6c0a39
#ifdef HAVE_ARGP_H
Packit 6c0a39
#include <argp.h>
Packit 6c0a39
#endif
Packit 6c0a39
#include <stdbool.h>
Packit 6c0a39
#include <stdlib.h>
Packit 6c0a39
#include <string.h>
Packit 6c0a39
#include <stdio.h>
Packit 6c0a39
#include <poll.h>
Packit 6c0a39
Packit 6c0a39
#ifndef KEYS_FOLDER
Packit 6c0a39
#ifdef _WIN32
Packit 6c0a39
#define KEYS_FOLDER
Packit 6c0a39
#else
Packit 6c0a39
#define KEYS_FOLDER "/etc/ssh/"
Packit 6c0a39
#endif
Packit 6c0a39
#endif
Packit 6c0a39
Packit 6c0a39
#define USER "user"
Packit 6c0a39
#define PASSWORD "pwd"
Packit 6c0a39
Packit 6c0a39
struct event_fd_data_struct {
Packit 6c0a39
    int *p_fd;
Packit 6c0a39
    ssh_channel channel;
Packit 6c0a39
    struct ssh_channel_callbacks_struct *cb_chan;
Packit 6c0a39
    int stacked;
Packit 6c0a39
};
Packit 6c0a39
Packit 6c0a39
struct cleanup_node_struct {
Packit 6c0a39
    struct event_fd_data_struct *data;
Packit 6c0a39
    struct cleanup_node_struct *next;
Packit 6c0a39
};
Packit 6c0a39
Packit 6c0a39
static bool authenticated = false;
Packit 6c0a39
static int tries = 0;
Packit 6c0a39
static bool error_set = false;
Packit 6c0a39
static int sockets_cnt = 0;
Packit 6c0a39
static ssh_event mainloop = NULL;
Packit 6c0a39
static struct cleanup_node_struct *cleanup_stack = NULL;
Packit 6c0a39
Packit 6c0a39
static void _close_socket(struct event_fd_data_struct event_fd_data);
Packit 6c0a39
Packit 6c0a39
static void cleanup_push(struct cleanup_node_struct** head_ref, struct event_fd_data_struct *new_data) {
Packit 6c0a39
    // Allocate memory for node
Packit 6c0a39
    struct cleanup_node_struct *new_node = malloc(sizeof *new_node);
Packit 6c0a39
Packit 6c0a39
    new_node->next = (*head_ref);
Packit 6c0a39
Packit 6c0a39
    // Copy new_data
Packit 6c0a39
    new_node->data = new_data;
Packit 6c0a39
Packit 6c0a39
    // Change head pointer as new node is added at the beginning
Packit 6c0a39
    (*head_ref) = new_node;
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
static void do_cleanup(struct cleanup_node_struct **head_ref) {
Packit 6c0a39
    struct cleanup_node_struct *current = (*head_ref);
Packit 6c0a39
    struct cleanup_node_struct *previous = NULL, *gone = NULL;
Packit 6c0a39
Packit 6c0a39
    while (current != NULL) {
Packit 6c0a39
        if (ssh_channel_is_closed(current->data->channel)) {
Packit 6c0a39
            if (current == (*head_ref)) {
Packit 6c0a39
                (*head_ref) = current->next;
Packit 6c0a39
            }
Packit 6c0a39
            if (previous != NULL) {
Packit 6c0a39
                previous->next = current->next;
Packit 6c0a39
            }
Packit 6c0a39
            gone = current;
Packit 6c0a39
            current = current->next;
Packit 6c0a39
Packit 6c0a39
            if (gone->data->channel) {
Packit 6c0a39
                _close_socket(*gone->data);
Packit 6c0a39
                ssh_remove_channel_callbacks(gone->data->channel, gone->data->cb_chan);
Packit 6c0a39
                ssh_channel_free(gone->data->channel);
Packit 6c0a39
                gone->data->channel = NULL;
Packit 6c0a39
Packit 6c0a39
                SAFE_FREE(gone->data->p_fd);
Packit 6c0a39
                SAFE_FREE(gone->data->cb_chan);
Packit 6c0a39
                SAFE_FREE(gone->data);
Packit 6c0a39
                SAFE_FREE(gone);
Packit 6c0a39
            }
Packit 6c0a39
            else {
Packit 6c0a39
                fprintf(stderr, "channel already freed!\n");
Packit 6c0a39
            }
Packit 6c0a39
            _ssh_log(SSH_LOG_FUNCTIONS, "=== do_cleanup", "Freed.");
Packit 6c0a39
        }
Packit 6c0a39
        else {
Packit 6c0a39
            ssh_channel_close(current->data->channel);
Packit 6c0a39
            previous = current;
Packit 6c0a39
            current = current->next;
Packit 6c0a39
        }
Packit 6c0a39
    }
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
static int auth_password(ssh_session session, const char *user,
Packit 6c0a39
            const char *password, void *userdata) {
Packit 6c0a39
    (void)userdata;
Packit 6c0a39
    _ssh_log(SSH_LOG_PROTOCOL, "=== auth_password", "Authenticating user %s pwd %s",user, password);
Packit 6c0a39
    if (strcmp(user,USER) == 0 && strcmp(password, PASSWORD) == 0){
Packit 6c0a39
        authenticated = true;
Packit 6c0a39
        printf("Authenticated\n");
Packit 6c0a39
        return SSH_AUTH_SUCCESS;
Packit 6c0a39
    }
Packit 6c0a39
    if (tries >= 3){
Packit 6c0a39
        printf("Too many authentication tries\n");
Packit 6c0a39
        ssh_disconnect(session);
Packit 6c0a39
        error_set = true;
Packit 6c0a39
        return SSH_AUTH_DENIED;
Packit 6c0a39
    }
Packit 6c0a39
    tries++;
Packit 6c0a39
    return SSH_AUTH_DENIED;
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
static int auth_gssapi_mic(ssh_session session, const char *user, const char *principal, void *userdata) {
Packit 6c0a39
    ssh_gssapi_creds creds = ssh_gssapi_get_creds(session);
Packit 6c0a39
    (void)userdata;
Packit 6c0a39
    printf("Authenticating user %s with gssapi principal %s\n", user, principal);
Packit 6c0a39
    if (creds != NULL)
Packit 6c0a39
        printf("Received some gssapi credentials\n");
Packit 6c0a39
    else
Packit 6c0a39
        printf("Not received any forwardable creds\n");
Packit 6c0a39
    printf("authenticated\n");
Packit 6c0a39
    authenticated = true;
Packit 6c0a39
    return SSH_AUTH_SUCCESS;
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
static int subsystem_request(ssh_session session, ssh_channel channel, const char *subsystem, void *userdata) {
Packit 6c0a39
    (void)session;
Packit 6c0a39
    (void)channel;
Packit 6c0a39
    //(void)subsystem;
Packit 6c0a39
    (void)userdata;
Packit 6c0a39
    _ssh_log(SSH_LOG_PROTOCOL, "=== subsystem_request", "Channel subsystem reqeuest: %s", subsystem);
Packit 6c0a39
    return 0;
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
struct ssh_channel_callbacks_struct channel_cb = {
Packit 6c0a39
    .channel_subsystem_request_function = subsystem_request
Packit 6c0a39
};
Packit 6c0a39
Packit 6c0a39
static ssh_channel new_session_channel(ssh_session session, void *userdata) {
Packit 6c0a39
    (void)session;
Packit 6c0a39
    (void)userdata;
Packit 6c0a39
    _ssh_log(SSH_LOG_PROTOCOL, "=== subsystem_request", "Session channel request");
Packit 6c0a39
    /* For TCP forward only there seems to be no need for a session channel */
Packit 6c0a39
    /*if(chan != NULL)
Packit 6c0a39
        return NULL;
Packit 6c0a39
    printf("Session channel request\n");
Packit 6c0a39
    chan = ssh_channel_new(session);
Packit 6c0a39
    ssh_callbacks_init(&channel_cb);
Packit 6c0a39
    ssh_set_channel_callbacks(chan, &channel_cb);
Packit 6c0a39
    return chan;*/
Packit 6c0a39
    return NULL;
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
static void stack_socket_close(UNUSED_PARAM(ssh_session session),
Packit 6c0a39
                               struct event_fd_data_struct *event_fd_data)
Packit 6c0a39
{
Packit 6c0a39
    if (event_fd_data->stacked != 1) {
Packit 6c0a39
        _ssh_log(SSH_LOG_FUNCTIONS, "=== stack_socket_close", "Closing fd = %d sockets_cnt = %d", *event_fd_data->p_fd, sockets_cnt);
Packit 6c0a39
        event_fd_data->stacked = 1;
Packit 6c0a39
        cleanup_push(&cleanup_stack, event_fd_data);
Packit 6c0a39
    }
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
static void _close_socket(struct event_fd_data_struct event_fd_data) {
Packit 6c0a39
    _ssh_log(SSH_LOG_FUNCTIONS, "=== close_socket", "Closing fd = %d sockets_cnt = %d", *event_fd_data.p_fd, sockets_cnt);
Packit 6c0a39
    ssh_event_remove_fd(mainloop, *event_fd_data.p_fd);
Packit 6c0a39
    sockets_cnt--;
Packit 6c0a39
#ifdef _WIN32
Packit 6c0a39
    closesocket(*event_fd_data.p_fd);
Packit 6c0a39
#else
Packit 6c0a39
    close(*event_fd_data.p_fd);
Packit 6c0a39
#endif // _WIN32
Packit 6c0a39
    (*event_fd_data.p_fd) = SSH_INVALID_SOCKET;
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
static int service_request(ssh_session session, const char *service, void *userdata) {
Packit 6c0a39
    (void)session;
Packit 6c0a39
    //(void)service;
Packit 6c0a39
    (void)userdata;
Packit 6c0a39
    _ssh_log(SSH_LOG_PROTOCOL, "=== service_request", "Service request: %s", service);
Packit 6c0a39
    return 0;
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
static void global_request(ssh_session session, ssh_message message, void *userdata) {
Packit 6c0a39
    (void)session;
Packit 6c0a39
    (void)userdata;
Packit 6c0a39
    _ssh_log(SSH_LOG_PROTOCOL, "=== global_request", "Global request, message type: %d", ssh_message_type(message));
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
static void my_channel_close_function(ssh_session session, ssh_channel channel, void *userdata) {
Packit 6c0a39
    struct event_fd_data_struct *event_fd_data = (struct event_fd_data_struct *)userdata;
Packit 6c0a39
    (void)session;
Packit 6c0a39
Packit 6c0a39
    _ssh_log(SSH_LOG_PROTOCOL, "=== my_channel_close_function", "Channel %d:%d closed by remote. State=%d", channel->local_channel, channel->remote_channel, channel->state);
Packit 6c0a39
Packit 6c0a39
    stack_socket_close(session, event_fd_data);
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
static void my_channel_eof_function(ssh_session session, ssh_channel channel, void *userdata) {
Packit 6c0a39
    struct event_fd_data_struct *event_fd_data = (struct event_fd_data_struct *)userdata;
Packit 6c0a39
    (void)session;
Packit 6c0a39
Packit 6c0a39
    _ssh_log(SSH_LOG_PROTOCOL, "=== my_channel_eof_function", "Got EOF on channel %d:%d. Shuting down write on socket (fd = %d).", channel->local_channel, channel->remote_channel, *event_fd_data->p_fd);
Packit 6c0a39
Packit 6c0a39
    stack_socket_close(session, event_fd_data);
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
static void my_channel_exit_status_function(ssh_session session, ssh_channel channel, int exit_status, void *userdata) {
Packit 6c0a39
    struct event_fd_data_struct *event_fd_data = (struct event_fd_data_struct *)userdata;
Packit 6c0a39
    (void)session;
Packit 6c0a39
Packit 6c0a39
    _ssh_log(SSH_LOG_PROTOCOL, "=== my_channel_exit_status_function", "Got exit status %d on channel %d:%d fd = %d.", exit_status, channel->local_channel, channel->remote_channel, *event_fd_data->p_fd);
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
static int my_channel_data_function(ssh_session session,
Packit 6c0a39
                                    ssh_channel channel,
Packit 6c0a39
                                    void *data,
Packit 6c0a39
                                    uint32_t len,
Packit 6c0a39
                                    UNUSED_PARAM(int is_stderr),
Packit 6c0a39
                                    void *userdata)
Packit 6c0a39
{
Packit 6c0a39
    int i = 0;
Packit 6c0a39
    struct event_fd_data_struct *event_fd_data = (struct event_fd_data_struct *)userdata;
Packit 6c0a39
Packit 6c0a39
    if (event_fd_data->channel == NULL) {
Packit 6c0a39
        fprintf(stderr, "Why we're here? Stacked = %d\n", event_fd_data->stacked);
Packit 6c0a39
    }
Packit 6c0a39
Packit 6c0a39
    _ssh_log(SSH_LOG_PROTOCOL, "=== my_channel_data_function", "%d bytes waiting on channel %d:%d for reading. Fd = %d",len, channel->local_channel, channel->remote_channel, *event_fd_data->p_fd);
Packit 6c0a39
    if (len > 0) {
Packit 6c0a39
        i = send(*event_fd_data->p_fd, data, len, 0);
Packit 6c0a39
    }
Packit 6c0a39
    if (i < 0) {
Packit 6c0a39
        _ssh_log(SSH_LOG_WARNING, "=== my_channel_data_function", "Writing to tcp socket %d: %s", *event_fd_data->p_fd, strerror(errno));
Packit 6c0a39
        stack_socket_close(session, event_fd_data);
Packit 6c0a39
    }
Packit 6c0a39
    else {
Packit 6c0a39
        _ssh_log(SSH_LOG_FUNCTIONS, "=== my_channel_data_function", "Sent %d bytes", i);
Packit 6c0a39
    }
Packit 6c0a39
    return i;
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
static int my_fd_data_function(UNUSED_PARAM(socket_t fd),
Packit 6c0a39
                               int revents,
Packit 6c0a39
                               void *userdata)
Packit 6c0a39
{
Packit 6c0a39
    struct event_fd_data_struct *event_fd_data = (struct event_fd_data_struct *)userdata;
Packit 6c0a39
    ssh_channel channel = event_fd_data->channel;
Packit 6c0a39
    ssh_session session;
Packit 6c0a39
    int len, i, wr;
Packit 6c0a39
    char buf[16384];
Packit 6c0a39
    int blocking;
Packit 6c0a39
Packit 6c0a39
    if (channel == NULL) {
Packit 6c0a39
        _ssh_log(SSH_LOG_FUNCTIONS, "=== my_fd_data_function", "channel == NULL!");
Packit 6c0a39
        return 0;
Packit 6c0a39
    }
Packit 6c0a39
Packit 6c0a39
    session = ssh_channel_get_session(channel);
Packit 6c0a39
Packit 6c0a39
    if (ssh_channel_is_closed(channel)) {
Packit 6c0a39
        _ssh_log(SSH_LOG_FUNCTIONS, "=== my_fd_data_function", "channel is closed!");
Packit 6c0a39
        stack_socket_close(session, event_fd_data);
Packit 6c0a39
        return 0;
Packit 6c0a39
    }
Packit 6c0a39
Packit 6c0a39
    if (!(revents & POLLIN)) {
Packit 6c0a39
        if (revents & POLLPRI) {
Packit 6c0a39
            _ssh_log(SSH_LOG_PROTOCOL, "=== my_fd_data_function", "poll revents & POLLPRI");
Packit 6c0a39
        }
Packit 6c0a39
        if (revents & POLLOUT) {
Packit 6c0a39
            _ssh_log(SSH_LOG_PROTOCOL, "=== my_fd_data_function", "poll revents & POLLOUT");
Packit 6c0a39
        }
Packit 6c0a39
        if (revents & POLLHUP) {
Packit 6c0a39
            _ssh_log(SSH_LOG_PROTOCOL, "=== my_fd_data_function", "poll revents & POLLHUP");
Packit 6c0a39
        }
Packit 6c0a39
        if (revents & POLLNVAL) {
Packit 6c0a39
            _ssh_log(SSH_LOG_PROTOCOL, "=== my_fd_data_function", "poll revents & POLLNVAL");
Packit 6c0a39
        }
Packit 6c0a39
        if (revents & POLLERR) {
Packit 6c0a39
            _ssh_log(SSH_LOG_PROTOCOL, "=== my_fd_data_function", "poll revents & POLLERR");
Packit 6c0a39
        }
Packit 6c0a39
        return 0;
Packit 6c0a39
    }
Packit 6c0a39
Packit 6c0a39
    blocking = ssh_is_blocking(session);
Packit 6c0a39
    ssh_set_blocking(session, 0);
Packit 6c0a39
Packit 6c0a39
    _ssh_log(SSH_LOG_FUNCTIONS, "=== my_fd_data_function", "Trying to read from tcp socket fd = %d... (Channel %d:%d state=%d)",
Packit 6c0a39
                        *event_fd_data->p_fd, channel->local_channel, channel->remote_channel, channel->state);
Packit 6c0a39
#ifdef _WIN32
Packit 6c0a39
    struct sockaddr from;
Packit 6c0a39
    int fromlen = sizeof(from);
Packit 6c0a39
    len = recvfrom(*event_fd_data->p_fd, buf, sizeof(buf), 0, &from, &fromlen);
Packit 6c0a39
#else
Packit 6c0a39
    len = recv(*event_fd_data->p_fd, buf, sizeof(buf), 0);
Packit 6c0a39
#endif // _WIN32
Packit 6c0a39
    if (len < 0) {
Packit 6c0a39
        _ssh_log(SSH_LOG_WARNING, "=== my_fd_data_function", "Reading from tcp socket: %s", strerror(errno));
Packit 6c0a39
Packit 6c0a39
        ssh_channel_send_eof(channel);
Packit 6c0a39
    }
Packit 6c0a39
    else if (len > 0) {
Packit 6c0a39
        if (ssh_channel_is_open(channel)) {
Packit 6c0a39
            wr = 0;
Packit 6c0a39
            do {
Packit 6c0a39
                i = ssh_channel_write(channel, buf, len);
Packit 6c0a39
                if (i < 0) {
Packit 6c0a39
                    _ssh_log(SSH_LOG_WARNING, "=== my_fd_data_function", "Error writing on the direct-tcpip channel: %d", i);
Packit 6c0a39
                    len = wr;
Packit 6c0a39
                    break;
Packit 6c0a39
                }
Packit 6c0a39
                wr += i;
Packit 6c0a39
                _ssh_log(SSH_LOG_FUNCTIONS, "=== my_fd_data_function", "channel_write (%d from %d)", wr, len);
Packit 6c0a39
            } while (i > 0 && wr < len);
Packit 6c0a39
        }
Packit 6c0a39
        else {
Packit 6c0a39
            _ssh_log(SSH_LOG_WARNING, "=== my_fd_data_function", "Can't write on closed channel!");
Packit 6c0a39
        }
Packit 6c0a39
    }
Packit 6c0a39
    else {
Packit 6c0a39
        _ssh_log(SSH_LOG_PROTOCOL, "=== my_fd_data_function", "The destination host has disconnected!");
Packit 6c0a39
Packit 6c0a39
        ssh_channel_close(channel);
Packit 6c0a39
#ifdef _WIN32
Packit 6c0a39
        shutdown(*event_fd_data->p_fd, SD_RECEIVE);
Packit 6c0a39
#else
Packit 6c0a39
        shutdown(*event_fd_data->p_fd, SHUT_RD);
Packit 6c0a39
#endif // _WIN32
Packit 6c0a39
    }
Packit 6c0a39
    ssh_set_blocking(session, blocking);
Packit 6c0a39
Packit 6c0a39
    return len;
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
static int open_tcp_socket(ssh_message msg) {
Packit 6c0a39
    struct sockaddr_in sin;
Packit 6c0a39
    int forwardsock = -1;
Packit 6c0a39
    struct hostent *host;
Packit 6c0a39
    const char *dest_hostname;
Packit 6c0a39
    int dest_port;
Packit 6c0a39
Packit 6c0a39
    forwardsock = socket(AF_INET, SOCK_STREAM, 0);
Packit 6c0a39
    if (forwardsock < 0) {
Packit 6c0a39
        _ssh_log(SSH_LOG_WARNING, "=== open_tcp_socket", "ERROR opening socket: %s", strerror(errno));
Packit 6c0a39
        return -1;
Packit 6c0a39
    }
Packit 6c0a39
Packit 6c0a39
    dest_hostname = ssh_message_channel_request_open_destination(msg);
Packit 6c0a39
    dest_port = ssh_message_channel_request_open_destination_port(msg);
Packit 6c0a39
Packit 6c0a39
    _ssh_log(SSH_LOG_PROTOCOL, "=== open_tcp_socket", "Connecting to %s on port %d", dest_hostname, dest_port);
Packit 6c0a39
Packit 6c0a39
    host = gethostbyname(dest_hostname);
Packit 6c0a39
    if (host == NULL) {
Packit 6c0a39
        close(forwardsock);
Packit 6c0a39
        _ssh_log(SSH_LOG_WARNING, "=== open_tcp_socket", "ERROR, no such host: %s", dest_hostname);
Packit 6c0a39
        return -1;
Packit 6c0a39
    }
Packit 6c0a39
Packit 6c0a39
    memset((char *)&sin, '\0', sizeof(sin));
Packit 6c0a39
    sin.sin_family = AF_INET;
Packit 6c0a39
    memcpy((char *)&sin.sin_addr.s_addr, (char *)host->h_addr, host->h_length);
Packit 6c0a39
    sin.sin_port = htons(dest_port);
Packit 6c0a39
Packit 6c0a39
    if (connect(forwardsock, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
Packit 6c0a39
        close(forwardsock);
Packit 6c0a39
        _ssh_log(SSH_LOG_WARNING, "=== open_tcp_socket", "ERROR connecting: %s", strerror(errno));
Packit 6c0a39
        return -1;
Packit 6c0a39
    }
Packit 6c0a39
Packit 6c0a39
    sockets_cnt++;
Packit 6c0a39
    _ssh_log(SSH_LOG_FUNCTIONS, "=== open_tcp_socket", "Connected. sockets_cnt = %d", sockets_cnt);
Packit 6c0a39
    return forwardsock;
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
static int message_callback(ssh_session session, ssh_message message, void *userdata) {
Packit 6c0a39
    ssh_channel channel;
Packit 6c0a39
    int socket_fd, *pFd;
Packit 6c0a39
    struct ssh_channel_callbacks_struct *cb_chan;
Packit 6c0a39
    struct event_fd_data_struct *event_fd_data;
Packit 6c0a39
    (void)session;
Packit 6c0a39
    (void)message;
Packit 6c0a39
    (void)userdata;
Packit 6c0a39
Packit 6c0a39
    _ssh_log(SSH_LOG_PACKET, "=== message_callback", "Message type: %d", ssh_message_type(message));
Packit 6c0a39
    _ssh_log(SSH_LOG_PACKET, "=== message_callback", "Message Subtype: %d", ssh_message_subtype(message));
Packit 6c0a39
    if (ssh_message_type(message) == SSH_REQUEST_CHANNEL_OPEN) {
Packit 6c0a39
        _ssh_log(SSH_LOG_PROTOCOL, "=== message_callback", "channel_request_open");
Packit 6c0a39
Packit 6c0a39
        if (ssh_message_subtype(message) == SSH_CHANNEL_DIRECT_TCPIP) {
Packit 6c0a39
            channel = ssh_message_channel_request_open_reply_accept(message);
Packit 6c0a39
Packit 6c0a39
            if (channel == NULL) {
Packit 6c0a39
                _ssh_log(SSH_LOG_WARNING, "=== message_callback", "Accepting direct-tcpip channel failed!");
Packit 6c0a39
                return 1;
Packit 6c0a39
            }
Packit 6c0a39
            else {
Packit 6c0a39
                _ssh_log(SSH_LOG_PROTOCOL, "=== message_callback", "Connected to channel!");
Packit 6c0a39
Packit 6c0a39
                socket_fd = open_tcp_socket(message);
Packit 6c0a39
                if (-1 == socket_fd) {
Packit 6c0a39
                    return 1;
Packit 6c0a39
                }
Packit 6c0a39
Packit 6c0a39
                pFd = malloc(sizeof *pFd);
Packit 6c0a39
                cb_chan = malloc(sizeof *cb_chan);
Packit 6c0a39
                event_fd_data = malloc(sizeof *event_fd_data);
Packit 6c0a39
Packit 6c0a39
                (*pFd) = socket_fd;
Packit 6c0a39
                event_fd_data->channel = channel;
Packit 6c0a39
                event_fd_data->p_fd = pFd;
Packit 6c0a39
                event_fd_data->stacked = 0;
Packit 6c0a39
                event_fd_data->cb_chan = cb_chan;
Packit 6c0a39
Packit 6c0a39
                cb_chan->userdata = event_fd_data;
Packit 6c0a39
                cb_chan->channel_eof_function = my_channel_eof_function;
Packit 6c0a39
                cb_chan->channel_close_function = my_channel_close_function;
Packit 6c0a39
                cb_chan->channel_data_function = my_channel_data_function;
Packit 6c0a39
                cb_chan->channel_exit_status_function = my_channel_exit_status_function;
Packit 6c0a39
Packit 6c0a39
                ssh_callbacks_init(cb_chan);
Packit 6c0a39
                ssh_set_channel_callbacks(channel, cb_chan);
Packit 6c0a39
Packit 6c0a39
                ssh_event_add_fd(mainloop, (socket_t)*pFd, POLLIN, my_fd_data_function, event_fd_data);
Packit 6c0a39
Packit 6c0a39
                return 0;
Packit 6c0a39
            }
Packit 6c0a39
        }
Packit 6c0a39
    }
Packit 6c0a39
    return 1;
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
#ifdef HAVE_ARGP_H
Packit 6c0a39
const char *argp_program_version = "libssh server example "
Packit 6c0a39
SSH_STRINGIFY(LIBSSH_VERSION);
Packit 6c0a39
const char *argp_program_bug_address = "<libssh@libssh.org>";
Packit 6c0a39
Packit 6c0a39
/* Program documentation. */
Packit 6c0a39
static char doc[] = "libssh -- a Secure Shell protocol implementation";
Packit 6c0a39
Packit 6c0a39
/* A description of the arguments we accept. */
Packit 6c0a39
static char args_doc[] = "BINDADDR";
Packit 6c0a39
Packit 6c0a39
/* The options we understand. */
Packit 6c0a39
static struct argp_option options[] = {
Packit 6c0a39
    {
Packit 6c0a39
        .name  = "port",
Packit 6c0a39
        .key   = 'p',
Packit 6c0a39
        .arg   = "PORT",
Packit 6c0a39
        .flags = 0,
Packit 6c0a39
        .doc   = "Set the port to bind.",
Packit 6c0a39
        .group = 0
Packit 6c0a39
    },
Packit 6c0a39
    {
Packit 6c0a39
        .name  = "hostkey",
Packit 6c0a39
        .key   = 'k',
Packit 6c0a39
        .arg   = "FILE",
Packit 6c0a39
        .flags = 0,
Packit 6c0a39
        .doc   = "Set the host key.",
Packit 6c0a39
        .group = 0
Packit 6c0a39
    },
Packit 6c0a39
    {
Packit 6c0a39
        .name  = "dsakey",
Packit 6c0a39
        .key   = 'd',
Packit 6c0a39
        .arg   = "FILE",
Packit 6c0a39
        .flags = 0,
Packit 6c0a39
        .doc   = "Set the dsa key.",
Packit 6c0a39
        .group = 0
Packit 6c0a39
    },
Packit 6c0a39
    {
Packit 6c0a39
        .name  = "rsakey",
Packit 6c0a39
        .key   = 'r',
Packit 6c0a39
        .arg   = "FILE",
Packit 6c0a39
        .flags = 0,
Packit 6c0a39
        .doc   = "Set the rsa key.",
Packit 6c0a39
        .group = 0
Packit 6c0a39
    },
Packit 6c0a39
    {
Packit 6c0a39
        .name  = "verbose",
Packit 6c0a39
        .key   = 'v',
Packit 6c0a39
        .arg   = NULL,
Packit 6c0a39
        .flags = 0,
Packit 6c0a39
        .doc   = "Get verbose output.",
Packit 6c0a39
        .group = 0
Packit 6c0a39
    },
Packit 6c0a39
    {NULL, 0, NULL, 0, NULL, 0}
Packit 6c0a39
};
Packit 6c0a39
Packit 6c0a39
/* Parse a single option. */
Packit 6c0a39
static error_t parse_opt (int key, char *arg, struct argp_state *state) {
Packit 6c0a39
    /* Get the input argument from argp_parse, which we
Packit 6c0a39
     * know is a pointer to our arguments structure.
Packit 6c0a39
     */
Packit 6c0a39
    ssh_bind sshbind = state->input;
Packit 6c0a39
Packit 6c0a39
    switch (key) {
Packit 6c0a39
        case 'p':
Packit 6c0a39
            ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDPORT_STR, arg);
Packit 6c0a39
            break;
Packit 6c0a39
        case 'd':
Packit 6c0a39
            ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_DSAKEY, arg);
Packit 6c0a39
            break;
Packit 6c0a39
        case 'k':
Packit 6c0a39
            ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, arg);
Packit 6c0a39
            break;
Packit 6c0a39
        case 'r':
Packit 6c0a39
            ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_RSAKEY, arg);
Packit 6c0a39
            break;
Packit 6c0a39
        case 'v':
Packit 6c0a39
            ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_LOG_VERBOSITY_STR, "1");
Packit 6c0a39
            break;
Packit 6c0a39
        case ARGP_KEY_ARG:
Packit 6c0a39
            if (state->arg_num >= 1) {
Packit 6c0a39
                /* Too many arguments. */
Packit 6c0a39
                argp_usage (state);
Packit 6c0a39
            }
Packit 6c0a39
            ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDADDR, arg);
Packit 6c0a39
            break;
Packit 6c0a39
        case ARGP_KEY_END:
Packit 6c0a39
            if (state->arg_num < 1) {
Packit 6c0a39
                /* Not enough arguments. */
Packit 6c0a39
                argp_usage (state);
Packit 6c0a39
            }
Packit 6c0a39
            break;
Packit 6c0a39
        default:
Packit 6c0a39
            return ARGP_ERR_UNKNOWN;
Packit 6c0a39
    }
Packit 6c0a39
Packit 6c0a39
    return 0;
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
/* Our argp parser. */
Packit 6c0a39
static struct argp argp = {options, parse_opt, args_doc, doc, NULL, NULL, NULL};
Packit 6c0a39
#endif /* HAVE_ARGP_H */
Packit 6c0a39
Packit 6c0a39
int main(int argc, char **argv){
Packit 6c0a39
    ssh_session session;
Packit 6c0a39
    ssh_bind sshbind;
Packit 6c0a39
    struct ssh_server_callbacks_struct cb = {
Packit 6c0a39
        .userdata = NULL,
Packit 6c0a39
        .auth_password_function = auth_password,
Packit 6c0a39
        .auth_gssapi_mic_function = auth_gssapi_mic,
Packit 6c0a39
        .channel_open_request_session_function = new_session_channel,
Packit 6c0a39
        .service_request_function = service_request
Packit 6c0a39
    };
Packit 6c0a39
    struct ssh_callbacks_struct cb_gen = {
Packit 6c0a39
        .userdata = NULL,
Packit 6c0a39
        .global_request_function = global_request
Packit 6c0a39
    };
Packit 6c0a39
Packit 6c0a39
    int ret = 1;
Packit 6c0a39
Packit 6c0a39
    sshbind = ssh_bind_new();
Packit 6c0a39
    session = ssh_new();
Packit 6c0a39
    mainloop = ssh_event_new();
Packit 6c0a39
Packit 6c0a39
    ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_DSAKEY, KEYS_FOLDER "ssh_host_dsa_key");
Packit 6c0a39
    ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_RSAKEY, KEYS_FOLDER "ssh_host_rsa_key");
Packit 6c0a39
Packit 6c0a39
#ifdef HAVE_ARGP_H
Packit 6c0a39
    /*
Packit 6c0a39
     * Parse our arguments; every option seen by parse_opt will
Packit 6c0a39
     * be reflected in arguments.
Packit 6c0a39
     */
Packit 6c0a39
    argp_parse (&argp, argc, argv, 0, 0, sshbind);
Packit 6c0a39
#else
Packit 6c0a39
    (void)argc;
Packit 6c0a39
    (void)argv;
Packit 6c0a39
#endif
Packit 6c0a39
Packit 6c0a39
    if (ssh_bind_listen(sshbind) < 0) {
Packit 6c0a39
        printf("Error listening to socket: %s\n", ssh_get_error(sshbind));
Packit 6c0a39
        return 1;
Packit 6c0a39
    }
Packit 6c0a39
Packit 6c0a39
    if (ssh_bind_accept(sshbind, session) == SSH_ERROR) {
Packit 6c0a39
        printf("error accepting a connection : %s\n", ssh_get_error(sshbind));
Packit 6c0a39
        ret = 1;
Packit 6c0a39
        goto shutdown;
Packit 6c0a39
    }
Packit 6c0a39
Packit 6c0a39
    ssh_callbacks_init(&cb;;
Packit 6c0a39
    ssh_callbacks_init(&cb_gen);
Packit 6c0a39
    ssh_set_server_callbacks(session, &cb;;
Packit 6c0a39
    ssh_set_callbacks(session, &cb_gen);
Packit 6c0a39
    ssh_set_message_callback(session, message_callback, (void *)NULL);
Packit 6c0a39
Packit 6c0a39
    if (ssh_handle_key_exchange(session)) {
Packit 6c0a39
        printf("ssh_handle_key_exchange: %s\n", ssh_get_error(session));
Packit 6c0a39
        ret = 1;
Packit 6c0a39
        goto shutdown;
Packit 6c0a39
    }
Packit 6c0a39
    ssh_set_auth_methods(session, SSH_AUTH_METHOD_PASSWORD | SSH_AUTH_METHOD_GSSAPI_MIC);
Packit 6c0a39
    ssh_event_add_session(mainloop, session);
Packit 6c0a39
Packit 6c0a39
    while (!authenticated) {
Packit 6c0a39
        if (error_set) {
Packit 6c0a39
            break;
Packit 6c0a39
        }
Packit 6c0a39
        if (ssh_event_dopoll(mainloop, -1) == SSH_ERROR) {
Packit 6c0a39
            printf("Error : %s\n", ssh_get_error(session));
Packit 6c0a39
            ret = 1;
Packit 6c0a39
            goto shutdown;
Packit 6c0a39
        }
Packit 6c0a39
    }
Packit 6c0a39
    if (error_set) {
Packit 6c0a39
        printf("Error, exiting loop\n");
Packit 6c0a39
    } else {
Packit 6c0a39
        printf("Authenticated and got a channel\n");
Packit 6c0a39
Packit 6c0a39
        while (!error_set) {
Packit 6c0a39
            if (ssh_event_dopoll(mainloop, 100) == SSH_ERROR) {
Packit 6c0a39
                printf("Error : %s\n", ssh_get_error(session));
Packit 6c0a39
                ret = 1;
Packit 6c0a39
                goto shutdown;
Packit 6c0a39
            }
Packit 6c0a39
            do_cleanup(&cleanup_stack);
Packit 6c0a39
        }
Packit 6c0a39
    }
Packit 6c0a39
Packit 6c0a39
shutdown:
Packit 6c0a39
    ssh_disconnect(session);
Packit 6c0a39
    ssh_bind_free(sshbind);
Packit 6c0a39
    ssh_finalize();
Packit 6c0a39
    return ret;
Packit 6c0a39
}