Blame examples/proxy.c

Packit 6c0a39
/* This is a sample implementation of a libssh based SSH proxy */
Packit 6c0a39
/*
Packit 6c0a39
Copyright 2003-2013 Aris Adamantiadis
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
#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
Packit 6c0a39
#ifdef HAVE_ARGP_H
Packit 6c0a39
#include <argp.h>
Packit 6c0a39
#endif
Packit 6c0a39
#include <stdlib.h>
Packit 6c0a39
#include <string.h>
Packit 6c0a39
#include <stdio.h>
Packit 6c0a39
Packit 6c0a39
#define USER "myuser"
Packit 6c0a39
#define PASSWORD "mypassword"
Packit 6c0a39
Packit 6c0a39
static int authenticated=0;
Packit 6c0a39
static int tries = 0;
Packit 6c0a39
static int error = 0;
Packit 6c0a39
static ssh_channel chan=NULL;
Packit 6c0a39
static char *username;
Packit 6c0a39
static ssh_gssapi_creds client_creds = NULL;
Packit 6c0a39
Packit 6c0a39
static int auth_password(ssh_session session, const char *user,
Packit 6c0a39
        const char *password, void *userdata){
Packit 6c0a39
Packit 6c0a39
    (void)userdata;
Packit 6c0a39
Packit 6c0a39
    printf("Authenticating user %s pwd %s\n",user, password);
Packit 6c0a39
    if(strcmp(user,USER) == 0 && strcmp(password, PASSWORD) == 0){
Packit 6c0a39
        authenticated = 1;
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 = 1;
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
    (void)userdata;
Packit 6c0a39
    client_creds = ssh_gssapi_get_creds(session);
Packit 6c0a39
    printf("Authenticating user %s with gssapi principal %s\n",user, principal);
Packit 6c0a39
    if (client_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 = 1;
Packit 6c0a39
    username = strdup(principal);
Packit 6c0a39
    return SSH_AUTH_SUCCESS;
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
static int pty_request(ssh_session session, ssh_channel channel, const char *term,
Packit 6c0a39
        int x,int y, int px, int py, void *userdata){
Packit 6c0a39
    (void) session;
Packit 6c0a39
    (void) channel;
Packit 6c0a39
    (void) term;
Packit 6c0a39
    (void) x;
Packit 6c0a39
    (void) y;
Packit 6c0a39
    (void) px;
Packit 6c0a39
    (void) py;
Packit 6c0a39
    (void) userdata;
Packit 6c0a39
    printf("Allocated terminal\n");
Packit 6c0a39
    return 0;
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
static int shell_request(ssh_session session, ssh_channel channel, void *userdata){
Packit 6c0a39
    (void)session;
Packit 6c0a39
    (void)channel;
Packit 6c0a39
    (void)userdata;
Packit 6c0a39
    printf("Allocated shell\n");
Packit 6c0a39
    return 0;
Packit 6c0a39
}
Packit 6c0a39
struct ssh_channel_callbacks_struct channel_cb = {
Packit 6c0a39
    .channel_pty_request_function = pty_request,
Packit 6c0a39
    .channel_shell_request_function = shell_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
    if(chan != NULL)
Packit 6c0a39
        return NULL;
Packit 6c0a39
    printf("Allocated session channel\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
}
Packit 6c0a39
Packit 6c0a39
Packit 6c0a39
#ifdef HAVE_ARGP_H
Packit 6c0a39
const char *argp_program_version = "libssh proxy 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, "3");
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
    ssh_event mainloop;
Packit 6c0a39
    ssh_session client_session;
Packit 6c0a39
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
    };
Packit 6c0a39
Packit 6c0a39
    char buf[2048];
Packit 6c0a39
    char host[128]="";
Packit 6c0a39
    char *ptr;
Packit 6c0a39
    int i,r, rc;
Packit 6c0a39
Packit 6c0a39
    sshbind=ssh_bind_new();
Packit 6c0a39
    session=ssh_new();
Packit 6c0a39
Packit 6c0a39
    ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_RSAKEY, "sshd_rsa");
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
    r=ssh_bind_accept(sshbind,session);
Packit 6c0a39
    if(r==SSH_ERROR){
Packit 6c0a39
        printf("error accepting a connection : %s\n",ssh_get_error(sshbind));
Packit 6c0a39
        return 1;
Packit 6c0a39
    }
Packit 6c0a39
    ssh_callbacks_init(&cb;;
Packit 6c0a39
    ssh_set_server_callbacks(session, &cb;;
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
        return 1;
Packit 6c0a39
    }
Packit 6c0a39
    ssh_set_auth_methods(session,SSH_AUTH_METHOD_PASSWORD | SSH_AUTH_METHOD_GSSAPI_MIC);
Packit 6c0a39
    mainloop = ssh_event_new();
Packit 6c0a39
    ssh_event_add_session(mainloop, session);
Packit 6c0a39
Packit 6c0a39
    while (!(authenticated && chan != NULL)){
Packit 6c0a39
        if(error)
Packit 6c0a39
            break;
Packit 6c0a39
        r = ssh_event_dopoll(mainloop, -1);
Packit 6c0a39
        if (r == SSH_ERROR){
Packit 6c0a39
            printf("Error : %s\n",ssh_get_error(session));
Packit 6c0a39
            ssh_disconnect(session);
Packit 6c0a39
            return 1;
Packit 6c0a39
        }
Packit 6c0a39
    }
Packit 6c0a39
    if(error){
Packit 6c0a39
        printf("Error, exiting loop\n");
Packit 6c0a39
        return 1;
Packit 6c0a39
    } else
Packit 6c0a39
        printf("Authenticated and got a channel\n");
Packit 6c0a39
    if (!client_creds){
Packit 6c0a39
        snprintf(buf,sizeof(buf), "Sorry, but you do not have forwardable tickets. Try again with -K\r\n");
Packit 6c0a39
        ssh_channel_write(chan,buf,strlen(buf));
Packit 6c0a39
        printf("%s",buf);
Packit 6c0a39
        ssh_disconnect(session);
Packit 6c0a39
        return 1;
Packit 6c0a39
    }
Packit 6c0a39
    snprintf(buf,sizeof(buf), "Hello %s, welcome to the Sample SSH proxy.\r\nPlease select your destination: ", username);
Packit 6c0a39
    ssh_channel_write(chan, buf, strlen(buf));
Packit 6c0a39
    do{
Packit 6c0a39
        i=ssh_channel_read(chan,buf, 2048, 0);
Packit 6c0a39
        if(i>0) {
Packit 6c0a39
            ssh_channel_write(chan, buf, i);
Packit 6c0a39
            if(strlen(host) + i < sizeof(host)){
Packit 6c0a39
                strncat(host, buf, i);
Packit 6c0a39
            }
Packit 6c0a39
            if (strchr(host, '\x0d')) {
Packit 6c0a39
                *strchr(host, '\x0d')='\0';
Packit 6c0a39
                ssh_channel_write(chan, "\n", 1);
Packit 6c0a39
                break;
Packit 6c0a39
            }
Packit 6c0a39
        } else {
Packit 6c0a39
            printf ("Error: %s\n", ssh_get_error(session) );
Packit 6c0a39
            return 1;
Packit 6c0a39
        }
Packit 6c0a39
    } while (i>0);
Packit 6c0a39
    snprintf(buf,sizeof(buf),"Trying to connect to \"%s\"\r\n", host);
Packit 6c0a39
    ssh_channel_write(chan, buf, strlen(buf));
Packit 6c0a39
    printf("%s",buf);
Packit 6c0a39
Packit 6c0a39
    client_session = ssh_new();
Packit 6c0a39
Packit 6c0a39
    /* ssh servers expect username without realm */
