Blame examples/ssh_client.c

Packit Service 31306d
/* ssh_client.c */
Packit Service 31306d
Packit Service 31306d
/*
Packit Service 31306d
 * Copyright 2003-2015 Aris Adamantiadis
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
#include "config.h"
Packit Service 31306d
#include <stdio.h>
Packit Service 31306d
#include <stdlib.h>
Packit Service 31306d
#include <string.h>
Packit Service 31306d
Packit Service 31306d
#include <sys/select.h>
Packit Service 31306d
#include <sys/time.h>
Packit Service 31306d
Packit Service 31306d
#ifdef HAVE_TERMIOS_H
Packit Service 31306d
#include <termios.h>
Packit Service 31306d
#endif
Packit Service 31306d
#ifdef HAVE_UNISTD_H
Packit Service 31306d
#include <unistd.h>
Packit Service 31306d
#endif
Packit Service 31306d
#ifdef HAVE_PTY_H
Packit Service 31306d
#include <pty.h>
Packit Service 31306d
#endif
Packit Service 31306d
Packit Service 31306d
#include <sys/ioctl.h>
Packit Service 31306d
#include <signal.h>
Packit Service 31306d
#include <errno.h>
Packit Service 31306d
#include <fcntl.h>
Packit Service 31306d
Packit Service 31306d
#include <libssh/callbacks.h>
Packit Service 31306d
#include <libssh/libssh.h>
Packit Service 31306d
#include <libssh/sftp.h>
Packit Service 31306d
Packit Service 31306d
Packit Service 31306d
#include "examples_common.h"
Packit Service 31306d
#define MAXCMD 10
Packit Service 31306d
Packit Service 31306d
static char *host;
Packit Service 31306d
static char *user;
Packit Service 31306d
static char *cmds[MAXCMD];
Packit Service 31306d
static struct termios terminal;
Packit Service 31306d
Packit Service 31306d
static char *pcap_file = NULL;
Packit Service 31306d
Packit Service 31306d
static char *proxycommand;
Packit Service 31306d
Packit Service 31306d
static int auth_callback(const char *prompt,
Packit Service 31306d
                         char *buf,
Packit Service 31306d
                         size_t len,
Packit Service 31306d
                         int echo,
Packit Service 31306d
                         int verify,
Packit Service 31306d
                         void *userdata)
Packit Service 31306d
{
Packit Service 31306d
    (void) verify;
Packit Service 31306d
    (void) userdata;
Packit Service 31306d
Packit Service 31306d
    return ssh_getpass(prompt, buf, len, echo, verify);
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
struct ssh_callbacks_struct cb = {
Packit Service 31306d
    .auth_function = auth_callback,
Packit Service 31306d
    .userdata = NULL,
Packit Service 31306d
};
Packit Service 31306d
Packit Service 31306d
static void add_cmd(char *cmd)
Packit Service 31306d
{
Packit Service 31306d
    int n;
Packit Service 31306d
Packit Service 31306d
    for (n = 0; (n < MAXCMD) && cmds[n] != NULL; n++);
Packit Service 31306d
Packit Service 31306d
    if (n == MAXCMD) {
Packit Service 31306d
        return;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    cmds[n] = strdup(cmd);
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static void usage(void)
Packit Service 31306d
{
Packit Service 31306d
    fprintf(stderr,
Packit Service 31306d
            "Usage : ssh [options] [login@]hostname\n"
Packit Service 31306d
            "sample client - libssh-%s\n"
Packit Service 31306d
            "Options :\n"
Packit Service 31306d
            "  -l user : log in as user\n"
Packit Service 31306d
            "  -p port : connect to port\n"
Packit Service 31306d
            "  -d : use DSS to verify host public key\n"
Packit Service 31306d
            "  -r : use RSA to verify host public key\n"
Packit Service 31306d
#ifdef WITH_PCAP
Packit Service 31306d
            "  -P file : create a pcap debugging file\n"
Packit Service 31306d
#endif
Packit Service 31306d
#ifndef _WIN32
Packit Service 31306d
            "  -T proxycommand : command to execute as a socket proxy\n"
Packit Service 31306d
#endif
Packit Service 31306d
            "\n",
Packit Service 31306d
            ssh_version(0));
Packit Service 31306d
Packit Service 31306d
    exit(0);
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static int opts(int argc, char **argv)
Packit Service 31306d
{
Packit Service 31306d
    int i;
Packit Service 31306d
Packit Service 31306d
    while((i = getopt(argc,argv,"T:P:")) != -1) {
Packit Service 31306d
        switch(i){
Packit Service 31306d
        case 'P':
Packit Service 31306d
            pcap_file = optarg;
Packit Service 31306d
            break;
Packit Service 31306d
#ifndef _WIN32
Packit Service 31306d
        case 'T':
Packit Service 31306d
            proxycommand = optarg;
Packit Service 31306d
            break;
Packit Service 31306d
#endif
Packit Service 31306d
        default:
Packit Service 31306d
            fprintf(stderr, "Unknown option %c\n", optopt);
Packit Service 31306d
            usage();
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
    if (optind < argc) {
Packit Service 31306d
        host = argv[optind++];
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    while(optind < argc) {
Packit Service 31306d
        add_cmd(argv[optind++]);
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (host == NULL) {
Packit Service 31306d
        usage();
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    return 0;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
#ifndef HAVE_CFMAKERAW
Packit Service 31306d
static void cfmakeraw(struct termios *termios_p)
Packit Service 31306d
{
Packit Service 31306d
    termios_p->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
Packit Service 31306d
    termios_p->c_oflag &= ~OPOST;
Packit Service 31306d
    termios_p->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
Packit Service 31306d
    termios_p->c_cflag &= ~(CSIZE|PARENB);
Packit Service 31306d
    termios_p->c_cflag |= CS8;
Packit Service 31306d
}
Packit Service 31306d
#endif
Packit Service 31306d
Packit Service 31306d
Packit Service 31306d
static void do_cleanup(int i)
Packit Service 31306d
{
Packit Service 31306d
  /* unused variable */
