From a34ad5825b588ad88a3bb4246f889de0fd872aa8 Mon Sep 17 00:00:00 2001 From: Aris Adamantiadis Date: Mon, 11 Feb 2013 21:44:51 +0100 Subject: Added server example with callbacks impl Reviewed-by: Andreas Schneider --- examples/CMakeLists.txt | 2 + examples/samplesshd-cb.c | 292 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 294 insertions(+) create mode 100644 examples/samplesshd-cb.c (limited to 'examples') diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 118eecb3..f29ae1f3 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -46,6 +46,8 @@ if (WITH_SERVER) add_executable(samplesshd samplesshd.c) target_link_libraries(samplesshd ${LIBSSH_SHARED_LIBRARY} ${ARGP_LIBRARIES}) + add_executable(samplesshd-cb samplesshd-cb.c) + target_link_libraries(samplesshd-cb ${LIBSSH_SHARED_LIBRARY} ${ARGP_LIBRARIES}) add_executable(samplesshd-kbdint samplesshd-kbdint.c) target_link_libraries(samplesshd-kbdint ${LIBSSH_SHARED_LIBRARY} ${ARGP_LIBRARIES}) diff --git a/examples/samplesshd-cb.c b/examples/samplesshd-cb.c new file mode 100644 index 00000000..2897a793 --- /dev/null +++ b/examples/samplesshd-cb.c @@ -0,0 +1,292 @@ +/* This is a sample implementation of a libssh based SSH server */ +/* +Copyright 2003-2009 Aris Adamantiadis + +This file is part of the SSH Library + +You are free to copy this file, modify it in any way, consider it being public +domain. This does not apply to the rest of the library though, but it is +allowed to cut-and-paste working code from this file to any license of +program. +The goal is to show the API in action. It's not a reference on how terminal +clients must be made or how a client should react. +*/ + +#include "config.h" + +#include +#include +#include + +#ifdef HAVE_ARGP_H +#include +#endif +#include +#include +#include + +#ifndef KEYS_FOLDER +#ifdef _WIN32 +#define KEYS_FOLDER +#else +#define KEYS_FOLDER "/etc/ssh/" +#endif +#endif + +#define USER "myuser" +#define PASSWORD "mypassword" + +static int authenticated=0; +static int tries = 0; +static int error = 0; +static ssh_channel chan=NULL; + +static int auth_password(ssh_session session, const char *user, + const char *password, void *userdata){ + (void)userdata; + printf("Authenticating user %s pwd %s\n",user, password); + if(strcmp(user,USER) == 0 && strcmp(password, PASSWORD) == 0){ + authenticated = 1; + printf("Authenticated\n"); + return SSH_AUTH_SUCCESS; + } + if (tries >= 3){ + printf("Too many authentication tries\n"); + ssh_disconnect(session); + error = 1; + return SSH_AUTH_DENIED; + } + tries++; + return SSH_AUTH_DENIED; +} + +static int pty_request(ssh_session session, ssh_channel channel, const char *term, + int x,int y, int px, int py, void *userdata){ + (void) session; + (void) channel; + (void) term; + (void) x; + (void) y; + (void) px; + (void) py; + (void) userdata; + printf("Allocated terminal\n"); + return 0; +} + +static int shell_request(ssh_session session, ssh_channel channel, void *userdata){ + (void)session; + (void)channel; + (void)userdata; + printf("Allocated shell\n"); + return 0; +} +struct ssh_channel_callbacks_struct channel_cb = { + .channel_pty_request_function = pty_request, + .channel_shell_request_function = shell_request +}; + +static int new_session_channel(ssh_session session, ssh_channel channel, void *userdata){ + (void) session; + (void) userdata; + if(chan != NULL) + return -1; + printf("Allocated session channel\n"); + chan = channel; + ssh_callbacks_init(&channel_cb); + ssh_set_channel_callbacks(channel, &channel_cb); + return 0; +} + + +#ifdef HAVE_ARGP_H +const char *argp_program_version = "libssh server example " +SSH_STRINGIFY(LIBSSH_VERSION); +const char *argp_program_bug_address = ""; + +/* Program documentation. */ +static char doc[] = "libssh -- a Secure Shell protocol implementation"; + +/* A description of the arguments we accept. */ +static char args_doc[] = "BINDADDR"; + +/* The options we understand. */ +static struct argp_option options[] = { + { + .name = "port", + .key = 'p', + .arg = "PORT", + .flags = 0, + .doc = "Set the port to bind.", + .group = 0 + }, + { + .name = "hostkey", + .key = 'k', + .arg = "FILE", + .flags = 0, + .doc = "Set the host key.", + .group = 0 + }, + { + .name = "dsakey", + .key = 'd', + .arg = "FILE", + .flags = 0, + .doc = "Set the dsa key.", + .group = 0 + }, + { + .name = "rsakey", + .key = 'r', + .arg = "FILE", + .flags = 0, + .doc = "Set the rsa key.", + .group = 0 + }, + { + .name = "verbose", + .key = 'v', + .arg = NULL, + .flags = 0, + .doc = "Get verbose output.", + .group = 0 + }, + {NULL, 0, NULL, 0, NULL, 0} +}; + +/* Parse a single option. */ +static error_t parse_opt (int key, char *arg, struct argp_state *state) { + /* Get the input argument from argp_parse, which we + * know is a pointer to our arguments structure. + */ + ssh_bind sshbind = state->input; + + switch (key) { + case 'p': + ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDPORT_STR, arg); + break; + case 'd': + ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_DSAKEY, arg); + break; + case 'k': + ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, arg); + break; + case 'r': + ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_RSAKEY, arg); + break; + case 'v': + ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_LOG_VERBOSITY_STR, "3"); + break; + case ARGP_KEY_ARG: + if (state->arg_num >= 1) { + /* Too many arguments. */ + argp_usage (state); + } + ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDADDR, arg); + break; + case ARGP_KEY_END: + if (state->arg_num < 1) { + /* Not enough arguments. */ + argp_usage (state); + } + break; + default: + return ARGP_ERR_UNKNOWN; + } + + return 0; +} + +/* Our argp parser. */ +static struct argp argp = {options, parse_opt, args_doc, doc, NULL, NULL, NULL}; +#endif /* HAVE_ARGP_H */ + +int main(int argc, char **argv){ + ssh_session session; + ssh_bind sshbind; + ssh_event mainloop; + struct ssh_server_callbacks_struct cb = { + .userdata = NULL, + .auth_password_function = auth_password, + .channel_open_request_session_function = new_session_channel + }; + + char buf[2048]; + int sftp=0; + int i; + int r; + + sshbind=ssh_bind_new(); + session=ssh_new(); + + ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_DSAKEY, KEYS_FOLDER "ssh_host_dsa_key"); + ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_RSAKEY, KEYS_FOLDER "ssh_host_rsa_key"); + +#ifdef HAVE_ARGP_H + /* + * Parse our arguments; every option seen by parse_opt will + * be reflected in arguments. + */ + argp_parse (&argp, argc, argv, 0, 0, sshbind); +#else + (void) argc; + (void) argv; +#endif + + if(ssh_bind_listen(sshbind)<0){ + printf("Error listening to socket: %s\n",ssh_get_error(sshbind)); + return 1; + } + r=ssh_bind_accept(sshbind,session); + if(r==SSH_ERROR){ + printf("error accepting a connection : %s\n",ssh_get_error(sshbind)); + return 1; + } + ssh_callbacks_init(&cb); + ssh_set_server_callbacks(session, &cb); + + if (ssh_handle_key_exchange(session)) { + printf("ssh_handle_key_exchange: %s\n", ssh_get_error(session)); + return 1; + } + mainloop = ssh_event_new(); + ssh_event_add_session(mainloop, session); + + while (!(authenticated && chan != NULL)){ + if(error) + break; + r = ssh_event_dopoll(mainloop, -1); + if (r == SSH_ERROR){ + printf("Error : %s\n",ssh_get_error(session)); + ssh_disconnect(session); + return 1; + } + } + if(error){ + printf("Error, exiting loop\n"); + } else + printf("Authenticated and got a channel\n"); + do{ + i=ssh_channel_read(chan,buf, 2048, 0); + if(i>0) { + ssh_channel_write(chan, buf, i); + if (write(1,buf,i) < 0) { + printf("error writing to buffer\n"); + return 1; + } + if (buf[0] == '\x0d') { + if (write(1, "\n", 1) < 0) { + printf("error writing to buffer\n"); + return 1; + } + ssh_channel_write(chan, "\n", 1); + } + } + } while (i>0); + ssh_disconnect(session); + ssh_bind_free(sshbind); + ssh_finalize(); + return 0; +} + -- cgit v1.2.3