aboutsummaryrefslogtreecommitdiff
path: root/ssh/client.c
diff options
context:
space:
mode:
Diffstat (limited to 'ssh/client.c')
-rw-r--r--ssh/client.c295
1 files changed, 74 insertions, 221 deletions
diff --git a/ssh/client.c b/ssh/client.c
index fc4ad96..b9bd52a 100644
--- a/ssh/client.c
+++ b/ssh/client.c
@@ -3,12 +3,10 @@
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
-#include <errno.h>
-#include <assert.h>
-#include <libssh/callbacks.h>
-#include <sys/select.h>
#include <poll.h>
+#include <unistd.h>
#include "util.h"
+#include "sshnc.h"
static bool prompt_yn(const char *text) {
@@ -47,86 +45,17 @@ static bool prompt_yn(const char *text) {
return response;
}
-struct session_data {
- ssh_session session;
- ssh_channel channel;
- bool should_close;
-};
+static bool hostkey_checker(const unsigned char *hash, size_t length) {
+ printf("Server host key hash: %s\n", sshnc_print_hash(hash, length));
-void channel_close_cb(ssh_session session, ssh_channel channel, void *sesdata_) {
- (void)session; (void)channel;
- struct session_data *sesdata = (struct session_data*)sesdata_;
- sesdata->should_close = true;
-}
-
-void channel_eof_cb(ssh_session session, ssh_channel channel, void *sesdata_) {
- (void)session; (void)channel;
- struct session_data *sesdata = (struct session_data*)sesdata_;
- sesdata->should_close = true;
-}
-
-int channel_data_cb(ssh_session session, ssh_channel channel, void *data, uint32_t len, int is_stderr, void *sesdata_) {
- (void)session; (void)channel; (void)is_stderr;
- struct session_data *sesdata = (struct session_data*)sesdata_;
-
- const char *start = (const char*)data;
- const char *cursor = start;
- const char *end = cursor + len;
-
- while (cursor < end) {
- ssize_t nw = write(STDOUT_FILENO, cursor, end - cursor);
- if (nw < 0) {
- if (errno == EINTR) continue;
- perror("write(stdout)");
- sesdata->should_close = true;
- return cursor - start;
- }
- assert(nw > 0);
- cursor += nw;
+ bool response = prompt_yn(
+ "Does this hash match the one given to you by the server administrator, or by a\n"
+ "member that you trust and is already connected to the server? [y/n] ");
+ if (!response) {
+ printf("Disconnecting.\n");
}
- return len;
-}
-
-int channel_write_wontblock_cb(ssh_session session, ssh_channel channel, size_t bytes, void *sesdata_) {
- (void)session; (void)channel; (void)sesdata_;
- fprintf(stderr, "(write won't block for %zu bytes)\n", bytes);
- return 0;
-}
-
-int stdin_data_cb(int fd, int revents, void *sesdata_) {
- (void)fd;
- struct session_data *sesdata = (struct session_data*)sesdata_;
-
- if (revents & POLLIN) {
- char buffer[1024];
- ssize_t nr = read(STDIN_FILENO, buffer, sizeof buffer);
- if (nr < 0) {
- if (errno == EINTR) return 0;
- perror("read(stdin)");
- sesdata->should_close = true;
- return 0;
- }
-
- if (nr == 0) { // eof
- sesdata->should_close = true;
- return 0;
- }
-
- const char *cursor = buffer;
- while (cursor < buffer + nr) {
- int ret = ssh_channel_write(sesdata->channel, cursor, buffer + nr - cursor);
- if (ret == SSH_ERROR) {
- fprintf(stderr, "Error writing to channel: %s\n",
- ssh_get_error(sesdata->channel));
- sesdata->should_close = true;
- return 0;
- }
- assert(ret > 0);
- cursor += ret;
- }
- }
- return 0;
+ return response;
}
int main(int argc, char **argv) {
@@ -144,156 +73,80 @@ int main(int argc, char **argv) {
return 1;
}
- ssh_session session = ssh_new();
- if (!session) {
- fprintf(stderr, "Could not open SSH session\n");
- goto cleanup_unconnected;
- }
-
- const char *ciphers_str = "aes256-gcm@openssh.com,aes256-ctr,aes256-cbc";
- bool procconfig = false;
- bool ok = true;
- ok &= ssh_options_set(session, SSH_OPTIONS_PROCESS_CONFIG, &procconfig) == SSH_OK;
- ok &= ssh_options_set(session, SSH_OPTIONS_USER, "tomsg") == SSH_OK;
- ok &= ssh_options_set(session, SSH_OPTIONS_HOST, server_host) == SSH_OK;
- ok &= ssh_options_set(session, SSH_OPTIONS_PORT, &port) == SSH_OK;
- ok &= ssh_options_set(session, SSH_OPTIONS_CIPHERS_C_S, ciphers_str) == SSH_OK;
- ok &= ssh_options_set(session, SSH_OPTIONS_CIPHERS_S_C, ciphers_str) == SSH_OK;
- // int loglevel = SSH_LOG_PROTOCOL;
- // ok &= ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &loglevel) == SSH_OK;
-
- if (!ok) {
- fprintf(stderr, "Could not set options on SSH session: %s\n", ssh_get_error(session));
- goto cleanup_unconnected;
- }
-
- if (ssh_connect(session) != SSH_OK) {
- fprintf(stderr, "Could not connect to %s:%d: %s\n",
- server_host, port, ssh_get_error(session));
- goto cleanup_unconnected;
- }
-
- ssh_key host_key;
- if (ssh_get_server_publickey(session, &host_key) != SSH_OK) {
- fprintf(stderr, "Could not get host key from session: %s\n", ssh_get_error(session));
- goto cleanup_connected;
- }
-
- unsigned char *host_key_hash = NULL;
- size_t host_key_hash_length = 0;
- if (ssh_get_publickey_hash(host_key, SSH_PUBLICKEY_HASH_SHA256, &host_key_hash, &host_key_hash_length) != SSH_OK) {
- fprintf(stderr, "Failed to hash host key!\n");
- goto cleanup_connected;
- }
-
- printf("Server host key hash: ");
- fflush(stdout);
- ssh_print_hash(SSH_PUBLICKEY_HASH_SHA256, host_key_hash, host_key_hash_length);
-
- bool response = prompt_yn(
- "Does this hash match the one given to you by the server administrator, or by a\n"
- "member that you trust and is already connected to the server? [y/n] ");
- if (!response) {
- printf("Disconnecting.\n");
- goto cleanup_connected;
- }
-
- printf("Connected.\n");
-
-retry_userauth:
- switch (ssh_userauth_none(session, NULL)) {
- case SSH_AUTH_ERROR:
- fprintf(stderr, "Error authenticating: %s\n", ssh_get_error(session));
- return 1;
-
- case SSH_AUTH_DENIED:
- case SSH_AUTH_PARTIAL:
- fprintf(stderr, "Server denied authentication.\n");
- return 1;
-
- case SSH_AUTH_SUCCESS:
- break;
-
- case SSH_AUTH_AGAIN:
- if (ssh_get_status(session) & (SSH_CLOSED | SSH_CLOSED_ERROR)) {
- fprintf(stderr, "Socket unexpectedly closed!\n");
- return 1;
- }
- goto retry_userauth;
- }
-
- printf("Authenticated.\n");
-
- ssh_channel channel = ssh_channel_new(session);
- if (!channel) {
- fprintf(stderr, "Failed to allocate channel: %s\n", ssh_get_error(session));
- goto cleanup_connected;
- }
+ struct sshnc_client *client;
+ enum sshnc_retval ret = sshnc_connect(
+ server_host, port, "tomsg", "tomsg", hostkey_checker, &client);
- printf("Created channel\n");
-
- if (ssh_channel_open_session(channel) != SSH_OK) {
- fprintf(stderr, "Failed to open channel: %s\n", ssh_get_error(channel));
- goto cleanup_connected;
- }
-
- printf("Opened channel\n");
-
- if (ssh_channel_request_subsystem(channel, "tomsg") != SSH_OK) {
- fprintf(stderr, "Server did not allow opening 'tomsg' channel: %s\n", ssh_get_error(channel));
- goto cleanup_connected;
- }
-
- printf("Obtained tomsg subsystem on channel\n");
-
- struct session_data *sesdata = malloc(sizeof(struct session_data));
- if (!sesdata) {
- fprintf(stderr, "Out of memory (allocating session_data)!\n");
+ if (ret != SSHNC_OK) {
+ fprintf(stderr, "Could not connect: %s\n", sshnc_strerror(ret));
return 1;
}
- sesdata->session = session;
- sesdata->channel = channel;
- sesdata->should_close = false;
+ struct pollfd polls[2];
+ polls[0] = (struct pollfd){
+ .fd = sshnc_poll_fd(client),
+ .events = POLLIN,
+ };
+ polls[1] = (struct pollfd){
+ .fd = STDIN_FILENO,
+ .events = POLLIN,
+ };
- struct ssh_channel_callbacks_struct chan_cb;
- memset(&chan_cb, 0, sizeof chan_cb);
- ssh_callbacks_init(&chan_cb);
- chan_cb.userdata = sesdata;
- chan_cb.channel_close_function = channel_close_cb;
- chan_cb.channel_eof_function = channel_eof_cb;
- chan_cb.channel_data_function = channel_data_cb;
- chan_cb.channel_write_wontblock_function = channel_write_wontblock_cb;
-
- if (ssh_set_channel_callbacks(channel, &chan_cb) != SSH_OK) {
- fprintf(stderr, "Failed to set channel callbacks\n");
- goto cleanup_connected;
- }
+ while (true) {
+ int pollret = poll(polls, sizeof polls / sizeof polls[0], -1);
+ if (pollret < 0) {
+ perror("poll");
+ goto cleanup;
+ }
- printf("Set callbacks\n");
+ if (polls[0].revents & (POLLERR | POLLNVAL)) {
+ fprintf(stderr, "Error reading from SSH socket\n");
+ goto cleanup;
+ }
+ if (polls[1].revents & (POLLERR | POLLNVAL)) {
+ fprintf(stderr, "Error reading from stdin\n");
+ goto cleanup;
+ }
- ssh_event event = ssh_event_new();
- if (!event
- || ssh_event_add_session(event, session) != SSH_OK
- || ssh_event_add_fd(event, STDIN_FILENO, POLLIN, stdin_data_cb, sesdata) != SSH_OK) {
- fprintf(stderr, "Failed to create ssh event context\n");
- goto cleanup_connected;
- }
+ if (polls[0].revents & (POLLIN | POLLHUP)) {
+ char buffer[4096];
+ size_t length = 0;
+ ret = sshnc_maybe_recv(client, sizeof buffer, buffer, &length);
+ if (ret == SSHNC_OK) {
+ fwrite(buffer, 1, length, stdout);
+ } else if (ret == SSHNC_EOF) {
+ break;
+ } else if (ret != SSHNC_AGAIN) {
+ fprintf(stderr, "Error on SSH recv: %s\n", sshnc_strerror(ret));
+ goto cleanup;
+ }
+ }
- printf("Created event object\n");
+ if (polls[1].revents & (POLLIN | POLLHUP)) {
+ char buffer[4096];
+ ssize_t nr = read(STDIN_FILENO, buffer, sizeof buffer);
+ if (nr < 0) {
+ perror("Error reading from stdin");
+ goto cleanup;
+ }
+ if (nr == 0) {
+ break;
+ }
- while (!sesdata->should_close) {
- // printf("poll loop...\n");
- ssh_event_dopoll(event, -1);
- int status = ssh_get_status(session);
- if (status & (SSH_CLOSED | SSH_CLOSED_ERROR)) goto cleanup_connected;
- if (status & SSH_READ_PENDING) {
- printf("read pending?\n");
+ ret = sshnc_send(client, buffer, nr);
+ if (ret == SSHNC_EOF) {
+ break;
+ } else if (ret != SSHNC_OK) {
+ fprintf(stderr, "Error on SSH send: %s\n", sshnc_strerror(ret));
+ goto cleanup;
+ }
}
}
-cleanup_connected:
- ssh_disconnect(session);
-cleanup_unconnected:
- ssh_free(session);
+ sshnc_close(client);
+ return 0;
+
+cleanup:
+ sshnc_close(client);
+ return 1;
}