diff options
Diffstat (limited to 'common')
-rw-r--r-- | common/CMakeLists.txt | 3 | ||||
-rw-r--r-- | common/mysql.c | 188 | ||||
-rw-r--r-- | common/mysql.h | 22 |
3 files changed, 213 insertions, 0 deletions
diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt new file mode 100644 index 0000000..8636758 --- /dev/null +++ b/common/CMakeLists.txt @@ -0,0 +1,3 @@ +file(GLOB_RECURSE SOURCES *.c) + +ADD_LIBRARY(common STATIC ${SOURCES}) diff --git a/common/mysql.c b/common/mysql.c new file mode 100644 index 0000000..0931116 --- /dev/null +++ b/common/mysql.c @@ -0,0 +1,188 @@ +#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 new file mode 100644 index 0000000..8c6040f --- /dev/null +++ b/common/mysql.h @@ -0,0 +1,22 @@ +#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 * // 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 |