aboutsummaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
authorJulien Dessaux2019-03-27 15:20:14 +0100
committerJulien Dessaux2019-03-27 15:21:16 +0100
commit455172075b6de6ffbb3900cb948c95844e27acd3 (patch)
treec0bca8b2b3dce39067ca22a4f620d58a8f690a89 /common
parentCleaning and reordering. (diff)
downloadbastion-455172075b6de6ffbb3900cb948c95844e27acd3.tar.gz
bastion-455172075b6de6ffbb3900cb948c95844e27acd3.tar.bz2
bastion-455172075b6de6ffbb3900cb948c95844e27acd3.zip
Removed mysql dependency and fetch all configuration from configuration file.
Diffstat (limited to 'common')
-rw-r--r--common/config.c4
-rw-r--r--common/config.h.in6
-rw-r--r--common/data.c276
-rw-r--r--common/data.h19
-rw-r--r--common/data_for_config.h10
-rw-r--r--common/mysql.c188
-rw-r--r--common/mysql.h22
7 files changed, 308 insertions, 217 deletions
diff --git a/common/config.c b/common/config.c
index e8196ce..1c45e7e 100644
--- a/common/config.c
+++ b/common/config.c
@@ -2,6 +2,7 @@
#include <stdlib.h>
#include "config.h"
+#include "data_for_config.h"
config_t * config = NULL;
@@ -26,7 +27,7 @@ config_load(void)
fprintf(stderr, "Configuration read error occured at %s:%d %s\n", config_error_file(config), config_error_line(config), config_error_text(config));
return 1;
}
- return 0;
+ return data_init(config);
}
int config_get_port(void)
@@ -79,6 +80,7 @@ const char * config_get_session_recording_path(void)
void config_clean(void)
{
if (config != NULL) {
+ data_clean();
config_destroy(config);
free(config);
config = NULL;
diff --git a/common/config.h.in b/common/config.h.in
index a1fe21b..95d43c9 100644
--- a/common/config.h.in
+++ b/common/config.h.in
@@ -5,18 +5,12 @@
#define CONFIG_PATH CONFIG_DIR "bastion.conf"
#define MAX_HOSTNAME_LENGTH 64
-#define MAX_USERNAME_LENGTH 64
#define DEFAULT_PORT 2222
#define DEFAULT_DSAKEY_PATH "@CMAKE_INSTALL_PREFIX@/etc/bastion/ssh_host_dsa_key"
#define DEFAULT_RSAKEY_PATH "@CMAKE_INSTALL_PREFIX@/etc/bastion/ssh_host_rsa_key"
#define DEFAULT_ECDSAKEY_PATH "@CMAKE_INSTALL_PREFIX@/etc/bastion/ssh_host_ecdsa_key"
-#define MYSQL_HOST "localhost"
-#define MYSQL_USER "sshportal"
-#define MYSQL_PASS "graou"
-#define MYSQL_DB "sshportal"
-
#ifdef SESSION_RECORDING
#define DEFAULT_SESSION_RECORDING_PATH "@CMAKE_INSTALL_PREFIX@/var/log/bastion/$d/$h/$u/$i.gz"
#define SESSION_RECORDING_FILENAME_MAX_LEN 255
diff --git a/common/data.c b/common/data.c
new file mode 100644
index 0000000..ab9710f
--- /dev/null
+++ b/common/data.c
@@ -0,0 +1,276 @@
+#include <ctype.h>
+#include <libconfig.h>
+#include <libssh/libssh.h>
+#include <uthash.h>
+
+#include "config.h"
+#include "data_for_config.h"
+
+struct key {
+ const char *name; // key
+ ssh_key key;
+ UT_hash_handle hh; // makes this structure hashable
+};
+
+struct user {
+ const char *name; // key for hh_user
+ const char *pubkeystr; // key for hh_pubkey
+ UT_hash_handle hh_user, hh_pubkey; // makes this structure hashable, twice
+};
+
+struct host {
+ const char *name;
+ const char *address;
+ const char *user;
+ ssh_key key;
+ const char *pubkeystr;
+ UT_hash_handle hh; // makes this structure hashable
+};
+
+struct key * keys = NULL;
+struct user * users = NULL;
+struct user * pubkeys = NULL;
+struct host *hosts = NULL;
+
+char // returns 0 if ok, something else otherwise
+data_init(const config_t * config)
+{
+ config_setting_t *setting;
+ const int config_dir_len = strlen(CONFIG_DIR);
+
+ // We load the ssh keys in the hastable
+ setting = config_lookup(config, "hostkeys");
+ if(setting != NULL) {
+ int count = config_setting_length(setting);
+ for(int i = 0; i < count; ++i) {
+ config_setting_t *elt = config_setting_get_elem(setting, i);
+ const char *name, *key_path;
+ if (config_setting_lookup_string(elt, "name", &name) == CONFIG_FALSE) {
+ fprintf(stderr, "Invalid key entry with no name.\n");
+ return 1;
+ }
+ struct key * tmp;
+ HASH_FIND_STR(keys, name, tmp);
+ if (tmp != NULL) {
+ fprintf(stderr, "Invalid key with duplicate name %s.\n", name);
+ return 1;
+ }
+ if (config_setting_lookup_string(elt, "path", &key_path) == CONFIG_FALSE) {
+ fprintf(stderr, "Invalid key entry %s with no path.\n", name);
+ return 1;
+ }
+ tmp = malloc(sizeof(struct key));
+ tmp->name = name;
+ char * key_realpath = malloc(strlen(key_path) + config_dir_len + 1);
+ strcpy(key_realpath, CONFIG_DIR);
+ strcpy(key_realpath + config_dir_len, key_path);
+ switch(ssh_pki_import_privkey_file(key_realpath, NULL, NULL, NULL, &tmp->key)) {
+ case SSH_EOF:
+ fprintf(stderr, "Error importing ssh key from file %s : file doesn't exist or permission denied.\n", key_realpath);
+ free(key_realpath);
+ free(tmp);
+ return 1;
+ break;
+ case SSH_ERROR:
+ fprintf(stderr, "Error importing ssh key from file %s.\n", key_realpath);
+ free(key_realpath);
+ free(tmp);
+ return 1;
+ break;
+ case SSH_OK:
+ break;
+ }
+ HASH_ADD_KEYPTR(hh, keys, tmp->name, strlen(tmp->name), tmp);
+ free(key_realpath);
+ }
+ }
+
+ // We load the users in the hastable
+ setting = config_lookup(config, "users");
+ if(setting != NULL) {
+ int count = config_setting_length(setting);
+ for(int i = 0; i < count; ++i) {
+ config_setting_t *elt = config_setting_get_elem(setting, i);
+ const char *name, *pubkeystr;
+ if (config_setting_lookup_string(elt, "name", &name) == CONFIG_FALSE) {
+ fprintf(stderr, "Invalid user entry with no name.\n");
+ return 1;
+ }
+ unsigned int name_len = strlen(name);
+ struct user * tmp;
+ HASH_FIND(hh_user, users, name, name_len, tmp);
+ if (tmp != NULL) {
+ fprintf(stderr, "Invalid user with duplicate name %s.\n", name);
+ return 1;
+ }
+ if (config_setting_lookup_string(elt, "public_key", &pubkeystr) == CONFIG_FALSE) {
+ fprintf(stderr, "Invalid user entry %s with no public_key.\n", name);
+ return 1;
+ }
+ // TODO support other key types
+ // And find a cleaner way to strip this key header before importing, and store a type flag
+ char * rsa = "ssh-rsa ";
+ pubkeystr += strlen(rsa);
+ unsigned int pubkeystr_len = strlen(pubkeystr);
+ for (unsigned int i = 0; i < pubkeystr_len; ++i) {
+ if (isspace(pubkeystr[i]) == 0)
+ continue;
+ fprintf(stderr, "Invalid trailing characters in public key for user %s :%s.\n", name, pubkeystr+i);
+ return 1;
+ }
+ HASH_FIND(hh_pubkey, pubkeys, pubkeystr, pubkeystr_len, tmp);
+ if (tmp != NULL) {
+ fprintf(stderr, "Invalid user %s with duplicate public_key with %s.\n", name, tmp->name);
+ return 1;
+ }
+ ssh_key tmpkey;
+ switch(ssh_pki_import_pubkey_base64(pubkeystr, SSH_KEYTYPE_RSA, &tmpkey)) {
+ case SSH_ERROR:
+ fprintf(stderr, "Error importing public key for user %s.\n", name);
+ return 1;
+ break;
+ case SSH_OK:
+ ssh_key_free(tmpkey);
+ break;
+ }
+ tmp = malloc(sizeof(struct user));
+ tmp->name = name;
+ tmp->pubkeystr = pubkeystr;
+ HASH_ADD_KEYPTR(hh_user, users, tmp->name, name_len, tmp);
+ HASH_ADD_KEYPTR(hh_pubkey, pubkeys, tmp->pubkeystr, pubkeystr_len, tmp);
+ }
+ }
+
+ // We load the hosts in the hastable
+ setting = config_lookup(config, "hosts");
+ if(setting != NULL) {
+ int count = config_setting_length(setting);
+ for(int i = 0; i < count; ++i) {
+ config_setting_t *elt = config_setting_get_elem(setting, i);
+ const char *name, *address, *user, *hostkey, *pubkeystr;
+ if (config_setting_lookup_string(elt, "name", &name) == CONFIG_FALSE) {
+ fprintf(stderr, "Invalid host entry with no name.\n");
+ return 1;
+ }
+ struct host * tmp;
+ HASH_FIND_STR(hosts, name, tmp);
+ if (tmp != NULL) {
+ fprintf(stderr, "Invalid host with duplicate name %s.\n", name);
+ return 1;
+ }
+ if (config_setting_lookup_string(elt, "address", &address) == CONFIG_FALSE) {
+ fprintf(stderr, "Invalid host entry %s with no address.\n", name);
+ return 1;
+ }
+ if (config_setting_lookup_string(elt, "user", &user) == CONFIG_FALSE) {
+ fprintf(stderr, "Invalid host entry %s with no user.\n", name);
+ return 1;
+ }
+ if (config_setting_lookup_string(elt, "hostkey", &hostkey) == CONFIG_FALSE) {
+ fprintf(stderr, "Invalid host entry %s with no ssh_key.\n", name);
+ return 1;
+ }
+ struct key * key;
+ HASH_FIND_STR(keys, hostkey, key);
+ if (key == NULL) {
+ fprintf(stderr, "Host key \"%s\" was not found for host \"%s\".\n", hostkey, name);
+ return 1;
+ }
+ if (config_setting_lookup_string(elt, "public_key", &pubkeystr) == CONFIG_FALSE) {
+ fprintf(stderr, "Invalid user entry %s with no public_key.\n", name);
+ return 1;
+ }
+ // TODO support other key types
+ // And find a cleaner way to strip this key header before importing, and store a type flag
+ char * ecdsa = "ssh-ed25519 ";
+ pubkeystr += strlen(ecdsa);
+ unsigned int pubkeystr_len = strlen(pubkeystr);
+ for (unsigned int i = 0; i < pubkeystr_len; ++i) {
+ if (isspace(pubkeystr[i]) == 0)
+ continue;
+ fprintf(stderr, "Invalid trailing characters in public key for user %s :%s.\n", name, pubkeystr+i);
+ return 1;
+ }
+ ssh_key tmpkey;
+ switch(ssh_pki_import_pubkey_base64(pubkeystr, SSH_KEYTYPE_ED25519, &tmpkey)) {
+ case SSH_ERROR:
+ fprintf(stderr, "Error importing public key for user %s.\n", name);
+ free(tmp);
+ return 1;
+ break;
+ case SSH_OK:
+ ssh_key_free(tmpkey);
+ break;
+ }
+ tmp = malloc(sizeof(struct host));
+ tmp->name = name;
+ tmp->address = address;
+ tmp->user = user;
+ tmp->key = key->key;
+ tmp->pubkeystr = pubkeystr;
+ HASH_ADD_KEYPTR(hh, hosts, tmp->name, strlen(tmp->name), tmp);
+ }
+ }
+
+ return 0;
+}
+
+void data_clean(void)
+{
+ struct key *current_key, *tmp_key;
+
+ HASH_ITER(hh, keys, current_key, tmp_key) {
+ HASH_DEL(keys, current_key);
+ ssh_key_free(current_key->key);
+ free(current_key);
+ }
+
+ HASH_CLEAR(hh_user, users);
+
+ struct user *current_pubkey, *tmp_pubkey;
+ HASH_ITER(hh_pubkey, pubkeys, current_pubkey, tmp_pubkey) {
+ HASH_DELETE(hh_pubkey, pubkeys, current_pubkey);
+ free(current_pubkey);
+ }
+
+ struct host *current_host, *tmp_host;
+ HASH_ITER(hh, hosts, current_host, tmp_host) {
+ HASH_DEL(hosts, current_host);
+ free(current_host);
+ }
+}
+
+const char * // returns NULL if no user found
+data_get_username_from_pubkey(ssh_key pubkey)
+{
+ const char *username = NULL;
+ char *pubkeystr;
+ if (ssh_pki_export_pubkey_base64(pubkey, &pubkeystr) != SSH_OK) {
+ fprintf(stderr, "Got invalid public key from auth attempt, this shouldn't happen.\n");
+ return NULL;
+ }
+ unsigned int pubkeystr_len = strlen(pubkeystr);
+ struct user *tmp;
+ HASH_FIND(hh_pubkey, pubkeys, pubkeystr, pubkeystr_len, tmp);
+ if (tmp != NULL) {
+ username = tmp->name;
+ }
+ free(pubkeystr);
+ return username;
+}
+
+struct data_host_info * // returns NULL if no key found, this struct is to be freed from the calling code
+data_get_host_info(const char * hostname)
+{
+ struct host * tmp;
+ HASH_FIND_STR(hosts, hostname, tmp);
+ if (tmp != NULL) {
+ struct data_host_info *info = malloc(sizeof(struct data_host_info));
+ info->address = tmp->address;
+ info->username = tmp->user;
+ info->key = tmp->key;
+ info->pubkey = tmp->pubkeystr;
+ return info;
+ }
+ return NULL;
+}
diff --git a/common/data.h b/common/data.h
new file mode 100644
index 0000000..1ede88b
--- /dev/null
+++ b/common/data.h
@@ -0,0 +1,19 @@
+#ifndef COMMON_DATA_H_
+#define COMMON_DATA_H_
+
+#include <libssh/server.h>
+
+void data_clean(void);
+
+struct data_host_info {
+ const char * address;
+ const char * username;
+ ssh_key key;
+ const char * pubkey;
+};
+
+const char * data_get_username_from_pubkey(ssh_key pubkey);
+struct data_host_info * // returns NULL if no key found, this struct is to be freed from the calling code
+data_get_host_info(const char * hostname);
+
+#endif
diff --git a/common/data_for_config.h b/common/data_for_config.h
new file mode 100644
index 0000000..acf0cac
--- /dev/null
+++ b/common/data_for_config.h
@@ -0,0 +1,10 @@
+#ifndef COMMON_DATA_FOR_CONFIG_H_
+#define COMMON_DATA_FOR_CONFIG_H_
+
+#include <libconfig.h>
+#include "data.h"
+
+char // returns 0 if ok, something else otherwise
+data_init(const config_t * config);
+
+#endif
diff --git a/common/mysql.c b/common/mysql.c
deleted file mode 100644
index 83a7930..0000000
--- a/common/mysql.c
+++ /dev/null
@@ -1,188 +0,0 @@
-#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);
- }
-}
-
-unsigned long long // returns 0 on error, or the session_id
-db_init_session_and_get_id(const char * hostname, const char * username)
-{
- char buff[255];
- sprintf(buff, "INSERT INTO sessions (created_at, status, user_id, host_id) SELECT NOW(), \"opened\", users.id, hosts.id from users, hosts WHERE users.name = \"%s\" and hosts.name = \"%s\"", username, hostname);
- int res = mysql_query(db, buff);
- if (res != 0) {
- fprintf(stderr, "FATAL: Couldn't insert new session in database for %s to %s\n", username, hostname);
- return 0;
- }
- unsigned long long id = mysql_insert_id(db);
- if (id == 0) {
- fprintf(stderr, "FATAL: Didn't get proper mysql last insert id after inserting new session for %s to %s\n", username, hostname);
- return 0;
- }
- res = mysql_commit(db);
- if (res != 0) {
- fprintf(stderr, "FATAL: Couldn't commit after inserting session for %s to %s\n", username, hostname);
- return 0;
- }
- return id;
-}
-
-void db_free_host_info(struct db_host_info * info)
-{
- free(info->privkeytxt);
- free(info->address);
- free(info->username);
- free(info->hostkeyhash);
- free(info);
-}
diff --git a/common/mysql.h b/common/mysql.h
deleted file mode 100644
index ac9a360..0000000
--- a/common/mysql.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef COMMON_MYSQL_H_
-#define COMMON_MYSQL_H_
-
-struct db_host_info {
- char * privkeytxt;
- char * address;
- char * username;
- char * hostkeyhash;
-};
-
-char db_init(void);
-void db_clean(void);
-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);
-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);
-void db_set_host_publickey_hash(const char * hostname, const char * hash);
-unsigned long long // returns 0 on error, or the session_id
-db_init_session_and_get_id(const char * hostname, const char * username);
-void db_free_host_info(struct db_host_info * info);
-
-#endif