Archived
1
0
Fork 0
This repository has been archived on 2025-03-10. You can view files and clone it, but cannot push or open issues or pull requests.
bastion/src/session.c

119 lines
3.7 KiB
C
Raw Normal View History

#include <libssh/callbacks.h>
#include <libssh/server.h>
#include <poll.h>
#include <pty.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
2018-06-20 13:23:48 +02:00
#include "../config.h"
#include "mysql.h"
2018-06-20 13:23:48 +02:00
#include "proxy.h"
#include "session.h"
#include "state.h"
static int auth_pubkey(ssh_session session, const char *user, ssh_key pubkey, char signature_state,
void *userdata) {
2018-06-20 13:23:48 +02:00
struct session_data_struct *sdata = (struct session_data_struct *) userdata;
(void) session;
2018-06-20 13:23:48 +02:00
// For some reason, libssh can call this twice for the same key
if (sdata->authenticated == 1)
return SSH_ERROR;
2018-06-20 13:23:48 +02:00
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;
}
2018-06-20 13:23:48 +02:00
// TODO check for an invite
char * bastion_username = db_get_username_from_pubkey(pubkey);
if (bastion_username != NULL) {
sdata->authenticated = 1;
if (state_set_ssh_destination(user) != 0)
2018-06-20 13:23:48 +02:00
return SSH_ERROR;
// TODO check access rights and host configs
state_set_bastion_username(bastion_username);
free(bastion_username);
// TODO log session creation in db
state_set_session_id(1337);
return SSH_AUTH_SUCCESS;
2018-06-20 13:23:48 +02:00
} else {
free(bastion_username);
2018-06-20 13:23:48 +02:00
sdata->auth_attempts++;
return SSH_AUTH_DENIED;
}
}
2018-07-31 08:52:51 +02:00
static ssh_channel channel_open(ssh_session session, void *userdata) {
struct session_data_struct *sdata = (struct session_data_struct *) userdata;
2018-06-20 13:23:48 +02:00
if (sdata->channel == NULL) {
sdata->channel = ssh_channel_new(session);
return sdata->channel;
} else {
// Only one channel allowed
return NULL;
}
}
void handle_session(ssh_event event, ssh_session session) {
/* Our struct holding information about the session. */
struct session_data_struct sdata = {
.channel = NULL,
.auth_attempts = 0,
2018-06-20 13:23:48 +02:00
.authenticated = 0,
};
struct ssh_server_callbacks_struct server_cb = {
.userdata = &sdata,
2018-06-20 13:23:48 +02:00
.auth_pubkey_function = auth_pubkey,
.channel_open_request_session_function = channel_open,
};
ssh_callbacks_init(&server_cb);
ssh_set_server_callbacks(session, &server_cb);
if (ssh_handle_key_exchange(session) != SSH_OK) {
fprintf(stderr, "%s\n", ssh_get_error(session));
return;
}
2018-06-20 13:23:48 +02:00
ssh_set_auth_methods(session, SSH_AUTH_METHOD_PUBLICKEY);
ssh_event_add_session(event, session);
2018-06-20 13:23:48 +02:00
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. */
2018-06-20 13:23:48 +02:00
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;
}
if (ssh_event_dopoll(event, 100) == SSH_ERROR) {
fprintf(stderr, "%s\n", ssh_get_error(session));
return;
}
}
handle_proxy_session(event, session, sdata.channel);
2018-06-20 13:23:48 +02:00
if (ssh_channel_is_open(sdata.channel)) {
ssh_channel_close(sdata.channel);
}
/* Wait up to 5 seconds for the client to terminate the session. */
2018-06-20 13:23:48 +02:00
for (int n = 0; n < 50 && (ssh_get_status(session) & SESSION_END) == 0; n++) {
ssh_event_dopoll(event, 100);
}
state_clean();
2018-06-20 13:23:48 +02:00
ssh_event_remove_session(event, session);
}