diff options
Diffstat (limited to 'src/analysis/db/server.c')
-rw-r--r-- | src/analysis/db/server.c | 163 |
1 files changed, 135 insertions, 28 deletions
diff --git a/src/analysis/db/server.c b/src/analysis/db/server.c index eaf3775..a996360 100644 --- a/src/analysis/db/server.c +++ b/src/analysis/db/server.c @@ -31,6 +31,8 @@ #include <string.h> #include <unistd.h> #include <arpa/inet.h> +#include <openssl/err.h> +#include <openssl/ssl.h> #include <i18n.h> @@ -41,6 +43,7 @@ #include "protocol.h" #include "misc/rlestr.h" #include "../../common/io.h" +#include "../../common/pathname.h" #include "../../common/xdg.h" #include "../../core/logs.h" #include "../../core/params.h" @@ -76,6 +79,10 @@ struct _GDbServer registered_user *users; /* Liste d'utilisateurs */ size_t users_count; /* Nombre d'enregistrés */ + SSL_CTX *tls_ctx; /* Contexte du chiffrement */ + char *cert_file; /* Fichier du certificat */ + char *key_file; /* Fichier de la clef privée */ + int fd; /* Canal de communication */ int domain; /* Domaine du canal */ gen_sockaddr_t addr; /* Adresse d'écoute générique */ @@ -172,6 +179,10 @@ static void g_db_server_class_init(GDbServerClass *klass) static void g_db_server_init(GDbServer *server) { + server->tls_ctx = NULL; + server->cert_file = NULL; + server->key_file = NULL; + server->fd = -1; server->basedir = NULL; @@ -197,6 +208,8 @@ static void g_db_server_dispose(GDbServer *server) { GList *iter; /* Boucle de parcours */ + g_db_server_stop(server); + for (iter = g_list_first(server->archives); iter != NULL; iter = g_list_first(server->archives)) @@ -230,6 +243,14 @@ static void g_db_server_finalize(GDbServer *server) free(server->desc); + assert(server->tls_ctx == NULL); + + if (server->cert_file != NULL) + free(server->cert_file); + + if (server->key_file != NULL) + free(server->key_file); + if (server->basedir != NULL) free(server->basedir); @@ -255,6 +276,7 @@ GDbServer *g_db_server_new_internal(const char *author, char *kfile) { GDbServer *result; /* Adresse à retourner */ bool status; /* Bilan d'un chargement */ + char *working; /* Répertoire par le client */ result = g_object_new(G_TYPE_DB_SERVER, NULL); @@ -263,6 +285,15 @@ GDbServer *g_db_server_new_internal(const char *author, char *kfile) status = g_db_server_register_user(result, author, kfile); if (!status) goto gdsni_error; + /* Paramètres de chiffrement */ + + working = get_cert_working_directory("servers", "standalone"); + + result->cert_file = build_absolute_filename(working, "server-cert.pem"); + result->key_file = build_absolute_filename(working, "server-key.pem"); + + free(working); + /* Détermination du point d'écoute */ result->domain = AF_UNIX; @@ -395,7 +426,7 @@ GDbServer *g_db_server_new_remote(const char *conf) result->sock_len = sizeof(struct sockaddr_in); desclen = INET6_ADDRSTRLEN + 1 + 5 + 1; - result->desc = (char *)calloc(desclen, sizeof(char)); + result->desc = calloc(desclen, sizeof(char)); ip = inet_ntop(AF_INET, &result->addr.inet_addr.sin_addr, result->desc, INET6_ADDRSTRLEN); if (ip == NULL) @@ -480,8 +511,7 @@ static bool g_db_server_register_user(GDbServer *server, const char *author, cha if (strlen(author) == 0) return false; - server->users = (registered_user *)realloc(server->users, - ++server->users_count * sizeof(registered_user)); + server->users = realloc(server->users, ++server->users_count * sizeof(registered_user)); dup_into_rle_string(&server->users[server->users_count - 1].author, author); /* FIXME : src ? */ server->users[server->users_count - 1].key_file = kfile; @@ -563,6 +593,7 @@ static void *g_db_server_listener(GDbServer *server) int ret; /* Bilan d'un appel */ gen_sockaddr_t peer; /* Adresse cliente */ int fd; /* Canal établi vers un client */ + SSL *tls_fd; /* Même canal, mais sécurisé */ rle_string hash; /* Empreinte du binaire visé */ rle_string user; /* Nom d'utilisateur du client */ const char *ip; /* Statut de la conversion */ @@ -598,6 +629,24 @@ static void *g_db_server_listener(GDbServer *server) continue; } + tls_fd = SSL_new(server->tls_ctx); + + if (tls_fd == NULL) + { + LOG_ERROR_OPENSSL; + goto end_of_client; + } + + SSL_set_fd(tls_fd, fd); + + ret = SSL_accept(tls_fd); + + if (ret != 1) + { + LOG_ERROR_OPENSSL; + goto invalid_conn; + } + /* Initialisation à vide pour les sorties en erreur */ init_dynamic_rle_string(&hash, NULL); @@ -610,13 +659,13 @@ static void *g_db_server_listener(GDbServer *server) else if (*((sa_family_t *)&peer) == AF_INET) { - peer_name = (char *)calloc(INET6_ADDRSTRLEN + 1 + 5 + 1, sizeof(char)); + peer_name = calloc(INET6_ADDRSTRLEN + 1 + 5 + 1, sizeof(char)); ip = inet_ntop(AF_INET, &peer.inet_addr.sin_addr, peer_name, INET6_ADDRSTRLEN); if (ip == NULL) { perror("inet_ntop"); - goto gdsl_error; + goto id_error; } snprintf(peer_name + strlen(ip), 1 + 5, ":%hu", ntohs(peer.inet_addr.sin_port)); @@ -624,7 +673,7 @@ static void *g_db_server_listener(GDbServer *server) } else - goto gdsl_invalid; + goto invalid_conn; error = DBE_NONE; archive = NULL; @@ -642,13 +691,13 @@ static void *g_db_server_listener(GDbServer *server) init_packed_buffer(&in_pbuf); - status = recv_packed_buffer(&in_pbuf, fd); + status = ssl_recv_packed_buffer(&in_pbuf, tls_fd); if (!status) { log_variadic_message(LMT_ERROR, _("Error while getting the initial packet from '%s'..."), peer_name); error = DBE_BAD_EXCHANGE; - goto gdsl_error_sending; + goto error_sending; } status = extract_packed_buffer(&in_pbuf, &cmd, sizeof(uint32_t), true); @@ -657,7 +706,7 @@ static void *g_db_server_listener(GDbServer *server) log_variadic_message(LMT_ERROR, _("Error while getting the initial command from '%s'..."), peer_name); error = DBE_BAD_EXCHANGE; - goto gdsl_error_sending; + goto error_sending; } status = extract_packed_buffer(&in_pbuf, &version, sizeof(uint32_t), true); @@ -666,7 +715,7 @@ static void *g_db_server_listener(GDbServer *server) log_variadic_message(LMT_ERROR, _("Error while getting the protocol version from '%s'..."), peer_name); error = DBE_BAD_EXCHANGE; - goto gdsl_error_sending; + goto error_sending; } status = unpack_rle_string(&hash, &in_pbuf); @@ -675,7 +724,7 @@ static void *g_db_server_listener(GDbServer *server) log_variadic_message(LMT_ERROR, _("Error while getting the binary hash from '%s'..."), peer_name); error = DBE_BAD_EXCHANGE; - goto gdsl_error_sending; + goto error_sending; } status = unpack_rle_string(&user, &in_pbuf); @@ -684,7 +733,7 @@ static void *g_db_server_listener(GDbServer *server) log_variadic_message(LMT_ERROR, _("Error while getting the user name from '%s'..."), peer_name); error = DBE_BAD_EXCHANGE; - goto gdsl_error_sending; + goto error_sending; } status = extract_packed_buffer(&in_pbuf, sig, RSA_USED_SIZE, false); @@ -693,7 +742,7 @@ static void *g_db_server_listener(GDbServer *server) log_variadic_message(LMT_ERROR, _("Error while getting the signature from '%s'..."), peer_name); error = DBE_BAD_EXCHANGE; - goto gdsl_error_sending; + goto error_sending; } if (cmd != DBC_HELO) @@ -701,7 +750,7 @@ static void *g_db_server_listener(GDbServer *server) log_variadic_message(LMT_ERROR, _("The client from '%s' did not introduce itself!"), peer_name); error = DBE_BAD_EXCHANGE; - goto gdsl_error_sending; + goto error_sending; } if (version != CDB_PROTOCOL_VERSION) @@ -709,7 +758,7 @@ static void *g_db_server_listener(GDbServer *server) log_variadic_message(LMT_ERROR, _("The client from '%s' does not use the same protocol: 0x%08x vs 0x%08x..."), peer_name, be32toh(version), CDB_PROTOCOL_VERSION); error = DBE_WRONG_VERSION; - goto gdsl_error_sending; + goto error_sending; } if (is_rle_string_empty(&hash)) @@ -717,7 +766,7 @@ static void *g_db_server_listener(GDbServer *server) log_variadic_message(LMT_ERROR, _("The submitted binary hash from '%s' is empty!"), peer_name); error = DBE_BAD_EXCHANGE; - goto gdsl_error_sending; + goto error_sending; } if (is_rle_string_empty(&user)) @@ -725,14 +774,14 @@ static void *g_db_server_listener(GDbServer *server) log_variadic_message(LMT_ERROR, _("No user is associated with the client from '%s'..."), peer_name); error = DBE_BAD_EXCHANGE; - goto gdsl_error_sending; + goto error_sending; } if (!g_db_server_is_registered_user(server, &user, sig)) { log_variadic_message(LMT_ERROR, _("This user is not registered.")); error = DBE_BAD_EXCHANGE; - goto gdsl_error_sending; + goto error_sending; } /** @@ -761,20 +810,20 @@ static void *g_db_server_listener(GDbServer *server) * ou 'DBE_WRONG_VERSION' ... 'DBE_LOADING_ERROR'). */ - gdsl_error_sending: + error_sending: exit_packed_buffer(&in_pbuf); init_packed_buffer(&out_pbuf); status = extend_packed_buffer(&out_pbuf, (uint32_t []) { DBC_WELCOME }, sizeof(uint32_t), true); - if (!status) goto gdsl_out_error; + if (!status) goto out_error; status = extend_packed_buffer(&out_pbuf, (uint32_t []) { error }, sizeof(uint32_t), true); - if (!status) goto gdsl_out_error; + if (!status) goto out_error; - status = send_packed_buffer(&out_pbuf, fd); - if (!status) goto gdsl_out_error; + status = ssl_send_packed_buffer(&out_pbuf, tls_fd); + if (!status) goto out_error; /** * L'ajout dans la liste des clients connectés provoque un envoi de mises à jour. @@ -790,7 +839,7 @@ static void *g_db_server_listener(GDbServer *server) if (iter == NULL) server->archives = g_list_append(server->archives, archive); - error = g_cdb_archive_add_client(archive, fd, &user); + error = g_cdb_archive_add_client(archive, tls_fd, &user); exit_packed_buffer(&out_pbuf); @@ -805,7 +854,7 @@ static void *g_db_server_listener(GDbServer *server) assert(error != DBE_NONE); - gdsl_out_error: + out_error: exit_packed_buffer(&out_pbuf); @@ -813,14 +862,18 @@ static void *g_db_server_listener(GDbServer *server) if (iter == NULL && archive != NULL) g_object_unref(G_OBJECT(archive)); - gdsl_error: + id_error: free(peer_name); exit_rle_string(&hash); exit_rle_string(&user); - gdsl_invalid: + invalid_conn: + + SSL_free(tls_fd); + + end_of_client: close(fd); @@ -847,10 +900,49 @@ static void *g_db_server_listener(GDbServer *server) bool g_db_server_start(GDbServer *server) { + const SSL_METHOD *method; /* Mode du canal sécurisé */ int ret; /* Bilan d'un appel */ bool status; /* Bilan d'un nettoyage */ int backlog; /* Nombre de connexions maximal*/ + /* Définition d'un environnement TLS */ + + method = TLS_server_method(); + + server->tls_ctx = SSL_CTX_new(method); + + if (server->tls_ctx == NULL) + { + LOG_ERROR_OPENSSL; + goto quick_error; + } + + ret = SSL_CTX_use_certificate_file(server->tls_ctx, server->cert_file, SSL_FILETYPE_PEM); + + if (ret != 1) + { + LOG_ERROR_OPENSSL; + goto tls_error; + } + + ret = SSL_CTX_use_PrivateKey_file(server->tls_ctx, server->key_file, SSL_FILETYPE_PEM); + + if (ret != 1) + { + LOG_ERROR_OPENSSL; + goto tls_error; + } + + ret = SSL_CTX_check_private_key(server->tls_ctx); + + if (ret != 1) + { + LOG_ERROR_OPENSSL; + goto tls_error; + } + + /* Mise en place d'un canal de communication */ + server->fd = socket(server->domain, SOCK_STREAM, 0); if (server->fd == -1) { @@ -899,6 +991,13 @@ bool g_db_server_start(GDbServer *server) close(server->fd); server->fd = -1; + tls_error: + + SSL_CTX_free(server->tls_ctx); + server->tls_ctx = NULL; + + quick_error: + return false; } @@ -920,8 +1019,13 @@ void g_db_server_stop(GDbServer *server) { int ret; /* Bilan d'un appel */ + /* Canal de communication */ + if (server->fd == -1) + { + assert(server->tls_ctx == NULL); return; + } ret = shutdown(server->fd, SHUT_RDWR); if (ret == -1) perror("shutdown"); @@ -936,6 +1040,9 @@ void g_db_server_stop(GDbServer *server) if (server->clean_socket != NULL) server->clean_socket(server); - /* TODO : s'occuper des archives ouvertes */ + /* Environnement TLS */ + + SSL_CTX_free(server->tls_ctx); + server->tls_ctx = NULL; } |