aboutsummaryrefslogtreecommitdiff
path: root/src/session.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/session.c')
-rw-r--r--src/session.c256
1 files changed, 53 insertions, 203 deletions
diff --git a/src/session.c b/src/session.c
index 6186e6c..90e2855 100644
--- a/src/session.c
+++ b/src/session.c
@@ -8,178 +8,76 @@
#include <string.h>
#include <sys/wait.h>
-#include "pty.h"
+#include "../config.h"
+#include "proxy.h"
#include "session.h"
-#define USER "julien"
-#define PASS "graou"
-#define BUF_SIZE 1048576
-#define SESSION_END (SSH_CLOSED | SSH_CLOSED_ERROR)
-#define SFTP_SERVER_PATH "/usr/lib/sftp-server"
-
-// callback function for channel data and exceptions
-static int data_function(ssh_session session, ssh_channel channel, void *data,
- uint32_t len, int is_stderr, void *userdata) {
- struct channel_data_struct *cdata = (struct channel_data_struct *) userdata;
-
- (void) session;
- (void) channel;
- (void) is_stderr;
-
- if (len == 0 || cdata->pid < 1 || kill(cdata->pid, 0) < 0) {
- return 0;
- }
-
- return write(cdata->child_stdin, (char *) data, len);
-}
-
-static int exec_request(ssh_session session, ssh_channel channel,
- const char *command, void *userdata) {
- struct channel_data_struct *cdata = (struct channel_data_struct *) userdata;
-
-
- (void) session;
- (void) channel;
-
- if(cdata->pid > 0) {
- return SSH_ERROR;
- }
-
- if (cdata->pty_master != -1 && cdata->pty_slave != -1) {
- return exec_pty("-c", command, cdata);
- }
- return exec_nopty(command, cdata);
-}
-
-static int shell_request(ssh_session session, ssh_channel channel,
- void *userdata) {
- struct channel_data_struct *cdata = (struct channel_data_struct *) userdata;
-
+int auth_pubkey(ssh_session session, const char *user,
+ struct ssh_key_struct *pubkey,
+ char signature_state, void *userdata) {
+ struct session_data_struct *sdata = (struct session_data_struct *) userdata;
(void) session;
- (void) channel;
- if(cdata->pid > 0) {
+ // For some reason, libssh can call this twice for the same key
+ if (sdata->authenticated == 1)
return SSH_ERROR;
- }
- if (cdata->pty_master != -1 && cdata->pty_slave != -1) {
- return exec_pty("-l", NULL, cdata);
+ if (signature_state != SSH_PUBLICKEY_STATE_NONE && signature_state != SSH_PUBLICKEY_STATE_VALID) {
+ fprintf(stderr, "Invalid signature state\n");
+ sdata->auth_attempts++;
+ return SSH_AUTH_DENIED;
}
- /* Client requested a shell without a pty, let's pretend we allow that */
- return SSH_OK;
-}
-static int subsystem_request(ssh_session session, ssh_channel channel,
- const char *subsystem, void *userdata) {
- /* subsystem requests behave simillarly to exec requests. */
- if (strcmp(subsystem, "sftp") == 0) {
- return exec_request(session, channel, SFTP_SERVER_PATH, userdata);
- }
- return SSH_ERROR;
-}
+ // TODO check for an invite
-static int auth_password(ssh_session session, const char *user,
- const char *pass, void *userdata) {
- struct session_data_struct *sdata = (struct session_data_struct *) userdata;
-
- (void) session;
-
- if (strcmp(user, USER) == 0 && strcmp(pass, PASS) == 0) {
+ ssh_key reference_key = ssh_key_new();
+ ssh_pki_import_pubkey_base64(USER_RSA_PUBKEY, SSH_KEYTYPE_RSA, &reference_key); // TODO fetch all pubkeys from db
+ if (!ssh_key_cmp(pubkey, reference_key, SSH_KEY_CMP_PUBLIC)) {
sdata->authenticated = 1;
+ ssh_key_free(reference_key);
+ size_t len = strnlen(user, MAX_HOSTNAME_LENGTH + 1);
+ if (len == MAX_HOSTNAME_LENGTH + 1) {
+ fprintf(stderr, "Hostname too long, max length is %d.\n", MAX_HOSTNAME_LENGTH);
+ return SSH_ERROR;
+ }
+ sdata->login_username = malloc(len+1);
+ memset(sdata->login_username, 0, len+1);
+ strncpy(sdata->login_username, user, len);
return SSH_AUTH_SUCCESS;
+ } else {
+ ssh_key_free(reference_key);
+ sdata->auth_attempts++;
+ return SSH_AUTH_DENIED;
}
-
- sdata->auth_attempts++;
- return SSH_AUTH_DENIED;
}
-static ssh_channel channel_open(ssh_session session, void *userdata) {
+ssh_channel channel_open(ssh_session session, void *userdata) {
struct session_data_struct *sdata = (struct session_data_struct *) userdata;
- sdata->channel = ssh_channel_new(session);
- return sdata->channel;
-}
-
-static int process_stdout(socket_t fd, int revents, void *userdata) {
- char buf[BUF_SIZE];
- int n = -1;
- ssh_channel channel = (ssh_channel) userdata;
-
- if (channel != NULL && (revents & POLLIN) != 0) {
- n = read(fd, buf, BUF_SIZE);
- if (n > 0) {
- ssh_channel_write(channel, buf, n);
- // TODO implement logging here
- }
- }
-
- return n;
-}
-
-static int process_stderr(socket_t fd, int revents, void *userdata) {
- char buf[BUF_SIZE];
- int n = -1;
- ssh_channel channel = (ssh_channel) userdata;
-
- if (channel != NULL && (revents & POLLIN) != 0) {
- n = read(fd, buf, BUF_SIZE);
- if (n > 0) {
- ssh_channel_write_stderr(channel, buf, n);
- }
+ if (sdata->channel == NULL) {
+ sdata->channel = ssh_channel_new(session);
+ return sdata->channel;
+ } else {
+ // Only one channel allowed
+ return NULL;
}
-
- return n;
}
void handle_session(ssh_event event, ssh_session session) {
- int n, rc;
-
- /* Structure for storing the pty size. */
- struct winsize wsize = {
- .ws_row = 0,
- .ws_col = 0,
- .ws_xpixel = 0,
- .ws_ypixel = 0
- };
-
- /* Our struct holding information about the channel. */
- struct channel_data_struct cdata = {
- .pid = 0,
- .pty_master = -1,
- .pty_slave = -1,
- .child_stdin = -1,
- .child_stdout = -1,
- .child_stderr = -1,
- .event = NULL,
- .winsize = &wsize
- };
-
/* Our struct holding information about the session. */
struct session_data_struct sdata = {
.channel = NULL,
.auth_attempts = 0,
- .authenticated = 0
- };
-
- struct ssh_channel_callbacks_struct channel_cb = {
- .userdata = &cdata,
- .channel_pty_request_function = pty_request,
- .channel_pty_window_change_function = pty_resize,
- .channel_shell_request_function = shell_request,
- .channel_exec_request_function = exec_request,
- .channel_data_function = data_function,
- .channel_subsystem_request_function = subsystem_request
+ .authenticated = 0,
+ .login_username = NULL
};
struct ssh_server_callbacks_struct server_cb = {
.userdata = &sdata,
- .auth_password_function = auth_password,
+ .auth_pubkey_function = auth_pubkey,
.channel_open_request_session_function = channel_open,
};
-
ssh_callbacks_init(&server_cb);
- ssh_callbacks_init(&channel_cb);
-
ssh_set_server_callbacks(session, &server_cb);
if (ssh_handle_key_exchange(session) != SSH_OK) {
@@ -187,14 +85,18 @@ void handle_session(ssh_event event, ssh_session session) {
return;
}
- ssh_set_auth_methods(session, SSH_AUTH_METHOD_PASSWORD);
+ ssh_set_auth_methods(session, SSH_AUTH_METHOD_PUBLICKEY);
ssh_event_add_session(event, session);
- n = 0;
- while (sdata.authenticated == 0 || sdata.channel == NULL) {
+ for (int n=0; sdata.authenticated == 0 || sdata.channel == NULL; n++) {
/* If the user has used up all attempts, or if he hasn't been able to
* authenticate in 10 seconds (n * 100ms), disconnect. */
- if (sdata.auth_attempts >= 3 || n >= 100) {
+ if (sdata.auth_attempts >= 3) {
+ fprintf(stderr, "Closing connection after 3 failed auth attempts\n");
+ return;
+ }
+ if (n >= 100) {
+ fprintf(stderr, "Closing connection after 10 seconds without successfull authentication\n");
return;
}
@@ -202,70 +104,18 @@ void handle_session(ssh_event event, ssh_session session) {
fprintf(stderr, "%s\n", ssh_get_error(session));
return;
}
- n++;
}
- ssh_set_channel_callbacks(sdata.channel, &channel_cb);
-
- do {
- /* Poll the main event which takes care of the session, the channel and
- * even our child process's stdout/stderr (once it's started). */
- if (ssh_event_dopoll(event, -1) == SSH_ERROR) {
- ssh_channel_close(sdata.channel);
- }
+ handle_proxy_session(event, session, sdata.channel, sdata.login_username);
- /* If child process's stdout/stderr has been registered with the event,
- * or the child process hasn't started yet, continue. */
- if (cdata.event != NULL || cdata.pid == 0) {
- continue;
- }
- /* Executed only once, once the child process starts. */
- cdata.event = event;
- /* If stdout valid, add stdout to be monitored by the poll event. */
- if (cdata.child_stdout != -1) {
- if (ssh_event_add_fd(event, cdata.child_stdout, POLLIN, process_stdout,
- sdata.channel) != SSH_OK) {
- fprintf(stderr, "Failed to register stdout to poll context\n");
- ssh_channel_close(sdata.channel);
- }
- }
-
- /* If stderr valid, add stderr to be monitored by the poll event. */
- if (cdata.child_stderr != -1){
- if (ssh_event_add_fd(event, cdata.child_stderr, POLLIN, process_stderr,
- sdata.channel) != SSH_OK) {
- fprintf(stderr, "Failed to register stderr to poll context\n");
- ssh_channel_close(sdata.channel);
- }
- }
- } while(ssh_channel_is_open(sdata.channel) &&
- (cdata.pid == 0 || waitpid(cdata.pid, &rc, WNOHANG) == 0));
-
- close(cdata.pty_master);
- close(cdata.child_stdin);
- close(cdata.child_stdout);
- close(cdata.child_stderr);
-
- /* Remove the descriptors from the polling context, since they are now
- * closed, they will always trigger during the poll calls. */
- ssh_event_remove_fd(event, cdata.child_stdout);
- ssh_event_remove_fd(event, cdata.child_stderr);
-
- /* If the child process exited. */
- if (kill(cdata.pid, 0) < 0 && WIFEXITED(rc)) {
- rc = WEXITSTATUS(rc);
- ssh_channel_request_send_exit_status(sdata.channel, rc);
- /* If client terminated the channel or the process did not exit nicely,
- * but only if something has been forked. */
- } else if (cdata.pid > 0) {
- kill(cdata.pid, SIGKILL);
+ if (ssh_channel_is_open(sdata.channel)) {
+ ssh_channel_close(sdata.channel);
}
- ssh_channel_send_eof(sdata.channel);
- ssh_channel_close(sdata.channel);
-
/* Wait up to 5 seconds for the client to terminate the session. */
- for (n = 0; n < 50 && (ssh_get_status(session) & SESSION_END) == 0; n++) {
+ for (int n = 0; n < 50 && (ssh_get_status(session) & SESSION_END) == 0; n++) {
ssh_event_dopoll(event, 100);
}
+ free(sdata.login_username);
+ ssh_event_remove_session(event, session);
}