Packit 6c0a39
    ptr = strchr(username,'@');
Packit 6c0a39
    if(ptr)
Packit 6c0a39
        *ptr= '\0';
Packit 6c0a39
    ssh_options_set(client_session, SSH_OPTIONS_HOST, host);
Packit 6c0a39
    ssh_options_set(client_session, SSH_OPTIONS_USER, username);
Packit 6c0a39
    ssh_gssapi_set_creds(client_session, client_creds);
Packit 6c0a39
    rc = ssh_connect(client_session);
Packit 6c0a39
    if (rc != SSH_OK){
Packit 6c0a39
        printf("Error connecting to %s: %s", host, ssh_get_error(client_session));
Packit 6c0a39
        return 1;
Packit 6c0a39
    }
Packit 6c0a39
    rc = ssh_userauth_none(client_session, NULL);
Packit 6c0a39
    if(rc == SSH_AUTH_SUCCESS){
Packit 6c0a39
        printf("Authenticated using method none\n");
Packit 6c0a39
    } else {
Packit 6c0a39
        rc = ssh_userauth_gssapi(client_session);
Packit 6c0a39
        if(rc != SSH_AUTH_SUCCESS){
Packit 6c0a39
            printf("GSSAPI Authentication failed: %s\n",ssh_get_error(client_session));
Packit 6c0a39
            return 1;
Packit 6c0a39
        }
Packit 6c0a39
    }
Packit 6c0a39
    snprintf(buf,sizeof(buf), "Authentication success\r\n");
Packit 6c0a39
    printf("%s",buf);
Packit 6c0a39
    ssh_channel_write(chan,buf,strlen(buf));
Packit 6c0a39
    ssh_disconnect(client_session);
Packit 6c0a39
    ssh_disconnect(session);
Packit 6c0a39
    ssh_bind_free(sshbind);
Packit 6c0a39
    ssh_finalize();
Packit 6c0a39
    return 0;
Packit 6c0a39
}
Packit 6c0a39