From 8aa6cf1e9bf35a7ed0c377b5562f7554a45c1a68 Mon Sep 17 00:00:00 2001 From: Tom Smeding Date: Tue, 23 Jun 2020 23:44:42 +0200 Subject: ssh: Working ssh echo server --- ssh/server.c | 176 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 168 insertions(+), 8 deletions(-) (limited to 'ssh/server.c') diff --git a/ssh/server.c b/ssh/server.c index 55a53c2..fa63d34 100644 --- a/ssh/server.c +++ b/ssh/server.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -20,6 +21,32 @@ } \ } while (0) +void xxd(FILE *stream, const void *buf_, size_t length) { + unsigned char *buf = (unsigned char*)buf_; + + for (size_t cursor = 0; cursor < length;) { + fprintf(stream, "%08zx:", cursor); + + for (int i = 0; i < 16; i++) { + if (i % 2 == 0) fprintf(stream, " "); + if (i % 8 == 0) fprintf(stream, " "); + if (cursor + i < length) fprintf(stream, "%02x", (unsigned)buf[cursor + i]); + else fprintf(stream, " "); + } + + fprintf(stream, " |"); + + for (int i = 0; i < 16 && cursor + i < length; i++) { + if (isprint(buf[cursor + i])) fprintf(stream, "%c", buf[cursor + i]); + else fprintf(stream, "."); + } + + fprintf(stream, "|\n"); + + cursor += 16; + } +} + // struct sessions { // // Always NULL-terminated // ssh_session *list; @@ -60,17 +87,25 @@ struct thread_data { int thread_id; ssh_session session; ssh_channel channel; // NULL before channel has been opened + bool should_close; struct ssh_server_callbacks_struct server_cb; struct ssh_channel_callbacks_struct chan_cb; }; -int subsystem_request_cb(ssh_session session, ssh_channel channel, const char *subsystem, void *tdata_) { +///////// CHANNEL CALLBACKS ////////// + +int channel_subsystem_request_cb(ssh_session session, ssh_channel channel, const char *subsystem, void *tdata_) { (void)session; (void)channel; struct thread_data *tdata = (struct thread_data*)tdata_; - printf("[%d] subsystem request: <%s>\n", tdata->thread_id, subsystem); - return 1; + if (strcmp(subsystem, "tomsg") == 0) { + printf("[%d] subsystem request: <%s>, allowing\n", tdata->thread_id, subsystem); + return 0; + } else { + printf("[%d] subsystem request: <%s>, denying!\n", tdata->thread_id, subsystem); + return 1; + } } void channel_close_cb(ssh_session session, ssh_channel channel, void *tdata_) { @@ -89,9 +124,80 @@ int channel_shell_request_cb(ssh_session session, ssh_channel channel, void *tda void channel_eof_cb(ssh_session session, ssh_channel channel, void *tdata_) { (void)session; (void)channel; struct thread_data *tdata = (struct thread_data*)tdata_; - printf("[%d] eof on channel\n", tdata->thread_id); + printf("[%d] eof on channel, setting close flag\n", tdata->thread_id); + tdata->should_close = true; } +int channel_data_cb(ssh_session session, ssh_channel channel, void *data, uint32_t len, int is_stderr, void *tdata_) { + (void)is_stderr; (void)data; (void)channel; (void)session; + struct thread_data *tdata = (struct thread_data*)tdata_; + printf("[%d] data on channel (length %u):\n", tdata->thread_id, len); + xxd(stdout, data, len); + printf("[%d] echoing back!\n", tdata->thread_id); + if (ssh_channel_write(channel, data, len) == SSH_ERROR) { + printf("[%d] write to channel failed! Setting close flag\n", tdata->thread_id); + tdata->should_close = true; + } + return len; +} + +void channel_signal_cb(ssh_session session, ssh_channel channel, const char *signal, void *tdata_) { + (void)channel; (void)session; + printf("[%d] signal SIG%s\n", ((struct thread_data*)tdata_)->thread_id, signal); +} + +void channel_exit_status_cb(ssh_session session, ssh_channel channel, int exit_status, void *tdata_) { + (void)channel; (void)session; + printf("[%d] exit status %d\n", ((struct thread_data*)tdata_)->thread_id, exit_status); +} + +void channel_exit_signal_cb(ssh_session session, ssh_channel channel, const char *signal, int core, const char *errmsg, const char *lang, void *tdata_) { + (void)lang; (void)errmsg; (void)core; (void)channel; (void)session; + printf("[%d] exit signal %s\n", ((struct thread_data*)tdata_)->thread_id, signal); +} + +int channel_pty_request_cb(ssh_session session, ssh_channel channel, const char *term, int width, int height, int pxwidth, int pwheight, void *tdata_) { + (void)pwheight; (void)pxwidth; (void)channel; (void)session; + printf("[%d] pty request (term %s, %dx%d), denying\n", ((struct thread_data*)tdata_)->thread_id, term, width, height); + return -1; +} + +void channel_auth_agent_req_cb(ssh_session session, ssh_channel channel, void *tdata_) { + (void)channel; (void)session; + printf("[%d] auth agent request\n", ((struct thread_data*)tdata_)->thread_id); +} + +void channel_x11_req_cb(ssh_session session, ssh_channel channel, int single_connection, const char *auth_protocol, const char *auth_cookie, uint32_t screen_number, void *tdata_) { + (void)screen_number; (void)auth_cookie; (void)auth_protocol; (void)single_connection; (void)channel; (void)session; + printf("[%d] X11 REQUEST WTF\n", ((struct thread_data*)tdata_)->thread_id); +} + +int channel_pty_window_change_cb(ssh_session session, ssh_channel channel, int width, int height, int pxwidth, int pwheight, void *tdata_) { + (void)pwheight; (void)pxwidth; (void)channel; (void)session; + printf("[%d] pty window change (%dx%d), denying\n", ((struct thread_data*)tdata_)->thread_id, width, height); + return -1; +} + +int channel_exec_request_cb(ssh_session session, ssh_channel channel, const char *command, void *tdata_) { + (void)channel; (void)session; + printf("[%d] exec request (<%s>), denying\n", ((struct thread_data*)tdata_)->thread_id, command); + return 1; +} + +int channel_env_request_cb(ssh_session session, ssh_channel channel, const char *env_name, const char *env_value, void *tdata_) { + (void)channel; (void)session; + printf("[%d] environment request (<%s> = <%s>), denying\n", ((struct thread_data*)tdata_)->thread_id, env_name, env_value); + return 1; +} + +int channel_write_wontblock_cb(ssh_session session, ssh_channel channel, size_t bytes, void *tdata_) { + (void)channel; (void)session; + printf("[%d] write won't block for %zu bytes notification\n", ((struct thread_data*)tdata_)->thread_id, bytes); + return 0; +} + +////////// SERVER CALLBACKS ////////// + int auth_none_cb(ssh_session session, const char *user, void *tdata_) { (void)session; struct thread_data *tdata = (struct thread_data*)tdata_; @@ -99,12 +205,46 @@ int auth_none_cb(ssh_session session, const char *user, void *tdata_) { return SSH_AUTH_SUCCESS; } +int auth_password_cb(ssh_session session, const char *user, const char *password, void *tdata_) { + (void)session; + struct thread_data *tdata = (struct thread_data*)tdata_; + printf("[%d] auth password (user <%s> password <%s>), denying\n", tdata->thread_id, user, password); + return SSH_AUTH_DENIED; +} + +int auth_gssapi_mic_cb(ssh_session session, const char *user, const char *principal, void *tdata_) { + (void)session; + struct thread_data *tdata = (struct thread_data*)tdata_; + printf("[%d] auth gssapi (user <%s> principal <%s>), denying\n", tdata->thread_id, user, principal); + return SSH_AUTH_DENIED; +} + +int auth_pubkey_cb(ssh_session session, const char *user, struct ssh_key_struct *pubkey, char signature_state, void *tdata_) { + (void)session; (void)pubkey; (void)signature_state; + struct thread_data *tdata = (struct thread_data*)tdata_; + printf("[%d] auth pubkey (user <%s>), denying\n", tdata->thread_id, user); + return SSH_AUTH_DENIED; +} + +int service_request_cb(ssh_session session, const char *service, void *tdata_) { + (void)session; + struct thread_data *tdata = (struct thread_data*)tdata_; + if (strcmp(service, "ssh-userauth") == 0) { + printf("[%d] ssh-userauth service request, allowing through\n", tdata->thread_id); + return 0; + } else { + printf("[%d] service request <%s>, not allowing\n", tdata->thread_id, service); + return -1; + } +} + ssh_channel chan_open_request_cb(ssh_session session, void *tdata_) { struct thread_data *tdata = (struct thread_data*)tdata_; if (tdata->channel == NULL) { ssh_channel chan = ssh_channel_new(session); if (chan != NULL) { - if (ssh_set_channel_callbacks(chan, &tdata->chan_cb)) { + if (ssh_set_channel_callbacks(chan, &tdata->chan_cb) == SSH_OK) { + printf("[%d] channel open request, allowing\n", tdata->thread_id); tdata->channel = chan; return chan; } @@ -112,6 +252,7 @@ ssh_channel chan_open_request_cb(ssh_session session, void *tdata_) { ssh_channel_free(chan); } } + printf("[%d] channel open request, denying!\n", tdata->thread_id); return NULL; } @@ -184,14 +325,32 @@ void* thread_entry(void *tdata_) { tdata->server_cb.userdata = tdata; tdata->server_cb.auth_none_function = auth_none_cb; tdata->server_cb.channel_open_request_session_function = chan_open_request_cb; + tdata->server_cb.auth_password_function = auth_password_cb; + tdata->server_cb.auth_gssapi_mic_function = auth_gssapi_mic_cb; + tdata->server_cb.auth_pubkey_function = auth_pubkey_cb; + tdata->server_cb.gssapi_select_oid_function = (void*)0x424242; // just crash if it attemps to invoke these + tdata->server_cb.gssapi_accept_sec_ctx_function = (void*)0x424242; + tdata->server_cb.gssapi_verify_mic_function = (void*)0x424242; + tdata->server_cb.service_request_function = service_request_cb; memset(&tdata->chan_cb, 0, sizeof tdata->chan_cb); ssh_callbacks_init(&tdata->chan_cb); tdata->chan_cb.userdata = tdata; - tdata->chan_cb.channel_subsystem_request_function = subsystem_request_cb; + tdata->chan_cb.channel_subsystem_request_function = channel_subsystem_request_cb; tdata->chan_cb.channel_close_function = channel_close_cb; tdata->chan_cb.channel_shell_request_function = channel_shell_request_cb; - tdata->chan_cb.channel_eof_function = channel_eof_cb;; + tdata->chan_cb.channel_eof_function = channel_eof_cb; + tdata->chan_cb.channel_data_function = channel_data_cb; + tdata->chan_cb.channel_signal_function = channel_signal_cb; + tdata->chan_cb.channel_exit_status_function = channel_exit_status_cb; + tdata->chan_cb.channel_exit_signal_function = channel_exit_signal_cb; + tdata->chan_cb.channel_pty_request_function = channel_pty_request_cb; + tdata->chan_cb.channel_auth_agent_req_function = channel_auth_agent_req_cb; + tdata->chan_cb.channel_x11_req_function = channel_x11_req_cb; + tdata->chan_cb.channel_pty_window_change_function = channel_pty_window_change_cb; + tdata->chan_cb.channel_exec_request_function = channel_exec_request_cb; + tdata->chan_cb.channel_env_request_function = channel_env_request_cb; + tdata->chan_cb.channel_write_wontblock_function = channel_write_wontblock_cb; if (ssh_set_server_callbacks(session, &tdata->server_cb) != SSH_OK) { printf("[%d] Failed setting server callbacks: %s\n", tid, ssh_get_error(session)); @@ -212,7 +371,7 @@ void* thread_entry(void *tdata_) { goto cleanup; } - while (true) { + while (!tdata->should_close) { // printf("[%d] poll loop...\n", tid); ssh_event_dopoll(event, -1); int status = ssh_get_status(session); @@ -295,6 +454,7 @@ int main(void) { tdata->thread_id = next_thread_id++; tdata->session = session; tdata->channel = NULL; + tdata->should_close = false; pthread_t thread; assert(pthread_create(&thread, &thread_attrs, thread_entry, tdata) == 0); -- cgit v1.2.3-54-g00ecf