aboutsummaryrefslogtreecommitdiff
path: root/ssh
diff options
context:
space:
mode:
authorTom Smeding <tom.smeding@gmail.com>2020-06-23 23:44:42 +0200
committerTom Smeding <tom.smeding@gmail.com>2020-06-25 17:21:29 +0200
commit8aa6cf1e9bf35a7ed0c377b5562f7554a45c1a68 (patch)
tree917022c2f0ac81ce6b0233946a5d8af3a375ef94 /ssh
parent95dafc361c5715d09f55360d488fd3ede97d1438 (diff)
ssh: Working ssh echo server
Diffstat (limited to 'ssh')
-rw-r--r--ssh/server.c176
1 files changed, 168 insertions, 8 deletions
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 <stdbool.h>
#include <stdatomic.h>
#include <string.h>
+#include <ctype.h>
#include <errno.h>
#include <assert.h>
#include <pthread.h>
@@ -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);