Packit Service 31306d
  (void) i;
Packit Service 31306d
Packit Service 31306d
  tcsetattr(0, TCSANOW, &terminal);
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static void do_exit(int i)
Packit Service 31306d
{
Packit Service 31306d
    /* unused variable */
Packit Service 31306d
    (void) i;
Packit Service 31306d
Packit Service 31306d
    do_cleanup(0);
Packit Service 31306d
    exit(0);
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static ssh_channel chan;
Packit Service 31306d
static int signal_delayed = 0;
Packit Service 31306d
Packit Service 31306d
static void sigwindowchanged(int i)
Packit Service 31306d
{
Packit Service 31306d
    (void) i;
Packit Service 31306d
    signal_delayed = 1;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static void setsignal(void)
Packit Service 31306d
{
Packit Service 31306d
    signal(SIGWINCH, sigwindowchanged);
Packit Service 31306d
    signal_delayed = 0;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static void sizechanged(void)
Packit Service 31306d
{
Packit Service 31306d
    struct winsize win = {
Packit Service 31306d
        .ws_row = 0,
Packit Service 31306d
    };
Packit Service 31306d
Packit Service 31306d
    ioctl(1, TIOCGWINSZ, &win);
Packit Service 31306d
    ssh_channel_change_pty_size(chan,win.ws_col, win.ws_row);
Packit Service 31306d
    setsignal();
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static void select_loop(ssh_session session,ssh_channel channel)
Packit Service 31306d
{
Packit Service 31306d
    ssh_connector connector_in, connector_out, connector_err;
Packit Service 31306d
    int rc;
Packit Service 31306d
Packit Service 31306d
    ssh_event event = ssh_event_new();
Packit Service 31306d
Packit Service 31306d
    /* stdin */
Packit Service 31306d
    connector_in = ssh_connector_new(session);
Packit Service 31306d
    ssh_connector_set_out_channel(connector_in, channel, SSH_CONNECTOR_STDINOUT);
Packit Service 31306d
    ssh_connector_set_in_fd(connector_in, 0);
Packit Service 31306d
    ssh_event_add_connector(event, connector_in);
Packit Service 31306d
Packit Service 31306d
    /* stdout */
Packit Service 31306d
    connector_out = ssh_connector_new(session);
Packit Service 31306d
    ssh_connector_set_out_fd(connector_out, 1);
Packit Service 31306d
    ssh_connector_set_in_channel(connector_out, channel, SSH_CONNECTOR_STDINOUT);
Packit Service 31306d
    ssh_event_add_connector(event, connector_out);
Packit Service 31306d
Packit Service 31306d
    /* stderr */
Packit Service 31306d
    connector_err = ssh_connector_new(session);
Packit Service 31306d
    ssh_connector_set_out_fd(connector_err, 2);
Packit Service 31306d
    ssh_connector_set_in_channel(connector_err, channel, SSH_CONNECTOR_STDERR);
Packit Service 31306d
    ssh_event_add_connector(event, connector_err);
Packit Service 31306d
Packit Service 31306d
    while (ssh_channel_is_open(channel)) {
Packit Service 31306d
        if (signal_delayed) {
Packit Service 31306d
            sizechanged();
Packit Service 31306d
        }
Packit Service 31306d
        rc = ssh_event_dopoll(event, 60000);
Packit Service 31306d
        if (rc == SSH_ERROR) {
Packit Service 31306d
            fprintf(stderr, "Error in ssh_event_dopoll()\n");
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
    ssh_event_remove_connector(event, connector_in);
Packit Service 31306d
    ssh_event_remove_connector(event, connector_out);
Packit Service 31306d
    ssh_event_remove_connector(event, connector_err);
Packit Service 31306d
Packit Service 31306d
    ssh_connector_free(connector_in);
Packit Service 31306d
    ssh_connector_free(connector_out);
Packit Service 31306d
    ssh_connector_free(connector_err);
Packit Service 31306d
Packit Service 31306d
    ssh_event_free(event);
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static void shell(ssh_session session)
Packit Service 31306d
{
Packit Service 31306d
    ssh_channel channel;
Packit Service 31306d
    struct termios terminal_local;
Packit Service 31306d
    int interactive=isatty(0);
Packit Service 31306d
Packit Service 31306d
    channel = ssh_channel_new(session);
Packit Service 31306d
    if (channel == NULL) {
Packit Service 31306d
        return;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (interactive) {
Packit Service 31306d
        tcgetattr(0, &terminal_local);
Packit Service 31306d
        memcpy(&terminal, &terminal_local, sizeof(struct termios));
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (ssh_channel_open_session(channel)) {
Packit Service 31306d
        printf("Error opening channel : %s\n", ssh_get_error(session));
Packit Service 31306d
        ssh_channel_free(channel);
Packit Service 31306d
        return;
Packit Service 31306d
    }
Packit Service 31306d
    chan = channel;
Packit Service 31306d
    if (interactive) {
Packit Service 31306d
        ssh_channel_request_pty(channel);
Packit Service 31306d
        sizechanged();
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (ssh_channel_request_shell(channel)) {
Packit Service 31306d
        printf("Requesting shell : %s\n", ssh_get_error(session));
Packit Service 31306d
        ssh_channel_free(channel);
Packit Service 31306d
        return;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (interactive) {
Packit Service 31306d
        cfmakeraw(&terminal_local);
Packit Service 31306d
        tcsetattr(0, TCSANOW, &terminal_local);
Packit Service 31306d
        setsignal();
Packit Service 31306d
    }
Packit Service 31306d
    signal(SIGTERM, do_cleanup);
Packit Service 31306d
    select_loop(session, channel);
Packit Service 31306d
    if (interactive) {
Packit Service 31306d
        do_cleanup(0);
Packit Service 31306d
    }
Packit Service 31306d
    ssh_channel_free(channel);
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static void batch_shell(ssh_session session)
Packit Service 31306d
{
Packit Service 31306d
    ssh_channel channel;
Packit Service 31306d
    char buffer[1024];
Packit Service 31306d
    size_t i;
Packit Service 31306d
    int s = 0;
Packit Service 31306d
Packit Service 31306d
    for (i = 0; i < MAXCMD && cmds[i]; ++i) {
Packit Service 31306d
        s += snprintf(buffer + s, sizeof(buffer) - s, "%s ", cmds[i]);
Packit Service 31306d
        free(cmds[i]);
Packit Service 31306d
        cmds[i] = NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    channel = ssh_channel_new(session);
Packit Service 31306d
    if (channel == NULL) {
Packit Service 31306d
        return;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    ssh_channel_open_session(channel);
Packit Service 31306d
    if (ssh_channel_request_exec(channel, buffer)) {
Packit Service 31306d
        printf("Error executing '%s' : %s\n", buffer, ssh_get_error(session));
Packit Service 31306d
        ssh_channel_free(channel);
Packit Service 31306d
        return;
Packit Service 31306d
    }
Packit Service 31306d
    select_loop(session, channel);
Packit Service 31306d
    ssh_channel_free(channel);
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static int client(ssh_session session)
Packit Service 31306d
{
Packit Service 31306d
    int auth = 0;
Packit Service 31306d
    char *banner;
Packit Service 31306d
    int state;
Packit Service 31306d
Packit Service 31306d
    if (user) {
Packit Service 31306d
        if (ssh_options_set(session, SSH_OPTIONS_USER, user) < 0) {
Packit Service 31306d
            return -1;
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
    if (ssh_options_set(session, SSH_OPTIONS_HOST ,host) < 0) {
Packit Service 31306d
        return -1;
Packit Service 31306d
    }
Packit Service 31306d
    if (proxycommand != NULL) {
Packit Service 31306d
        if (ssh_options_set(session, SSH_OPTIONS_PROXYCOMMAND, proxycommand)) {
Packit Service 31306d
            return -1;
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
    ssh_options_parse_config(session, NULL);
Packit Service 31306d
Packit Service 31306d
    if (ssh_connect(session)) {
Packit Service 31306d
        fprintf(stderr, "Connection failed : %s\n", ssh_get_error(session));
Packit Service 31306d
        return -1;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    state = verify_knownhost(session);
Packit Service 31306d
    if (state != 0) {
Packit Service 31306d
        return -1;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    ssh_userauth_none(session, NULL);
Packit Service 31306d
    banner = ssh_get_issue_banner(session);
Packit Service 31306d
    if (banner) {
Packit Service 31306d
        printf("%s\n", banner);
Packit Service 31306d
        free(banner);
Packit Service 31306d
    }
Packit Service 31306d
    auth = authenticate_console(session);
Packit Service 31306d
    if (auth != SSH_AUTH_SUCCESS) {
Packit Service 31306d
        return -1;
Packit Service 31306d
    }
Packit Service 31306d
    if (cmds[0] == NULL) {
Packit Service 31306d
        shell(session);
Packit Service 31306d
    } else {
Packit Service 31306d
        batch_shell(session);
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    return 0;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static ssh_pcap_file pcap;
Packit Service 31306d
static void set_pcap(ssh_session session)
Packit Service 31306d
{
Packit Service 31306d
    if (pcap_file == NULL) {
Packit Service 31306d
        return;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    pcap = ssh_pcap_file_new();
Packit Service 31306d
    if (pcap == NULL) {
Packit Service 31306d
        return;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (ssh_pcap_file_open(pcap, pcap_file) == SSH_ERROR) {
Packit Service 31306d
        printf("Error opening pcap file\n");
Packit Service 31306d
        ssh_pcap_file_free(pcap);
Packit Service 31306d
        pcap = NULL;
Packit Service 31306d
        return;
Packit Service 31306d
    }
Packit Service 31306d
    ssh_set_pcap_file(session, pcap);
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static void cleanup_pcap(void)
Packit Service 31306d
{
Packit Service 31306d
    if (pcap != NULL) {
Packit Service 31306d
        ssh_pcap_file_free(pcap);
Packit Service 31306d
    }
Packit Service 31306d
    pcap = NULL;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
int main(int argc, char **argv)
Packit Service 31306d
{
Packit Service 31306d
    ssh_session session;
Packit Service 31306d
Packit Service 31306d
    session = ssh_new();
Packit Service 31306d
Packit Service 31306d
    ssh_callbacks_init(&cb;;
Packit Service 31306d
    ssh_set_callbacks(session,&cb;;
Packit Service 31306d
Packit Service 31306d
    if (ssh_options_getopt(session, &argc, argv)) {
Packit Service 31306d
        fprintf(stderr,
Packit Service 31306d
                "Error parsing command line: %s\n",
Packit Service 31306d
                ssh_get_error(session));
Packit Service 31306d
        usage();
Packit Service 31306d
    }
Packit Service 31306d
    opts(argc, argv);
Packit Service 31306d
    signal(SIGTERM, do_exit);
Packit Service 31306d
Packit Service 31306d
    set_pcap(session);
Packit Service 31306d
    client(session);
Packit Service 31306d
Packit Service 31306d
    ssh_disconnect(session);
Packit Service 31306d
    ssh_free(session);
Packit Service 31306d
    cleanup_pcap();
Packit Service 31306d
Packit Service 31306d
    ssh_finalize();
Packit Service 31306d
Packit Service 31306d
    return 0;
Packit Service 31306d
}