Blame examples/sshd_direct-tcpip.c

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