Began implementing configuration fetching from an sshportal mysql database
This commit is contained in:
parent
beff818f25
commit
fecf526ed3
11 changed files with 251 additions and 45 deletions
|
@ -8,7 +8,7 @@ OBJ=$(sources:.c=.o)
|
||||||
all: bastion
|
all: bastion
|
||||||
|
|
||||||
bastion: $(OBJ)
|
bastion: $(OBJ)
|
||||||
$(CC) ${DEBUG} -o bastion $(OBJ) -lssh -lutil -ltty
|
$(CC) ${DEBUG} -o bastion $(OBJ) -lssh -lutil -ltty -lmysqlclient
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
$(RM) bastion *.[do] src/*.[do]
|
$(RM) bastion *.[do] src/*.[do]
|
||||||
|
|
13
config.h
13
config.h
|
@ -1,18 +1,19 @@
|
||||||
#ifndef CONFIG_H_
|
#ifndef CONFIG_H_
|
||||||
#define CONFIG_H_
|
#define CONFIG_H_
|
||||||
|
|
||||||
#define USER_TO_LOGIN_AS "root"
|
|
||||||
|
|
||||||
#define LISTEN_PORT 2222
|
#define LISTEN_PORT 2222
|
||||||
#define MAX_HOSTNAME_LENGTH 255
|
#define MAX_HOSTNAME_LENGTH 64
|
||||||
#define MAX_USERNAME_LENGTH 255
|
#define MAX_USERNAME_LENGTH 64
|
||||||
#define USER_RSA_PUBKEY "AAAAB3NzaC1yc2EAAAADAQABAAACAQDMdBAFjENiPMTtq90GT3+NZ68nfGxQiRExaYYnLzm1ecmulCvsuA4AOpeLY6f+FWe+ludiw7nhrXzssDdsKBy0QL+XQyvjjjW4X+k9MYhP1gAWXEOGJnjJ/1ovEsMt++6fLyNKLUTA46kErbEehDs22r+rIiEKatrn0BNrJcRI94H44oEL1/ImzVam0cSBL0tPiaJxe60sBs7M76zfyFtVdMGkeuBpS7ee+FLA58fsS3/sEZmkas8MT0QdvZz1y/66MknXYbIaqDSOUACXGF4yVKpogLRRJ1SgNo1Ujo/U3VOR1O4CiQczsZOcbSdjgl0x3fJb7BaIxrZy9iW2I7G/L/chfTvRws+x1s1y5FNZOOiXMCdZjhgLaRwb6p5gMsMVn9sJbhDjmejcAkBKQDkzbvxxhfVkH225FoVXA9YF0msWLyOEyZQYbA8autLDJsAOT5RDfw/G82DQBufAPEBR/bPby0Hl5kjqW75bpSVxDvzmKwt3EpITg9iuYEhvYZ/Zq5qC1UJ54ZfOvaf0PsTUzFePty6ve/JzfxCV1XgFQ+B8l4NSz11loDfNXSUngf7lL4qu5X4aN6WmLFO1YbyFlfpvt3K1CekJmWVeE5mV9EFTUJ4ParVWRGiA4W+zaCOsHgRkcGkp4eYGyWW8gOR/lVxYU2IFl9mbMrC9bkdRbQ=="
|
|
||||||
#define PRIVKEY_PATH "./id_rsa"
|
|
||||||
|
|
||||||
#define DSAKEY_PATH "./ssh_host_dsa_key"
|
#define DSAKEY_PATH "./ssh_host_dsa_key"
|
||||||
#define RSAKEY_PATH "./ssh_host_rsa_key"
|
#define RSAKEY_PATH "./ssh_host_rsa_key"
|
||||||
#define ECDSAKEY_PATH "./ssh_host_ecdsa_key"
|
#define ECDSAKEY_PATH "./ssh_host_ecdsa_key"
|
||||||
|
|
||||||
|
#define MYSQL_HOST "::"
|
||||||
|
#define MYSQL_USER "root"
|
||||||
|
#define MYSQL_PASS "graou"
|
||||||
|
#define MYSQL_DB "sshportal"
|
||||||
|
|
||||||
#define SESSION_RECORDING // comment this to deactivate
|
#define SESSION_RECORDING // comment this to deactivate
|
||||||
#define LOG_FILENAME_FORMAT "./log/$d/$h/$u/$i.gz" // $d : date in iso format, $h : hostname, $u : username : $i session id
|
#define LOG_FILENAME_FORMAT "./log/$d/$h/$u/$i.gz" // $d : date in iso format, $h : hostname, $u : username : $i session id
|
||||||
#define LOG_FILENAME_MAX_LEN 255
|
#define LOG_FILENAME_MAX_LEN 255
|
||||||
|
|
43
src/client.c
43
src/client.c
|
@ -7,6 +7,7 @@
|
||||||
#ifdef SESSION_RECORDING
|
#ifdef SESSION_RECORDING
|
||||||
#include "recording.h"
|
#include "recording.h"
|
||||||
#endif
|
#endif
|
||||||
|
#include "mysql.h"
|
||||||
#include "state.h"
|
#include "state.h"
|
||||||
|
|
||||||
// callback function for channel data and exceptions
|
// callback function for channel data and exceptions
|
||||||
|
@ -87,8 +88,12 @@ struct client_channel_data_struct* client_dial(ssh_event event, struct proxy_cha
|
||||||
cdata->client_channel_cb = NULL;
|
cdata->client_channel_cb = NULL;
|
||||||
|
|
||||||
/* First we try to add the private key that the server will accept */
|
/* First we try to add the private key that the server will accept */
|
||||||
ssh_key privkey;
|
struct db_host_info * info = db_get_host_info(hostname);
|
||||||
if (ssh_pki_import_privkey_file(PRIVKEY_PATH, NULL, NULL, NULL, &privkey) != SSH_OK) {
|
if (info == NULL)
|
||||||
|
goto host_info_clean;
|
||||||
|
|
||||||
|
ssh_key privkey = NULL;
|
||||||
|
if (ssh_pki_import_privkey_base64(info->privkeytxt, NULL, NULL, NULL, &privkey) != SSH_OK) {
|
||||||
printf("Error importing private key");
|
printf("Error importing private key");
|
||||||
goto privkey_clean;
|
goto privkey_clean;
|
||||||
}
|
}
|
||||||
|
@ -97,8 +102,8 @@ struct client_channel_data_struct* client_dial(ssh_event event, struct proxy_cha
|
||||||
printf("Connecting to %s\n", hostname);
|
printf("Connecting to %s\n", hostname);
|
||||||
cdata->my_session = ssh_new();
|
cdata->my_session = ssh_new();
|
||||||
|
|
||||||
ssh_options_set(cdata->my_session, SSH_OPTIONS_HOST, hostname);
|
ssh_options_set(cdata->my_session, SSH_OPTIONS_HOST, info->address);
|
||||||
ssh_options_set(cdata->my_session, SSH_OPTIONS_USER, state_get_username());
|
ssh_options_set(cdata->my_session, SSH_OPTIONS_USER, info->username);
|
||||||
#ifdef LIBSSH_VERBOSE_OUTPOUT
|
#ifdef LIBSSH_VERBOSE_OUTPOUT
|
||||||
int verbosity = SSH_LOG_PROTOCOL;
|
int verbosity = SSH_LOG_PROTOCOL;
|
||||||
ssh_options_set(cdata->my_session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
|
ssh_options_set(cdata->my_session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
|
||||||
|
@ -110,7 +115,7 @@ struct client_channel_data_struct* client_dial(ssh_event event, struct proxy_cha
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We now validate the remote server's public key */
|
/* We now validate the remote server's public key */
|
||||||
ssh_key server_pub_key;
|
ssh_key server_pub_key = NULL;
|
||||||
unsigned char * hash = NULL;
|
unsigned char * hash = NULL;
|
||||||
size_t hlen;
|
size_t hlen;
|
||||||
char * hexa = NULL;
|
char * hexa = NULL;
|
||||||
|
@ -123,15 +128,26 @@ struct client_channel_data_struct* client_dial(ssh_event event, struct proxy_cha
|
||||||
goto pubkey_hash_clean;
|
goto pubkey_hash_clean;
|
||||||
}
|
}
|
||||||
hexa = ssh_get_hexa(hash, hlen);
|
hexa = ssh_get_hexa(hash, hlen);
|
||||||
printf("Server public key hash : %s\n", hexa); // TODO validate the key
|
if (strlen(info->hostkeyhash) > 0) {
|
||||||
// if error goto pubkey_nomatch_clean
|
if (strcmp(hexa, info->hostkeyhash) != 0) {
|
||||||
|
fprintf(stderr, "Error invalid host key for %s\n", hostname);
|
||||||
|
goto pubkey_hexa_clean;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// TODO we got a broken sshportal record, we need to fix it but only
|
||||||
|
// after we completed the migration from sshportal
|
||||||
|
//db_set_host_publickey_hash(hostname, hexa);
|
||||||
|
}
|
||||||
|
ssh_string_free_char(hexa);
|
||||||
|
ssh_clean_pubkey_hash(&hash);
|
||||||
|
ssh_key_free(server_pub_key);
|
||||||
|
|
||||||
/* With the server checked, we can authenticate */
|
/* With the server checked, we can authenticate */
|
||||||
if(ssh_userauth_publickey(cdata->my_session, NULL, privkey) == SSH_AUTH_SUCCESS){
|
if(ssh_userauth_publickey(cdata->my_session, NULL, privkey) == SSH_AUTH_SUCCESS){
|
||||||
printf("Authentication success\n");
|
printf("Authentication success\n");
|
||||||
} else {
|
} else {
|
||||||
printf("Error private key was rejected\n");
|
printf("Error private key was rejected\n");
|
||||||
goto auth_clean;
|
goto session_clean;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* we open the client channel */
|
/* we open the client channel */
|
||||||
|
@ -170,17 +186,14 @@ struct client_channel_data_struct* client_dial(ssh_event event, struct proxy_cha
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ssh_string_free_char(hexa);
|
|
||||||
ssh_clean_pubkey_hash(&hash);
|
|
||||||
ssh_key_free(server_pub_key);
|
|
||||||
ssh_key_free(privkey);
|
ssh_key_free(privkey);
|
||||||
|
db_free_host_info(info);
|
||||||
return cdata;
|
return cdata;
|
||||||
|
|
||||||
channel_clean:
|
channel_clean:
|
||||||
ssh_channel_free(cdata->my_channel);
|
ssh_channel_free(cdata->my_channel);
|
||||||
auth_clean:
|
goto session_clean;
|
||||||
// TODO when pubkey match implemented fix this
|
pubkey_hexa_clean:
|
||||||
//pubkey_nomatch_clean:
|
|
||||||
ssh_string_free_char(hexa);
|
ssh_string_free_char(hexa);
|
||||||
pubkey_hash_clean:
|
pubkey_hash_clean:
|
||||||
ssh_clean_pubkey_hash(&hash);
|
ssh_clean_pubkey_hash(&hash);
|
||||||
|
@ -189,8 +202,10 @@ pubkey_clean:
|
||||||
session_clean:
|
session_clean:
|
||||||
ssh_disconnect(cdata->my_session);
|
ssh_disconnect(cdata->my_session);
|
||||||
ssh_free(cdata->my_session);
|
ssh_free(cdata->my_session);
|
||||||
|
db_free_host_info(info);
|
||||||
privkey_clean:
|
privkey_clean:
|
||||||
ssh_key_free(privkey);
|
ssh_key_free(privkey);
|
||||||
|
host_info_clean:
|
||||||
free(cdata);
|
free(cdata);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
|
|
||||||
#include "../config.h"
|
#include "../config.h"
|
||||||
|
#include "mysql.h"
|
||||||
#include "session.h"
|
#include "session.h"
|
||||||
|
|
||||||
/* SIGCHLD handler for cleaning up dead children. */
|
/* SIGCHLD handler for cleaning up dead children. */
|
||||||
|
@ -24,6 +25,7 @@ __attribute__((noreturn)) static void sigint_handler(int signo)
|
||||||
ssh_free(session);
|
ssh_free(session);
|
||||||
ssh_bind_free(sshbind);
|
ssh_bind_free(sshbind);
|
||||||
ssh_finalize();
|
ssh_finalize();
|
||||||
|
db_clean();
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,6 +94,9 @@ int main()
|
||||||
ssh_bind_free(sshbind);
|
ssh_bind_free(sshbind);
|
||||||
sshbind = NULL;
|
sshbind = NULL;
|
||||||
|
|
||||||
|
if (db_init() !=0)
|
||||||
|
goto child_cleaning;
|
||||||
|
|
||||||
ssh_event event = ssh_event_new();
|
ssh_event event = ssh_event_new();
|
||||||
if (event != NULL) {
|
if (event != NULL) {
|
||||||
/* Blocks until the SSH session ends */
|
/* Blocks until the SSH session ends */
|
||||||
|
@ -100,6 +105,7 @@ int main()
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "Could not create polling context\n");
|
fprintf(stderr, "Could not create polling context\n");
|
||||||
}
|
}
|
||||||
|
child_cleaning:
|
||||||
ssh_disconnect(session);
|
ssh_disconnect(session);
|
||||||
ssh_free(session);
|
ssh_free(session);
|
||||||
ssh_finalize();
|
ssh_finalize();
|
||||||
|
@ -122,5 +128,6 @@ int main()
|
||||||
}
|
}
|
||||||
ssh_bind_free(sshbind);
|
ssh_bind_free(sshbind);
|
||||||
ssh_finalize();
|
ssh_finalize();
|
||||||
|
db_clean();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
165
src/mysql.c
Normal file
165
src/mysql.c
Normal file
|
@ -0,0 +1,165 @@
|
||||||
|
#include <libssh/server.h>
|
||||||
|
#include <mysql/mysql.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "../config.h"
|
||||||
|
#include "mysql.h"
|
||||||
|
|
||||||
|
static MYSQL *db;
|
||||||
|
|
||||||
|
char // returns 0 if ok, greater than 0 otherwise
|
||||||
|
db_init(void)
|
||||||
|
{
|
||||||
|
printf("MySQL client version: %s\n", mysql_get_client_info());
|
||||||
|
db = mysql_init(NULL);
|
||||||
|
if (db == NULL) {
|
||||||
|
fprintf(stderr, "%s\n", mysql_error(db));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (mysql_real_connect(db, MYSQL_HOST, MYSQL_USER, MYSQL_PASS, MYSQL_DB, 0, NULL, 0) == NULL) {
|
||||||
|
fprintf(stderr, "%s\n", mysql_error(db));
|
||||||
|
mysql_close(db);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void db_clean(void)
|
||||||
|
{
|
||||||
|
mysql_close(db);
|
||||||
|
db = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
char * // returns NULL if no user found, this char * is to be freed from the calling code
|
||||||
|
db_get_username_from_pubkey(ssh_key pubkey)
|
||||||
|
{
|
||||||
|
int res = mysql_query(db, "SELECT name, authorized_key FROM users, user_keys WHERE users.id = user_keys.user_id");
|
||||||
|
if (res != 0) {
|
||||||
|
fprintf(stderr, "WARNING: Couldn't get usernames from database.\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
MYSQL_RES *result = mysql_store_result(db);
|
||||||
|
if (result == NULL) {
|
||||||
|
fprintf(stderr, "FATAL: Couldn't retrieve public keys from database.\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
MYSQL_ROW row;
|
||||||
|
while ((row = mysql_fetch_row(result))) {
|
||||||
|
char * rsa = "ssh-rsa ";
|
||||||
|
if (strncmp (row[1], rsa, strlen(rsa)) != 0) {
|
||||||
|
fprintf(stderr, "Unsupported public key type for user %s : %s\n", row[0], row[1]);
|
||||||
|
} else {
|
||||||
|
ssh_key tmp_key;
|
||||||
|
if (ssh_pki_import_pubkey_base64(row[1] + strlen(rsa), SSH_KEYTYPE_RSA, &tmp_key) != SSH_OK) {
|
||||||
|
fprintf(stderr, "Error importing public key for user %s : %s\n", row[0], row[1]);
|
||||||
|
} else if (!ssh_key_cmp(pubkey, tmp_key, SSH_KEY_CMP_PUBLIC)) {
|
||||||
|
size_t len = strlen(row[0]);
|
||||||
|
char * username = malloc(len+1);
|
||||||
|
strcpy(username, row[0]);
|
||||||
|
ssh_key_free(tmp_key);
|
||||||
|
mysql_free_result(result);
|
||||||
|
return username;
|
||||||
|
} else {
|
||||||
|
ssh_key_free(tmp_key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "ERROR: Didn't find public key in database.\n");
|
||||||
|
mysql_free_result(result);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct db_host_info * // returns NULL if no key found, this char * is to be freed from the calling code
|
||||||
|
db_get_host_info(const char * hostname)
|
||||||
|
{
|
||||||
|
char buff[255];
|
||||||
|
sprintf(buff, "SELECT priv_key, url, host_key FROM ssh_keys, hosts WHERE ssh_keys.id = hosts.ssh_key_id and hosts.name = \"%s\"", hostname);
|
||||||
|
int res = mysql_query(db, buff);
|
||||||
|
if (res != 0) {
|
||||||
|
fprintf(stderr, "WARNING: Couldn't query db for server infos for host %s\n", hostname);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
MYSQL_RES *result = mysql_store_result(db);
|
||||||
|
if (result == NULL) {
|
||||||
|
fprintf(stderr, "FATAL: Couldn't retrieve server infos for %s from database.\n", hostname);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
MYSQL_ROW row = mysql_fetch_row(result);
|
||||||
|
if (row == NULL) {
|
||||||
|
fprintf(stderr, "FATAL: Couldn't retrieve server db results for %s from database.\n", hostname);
|
||||||
|
mysql_free_result(result);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct db_host_info * info = malloc(sizeof(struct db_host_info));
|
||||||
|
memset(info, 0, sizeof(struct db_host_info));
|
||||||
|
|
||||||
|
size_t len = strlen(row[0]);
|
||||||
|
info->privkeytxt = malloc(len+1);
|
||||||
|
strcpy(info->privkeytxt, row[0]);
|
||||||
|
|
||||||
|
if (strncmp(row[1], "ssh://", 6) != 0) {
|
||||||
|
fprintf(stderr, "FATAL: invalid host url %s\n", row[1]);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
size_t at_pos = 0;
|
||||||
|
char done = 0;
|
||||||
|
for(size_t i = 6; !done; ++i) {
|
||||||
|
switch(*(row[1]+i)) {
|
||||||
|
case '@':
|
||||||
|
info->username = malloc(i-6+1);
|
||||||
|
strncpy(info->username, row[1]+6, i-6);
|
||||||
|
info->username[i-6] = '\0';
|
||||||
|
at_pos = i;
|
||||||
|
break;
|
||||||
|
case '\0':
|
||||||
|
info->address = malloc(i-at_pos);
|
||||||
|
strncpy(info->address, row[1]+at_pos+1, i-at_pos-1);
|
||||||
|
info->address[i-at_pos-1] = '\0';
|
||||||
|
done = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (i > MAX_HOSTNAME_LENGTH + MAX_USERNAME_LENGTH + 6 + 1) {
|
||||||
|
fprintf(stderr, "FATAL: Couldn't parse host url for host %s, too long.\n", hostname);
|
||||||
|
if (info->username != NULL)
|
||||||
|
free(info->username);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
len = strlen(row[2]);
|
||||||
|
info->hostkeyhash = malloc(len+1);
|
||||||
|
strcpy(info->hostkeyhash, row[2]);
|
||||||
|
|
||||||
|
mysql_free_result(result);
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
void db_set_host_publickey_hash(const char * hostname, const char * hash)
|
||||||
|
{
|
||||||
|
char buff[255];
|
||||||
|
sprintf(buff, "UPDATE ssh_keys, hosts SET host_key = \"%s\" WHERE ssh_keys.id = hosts.ssh_key_id and hosts.name = \"%s\"", hash, hostname);
|
||||||
|
int res = mysql_query(db, buff);
|
||||||
|
if (res != 0) {
|
||||||
|
fprintf(stderr, "WARNING: Couldn't set host key for host %s: %s\n", hostname, hash);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
res = mysql_commit(db);
|
||||||
|
if (res != 0) {
|
||||||
|
fprintf(stderr, "WARNING: Couldn't commit after setting host key for host %s: %s\n", hostname, hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void db_free_host_info(struct db_host_info * info)
|
||||||
|
{
|
||||||
|
free(info->privkeytxt);
|
||||||
|
free(info->address);
|
||||||
|
free(info->username);
|
||||||
|
free(info->hostkeyhash);
|
||||||
|
free(info);
|
||||||
|
}
|
18
src/mysql.h
Normal file
18
src/mysql.h
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#ifndef MYSQL_H_
|
||||||
|
#define MYSQL_H_
|
||||||
|
|
||||||
|
struct db_host_info {
|
||||||
|
char * privkeytxt;
|
||||||
|
char * address;
|
||||||
|
char * username;
|
||||||
|
char * hostkeyhash;
|
||||||
|
};
|
||||||
|
|
||||||
|
char db_init(void);
|
||||||
|
void db_clean(void);
|
||||||
|
char * db_get_username_from_pubkey(ssh_key pubkey);
|
||||||
|
struct db_host_info * db_get_host_info(const char * hostname);
|
||||||
|
void db_free_host_info(struct db_host_info * info);
|
||||||
|
void db_set_host_publickey_hash(const char * hostname, const char * hash);
|
||||||
|
|
||||||
|
#endif
|
|
@ -3,6 +3,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "client.h"
|
#include "client.h"
|
||||||
|
#include "mysql.h"
|
||||||
#include "proxy.h"
|
#include "proxy.h"
|
||||||
#include "state.h"
|
#include "state.h"
|
||||||
|
|
||||||
|
@ -201,6 +202,8 @@ void handle_proxy_session(ssh_event event, ssh_session session, ssh_channel my_c
|
||||||
ssh_callbacks_init(&channel_cb);
|
ssh_callbacks_init(&channel_cb);
|
||||||
ssh_set_channel_callbacks(my_channel, &channel_cb);
|
ssh_set_channel_callbacks(my_channel, &channel_cb);
|
||||||
|
|
||||||
|
db_clean(); // we close the mysql connection before the main loop, as to not waste ressources
|
||||||
|
|
||||||
do {
|
do {
|
||||||
/* Poll the main event which takes care of the sessions and channels */
|
/* Poll the main event which takes care of the sessions and channels */
|
||||||
if (ssh_event_dopoll(event, -1) == SSH_ERROR) {
|
if (ssh_event_dopoll(event, -1) == SSH_ERROR) {
|
||||||
|
|
|
@ -23,7 +23,7 @@ void clean_recorder(void)
|
||||||
recorder_handle = NULL;
|
recorder_handle = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char * // this char * is to be freed from the calling code
|
static char * // returns NULL if error, this char * is to be freed from the calling code
|
||||||
make_filename(void)
|
make_filename(void)
|
||||||
{
|
{
|
||||||
char * format = LOG_FILENAME_FORMAT;
|
char * format = LOG_FILENAME_FORMAT;
|
||||||
|
@ -49,7 +49,7 @@ make_filename(void)
|
||||||
strcpy(filename + fname_pos, hostname);
|
strcpy(filename + fname_pos, hostname);
|
||||||
fname_pos += len;
|
fname_pos += len;
|
||||||
} else if (format[format_pos] == 'u') {
|
} else if (format[format_pos] == 'u') {
|
||||||
const char * username = state_get_username();
|
const char * username = state_get_bastion_username();
|
||||||
size_t len = strlen(username);
|
size_t len = strlen(username);
|
||||||
strcpy(filename + fname_pos, username);
|
strcpy(filename + fname_pos, username);
|
||||||
fname_pos += len;
|
fname_pos += len;
|
||||||
|
|
|
@ -9,13 +9,13 @@
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
|
|
||||||
#include "../config.h"
|
#include "../config.h"
|
||||||
|
#include "mysql.h"
|
||||||
#include "proxy.h"
|
#include "proxy.h"
|
||||||
#include "session.h"
|
#include "session.h"
|
||||||
#include "state.h"
|
#include "state.h"
|
||||||
|
|
||||||
static int auth_pubkey(ssh_session session, const char *user,
|
static int auth_pubkey(ssh_session session, const char *user, ssh_key pubkey, char signature_state,
|
||||||
struct ssh_key_struct *pubkey,
|
void *userdata) {
|
||||||
char signature_state, void *userdata) {
|
|
||||||
struct session_data_struct *sdata = (struct session_data_struct *) userdata;
|
struct session_data_struct *sdata = (struct session_data_struct *) userdata;
|
||||||
(void) session;
|
(void) session;
|
||||||
|
|
||||||
|
@ -31,20 +31,19 @@ static int auth_pubkey(ssh_session session, const char *user,
|
||||||
|
|
||||||
// TODO check for an invite
|
// TODO check for an invite
|
||||||
|
|
||||||
ssh_key reference_key;
|
char * bastion_username = db_get_username_from_pubkey(pubkey);
|
||||||
ssh_pki_import_pubkey_base64(USER_RSA_PUBKEY, SSH_KEYTYPE_RSA, &reference_key); // TODO fetch all pubkeys from db
|
if (bastion_username != NULL) {
|
||||||
if (!ssh_key_cmp(pubkey, reference_key, SSH_KEY_CMP_PUBLIC)) {
|
|
||||||
sdata->authenticated = 1;
|
sdata->authenticated = 1;
|
||||||
ssh_key_free(reference_key);
|
|
||||||
if (state_set_ssh_destination(user) != 0)
|
if (state_set_ssh_destination(user) != 0)
|
||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
// TODO check access rights and host configs
|
// TODO check access rights and host configs
|
||||||
state_set_username(USER_TO_LOGIN_AS);
|
state_set_bastion_username(bastion_username);
|
||||||
|
free(bastion_username);
|
||||||
// TODO log session creation in db
|
// TODO log session creation in db
|
||||||
state_set_session_id(1337);
|
state_set_session_id(1337);
|
||||||
return SSH_AUTH_SUCCESS;
|
return SSH_AUTH_SUCCESS;
|
||||||
} else {
|
} else {
|
||||||
ssh_key_free(reference_key);
|
free(bastion_username);
|
||||||
sdata->auth_attempts++;
|
sdata->auth_attempts++;
|
||||||
return SSH_AUTH_DENIED;
|
return SSH_AUTH_DENIED;
|
||||||
}
|
}
|
||||||
|
|
20
src/state.c
20
src/state.c
|
@ -7,9 +7,9 @@
|
||||||
|
|
||||||
struct state {
|
struct state {
|
||||||
char * destination;
|
char * destination;
|
||||||
char * username;
|
char * bastion_username;
|
||||||
int session_id;
|
int session_id;
|
||||||
int padding;
|
int padding; // makes compiler happy
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct state state = {0};
|
static struct state state = {0};
|
||||||
|
@ -37,10 +37,10 @@ const char * state_get_ssh_destination(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
char // return 0 if ok, greater than 0 otherwise
|
char // return 0 if ok, greater than 0 otherwise
|
||||||
state_set_username(const char * name)
|
state_set_bastion_username(const char * name)
|
||||||
{
|
{
|
||||||
if (state.username != NULL) {
|
if (state.bastion_username != NULL) {
|
||||||
fprintf(stderr, "BUG found, attempting to overwrite state.username that has already been set\n");
|
fprintf(stderr, "BUG found, attempting to overwrite state.bastion_username that has already been set\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
size_t len = strnlen(name, MAX_USERNAME_LENGTH + 1);
|
size_t len = strnlen(name, MAX_USERNAME_LENGTH + 1);
|
||||||
|
@ -48,14 +48,14 @@ state_set_username(const char * name)
|
||||||
fprintf(stderr, "Username too long, max length is %d.\n", MAX_USERNAME_LENGTH);
|
fprintf(stderr, "Username too long, max length is %d.\n", MAX_USERNAME_LENGTH);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
state.username = malloc(len+1);
|
state.bastion_username = malloc(len+1);
|
||||||
strncpy(state.username, name, len+1);
|
strncpy(state.bastion_username, name, len+1);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char * state_get_username(void)
|
const char * state_get_bastion_username(void)
|
||||||
{
|
{
|
||||||
return state.username;
|
return state.bastion_username;
|
||||||
}
|
}
|
||||||
|
|
||||||
char // return 0 if ok, greater than 0 otherwise
|
char // return 0 if ok, greater than 0 otherwise
|
||||||
|
@ -78,6 +78,4 @@ void state_clean(void)
|
||||||
{
|
{
|
||||||
free(state.destination);
|
free(state.destination);
|
||||||
state.destination = NULL;
|
state.destination = NULL;
|
||||||
free(state.username);
|
|
||||||
state.username = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
|
|
||||||
char state_set_ssh_destination(const char * dest);
|
char state_set_ssh_destination(const char * dest);
|
||||||
const char * state_get_ssh_destination(void);
|
const char * state_get_ssh_destination(void);
|
||||||
char state_set_username(const char * name);
|
char state_set_bastion_username(const char * name);
|
||||||
const char * state_get_username(void);
|
const char * state_get_bastion_username(void);
|
||||||
char state_set_session_id(const int id);
|
char state_set_session_id(const int id);
|
||||||
int state_get_session_id(void);
|
int state_get_session_id(void);
|
||||||
void state_clean(void);
|
void state_clean(void);
|
||||||
|
|
Reference in a new issue