summaryrefslogtreecommitdiff
path: root/src/analysis
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2019-08-29 21:43:47 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2019-08-29 21:43:47 (GMT)
commitfa40856e942a7e1bd1cb2729645182c1fa717468 (patch)
tree954db169d2b734e661d904e502cd1c803f51c6ea /src/analysis
parent7f973e015eb59b626edc584a19a1ad3ffddf4867 (diff)
Defined a new way to launch updates share servers.
Diffstat (limited to 'src/analysis')
-rw-r--r--src/analysis/binary.c34
-rw-r--r--src/analysis/binary.h2
-rw-r--r--src/analysis/contents/file.c2
-rw-r--r--src/analysis/db/Makefile.am1
-rw-r--r--src/analysis/db/auth.c705
-rw-r--r--src/analysis/db/auth.h59
-rw-r--r--src/analysis/db/cdb.c84
-rw-r--r--src/analysis/db/cdb.h4
-rw-r--r--src/analysis/db/certs.c4
-rw-r--r--src/analysis/db/certs.h4
-rw-r--r--src/analysis/db/client.c373
-rw-r--r--src/analysis/db/client.h34
-rw-r--r--src/analysis/db/keymgn.c6
-rw-r--r--src/analysis/db/keymgn.h2
-rw-r--r--src/analysis/db/protocol.h2
-rw-r--r--src/analysis/db/server.c810
-rw-r--r--src/analysis/db/server.h38
17 files changed, 1640 insertions, 524 deletions
diff --git a/src/analysis/binary.c b/src/analysis/binary.c
index 80d12d3..5ac8e04 100644
--- a/src/analysis/binary.c
+++ b/src/analysis/binary.c
@@ -72,8 +72,8 @@ struct _GLoadedBinary
char *remote_host; /* Nom du serveur distant */
unsigned short remote_port; /* Port du serveur distant */
- GDbClient *local; /* Enregistrements locaux */
- GDbClient *remote; /* Enregistrements distants */
+ GHubClient *local; /* Enregistrements locaux */
+ GHubClient *remote; /* Enregistrements distants */
DBStorage storages[DBF_COUNT]; /* Lieux d'enregistrement */
GList *collections; /* Ensemble de modifications */
@@ -862,12 +862,12 @@ static bool g_loaded_binary_connect_internal(GLoadedBinary *binary)
/* Tentative de connexion */
- binary->local = g_db_client_new(author, priv,
+ binary->local = g_hub_client_new(/*author, priv,
g_loaded_binary_get_name(binary, false),
- checksum,
+ */checksum,
binary->collections);
- result = g_db_client_start_internal(binary->local);
+ result = g_hub_client_start_internal(binary->local);
glbcl_exit:
@@ -920,12 +920,12 @@ static bool g_loaded_binary_connect_remote(GLoadedBinary *binary)
/* Tentative de connexion */
- binary->remote = g_db_client_new(author, priv,
+ binary->remote = g_hub_client_new(/*author, priv,
g_loaded_binary_get_name(binary, false),
- checksum,
+ */checksum,
binary->collections);
- result = g_db_client_start_remote(binary->local, binary->remote_host, binary->remote_port);
+ result = g_hub_client_start_remote(binary->local, binary->remote_host, "1337", true);//binary->remote_port);
if (!result)
{
@@ -1008,9 +1008,9 @@ bool g_loaded_binary_save_cache(const GLoadedBinary *binary)
* *
******************************************************************************/
-GDbClient *g_loaded_binary_get_db_client(const GLoadedBinary *binary)
+GHubClient *g_loaded_binary_get_db_client(const GLoadedBinary *binary)
{
- GDbClient *result; /* Instance à retourner */
+ GHubClient *result; /* Instance à retourner */
result = binary->local;
@@ -1106,7 +1106,7 @@ bool _g_loaded_binary_add_to_collection(GLoadedBinary *binary, GDbItem *item, bo
DBFeatures feature; /* Domaine de fonctionnalité */
GDbCollection *collec; /* Collection visée au final */
DBStorage storage; /* Forme d'enregistrement */
- GDbClient *client; /* Liaison à utiliser */
+ GHubClient *client; /* Liaison à utiliser */
packed_buffer out_pbuf; /* Tampon d'émission */
int fd; /* Identifiant du canal de com.*/
@@ -1134,11 +1134,11 @@ bool _g_loaded_binary_add_to_collection(GLoadedBinary *binary, GDbItem *item, bo
init_packed_buffer(&out_pbuf);
- fd = g_db_client_get_fd(client);
+ fd = g_hub_client_get_fd(client);
result = g_db_collection_pack(collec, &out_pbuf, DBA_ADD_ITEM, item);
- g_db_client_put_fd(client);
+ g_hub_client_put_fd(client);
if (result)
result = send_packed_buffer(&out_pbuf, fd);
@@ -1175,7 +1175,7 @@ bool _g_loaded_binary_remove_from_collection(GLoadedBinary *binary, DBFeatures f
bool result; /* Bilan à faire remonter */
GDbCollection *collec; /* Collection visée au final */
DBStorage storage; /* Forme d'enregistrement */
- GDbClient *client; /* Liaison à utiliser */
+ GHubClient *client; /* Liaison à utiliser */
packed_buffer out_pbuf; /* Tampon d'émission */
int fd; /* Identifiant du canal de com.*/
@@ -1201,11 +1201,11 @@ bool _g_loaded_binary_remove_from_collection(GLoadedBinary *binary, DBFeatures f
init_packed_buffer(&out_pbuf);
- fd = g_db_client_get_fd(client);
+ fd = g_hub_client_get_fd(client);
result = g_db_collection_pack(collec, &out_pbuf, DBA_REM_ITEM, item);
- g_db_client_put_fd(client);
+ g_hub_client_put_fd(client);
if (result)
result = send_packed_buffer(&out_pbuf, fd);
@@ -1629,7 +1629,7 @@ static bool g_loaded_binary_save(GLoadedBinary *binary, xmlDoc *xdoc, xmlXPathCo
/* Sauvegarde côté serveur */
if (result)
- g_db_client_save(binary->local);
+ g_hub_client_save(binary->local);
return result;
diff --git a/src/analysis/binary.h b/src/analysis/binary.h
index ad4f568..2c57283 100644
--- a/src/analysis/binary.h
+++ b/src/analysis/binary.h
@@ -117,7 +117,7 @@ bool g_loaded_binary_save_cache(const GLoadedBinary *);
/* Fournit le client assurant la liaison avec un serveur. */
-GDbClient *g_loaded_binary_get_db_client(const GLoadedBinary *);
+GHubClient *g_loaded_binary_get_db_client(const GLoadedBinary *);
/* Fournit l'ensemble des collections utilisées par un binaire. */
GDbCollection **g_loaded_binary_get_all_collections(const GLoadedBinary *, size_t *);
diff --git a/src/analysis/contents/file.c b/src/analysis/contents/file.c
index 951828f..5509455 100644
--- a/src/analysis/contents/file.c
+++ b/src/analysis/contents/file.c
@@ -294,7 +294,7 @@ static void g_file_content_finalize(GFileContent *content)
GBinContent *g_file_content_new(const char *filename)
{
- GFileContent *result; /* Structure à retourner */
+ GFileContent *result; /* Structure à retourner */
int fd; /* Descripteur du fichier */
struct stat info; /* Informations sur le fichier */
int ret; /* Bilan d'un appel */
diff --git a/src/analysis/db/Makefile.am b/src/analysis/db/Makefile.am
index 53d7c36..2f7cddd 100644
--- a/src/analysis/db/Makefile.am
+++ b/src/analysis/db/Makefile.am
@@ -3,6 +3,7 @@ noinst_LTLIBRARIES = libanalysisdb.la libanalysiskeys.la
libanalysisdb_la_SOURCES = \
+ auth.h auth.c \
cdb.h cdb.c \
certs.h certs.c \
client.h client.c \
diff --git a/src/analysis/db/auth.c b/src/analysis/db/auth.c
new file mode 100644
index 0000000..af51af6
--- /dev/null
+++ b/src/analysis/db/auth.c
@@ -0,0 +1,705 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * auth.c - mise en place et gestion des autorisations pour les partages
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "auth.h"
+
+
+#include <fcntl.h>
+#include <glib.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+
+#include "../../common/extstr.h"
+#include "../../common/io.h"
+#include "../../common/pathname.h"
+#include "../../common/xdg.h"
+#include "../../core/logs.h"
+
+
+
+/* Fournit le répertoire d'enregistrement des certificats. */
+static char *get_cert_storage_directory(const char *, const char *, const char *);
+
+/* Calcule l'empreinte d'un fichier de demande de signature. */
+static char *compute_csr_fingerprint(const char *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : addr = adresse UNIX constituée. [OUT] *
+* *
+* Description : Met en place un canal UNIX pour un serveur interne. *
+* *
+* Retour : Bilan de la définition. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool build_internal_server_socket(struct sockaddr_un *addr)
+{
+ bool result; /* Bilan à retourner */
+ char *suffix; /* Fin de la destination */
+ char *path; /* Chemin d'accès au canal */
+ int ret; /* Bilan intermédiaire */
+ size_t length; /* Taille du chemin complet */
+
+ suffix = strdup("chrysalide");
+ suffix = stradd(suffix, G_DIR_SEPARATOR_S);
+ suffix = stradd(suffix, "internal-server");
+
+ path = get_xdg_config_dir(suffix);
+
+ free(suffix);
+
+ ret = ensure_path_exists(path);
+ if (ret != 0) goto mts_exit;
+
+ length = strlen(path) + 1;
+
+#ifndef UNIX_PATH_MAX
+# define UNIX_PATH_MAX 108
+#endif
+
+ if (length > UNIX_PATH_MAX)
+ {
+ log_variadic_message(LMT_ERROR,
+ _("Impossible to use '%s' as UNIX socket path: string is too long ! (%zu vs %u)\n"),
+ path, length, UNIX_PATH_MAX);
+ goto mts_exit;
+ }
+
+ memset(addr, 0, sizeof(struct sockaddr_un));
+
+ addr->sun_family = AF_UNIX;
+ strncpy(addr->sun_path, path, UNIX_PATH_MAX - 1);
+
+ result = true;
+
+ mts_exit:
+
+ free(path);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : type = type de certificat à gérer. *
+* host = dénomination du serveur visé ou NULL. *
+* port = port d'écoute ou NULL. *
+* sub = éventuelle sous-partie ou NULL. *
+* *
+* Description : Fournit le répertoire de travail pour les données d'analyse. *
+* *
+* Retour : Définition d'emplacement à libérer de la mémoire après usage.*
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+char *get_db_working_directory(const char *type, const char *host, const char *port, const char *sub)
+{
+ char *result; /* Chemin à retourner */
+ char *suffix; /* Fin de la destination */
+
+ suffix = strdup("chrysalide");
+ suffix = stradd(suffix, G_DIR_SEPARATOR_S);
+ suffix = stradd(suffix, type);
+ suffix = stradd(suffix, G_DIR_SEPARATOR_S);
+
+ if (host != NULL)
+ {
+ suffix = stradd(suffix, host);
+
+ if (port == NULL)
+ suffix = stradd(suffix, G_DIR_SEPARATOR_S);
+
+ }
+
+ if (port != NULL)
+ {
+ suffix = stradd(suffix, "-");
+ suffix = stradd(suffix, port);
+ suffix = stradd(suffix, G_DIR_SEPARATOR_S);
+ }
+
+ if (sub != NULL)
+ {
+ suffix = stradd(suffix, sub);
+ suffix = stradd(suffix, G_DIR_SEPARATOR_S);
+ }
+
+ result = get_xdg_config_dir(suffix);
+
+ free(suffix);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : outdir = répertoire de sortie pour les nouveaux fichiers. *
+* host = dénomination du serveur visé. *
+* port = port d'écoute ou NULL. *
+* *
+* Description : Fournit le répertoire d'enregistrement des certificats. *
+* *
+* Retour : Définition d'emplacement à libérer de la mémoire après usage.*
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *get_cert_storage_directory(const char *outdir, const char *host, const char *port)
+{
+ char *result; /* Chemin à retourner */
+
+ result = strdup(outdir);
+
+ if (!endswith(result, G_DIR_SEPARATOR_S))
+ result = stradd(result, G_DIR_SEPARATOR_S);
+
+ result = stradd(result, host);
+
+ if (port == NULL)
+ result = stradd(result, G_DIR_SEPARATOR_S);
+
+ else
+ {
+ result = stradd(result, "-");
+ result = stradd(result, port);
+ result = stradd(result, G_DIR_SEPARATOR_S);
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : valid = durée de validité des certificats. *
+* entries = éléments d'identité à utiliser pour l'opération. *
+* *
+* Description : Etablit une base pour l'identité de l'utilisateur. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool setup_client_identity(unsigned long valid, x509_entries *entries)
+{
+ bool result; /* Bilan de l'opération */
+ char *working; /* Répertoire pour le client */
+ uid_t uid; /* Identifiant d'utilisateur */
+ struct passwd *pw; /* Indications sur l'usager */
+
+ working = get_db_working_directory("clients", NULL, NULL, NULL);
+
+ result = mkpath(working);
+
+ if (result)
+ {
+ if (entries->common_name == NULL)
+ {
+ uid = geteuid();
+ pw = getpwuid(uid);
+
+ if (pw != NULL)
+ {
+ log_variadic_message(LMT_WARNING,
+ _("Replaced the empty identity common name with '%s'"),
+ pw->pw_name);
+
+ entries->common_name = strdup(pw->pw_name);
+
+ }
+
+ }
+
+ result = build_keys_and_request(working, "client", entries);
+
+ }
+
+ free(working);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : host = désignation du serveur à contacter. *
+* port = port d'écoute correspondant. *
+* valid = durée de validité des certificats. *
+* entries = éléments d'identité à utiliser pour l'opération. *
+* *
+* Description : Etablit une base pour l'identité d'un serveur. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool setup_server_identity(const char *host, const char *port, unsigned long valid, x509_entries *entries)
+{
+ bool result; /* Bilan de l'opération */
+ char *working; /* Répertoire pour le serveur */
+ char *csr; /* Requête de signature */
+ char *old; /* Conservation de l'origine */
+ char *new; /* Nouvelle désignation */
+ char *cacert; /* Certificat d'autorité */
+ char *cakey; /* Clef de cette autorité */
+ char *cert; /* Certificat signé en sortie */
+
+ if (host == NULL)
+ {
+ host = "standalone";
+ port = NULL;
+ }
+
+ else if (strcmp(host, "standalone") != 0 && port == NULL)
+ port = "1337";
+
+ working = get_db_working_directory("servers", host, port, NULL);
+
+ result = mkpath(working);
+
+ if (result)
+ {
+ if (entries->common_name == NULL)
+ {
+ log_variadic_message(LMT_WARNING,
+ _("Replaced the empty identity common name with '%s'"),
+ host);
+
+ entries->common_name = strdup(host);
+
+ }
+
+ old = entries->common_name;
+
+ new = strdup(old);
+ new = stradd(new, " CA");
+
+ entries->common_name = new;
+
+ result = build_keys_and_ca(working, "ca", valid, entries);
+
+ entries->common_name = old;
+
+ free(new);
+
+ if (result)
+ result = build_keys_and_request(working, "server", entries);
+
+ if (result)
+ {
+ csr = build_absolute_filename(working, "server-csr.pem");
+ cacert = build_absolute_filename(working, "ca-cert.pem");
+ cakey = build_absolute_filename(working, "ca-key.pem");
+ cert = build_absolute_filename(working, "server-cert.pem");
+
+ result = sign_cert(csr, cacert, cakey, cert, valid);
+
+ free(csr);
+ free(cacert);
+ free(cakey);
+ free(cert);
+
+ }
+
+ }
+
+ free(working);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : csr = fichier contenant le certificat à signer. *
+* *
+* Description : Calcule l'empreinte d'un fichier de demande de signature. *
+* *
+* Retour : Empreinte calculée ou NULL en cas d'erreur. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *compute_csr_fingerprint(const char *csr)
+{
+ char *result; /* Empreinte à retourner */
+ int fd; /* Descripteur du fichier */
+ struct stat info; /* Informations sur le fichier */
+ int ret; /* Bilan d'un appel */
+ void *data; /* Quantité de données traitées*/
+ bool status; /* Bilan de la lecture */
+
+ result = NULL;
+
+ fd = open(csr, O_RDONLY);
+ if (fd == -1)
+ {
+ LOG_ERROR_N("open");
+ goto exit;
+ }
+
+ ret = fstat(fd, &info);
+ if (ret == -1)
+ {
+ LOG_ERROR_N("fstat");
+ goto done;
+ }
+
+ data = malloc(info.st_size);
+
+ status = safe_read(fd, data, info.st_size);
+
+ if (status)
+ result = g_compute_checksum_for_data(G_CHECKSUM_SHA256, data, info.st_size);
+
+ free(data);
+
+ done:
+
+ close(fd);
+
+ exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : host = désignation du serveur à contacter. *
+* port = port d'écoute correspondant. *
+* valid = durée de validité des certificats. *
+* csr = fichier contenant le certificat à signer. *
+* outdir = répertoire de sortie pour les nouveaux fichiers. *
+* *
+* Description : Ajoute un certificat dans les utilisateurs d'un serveur. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool add_client_to_server(const char *host, const char *port, unsigned long valid, const char *csr, const char *outdir)
+{
+ bool result; /* Bilan de l'opération */
+ char *hash; /* Empreinte de la requête */
+ char *working; /* Répertoire pour le serveur */
+ char *cacert; /* Certificat d'autorité */
+ char *cakey; /* Clef de cette autorité */
+ char *storage; /* Répertoire de stockage */
+ char *dest; /* Destination d'une copie */
+
+ result = false;
+
+ if (host == NULL)
+ {
+ host = "standalone";
+ port = NULL;
+ }
+
+ else if (strcmp(host, "standalone") != 0 && port == NULL)
+ port = "1337";
+
+ hash = compute_csr_fingerprint(csr);
+ if (hash == NULL) goto exit;
+
+ working = get_db_working_directory("servers", host, port, "authorized");
+
+ result = mkpath(working);
+
+ if (result)
+ {
+ hash = strprep(hash, working);
+ hash = stradd(hash, "-cert.pem");
+
+ free(working);
+
+ working = get_db_working_directory("servers", host, port, NULL);
+
+ cacert = build_absolute_filename(working, "ca-cert.pem");
+ cakey = build_absolute_filename(working, "ca-key.pem");
+
+ result = sign_cert(csr, cacert, cakey, hash, valid);
+
+ if (result)
+ {
+ storage = get_cert_storage_directory(outdir, host, port);
+
+ result = mkpath(storage);
+
+ if (result)
+ {
+ dest = build_absolute_filename(storage, "ca-cert.pem");
+
+ result = copy_file(dest, cacert);
+
+ free(dest);
+
+ }
+
+ if (result)
+ {
+ dest = build_absolute_filename(storage, "client-cert.pem");
+
+ result = copy_file(dest, hash);
+
+ free(dest);
+
+ }
+
+ free(storage);
+
+ }
+
+ free(cacert);
+ free(cakey);
+
+ free(hash);
+
+ }
+
+ free(working);
+
+ exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Assure la présence d'unenvironnement pour serveur interne. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool ensure_internal_connections_setup(void)
+{
+ bool result; /* Bilan à retourner */
+ unsigned long valid; /* Durée de validité */
+ char *filename; /* Fichier devant être présent */
+ int ret; /* Bilan d'une validation */
+ x509_entries identity; /* Nouvelle identité à pousser */
+ bool status; /* Bilan intermédiaire */
+ char *csr; /* Fichier de requête */
+ char *outdir; /* Répertoire de sortie */
+
+ result = false;
+
+ valid = 3 * 365 * 24 * 60 * 60;
+
+ /* Teste la présence d'une identitié pour le client */
+
+ filename = get_db_working_directory("clients", NULL, NULL, NULL);
+ filename = stradd(filename, "client-csr.pem");
+
+ ret = access(filename, R_OK);
+
+ if (ret != 0)
+ {
+ memset(&identity, 0, sizeof(identity));
+
+ status = setup_client_identity(valid, &identity);
+
+ free_x509_entries(&identity);
+
+ if (status)
+ ret = access(filename, R_OK);
+ else
+ ret = -1;
+
+ }
+
+ free(filename);
+
+ if (ret != 0)
+ goto done;
+
+ /* Teste la présence d'une identitié pour le serveur interne */
+
+ filename = get_db_working_directory("servers", "standalone", NULL, NULL);
+ filename = stradd(filename, "server-csr.pem");
+
+ ret = access(filename, R_OK);
+
+ if (ret != 0)
+ {
+ memset(&identity, 0, sizeof(identity));
+
+ status = setup_server_identity("standalone", NULL, valid, &identity);
+
+ free_x509_entries(&identity);
+
+ if (status)
+ ret = access(filename, R_OK);
+ else
+ ret = -1;
+
+ }
+
+ free(filename);
+
+ if (ret != 0)
+ goto done;
+
+ /* Teste la présence d'une autorisation pour l'accès à ce serveur */
+
+ filename = get_db_working_directory("clients", "standalone", NULL, NULL);
+ filename = stradd(filename, "client-cert.pem");
+
+ ret = access(filename, R_OK);
+
+ if (ret != 0)
+ {
+ csr = get_db_working_directory("clients", NULL, NULL, NULL);
+ csr = stradd(csr, "client-csr.pem");
+
+ outdir = get_db_working_directory("clients", NULL, NULL, NULL);
+
+ status = add_client_to_server("standalone", NULL, valid, csr, outdir);
+
+ free(outdir);
+ free(csr);
+
+ if (status)
+ ret = access(filename, R_OK);
+ else
+ ret = -1;
+
+ }
+
+ free(filename);
+
+ if (ret != 0)
+ goto done;
+
+ result = true;
+
+ done:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Lance un serveur interne si besoin est. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool launch_internal_server(void)
+{
+ bool result; /* Bilan à retourner */
+ pid_t child; /* Identifiant de processus */
+ const char *prgm; /* Programme à exécuter */
+ int wstatus; /* Etat du serveur lancé */
+ pid_t ret; /* Bilan d'un appel */
+
+ char * const argv[] = {
+ "chrysalide-hub",
+ "run",
+ NULL
+ };
+
+ child = fork();
+
+ switch (child)
+ {
+ case -1:
+ result = false;
+ LOG_ERROR_N("fork");
+ break;
+
+ case 0:
+#ifndef DISCARD_LOCAL
+ prgm = PACKAGE_SOURCE_DIR "/src/chrysalide-hub";
+#else
+ prgm = "chrysalide-hub";
+#endif
+
+ execvp(prgm, argv);
+
+ LOG_ERROR_N("execvp");
+ exit(EXIT_FAILURE);
+ break;
+
+ default:
+
+ ret = waitpid(child, &wstatus, 0);
+
+ if (ret == -1)
+ {
+ result = false;
+ LOG_ERROR_N("waitpid");
+ }
+
+ else
+ result = (WEXITSTATUS(wstatus) == EXIT_SUCCESS);
+
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/src/analysis/db/auth.h b/src/analysis/db/auth.h
new file mode 100644
index 0000000..4db7af7
--- /dev/null
+++ b/src/analysis/db/auth.h
@@ -0,0 +1,59 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * auth.h - prototypes pour la mise en place et gestion des autorisations pour les partages
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_DB_AUTH_H
+#define _ANALYSIS_DB_AUTH_H
+
+
+#include <stdbool.h>
+#include <sys/un.h>
+
+
+#include "certs.h"
+
+
+
+/* Met en place un canal UNIX pour un serveur interne. */
+bool build_internal_server_socket(struct sockaddr_un *);
+
+/* Fournit le répertoire de travail pour les données d'analyse. */
+char *get_db_working_directory(const char *, const char *, const char *, const char *);
+
+/* Etablit une base pour l'identité de l'utilisateur. */
+bool setup_client_identity(unsigned long, x509_entries *);
+
+/* Etablit une base pour l'identité d'un serveur. */
+bool setup_server_identity(const char *, const char *, unsigned long, x509_entries *);
+
+/* Ajoute un certificat dans les utilisateurs d'un serveur. */
+bool add_client_to_server(const char *, const char *, unsigned long, const char *, const char *);
+
+/* Assure la présence d'unenvironnement pour serveur interne. */
+bool ensure_internal_connections_setup(void);
+
+/* Lance un serveur interne si besoin est. */
+bool launch_internal_server(void);
+
+
+
+#endif /* _ANALYSIS_DB_AUTH_H */
diff --git a/src/analysis/db/cdb.c b/src/analysis/db/cdb.c
index c2855f7..74e8501 100644
--- a/src/analysis/db/cdb.c
+++ b/src/analysis/db/cdb.c
@@ -51,7 +51,6 @@
#include "../../common/xml.h"
#include "../../core/collections.h"
#include "../../core/logs.h"
-#include "../../core/params.h"
@@ -59,7 +58,7 @@
typedef struct _cdb_client
{
SSL *ssl_fd; /* Canal de communication */
- rle_string user; /* Utilisateur à l'autre bout */
+ char *user; /* Utilisateur à l'autre bout */
uint64_t last_time; /* Date de dernier envoi */
@@ -125,7 +124,7 @@ static bool g_cdb_archive_read(GCdbArchive *);
/* Crée la description XML correspondant à l'archive. */
-static bool g_cdb_archive_create_xml_desc(GCdbArchive *, const rle_string *);
+static bool g_cdb_archive_create_xml_desc(GCdbArchive *);
/* Vérifie la conformité d'une description XML avec le serveur. */
static bool g_cdb_archive_check_xml_version(const GCdbArchive *);
@@ -263,7 +262,7 @@ static void g_cdb_archive_finalize(GCdbArchive *archive)
if (archive->xml_desc != NULL)
{
ret = unlink(archive->xml_desc);
- if (ret != 0) perror("unlink");
+ if (ret != 0) LOG_ERROR_N("unlink");
free(archive->xml_desc);
@@ -272,7 +271,7 @@ static void g_cdb_archive_finalize(GCdbArchive *archive)
if (archive->sql_db != NULL)
{
ret = unlink(archive->sql_db);
- if (ret != 0) perror("unlink");
+ if (ret != 0) LOG_ERROR_N("unlink");
free(archive->sql_db);
@@ -290,8 +289,8 @@ static void g_cdb_archive_finalize(GCdbArchive *archive)
/******************************************************************************
* *
* Paramètres : basedir = répertoire de stockage des enregistrements. *
+* tmpdir = répertoire de travail temporaire. *
* hash = empreinte du binaire à représenter. *
-* user = désignation d'un éventuel nouveau créateur. *
* error = indication éventuelle en cas d'échec. [OUT] *
* *
* Description : Définit ou ouvre une archive d'éléments utilisateur. *
@@ -303,11 +302,9 @@ static void g_cdb_archive_finalize(GCdbArchive *archive)
* *
******************************************************************************/
-GCdbArchive *g_cdb_archive_new(const char *basedir, const rle_string *hash, const rle_string *user, DBError *error)
+GCdbArchive *g_cdb_archive_new(const char *basedir, const char *tmpdir, const rle_string *hash, DBError *error)
{
GCdbArchive *result; /* Adresse à retourner */
- const char *tmpdir; /* Répertoire d'accueil */
- bool status; /* Bilan d'un consultation */
int ret; /* Retour d'un appel */
struct stat finfo; /* Information sur l'archive */
@@ -318,7 +315,6 @@ GCdbArchive *g_cdb_archive_new(const char *basedir, const rle_string *hash, cons
/* Chemin de l'archive */
result->filename = strdup(basedir);
- result->filename = stradd(result->filename, G_DIR_SEPARATOR_S);
result->filename = stradd(result->filename, hash->data);
result->filename = stradd(result->filename, ".cdb.tar.xz");
@@ -327,8 +323,8 @@ GCdbArchive *g_cdb_archive_new(const char *basedir, const rle_string *hash, cons
/* Chemin des enregistrements temporaires */
- status = g_generic_config_get_value(get_main_configuration(), MPK_TMPDIR, &tmpdir);
- if (!status) goto gcan_no_tmp;
+ if (!mkpath(tmpdir))
+ goto gcan_error;
ret = asprintf(&result->xml_desc, "%s" G_DIR_SEPARATOR_S "%s_desc.xml", tmpdir, result->hash.data);
if (ret == -1) goto gcan_no_tmp;
@@ -348,7 +344,7 @@ GCdbArchive *g_cdb_archive_new(const char *basedir, const rle_string *hash, cons
/* Le soucis ne vient pas de l'absence du fichier... */
if (errno != ENOENT) goto gcan_error;
- g_cdb_archive_create_xml_desc(result, user);
+ g_cdb_archive_create_xml_desc(result);
g_cdb_archive_create_db(result);
*error = g_cdb_archive_write(result);
@@ -573,7 +569,6 @@ int g_cdb_archive_compare_hash(const GCdbArchive *archive, const rle_string *has
/******************************************************************************
* *
* Paramètres : archive = archive à constituer. *
-* user = désignation d'un éventuel nouveau créateur. *
* *
* Description : Crée la description XML correspondant à l'archive. *
* *
@@ -583,34 +578,38 @@ int g_cdb_archive_compare_hash(const GCdbArchive *archive, const rle_string *has
* *
******************************************************************************/
-static bool g_cdb_archive_create_xml_desc(GCdbArchive *archive, const rle_string *user)
+static bool g_cdb_archive_create_xml_desc(GCdbArchive *archive)
{
bool result; /* Bilan à retourner */
timestamp_t timestamp; /* Date de création */
char tmp[sizeof(XSTR(UINT64_MAX))]; /* Stockage temporaire */
result = create_new_xml_file(&archive->xdoc, &archive->context);
- if (!result) return false;
- result &= add_content_to_node(archive->xdoc, archive->context,
- "/ChrysalideBinary/Version", PACKAGE_VERSION);
+ if (result)
+ result = add_content_to_node(archive->xdoc, archive->context,
+ "/ChrysalideBinary/Version", PACKAGE_VERSION);
- result &= add_content_to_node(archive->xdoc, archive->context,
- "/ChrysalideBinary/Protocol", XSTR(CDB_PROTOCOL_VERSION));
+ if (result)
+ result = add_content_to_node(archive->xdoc, archive->context,
+ "/ChrysalideBinary/Protocol", XSTR(CDB_PROTOCOL_VERSION));
- result &= add_content_to_node(archive->xdoc, archive->context,
- "/ChrysalideBinary/Hash", archive->hash.data);
+ if (result)
+ result = add_content_to_node(archive->xdoc, archive->context,
+ "/ChrysalideBinary/Hash", archive->hash.data);
- result &= add_content_to_node(archive->xdoc, archive->context,
- "/ChrysalideBinary/Creation/Author", user->data);
+ if (result)
+ {
+ init_timestamp(&timestamp);
+ snprintf(tmp, sizeof(tmp), "%" PRIu64, timestamp);
- init_timestamp(&timestamp);
- snprintf(tmp, sizeof(tmp), "%" PRIu64, timestamp);
+ result = add_content_to_node(archive->xdoc, archive->context,
+ "/ChrysalideBinary/CreationDate", tmp);
- result &= add_content_to_node(archive->xdoc, archive->context,
- "/ChrysalideBinary/Creation/Date", tmp);
+ }
- save_xml_file(archive->xdoc, archive->xml_desc);
+ if (result)
+ result = save_xml_file(archive->xdoc, archive->xml_desc);
return result;
@@ -863,7 +862,7 @@ static void *g_cdb_archive_process(GCdbArchive *archive)
{
if (errno == EINTR) continue;
- perror("poll");
+ LOG_ERROR_N("poll");
break;
}
@@ -874,7 +873,15 @@ static void *g_cdb_archive_process(GCdbArchive *archive)
{
/* Le canal est fermé, une sortie doit être demandée... */
if (fds[i].revents & POLLNVAL)
- goto gcap_closed_exchange;
+ goto closed_exchange;
+
+ /**
+ * Même chose, cf. "TCP: When is EPOLLHUP generated?"
+ * https://stackoverflow.com/questions/52976152/tcp-when-is-epollhup-generated/52976327#52976327
+ */
+
+ if (fds[i].revents & (POLLHUP | POLLRDHUP))
+ goto closed_exchange;
/* Données présentes en entrée */
if (fds[i].revents & (POLLIN | POLLPRI))
@@ -979,7 +986,7 @@ static void *g_cdb_archive_process(GCdbArchive *archive)
exit_packed_buffer(&in_pbuf);
- gcap_closed_exchange:
+ closed_exchange:
g_cdb_archive_remove_client(archive, i);
@@ -1012,7 +1019,6 @@ static void *g_cdb_archive_process(GCdbArchive *archive)
* *
* Paramètres : archive = archive à connecter avec un utilisateur. *
* fd = canal de communication réseau ouvert. *
-* user = désignation de l'utilisateur associé. *
* *
* Description : Associe un nouvel utilisateur à l'archive. *
* *
@@ -1022,8 +1028,9 @@ static void *g_cdb_archive_process(GCdbArchive *archive)
* *
******************************************************************************/
-void g_cdb_archive_add_client(GCdbArchive *archive, SSL *fd, const rle_string *user)
+void g_cdb_archive_add_client(GCdbArchive *archive, SSL *fd)
{
+ X509 *peer_cert; /* Certificat présenté */
volatile pthread_t *process_id; /* Identifiant de la procédure */
/**
@@ -1051,7 +1058,12 @@ void g_cdb_archive_add_client(GCdbArchive *archive, SSL *fd, const rle_string *u
archive->clients = realloc(archive->clients, ++archive->count * sizeof(cdb_client));
archive->clients[archive->count - 1].ssl_fd = fd;
- dup_into_rle_string(&archive->clients[archive->count - 1].user, get_rle_string(user));
+
+ peer_cert = SSL_get_peer_certificate(fd);
+
+ archive->clients[archive->count - 1].user = X509_NAME_oneline(X509_get_subject_name(peer_cert), NULL, -1);
+
+ X509_free(peer_cert);
/* Démarrage ou redémarrage du processus d'écoute */
@@ -1099,7 +1111,7 @@ static void g_cdb_archive_remove_client(GCdbArchive *archive, size_t index)
g_mutex_lock(&archive->clients_access);
SSL_free(client->ssl_fd);
- exit_rle_string(&client->user);
+ free(client->user);
if ((index + 1) < archive->count)
memmove(&archive->clients[index], &archive->clients[index + 1],
diff --git a/src/analysis/db/cdb.h b/src/analysis/db/cdb.h
index 601b10f..8d4a86b 100644
--- a/src/analysis/db/cdb.h
+++ b/src/analysis/db/cdb.h
@@ -54,7 +54,7 @@ typedef struct _GCdbArchiveClass GCdbArchiveClass;
GType g_cdb_archive_get_type(void);
/* Prépare un client pour une connexion à une BD. */
-GCdbArchive *g_cdb_archive_new(const char *, const rle_string *, const rle_string *, DBError *);
+GCdbArchive *g_cdb_archive_new(const char *, const char *, const rle_string *, DBError *);
/* Enregistre une archive avec tous les éléments à conserver. */
DBError g_cdb_archive_write(const GCdbArchive *);
@@ -67,7 +67,7 @@ int g_cdb_archive_compare_hash(const GCdbArchive *, const rle_string *);
/* Associe un nouvel utilisateur à l'archive. */
-void g_cdb_archive_add_client(GCdbArchive *, SSL *, const rle_string *);
+void g_cdb_archive_add_client(GCdbArchive *, SSL *);
diff --git a/src/analysis/db/certs.c b/src/analysis/db/certs.c
index 41a40b7..a333d9a 100644
--- a/src/analysis/db/certs.c
+++ b/src/analysis/db/certs.c
@@ -252,7 +252,7 @@ static RSA *generate_rsa_key(unsigned int bits, unsigned long e)
* *
******************************************************************************/
-bool make_ca(const char *dir, const char *label, unsigned long valid, const x509_entries *entries)
+bool build_keys_and_ca(const char *dir, const char *label, unsigned long valid, const x509_entries *entries)
{
RSA *rsa; /* Clef RSA pour le certificat */
EVP_PKEY *pk; /* Enveloppe pour clef publique*/
@@ -455,7 +455,7 @@ static bool add_extension_to_req(STACK_OF(X509_EXTENSION) *sk, int nid, /*const
* *
******************************************************************************/
-bool make_request(const char *dir, const char *label, const x509_entries *entries)
+bool build_keys_and_request(const char *dir, const char *label, const x509_entries *entries)
{
RSA *rsa; /* Clef RSA pour le certificat */
EVP_PKEY *pk; /* Enveloppe pour clef publique*/
diff --git a/src/analysis/db/certs.h b/src/analysis/db/certs.h
index 31da82f..132cd7f 100644
--- a/src/analysis/db/certs.h
+++ b/src/analysis/db/certs.h
@@ -49,10 +49,10 @@ bool are_x509_entries_empty(const x509_entries *);
void free_x509_entries(x509_entries *);
/* Crée un certificat de signature racine. */
-bool make_ca(const char *, const char *, unsigned long, const x509_entries *);
+bool build_keys_and_ca(const char *, const char *, unsigned long, const x509_entries *);
/* Crée un certificat pour application. */
-bool make_request(const char *, const char *, const x509_entries *);
+bool build_keys_and_request(const char *, const char *, const x509_entries *);
/* Signe un certificat pour application. */
bool sign_cert(const char *, const char *, const char *, const char *, unsigned long);
diff --git a/src/analysis/db/client.c b/src/analysis/db/client.c
index 24198f6..c608bfa 100644
--- a/src/analysis/db/client.c
+++ b/src/analysis/db/client.c
@@ -37,31 +37,39 @@
#include <i18n.h>
-#include "keymgn.h"
+#include "auth.h"
#include "protocol.h"
#include "misc/rlestr.h"
+#include "../../common/extstr.h"
#include "../../common/io.h"
#include "../../common/xdg.h"
#include "../../core/logs.h"
+/* Format générique des adresses de connexion */
+typedef union _gen_sockaddr_t
+{
+ struct sockaddr_in inet4_addr; /* Adresse d'écoute IPv4 */
+ struct sockaddr_in6 inet6_addr; /* Adresse d'écoute IPv6 */
+ struct sockaddr inet_4_6_addr; /* Adresse d'écoute IPv4/6 */
+
+} gen_sockaddr_t;
+
+
/* Description de client à l'écoute (instance) */
-struct _GDbClient
+struct _GHubClient
{
GObject parent; /* A laisser en premier */
- char *author; /* Utilisateur représenté */
- //char *key_file; /* Accès sa la clef privée */
-
const char *name; /* Désignation du binaire */
rle_string hash; /* Empreinte du binaire lié */
GList *collections; /* Collections d'un binaire */
+ char *working; /* Répertoire de travail */
+
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 */
SSL *tls_fd; /* Même canal, mais sécurisé */
@@ -74,7 +82,7 @@ struct _GDbClient
};
/* Description de client à l'écoute (classe) */
-struct _GDbClientClass
+struct _GHubClientClass
{
GObjectClass parent; /* A laisser en premier */
@@ -82,24 +90,27 @@ struct _GDbClientClass
/* Initialise la classe des descriptions de fichier binaire. */
-static void g_db_client_class_init(GDbClientClass *);
+static void g_hub_client_class_init(GHubClientClass *);
/* Initialise une description de fichier binaire. */
-static void g_db_client_init(GDbClient *);
+static void g_hub_client_init(GHubClient *);
+
+/* Supprime toutes les références externes. */
+static void g_hub_client_dispose(GHubClient *);
/* Procède à la libération totale de la mémoire. */
-static void g_db_client_finalize(GDbClient *);
+static void g_hub_client_finalize(GHubClient *);
/* Démarre réellement la connexion à la base de données. */
-static bool g_db_client_start_common(GDbClient *, char *);
+static bool g_hub_client_start_common(GHubClient *, char *);
/* Assure l'accueil des nouvelles mises à jour. */
-static void *g_db_client_update(GDbClient *);
+static void *g_hub_client_update(GHubClient *);
/* Indique le type défini pour une description de client à l'écoute. */
-G_DEFINE_TYPE(GDbClient, g_db_client, G_TYPE_OBJECT);
+G_DEFINE_TYPE(GHubClient, g_hub_client, G_TYPE_OBJECT);
/******************************************************************************
@@ -114,13 +125,14 @@ G_DEFINE_TYPE(GDbClient, g_db_client, G_TYPE_OBJECT);
* *
******************************************************************************/
-static void g_db_client_class_init(GDbClientClass *klass)
+static void g_hub_client_class_init(GHubClientClass *klass)
{
GObjectClass *object; /* Autre version de la classe */
object = G_OBJECT_CLASS(klass);
- object->finalize = (GObjectFinalizeFunc)g_db_client_finalize;
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_hub_client_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_hub_client_finalize;
}
@@ -137,11 +149,11 @@ static void g_db_client_class_init(GDbClientClass *klass)
* *
******************************************************************************/
-static void g_db_client_init(GDbClient *client)
+static void g_hub_client_init(GHubClient *client)
{
+ client->working = NULL;
+
client->tls_ctx = NULL;
- client->cert_file = NULL;
- client->key_file = NULL;
client->fd = -1;
client->tls_fd = NULL;
@@ -152,6 +164,27 @@ static void g_db_client_init(GDbClient *client)
/******************************************************************************
* *
+* Paramètres : archive = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_hub_client_dispose(GHubClient *client)
+{
+ g_hub_client_stop(client);
+
+ G_OBJECT_CLASS(g_hub_client_parent_class)->dispose(G_OBJECT(client));
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : client = instance d'objet GLib à traiter. *
* *
* Description : Procède à la libération totale de la mémoire. *
@@ -162,36 +195,28 @@ static void g_db_client_init(GDbClient *client)
* *
******************************************************************************/
-static void g_db_client_finalize(GDbClient *client)
+static void g_hub_client_finalize(GHubClient *client)
{
- free(client->author);
-
unset_rle_string(&client->hash);
- assert(client->tls_ctx == NULL);
-
- if (client->cert_file != NULL)
- free(client->cert_file);
+ if (client->working != NULL)
+ free(client->working);
- if (client->key_file != NULL)
- free(client->key_file);
+ assert(client->tls_ctx == NULL);
assert(client->tls_fd == NULL);
if (client->desc != NULL)
free(client->desc);
- G_OBJECT_CLASS(g_db_client_parent_class)->finalize(G_OBJECT(client));
+ G_OBJECT_CLASS(g_hub_client_parent_class)->finalize(G_OBJECT(client));
}
/******************************************************************************
* *
-* Paramètres : author = utilisateur à représenter via le client. *
-* kfile = clef menant à sa clef privée. *
-* name = désignation humaine du binaire associé. *
-* hash = empreinte d'un binaire en cours d'analyse. *
+* Paramètres : hash = empreinte d'un binaire en cours d'analyse. *
* collections = ensemble de collections existantes. *
* *
* Description : Prépare un client pour une connexion à une BD. *
@@ -202,16 +227,11 @@ static void g_db_client_finalize(GDbClient *client)
* *
******************************************************************************/
-GDbClient *g_db_client_new(char *author, char *kfile, const char *name, const char *hash, GList *collections)
+GHubClient *g_hub_client_new(const char *hash, GList *collections)
{
- GDbClient *result; /* Adresse à retourner */
+ GHubClient *result; /* Adresse à retourner */
- result = g_object_new(G_TYPE_DB_CLIENT, NULL);
-
- result->author = author;
- result->key_file = kfile;
-
- result->name = name;
+ result = g_object_new(G_TYPE_HUB_CLIENT, NULL);
init_static_rle_string(&result->hash, hash);
result->collections = collections;
@@ -233,7 +253,7 @@ GDbClient *g_db_client_new(char *author, char *kfile, const char *name, const ch
* *
******************************************************************************/
-bool g_db_client_start_internal(GDbClient *client)
+bool g_hub_client_start_internal(GHubClient *client)
{
bool status; /* Bilan de la connexion */
struct sockaddr_un addr; /* Adresse de transmission */
@@ -242,42 +262,43 @@ bool g_db_client_start_internal(GDbClient *client)
/* Identification du serveur à contacter */
- status = build_tmp_socket("internal-server", &addr);
- if (!status) goto gdcni_error;
+ status = build_internal_server_socket(&addr);
+ if (!status) goto fs_error;
/* Création d'un canal de communication */
client->fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (client->fd == -1)
{
- perror("socket");
- goto gdcni_error;
+ LOG_ERROR_N("socket");
+ goto fs_error;
}
ret = connect(client->fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_un));
if (ret == -1)
{
- perror("connect");
- goto gdcsi_no_listening;
+ LOG_ERROR_N("connect");
+ goto no_listening;
}
asprintf(&desc, "unix://%s", addr.sun_path);
- status = g_db_client_start_common(client, desc);
+ client->working = get_db_working_directory("clients", "standalone", NULL, NULL);
+
+ status = g_hub_client_start_common(client, desc);
if (!status)
- goto gdcsi_no_listening;
+ goto no_listening;
return true;
- gdcsi_no_listening:
+ no_listening:
close(client->fd);
-
- gdcni_error:
-
client->fd = -1;
+ fs_error:
+
return false;
}
@@ -288,6 +309,7 @@ bool g_db_client_start_internal(GDbClient *client)
* Paramètres : client = client pour les accès distants à manipuler. *
* host = hôte à représenter pour le service. *
* port = port de connexion pour les clients. *
+* ipv6 = adopte une préférence pour les adresses IPv6. *
* *
* Description : Démarre la connexion à la base de données distante. *
* *
@@ -297,54 +319,114 @@ bool g_db_client_start_internal(GDbClient *client)
* *
******************************************************************************/
-bool g_db_client_start_remote(GDbClient *client, const char *host, unsigned short port)
+bool g_hub_client_start_remote(GHubClient *client, const char *host, const char *port, bool ipv6)
{
- struct hostent *hp; /* Informations sur l'hôte */
- struct sockaddr_in addr; /* Adresse de transmission */
- int ret; /* Bilan d'un appel */
+ struct addrinfo hints; /* Cadre de connexion souhaité */
+ struct addrinfo *available; /* Cadres de connexion dispos */
+ int ret; /* Bilan d'une consultation */
+ int domain; /* Domaine du canal */
+ struct addrinfo *iter; /* Boucle de parcours */
+ gen_sockaddr_t addr; /* Adresse d'écoute générique */
+ socklen_t sock_len; /* Taille de cette adresse */
char *desc; /* Description du serveur ciblé*/
bool status; /* Bilan de la connexion */
- /* Identification du serveur à contacter */
+ /* Détermination du point d'écoute */
+
+ memset(&hints, 0, sizeof(hints));
+
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
+
+ ret = getaddrinfo(host, port, &hints, &available);
+ if (ret != 0)
+ {
+ LOG_ERROR_GAI_N("getaddrinfo", ret);
+ goto no_target;
+ }
+
+ domain = AF_UNSPEC;
+
+ /**
+ * Premier tour : on essaie de se plier à la demande.
+ */
+
+ for (iter = available; iter != NULL && domain == AF_UNSPEC; iter = iter->ai_next)
+ {
+ if (ipv6 && iter->ai_family != AF_INET6)
+ continue;
- hp = gethostbyname(host);
- if (hp == NULL) return false;
+ if (!ipv6 && iter->ai_family != AF_INET)
+ continue;
+
+ domain = iter->ai_family;
+
+ memcpy(&addr.inet_4_6_addr, iter->ai_addr, iter->ai_addrlen);
+ sock_len = iter->ai_addrlen;
+
+ }
+
+ /**
+ * Second tour : on fait avec ce qu'on a.
+ */
+
+ for (iter = available; iter != NULL && domain == AF_UNSPEC; iter = iter->ai_next)
+ {
+ if (iter->ai_family != AF_INET6 && iter->ai_family != AF_INET)
+ continue;
+
+ domain = iter->ai_family;
+
+ memcpy(&addr.inet_4_6_addr, iter->ai_addr, iter->ai_addrlen);
+ sock_len = iter->ai_addrlen;
+
+ }
- addr.sin_family = hp->h_addrtype;
- memcpy(&addr.sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
+ if (available != NULL)
+ freeaddrinfo(available);
- addr.sin_port = htons(port);
+ if (domain == AF_UNSPEC)
+ {
+ log_variadic_message(LMT_ERROR, _("No suitable address found for %s:%s"), host, port);
+ goto no_target;
+ }
/* Création d'un canal de communication */
- client->fd = socket(AF_INET, SOCK_STREAM, 0);
+ client->fd = socket(domain, SOCK_STREAM, 0);
if (client->fd == -1)
{
- perror("socket");
- return false;
+ LOG_ERROR_N("socket");
+ goto error_socket;
}
- ret = connect(client->fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in));
+ ret = connect(client->fd, (struct sockaddr *)&addr, sock_len);
if (ret == -1)
{
- perror("connect");
- goto gdcsr_no_listening;
+ LOG_ERROR_N("connect");
+ goto no_listening;
}
- asprintf(&desc, "%s:%hu", host, port);
+ asprintf(&desc, "%s:%s", host, port);
- status = g_db_client_start_common(client, desc);
+ client->working = get_db_working_directory("clients", host, port, NULL);
+
+ status = g_hub_client_start_common(client, desc);
if (!status)
- goto gdcsr_no_listening;
+ goto no_listening;
return true;
- gdcsr_no_listening:
+ no_listening:
close(client->fd);
client->fd = -1;
+ error_socket:
+ no_target:
+
return false;
}
@@ -364,26 +446,21 @@ bool g_db_client_start_remote(GDbClient *client, const char *host, unsigned shor
* *
******************************************************************************/
-static bool g_db_client_start_common(GDbClient *client, char *desc)
+static bool g_hub_client_start_common(GHubClient *client, char *desc)
{
const SSL_METHOD *method; /* Mode du canal sécurisé */
+ char *filename; /* Fichier PEM à manipuler */
int ret; /* Bilan d'un appel */
+ char *rootdir; /* Racine pour le client */
packed_buffer out_pbuf; /* Tampon d'émission */
bool status; /* Bilan d'une opération */
- rle_string user; /* Nom d'utilisateur associé */
- GChecksum *checksum; /* Empreinte MD5 à signer */
- unsigned char md5_digest[16]; /* Empreinte MD5 calculée */
- RSA *key; /* Clef pour la signature */
- unsigned char sig[RSA_USED_SIZE]; /* Signature effectuée */
packed_buffer in_pbuf; /* Tampon de réception */
uint32_t data; /* Mot de données lues */
DBError error; /* Validation de la connexion */
client->desc = desc;
- /**
- * Mise en place d'un environnement sécurisé.
- */
+ /* Définition d'un environnement TLS */
method = TLS_client_method();
@@ -395,6 +472,54 @@ static bool g_db_client_start_common(GDbClient *client, char *desc)
goto quick_error;
}
+ filename = strdup(client->working);
+ filename = stradd(filename, "client-cert.pem");
+
+ ret = SSL_CTX_use_certificate_file(client->tls_ctx, filename, SSL_FILETYPE_PEM);
+
+ free(filename);
+
+ if (ret != 1)
+ {
+ LOG_ERROR_OPENSSL;
+ goto tls_error;
+ }
+
+ rootdir = get_db_working_directory("clients", NULL, NULL, NULL);
+
+ filename = strdup(rootdir);
+ filename = stradd(filename, "client-key.pem");
+
+ ret = SSL_CTX_use_PrivateKey_file(client->tls_ctx, filename, SSL_FILETYPE_PEM);
+
+ free(filename);
+ free(rootdir);
+
+ if (ret != 1)
+ {
+ LOG_ERROR_OPENSSL;
+ goto tls_error;
+ }
+
+ /* Validation des certificats */
+
+ SSL_CTX_set_verify(client->tls_ctx, SSL_VERIFY_PEER, NULL);
+
+ filename = strdup(client->working);
+ filename = stradd(filename, "ca-cert.pem");
+
+ ret = SSL_CTX_load_verify_locations(client->tls_ctx, filename, NULL);
+
+ free(filename);
+
+ if (ret != 1)
+ {
+ LOG_ERROR_OPENSSL;
+ goto tls_error;
+ }
+
+ /* Mise en place d'un canal de communication */
+
client->tls_fd = SSL_new(client->tls_ctx);
if (client->tls_fd == NULL)
@@ -410,7 +535,7 @@ static bool g_db_client_start_common(GDbClient *client, char *desc)
if (ret != 1)
{
LOG_ERROR_OPENSSL;
- goto tls_error;
+ goto ssl_error;
}
/**
@@ -418,8 +543,6 @@ static bool g_db_client_start_common(GDbClient *client, char *desc)
* - la commande 'DBC_HELO'.
* - le numéro de version du client.
* - l'empreinte du binaire analysé.
- * - l'identifiant de l'utilisateur effectuant des modifications.
- * - la signature de l'empreinte MD5 de l'identifiant.
*
* Tout ceci est à synchroniser avec la fonction g_db_server_listener().
*/
@@ -435,30 +558,6 @@ static bool g_db_client_start_common(GDbClient *client, char *desc)
status = pack_rle_string(&client->hash, &out_pbuf);
if (!status) goto setup_error;
- dup_into_rle_string(&user, client->author);
-
- status = pack_rle_string(&user, &out_pbuf);
- if (!status) goto setup_error;
-
- checksum = g_checksum_new(G_CHECKSUM_MD5);
- g_checksum_update(checksum, (guchar *)get_rle_string(&user), get_rle_length(&user));
- g_checksum_get_digest(checksum, (guint8 *)md5_digest, (gsize []) { sizeof(md5_digest) });
- g_checksum_free(checksum);
-
- key = load_rsa_key(client->key_file, true);
- if (key == NULL) goto setup_error;
-
- if (!sign_md5_hash(key, md5_digest, sig))
- {
- RSA_free(key);
- goto setup_error;
- }
-
- RSA_free(key);
-
- status = extend_packed_buffer(&out_pbuf, sig, RSA_USED_SIZE, false);
- if (!status) goto setup_error;
-
status = ssl_send_packed_buffer(&out_pbuf, client->tls_fd);
if (!status) goto setup_error;
@@ -522,7 +621,7 @@ static bool g_db_client_start_common(GDbClient *client, char *desc)
client->can_get_updates = false;
- client->update = g_thread_try_new("cdb_client", (GThreadFunc)g_db_client_update, client, NULL);
+ client->update = g_thread_try_new("cdb_client", (GThreadFunc)g_hub_client_update, client, NULL);
if (client->update == NULL)
{
log_variadic_message(LMT_ERROR, _("Failed to start a listening thread for the server '%s'!"),
@@ -543,7 +642,10 @@ static bool g_db_client_start_common(GDbClient *client, char *desc)
exit_packed_buffer(&out_pbuf);
- unset_rle_string(&user);
+ ssl_error:
+
+ SSL_free(client->tls_fd);
+ client->tls_fd = NULL;
tls_error:
@@ -552,9 +654,6 @@ static bool g_db_client_start_common(GDbClient *client, char *desc)
quick_error:
- close(client->fd);
- client->fd = -1;
-
return false;
}
@@ -572,7 +671,7 @@ static bool g_db_client_start_common(GDbClient *client, char *desc)
* *
******************************************************************************/
-static void *g_db_client_update(GDbClient *client)
+static void *g_hub_client_update(GHubClient *client)
{
packed_buffer out_pbuf; /* Tampon d'émission */
bool status; /* Bilan d'une opération */
@@ -617,7 +716,7 @@ static void *g_db_client_update(GDbClient *client)
init_packed_buffer(&in_pbuf);
- while (1)
+ while (client->fd != -1)
{
ret = poll(&fds, 1, -1);
if (ret != 1) continue;
@@ -626,6 +725,14 @@ static void *g_db_client_update(GDbClient *client)
if (fds.revents & POLLNVAL)
break;
+ /**
+ * Même chose, cf. "TCP: When is EPOLLHUP generated?"
+ * https://stackoverflow.com/questions/52976152/tcp-when-is-epollhup-generated/52976327#52976327
+ */
+
+ if (fds.revents & (POLLHUP | POLLRDHUP))
+ break;
+
if (fds.revents & (POLLIN | POLLPRI))
{
reset_packed_buffer(&in_pbuf);
@@ -701,7 +808,7 @@ static void *g_db_client_update(GDbClient *client)
exit:
- g_db_client_stop(client);
+ g_hub_client_stop(client);
exit_packed_buffer(&in_pbuf);
@@ -722,13 +829,14 @@ static void *g_db_client_update(GDbClient *client)
* *
******************************************************************************/
-void g_db_client_stop(GDbClient *client)
+void g_hub_client_stop(GHubClient *client)
{
+ int fd; /* Canal à clôturer */
int ret; /* Bilan d'un appel */
/* Canal de communication */
- if (client->fd != -1)
+ if (client->fd == -1)
{
/**
* Si la fermture est forcée, le thread de traitement va terminer en erreur.
@@ -741,15 +849,20 @@ void g_db_client_stop(GDbClient *client)
return;
}
- ret = close(client->fd);
- if (ret == -1) perror("close");
+ fd = client->fd;
client->fd = -1;
+ ret = close(fd);
+ if (ret == -1) LOG_ERROR_N("close");
+
g_thread_join(client->update);
/* Environnement TLS */
+ SSL_free(client->tls_fd);
+ client->tls_fd = NULL;
+
SSL_CTX_free(client->tls_ctx);
client->tls_ctx = NULL;
@@ -768,7 +881,7 @@ void g_db_client_stop(GDbClient *client)
* *
******************************************************************************/
-int g_db_client_get_fd(GDbClient *client)
+int g_hub_client_get_fd(GHubClient *client)
{
g_mutex_lock(&client->sending_lock);
@@ -789,7 +902,7 @@ int g_db_client_get_fd(GDbClient *client)
* *
******************************************************************************/
-void g_db_client_put_fd(GDbClient *client)
+void g_hub_client_put_fd(GHubClient *client)
{
g_mutex_unlock(&client->sending_lock);
@@ -808,18 +921,18 @@ void g_db_client_put_fd(GDbClient *client)
* *
******************************************************************************/
-bool g_db_client_save(GDbClient *client)
+bool g_hub_client_save(GHubClient *client)
{
bool result; /* Bilan partiel à remonter */
int sent; /* Quantité de données traitées*/
- g_db_client_get_fd(client);
+ g_hub_client_get_fd(client);
sent = SSL_write(client->tls_fd, (uint32_t []) { htobe32(DBC_SAVE) }, sizeof(uint32_t));
result = (sent == sizeof(uint32_t));
- g_db_client_put_fd(client);
+ g_hub_client_put_fd(client);
return result;
@@ -839,21 +952,21 @@ bool g_db_client_save(GDbClient *client)
* *
******************************************************************************/
-bool g_db_client_set_last_active(GDbClient *client, timestamp_t timestamp)
+bool g_hub_client_set_last_active(GHubClient *client, timestamp_t timestamp)
{
bool result; /* Bilan partiel à remonter */
packed_buffer out_pbuf; /* Tampon d'émission */
init_packed_buffer(&out_pbuf);
- g_db_client_get_fd(client);
+ g_hub_client_get_fd(client);
result = extend_packed_buffer(&out_pbuf, (uint32_t []) { DBC_SET_LAST_ACTIVE }, sizeof(uint32_t), true);
if (result)
result = pack_timestamp(&timestamp, &out_pbuf);
- g_db_client_put_fd(client);
+ g_hub_client_put_fd(client);
if (result)
result = ssl_send_packed_buffer(&out_pbuf, client->tls_fd);
diff --git a/src/analysis/db/client.h b/src/analysis/db/client.h
index 23b85f8..66ca6ab 100644
--- a/src/analysis/db/client.h
+++ b/src/analysis/db/client.h
@@ -33,47 +33,47 @@
-#define G_TYPE_DB_CLIENT g_db_client_get_type()
-#define G_DB_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_DB_CLIENT, GDbClient))
-#define G_IS_DB_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_DB_CLIENT))
-#define G_DB_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_DB_CLIENT, GDbClientClass))
-#define G_IS_DB_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_DB_CLIENT))
-#define G_DB_CLIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_DB_CLIENT, GDbClientClass))
+#define G_TYPE_HUB_CLIENT g_hub_client_get_type()
+#define G_HUB_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_HUB_CLIENT, GHubClient))
+#define G_IS_HUB_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_HUB_CLIENT))
+#define G_HUB_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_HUB_CLIENT, GHubClientClass))
+#define G_IS_HUB_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_HUB_CLIENT))
+#define G_HUB_CLIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_HUB_CLIENT, GHubClientClass))
/* Description de client à l'écoute (instance) */
-typedef struct _GDbClient GDbClient;
+typedef struct _GHubClient GHubClient;
/* Description de client à l'écoute (classe) */
-typedef struct _GDbClientClass GDbClientClass;
+typedef struct _GHubClientClass GHubClientClass;
/* Indique le type défini pour une description de client à l'écoute. */
-GType g_db_client_get_type(void);
+GType g_hub_client_get_type(void);
/* Prépare un client pour une connexion à une BD. */
-GDbClient *g_db_client_new(char *, char *, const char *, const char *, GList *);
+GHubClient *g_hub_client_new(const char *, GList *);
/* Démarre la connexion à la base de données interne. */
-bool g_db_client_start_internal(GDbClient *);
+bool g_hub_client_start_internal(GHubClient *);
/* Démarre la connexion à la base de données distante. */
-bool g_db_client_start_remote(GDbClient *, const char *, unsigned short);
+bool g_hub_client_start_remote(GHubClient *, const char *, const char *, bool);
/* Arrête la connexion à la base de données. */
-void g_db_client_stop(GDbClient *);
+void g_hub_client_stop(GHubClient *);
/* Identifie le canal de communication pour envois au serveur. */
-int g_db_client_get_fd(GDbClient *);
+int g_hub_client_get_fd(GHubClient *);
/* Marque le canal de communication comme disponible. */
-void g_db_client_put_fd(GDbClient *);
+void g_hub_client_put_fd(GHubClient *);
/* Effectue une demande de sauvegarde de l'état courant. */
-bool g_db_client_save(GDbClient *);
+bool g_hub_client_save(GHubClient *);
/* Active les éléments en amont d'un horodatage donné. */
-bool g_db_client_set_last_active(GDbClient *, timestamp_t);
+bool g_hub_client_set_last_active(GHubClient *, timestamp_t);
diff --git a/src/analysis/db/keymgn.c b/src/analysis/db/keymgn.c
index 4334896..d2abd7c 100644
--- a/src/analysis/db/keymgn.c
+++ b/src/analysis/db/keymgn.c
@@ -329,10 +329,10 @@ bool register_server_cert(const char *name, const x509_entries *entries)
if (!result)
goto rsc_quick_exit;
- result = make_ca(working, "ca", valid, entries);
+ result = build_keys_and_ca(working, "ca", valid, entries);
if (!result) goto rsc_quick_exit;
- result = make_request(working, "server", entries);
+ result = build_keys_and_request(working, "server", entries);
if (!result) goto rsc_quick_exit;
csr = build_absolute_filename(working, "server-csr.pem");
@@ -384,7 +384,7 @@ bool make_client_sign_request(const char *name, const x509_entries *entries)
result = mkpath(working);
if (result)
- result = make_request(working, "client", entries);
+ result = build_keys_and_request(working, "client", entries);
if (result)
store_identity(entries, true);
diff --git a/src/analysis/db/keymgn.h b/src/analysis/db/keymgn.h
index df4f1f5..24ada61 100644
--- a/src/analysis/db/keymgn.h
+++ b/src/analysis/db/keymgn.h
@@ -31,6 +31,8 @@
#include "certs.h"
+#include "auth.h"
+
/* Charge en mémoire la définition de l'identité courante. */
void load_identity(bool, x509_entries *);
diff --git a/src/analysis/db/protocol.h b/src/analysis/db/protocol.h
index 311a691..1c03d62 100644
--- a/src/analysis/db/protocol.h
+++ b/src/analysis/db/protocol.h
@@ -29,7 +29,7 @@
/**
* Version de la définition courante du protocole.
*/
-#define CDB_PROTOCOL_VERSION 0xc0de0003
+#define CDB_PROTOCOL_VERSION 0xc0de0004
diff --git a/src/analysis/db/server.c b/src/analysis/db/server.c
index deb54e9..bd221d7 100644
--- a/src/analysis/db/server.c
+++ b/src/analysis/db/server.c
@@ -25,6 +25,8 @@
#include <assert.h>
+#include <dirent.h>
+#include <fcntl.h>
#include <malloc.h>
#include <netdb.h>
#include <poll.h>
@@ -33,55 +35,50 @@
#include <arpa/inet.h>
#include <openssl/err.h>
#include <openssl/ssl.h>
+#include <sys/file.h>
#include <i18n.h>
+#include "auth.h"
#include "cdb.h"
-#include "keymgn.h"
#include "protocol.h"
#include "misc/rlestr.h"
+#include "../../common/extstr.h"
#include "../../common/io.h"
#include "../../common/pathname.h"
#include "../../common/xdg.h"
#include "../../core/logs.h"
-#include "../../core/params.h"
-/* Utilisateur enregistré */
-typedef struct _registered_user
-{
- rle_string author; /* Désignation d'utilisateur */
- char *key_file; /* Chemin vers sa clef publique*/
-
-} registered_user;
-
/* Format générique des adresses de connexion */
typedef union _gen_sockaddr_t
{
- struct sockaddr_in inet_addr; /* Adresse d'écoute IPv4 */
struct sockaddr_un unix_addr; /* Adresse d'écoute Unix */
+ struct sockaddr_in inet4_addr; /* Adresse d'écoute IPv4 */
+ struct sockaddr_in6 inet6_addr; /* Adresse d'écoute IPv6 */
+ struct sockaddr inet_4_6_addr; /* Adresse d'écoute IPv4/6 */
} gen_sockaddr_t;
/* Assure que le point de connexion est vierge. */
-typedef bool (* clean_server_socket_cb) (GDbServer *);
+typedef bool (* lock_server_socket_cb) (GHubServer *);
+
+/* Assure que le point de connexion est rendu disponible. */
+typedef void (* unlock_server_socket_cb) (GHubServer *);
/* Description de serveur à l'écoute (instance) */
-struct _GDbServer
+struct _GHubServer
{
GObject parent; /* A laisser en premier */
- registered_user *users; /* Liste d'utilisateurs */
- size_t users_count; /* Nombre d'enregistrés */
+ char *working; /* Répertoire de travail */
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 */
@@ -89,56 +86,60 @@ struct _GDbServer
socklen_t sock_len; /* Taille de cette adresse */
char *desc; /* Désignation du serveur */
- clean_server_socket_cb clean_socket; /* Procédure de nettoyage ? */
-
- char *basedir; /* Répertoire de stockage */
+ lock_server_socket_cb lock_socket; /* Procédure de nettoyage ? */
+ unlock_server_socket_cb unlock_socket; /* Procédure de nettoyage ? */
+ int lock_fd; /* Eventuel verrou d'accès */
GThread *listener; /* Procédure de traitement */
GList *archives; /* Liste des binaires ouverts */
GMutex mutex; /* Verrou pour l'accès */
+ GMutex wait_mutex; /* Accès à la condition */
+ GCond wait_cond; /* Attente de signal */
+
};
/* Description de serveur à l'écoute (classe) */
-struct _GDbServerClass
+struct _GHubServerClass
{
GObjectClass parent; /* A laisser en premier */
};
+/* Indice pour le passage d'arguments */
+static int _ssl_data_index = -1;
+
+
/* Initialise la classe des descriptions de fichier binaire. */
-static void g_db_server_class_init(GDbServerClass *);
+static void g_hub_server_class_init(GHubServerClass *);
/* Initialise une description de fichier binaire. */
-static void g_db_server_init(GDbServer *);
+static void g_hub_server_init(GHubServer *);
/* Supprime toutes les références externes. */
-static void g_db_server_dispose(GDbServer *);
+static void g_hub_server_dispose(GHubServer *);
/* Procède à la libération totale de la mémoire. */
-static void g_db_server_finalize(GDbServer *);
+static void g_hub_server_finalize(GHubServer *);
/* Assure que le point de connexion est vierge. */
-static bool g_db_server_clean_internal_socket(GDbServer *);
+static bool g_hub_server_lock_internal_socket(GHubServer *);
-/* Supprime toute trace d'utilisateur inscrit. */
-static void g_db_server_unregister_all_user(GDbServer *);
+/* Assure que le point de connexion est rendu disponible. */
+static void g_hub_server_unlock_internal_socket(GHubServer *);
-/* Inscrit un nouvel utilisateur comme étant enregistré. */
-static bool g_db_server_register_user(GDbServer *, const char *, char *);
-
-/* Inscrit un nouvel utilisateur comme étant enregistré. */
-static bool g_db_server_is_registered_user(GDbServer *, const rle_string *, unsigned char *);
+/* Vérifie la légitimité d'une connexion sécurisée au serveur. */
+static int g_hub_server_verify(int, X509_STORE_CTX *);
/* Assure l'accueil des nouveaux clients. */
-static void *g_db_server_listener(GDbServer *);
+static void *g_hub_server_listener(GHubServer *);
/* Indique le type défini pour une description de serveur à l'écoute. */
-G_DEFINE_TYPE(GDbServer, g_db_server, G_TYPE_OBJECT);
+G_DEFINE_TYPE(GHubServer, g_hub_server, G_TYPE_OBJECT);
/******************************************************************************
@@ -153,14 +154,14 @@ G_DEFINE_TYPE(GDbServer, g_db_server, G_TYPE_OBJECT);
* *
******************************************************************************/
-static void g_db_server_class_init(GDbServerClass *klass)
+static void g_hub_server_class_init(GHubServerClass *klass)
{
GObjectClass *object; /* Autre version de la classe */
object = G_OBJECT_CLASS(klass);
- object->dispose = (GObjectFinalizeFunc/* ! */)g_db_server_dispose;
- object->finalize = (GObjectFinalizeFunc)g_db_server_finalize;
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_hub_server_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_hub_server_finalize;
}
@@ -177,18 +178,23 @@ static void g_db_server_class_init(GDbServerClass *klass)
* *
******************************************************************************/
-static void g_db_server_init(GDbServer *server)
+static void g_hub_server_init(GHubServer *server)
{
+ server->working = NULL;
+
server->tls_ctx = NULL;
- server->cert_file = NULL;
- server->key_file = NULL;
server->fd = -1;
- server->basedir = NULL;
+ server->lock_socket = NULL;
+ server->unlock_socket = NULL;
+ server->lock_fd = -1;
g_mutex_init(&server->mutex);
+ g_mutex_init(&server->wait_mutex);
+ g_cond_init(&server->wait_cond);
+
}
@@ -204,11 +210,11 @@ static void g_db_server_init(GDbServer *server)
* *
******************************************************************************/
-static void g_db_server_dispose(GDbServer *server)
+static void g_hub_server_dispose(GHubServer *server)
{
GList *iter; /* Boucle de parcours */
- g_db_server_stop(server);
+ g_hub_server_stop(server);
for (iter = g_list_first(server->archives);
iter != NULL;
@@ -220,7 +226,10 @@ static void g_db_server_dispose(GDbServer *server)
g_mutex_clear(&server->mutex);
- G_OBJECT_CLASS(g_db_server_parent_class)->dispose(G_OBJECT(server));
+ g_mutex_clear(&server->wait_mutex);
+ g_cond_clear(&server->wait_cond);
+
+ G_OBJECT_CLASS(g_hub_server_parent_class)->dispose(G_OBJECT(server));
}
@@ -237,32 +246,37 @@ static void g_db_server_dispose(GDbServer *server)
* *
******************************************************************************/
-static void g_db_server_finalize(GDbServer *server)
+static void g_hub_server_finalize(GHubServer *server)
{
- g_db_server_unregister_all_user(server);
+ int ret; /* Bilan d'un appel */
- free(server->desc);
+ if (server->working != NULL)
+ free(server->working);
assert(server->tls_ctx == NULL);
- if (server->cert_file != NULL)
- free(server->cert_file);
+ free(server->desc);
- if (server->key_file != NULL)
- free(server->key_file);
+ if (server->lock_fd != -1)
+ {
+ ret = flock(server->lock_fd, LOCK_UN);
+ if (ret == -1)
+ LOG_ERROR_N("flock");
- if (server->basedir != NULL)
- free(server->basedir);
+ ret = close(server->lock_fd);
+ if (ret == -1)
+ LOG_ERROR_N("close");
- G_OBJECT_CLASS(g_db_server_parent_class)->finalize(G_OBJECT(server));
+ }
+
+ G_OBJECT_CLASS(g_hub_server_parent_class)->finalize(G_OBJECT(server));
}
/******************************************************************************
* *
-* Paramètres : author = utilisateur à représenter via le client. *
-* kfile = clef menant à sa clef publique. *
+* Paramètres : - *
* *
* Description : Prépare un serveur de BD pour les clients internes. *
* *
@@ -272,49 +286,21 @@ static void g_db_server_finalize(GDbServer *server)
* *
******************************************************************************/
-GDbServer *g_db_server_new_internal(const char *author, char *kfile)
+GHubServer *g_hub_server_new_internal(void)
{
- GDbServer *result; /* Adresse à retourner */
+ GHubServer *result; /* Adresse à retourner */
bool status; /* Bilan d'un chargement */
- char *working; /* Répertoire par le client */
- int ret[2]; /* Bilan d'une vérification */
-
- result = g_object_new(G_TYPE_DB_SERVER, NULL);
-
- /* Chargement du profil */
-
- 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");
- ret[0] = access(result->cert_file, R_OK);
- ret[1] = access(result->key_file, R_OK);
+ result = g_object_new(G_TYPE_HUB_SERVER, NULL);
- if (ret[0] != 0 || ret[1] != 0)
- {
- log_variadic_message(LMT_ERROR, _("The serveur certificate is missing in the '%s' directory!"), working);
- log_simple_message(LMT_ERROR, _("Generate it using the menu (Tool > Identity) and restart the program."));
-
- free(working);
-
- goto gdsni_missing_pem;
-
- }
-
- free(working);
+ result->working = get_db_working_directory("servers", "standalone", NULL, NULL);
/* Détermination du point d'écoute */
result->domain = AF_UNIX;
- status = build_tmp_socket("internal-server", &result->addr.unix_addr);
- if (!status) goto gdsni_error;
+ status = build_internal_server_socket(&result->addr.unix_addr);
+ if (!status) goto sock_error;
result->sock_len = sizeof(struct sockaddr_un);
@@ -324,17 +310,12 @@ GDbServer *g_db_server_new_internal(const char *author, char *kfile)
/* Aide pour une sortie propre ? */
- result->clean_socket = g_db_server_clean_internal_socket;
-
- /* Répertoire de stockage */
-
- result->basedir = get_xdg_config_dir("chrysalide" G_DIR_SEPARATOR_S "cdbs");
+ result->lock_socket = g_hub_server_lock_internal_socket;
+ result->unlock_socket = g_hub_server_unlock_internal_socket;
return result;
- gdsni_missing_pem:
-
- gdsni_error:
+ sock_error:
g_object_unref(G_OBJECT(result));
@@ -355,16 +336,42 @@ GDbServer *g_db_server_new_internal(const char *author, char *kfile)
* *
******************************************************************************/
-static bool g_db_server_clean_internal_socket(GDbServer *server)
+static bool g_hub_server_lock_internal_socket(GHubServer *server)
{
bool result; /* Bilan à faire remonter */
char *sock_path; /* Chemin vers le canal UNIX */
+ char *lock_path; /* Chemin vers le verrou */
int ret; /* Bilan d'un appel */
- result = true;
+ result = false;
sock_path = server->addr.unix_addr.sun_path;
+ /* Partie d'exclusivité */
+
+ lock_path = strdup(sock_path);
+ lock_path = stradd(lock_path, ".lock");
+
+ assert(server->lock_fd == -1);
+
+ server->lock_fd = open(lock_path, O_RDONLY | O_CREAT, 0600);
+ if (server->lock_fd == -1)
+ {
+ LOG_ERROR_N("open");
+ goto exit;
+ }
+
+ free(lock_path);
+
+ ret = flock(server->lock_fd, LOCK_EX | LOCK_NB);
+
+ result = (ret == 0);
+
+ if (!result)
+ goto exit;
+
+ /* Partie de nettoye */
+
ret = access(sock_path, F_OK);
if (ret == 0)
@@ -373,12 +380,24 @@ static bool g_db_server_clean_internal_socket(GDbServer *server)
if (ret != 0)
{
- perror("unlink");
+ LOG_ERROR_N("unlink");
+
+ ret = flock(server->lock_fd, LOCK_UN);
+ if (ret == -1)
+ LOG_ERROR_N("flock");
+
+ ret = close(server->lock_fd);
+ if (ret == -1)
+ LOG_ERROR_N("close");
+
result = false;
+
}
}
+ exit:
+
return result;
}
@@ -386,90 +405,164 @@ static bool g_db_server_clean_internal_socket(GDbServer *server)
/******************************************************************************
* *
-* Paramètres : conf = fichier de configuration à interpréter. *
+* Paramètres : server = instance à consulter et nettoyer. *
* *
-* Description : Prépare un serveur de BD pour les clients distants. *
+* Description : Assure que le point de connexion est rendu disponible. *
* *
-* Retour : Structure mise en place ou NULL en cas d'échec. *
+* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
-GDbServer *g_db_server_new_remote(const char *conf)
+static void g_hub_server_unlock_internal_socket(GHubServer *server)
{
- GDbServer *result; /* Adresse à retourner */
+ int ret; /* Bilan d'un appel */
+
+ assert(server->lock_fd != -1);
+
+ ret = flock(server->lock_fd, LOCK_UN);
+ if (ret == -1)
+ LOG_ERROR_N("flock");
- char *host;
- short port;
+ ret = close(server->lock_fd);
+ if (ret == -1)
+ LOG_ERROR_N("close");
+
+ server->lock_fd = -1;
+
+}
- struct hostent *hp; /* Informations sur l'hôte */
+/******************************************************************************
+* *
+* Paramètres : host = désignation du serveur à lancer. *
+* port = port d'écoute à ouvrir. *
+* ipv6 = adopte une préférence pour les adresses IPv6. *
+* *
+* Description : Prépare un serveur de BD pour les clients distants. *
+* *
+* Retour : Structure mise en place ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GHubServer *g_hub_server_new_remote(const char *host, const char *port, bool ipv6)
+{
+ GHubServer *result; /* Adresse à retourner */
+ struct addrinfo hints; /* Cadre de connexion souhaité */
+ struct addrinfo *available; /* Cadres de connexion dispos */
+ int ret; /* Bilan d'une consultation */
+ struct addrinfo *iter; /* Boucle de parcours */
size_t desclen; /* Taille de désignation */
+ struct sockaddr_in *addr4; /* Adresse IPv4 brute */
+ struct sockaddr_in6 *addr6; /* Adresse IPv6 brute */
const char *ip; /* Adresse IPv4 ou IPv6 */
- const char *tmpdir; /* Répertoire de travail */
- bool status; /* Bilan d'un consultation */
- result = g_object_new(G_TYPE_DB_SERVER, NULL);
+ result = g_object_new(G_TYPE_HUB_SERVER, NULL);
- /* Chargement des profils */
+ assert(host != NULL);
+ if (port == NULL)
+ port = "1337";
- /*
- ret = g_db_server_register_user(result, author, kfile);
- if (!ret) goto gdsni_error;
- */
+ result->working = get_db_working_directory("servers", host, port, NULL);
- result->domain = AF_INET;
+ /* Détermination du point d'écoute */
- host = "localhost";
- port = 9999;
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
- /* Détermination du point d'écoute */
+ ret = getaddrinfo(host, port, &hints, &available);
+ if (ret != 0)
+ {
+ LOG_ERROR_GAI_N("getaddrinfo", ret);
+ goto error;
+ }
+
+ result->domain = AF_UNSPEC;
- hp = gethostbyname(host);
- if (hp == NULL)
+ /**
+ * Premier tour : on essaie de se plier à la demande.
+ */
+
+ for (iter = available; iter != NULL && result->domain == AF_UNSPEC; iter = iter->ai_next)
{
- perror("gethostbyname");
- goto gdsn_error;
+ if (ipv6 && iter->ai_family != AF_INET6)
+ continue;
+
+ if (!ipv6 && iter->ai_family != AF_INET)
+ continue;
+
+ result->domain = iter->ai_family;
+
+ memcpy(&result->addr.inet_4_6_addr, iter->ai_addr, iter->ai_addrlen);
+ result->sock_len = iter->ai_addrlen;
+
}
- result->addr.inet_addr.sin_family = hp->h_addrtype;
- memcpy(&result->addr.inet_addr.sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
+ /**
+ * Second tour : on fait avec ce qu'on a.
+ */
- result->addr.inet_addr.sin_port = htons(port);
+ for (iter = available; iter != NULL && result->domain == AF_UNSPEC; iter = iter->ai_next)
+ {
+ if (iter->ai_family != AF_INET6 && iter->ai_family != AF_INET)
+ continue;
- result->sock_len = sizeof(struct sockaddr_in);
+ result->domain = iter->ai_family;
- desclen = INET6_ADDRSTRLEN + 1 + 5 + 1;
- result->desc = calloc(desclen, sizeof(char));
+ memcpy(&result->addr.inet_4_6_addr, iter->ai_addr, iter->ai_addrlen);
+ result->sock_len = iter->ai_addrlen;
- ip = inet_ntop(AF_INET, &result->addr.inet_addr.sin_addr, result->desc, INET6_ADDRSTRLEN);
- if (ip == NULL)
+ }
+
+ if (available != NULL)
+ freeaddrinfo(available);
+
+ if (result->domain == AF_UNSPEC)
{
- perror("inet_ntop");
- goto gdsn_error;
+ log_variadic_message(LMT_ERROR, _("No suitable address found for %s:%s"), host, port);
+ goto error;
}
/* Désignation humaine */
- snprintf(result->desc + strlen(ip), 1 + 5, ":%hu", port);
+ desclen = INET6_ADDRSTRLEN + 1 + strlen(port) + 1;
+ result->desc = calloc(desclen, sizeof(char));
- /* Aide pour une sortie propre ? */
+ if (result->domain == AF_INET)
+ {
+ addr4 = (struct sockaddr_in *)&result->addr.inet_4_6_addr;
+ ip = inet_ntop(result->domain, &addr4->sin_addr, result->desc, INET6_ADDRSTRLEN);
+ }
- result->clean_socket = NULL;
+ else if (result->domain == AF_INET6)
+ {
+ addr6 = (struct sockaddr_in6 *)&result->addr.inet_4_6_addr;
+ ip = inet_ntop(result->domain, &addr6->sin6_addr, result->desc, INET6_ADDRSTRLEN);
+ }
- /* Répertoire de stockage */
+ else
+ assert(false);
- status = g_generic_config_get_value(get_main_configuration(), MPK_TMPDIR, &tmpdir);
- if (!status) goto gdsn_error;
+ if (ip == NULL)
+ {
+ LOG_ERROR_N("inet_ntop");
+ goto error;
+ }
- result->basedir = strdup(tmpdir);
+ log_variadic_message(LMT_INFO, _("Resolved server IP: %s"), ip);
+
+ snprintf(result->desc + strlen(ip), 1 + strlen(port) + 1, ":%s", port);
return result;
- gdsn_error:
+ error:
g_object_unref(G_OBJECT(result));
@@ -480,112 +573,126 @@ GDbServer *g_db_server_new_remote(const char *conf)
/******************************************************************************
* *
-* Paramètres : server = serveur pour les accès distants à manipuler. *
+* Paramètres : preverify_ok = état de la prévalidation. *
+* ctx = contexte de la certification en cours. *
* *
-* Description : Supprime toute trace d'utilisateur inscrit. *
+* Description : Vérifie la légitimité d'une connexion sécurisée au serveur. *
* *
-* Retour : - *
+* Retour : 1 si la connexion est validée, 0 sinon. *
* *
* Remarques : - *
* *
******************************************************************************/
-static void g_db_server_unregister_all_user(GDbServer *server)
+static int g_hub_server_verify(int preverify_ok, X509_STORE_CTX *ctx)
{
- size_t i; /* Boucle de parcours */
+ int result; /* Bilan à retourner */
+ X509 *peer_cert; /* Certificat côté client */
+ SSL *ssl; /* Structure de connexion SLL */
+ SSL_CTX *ssl_ctx; /* Contexte SSL du serveur */
+ GHubServer *server; /* Serveur concerné */
+ char *filename; /* Chemin d'accès reconstruit */
+ FILE *stream; /* Flux ouvert en lecture */
+ X509 *ca_cert; /* Certificat CA du serveur */
+ int status; /* Bilan d'une comparaison */
+ char *authorized_dir; /* Répertoire des autorisations*/
+ DIR *dir; /* Répertoire à parcourir */
+ struct dirent *entry; /* Elément trouvé */
+ X509 *authorized_cert; /* Certificat de client validé */
- for (i = 0; i < server->users_count; i++)
- {
- exit_rle_string(&server->users[i].author);
- free(server->users[i].key_file);
- }
+ result = 0;
- if (server->users != NULL)
- free(server->users);
+ peer_cert = X509_STORE_CTX_get_current_cert(ctx);
- server->users = NULL;
- server->users_count = 0;
+ /* Récupération du serveur interne */
-}
+ ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
+ ssl_ctx = SSL_get_SSL_CTX(ssl);
+ server = SSL_CTX_get_ex_data(ssl_ctx, _ssl_data_index);
+ assert(server != NULL);
-/******************************************************************************
-* *
-* Paramètres : server = serveur pour les accès distants à manipuler. *
-* author = utilisateur à représenter via le client. *
-* kfile = clef menant à sa clef publique. *
-* *
-* Description : Inscrit un nouvel utilisateur comme étant enregistré. *
-* *
-* Retour : Bilan de l'inscription. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
+ /* Test du certificat d'autorité */
-static bool g_db_server_register_user(GDbServer *server, const char *author, char *kfile)
-{
- if (strlen(author) == 0)
- return false;
+ filename = strdup(server->working);
+ filename = stradd(filename, "ca-cert.pem");
- server->users = realloc(server->users, ++server->users_count * sizeof(registered_user));
+ stream = fopen(filename, "rb");
+ if (stream == NULL) goto authorized;
- dup_into_rle_string(&server->users[server->users_count - 1].author, author);
- server->users[server->users_count - 1].key_file = kfile;
+ ca_cert = PEM_read_X509(stream, NULL, NULL, NULL);
- return true;
+ fclose(stream);
-}
+ status = X509_cmp(peer_cert, ca_cert);
+ if (status == 0)
+ result = 1;
-/******************************************************************************
-* *
-* Paramètres : server = serveur pour les accès distants à manipuler. *
-* author = utilisateur à représenter via le client. *
-* sig = signature d'utilisateur à valider. *
-* *
-* Description : Inscrit un nouvel utilisateur comme étant enregistré. *
-* *
-* Retour : true si l'utilisateur est bien enregistré, false sinon. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
+ X509_free(ca_cert);
-static bool g_db_server_is_registered_user(GDbServer *server, const rle_string *author, unsigned char *sig)
-{
- bool result; /* Bilan à retourner */
- size_t i; /* Boucle de parcours */
- GChecksum *checksum; /* Empreinte MD5 à signer */
- unsigned char md5_digest[16]; /* Empreinte MD5 calculée */
- RSA *key; /* Clef pour la signature */
+ free(filename);
- result = false;
+ if (result == 1)
+ goto verified;
+
+ /* Détermination du répertoire des autorisations */
+
+ authorized:
+
+ authorized_dir = strdup(server->working);
+ authorized_dir = stradd(authorized_dir, "authorized" G_DIR_SEPARATOR_S);
- /* Recherche de l'utilisateur */
+ dir = opendir(authorized_dir);
+ if (dir == NULL) goto verified;
+
+ /* Recherche d'une entrée de validation */
+
+ while (result == 0)
+ {
+ entry = readdir(dir);
+
+ if (entry == NULL)
+ {
+ if (errno != 0)
+ LOG_ERROR_N("readdir");
- for (i = 0; i < server->users_count; i++)
- if (cmp_rle_string(&server->users[i].author, author) == 0)
break;
- if (i == server->users_count)
- goto gdsiru_exit;
+ }
+
+ if (entry->d_type != DT_REG && entry->d_type != DT_LNK) continue;
+ if (entry->d_name[0] == '.') continue;
+
+ filename = strdup(authorized_dir);
+ filename = stradd(filename, G_DIR_SEPARATOR_S);
+ filename = stradd(filename, entry->d_name);
+
+ stream = fopen(filename, "rb");
+ if (stream == NULL) goto next;
- /* Validation de la signature présentée */
+ authorized_cert = PEM_read_X509(stream, NULL, NULL, NULL);
- checksum = g_checksum_new(G_CHECKSUM_MD5);
- g_checksum_update(checksum, (guchar *)get_rle_string(author), get_rle_length(author));
- g_checksum_get_digest(checksum, (guint8 *)md5_digest, (gsize []) { sizeof(md5_digest) });
- g_checksum_free(checksum);
+ fclose(stream);
- key = load_rsa_key(server->users[i].key_file, false);
- if (key == NULL) goto gdsiru_exit;
+ status = X509_cmp(peer_cert, authorized_cert);
- result = verify_md5_hash(key, md5_digest, sig);
+ if (status == 0)
+ result = 1;
- RSA_free(key);
+ X509_free(authorized_cert);
- gdsiru_exit:
+ next:
+
+ free(filename);
+
+ }
+
+ /* Sortie */
+
+ closedir(dir);
+
+ verified:
return result;
@@ -604,7 +711,7 @@ static bool g_db_server_is_registered_user(GDbServer *server, const rle_string *
* *
******************************************************************************/
-static void *g_db_server_listener(GDbServer *server)
+static void *g_hub_server_listener(GHubServer *server)
{
struct pollfd fds; /* Surveillance des flux */
int ret; /* Bilan d'un appel */
@@ -612,29 +719,37 @@ static void *g_db_server_listener(GDbServer *server)
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 */
char *peer_name; /* Désignation du correspondant*/
DBError error; /* Validation de la connexion */
GCdbArchive *archive; /* Destinataire final du client*/
+ GList *iter; /* Boucle de parcours */
packed_buffer in_pbuf; /* Tampon de réception */
bool status; /* Bilan d'une opération */
uint32_t cmd; /* Commande initiale lue */
uint32_t version; /* Version du client lue */
- unsigned char sig[RSA_USED_SIZE]; /* Signature effectuée */
- GList *iter; /* Boucle de parcours */
+ char *basedir; /* Répertoire de stockage */
+ char *tmpdir; /* Répertoire de travail */
packed_buffer out_pbuf; /* Tampon d'émission */
fds.fd = server->fd;
fds.events = POLLIN | POLLPRI;
- while (1)
+ while (server->fd != -1)
{
ret = poll(&fds, 1, -1);
if (ret != 1) continue;
/* Le canal est fermé, une sortie doit être demandée... */
- if (fds.revents & POLLHUP)
+ if (fds.revents & POLLNVAL)
+ break;
+
+ /**
+ * Même chose, cf. "TCP: When is EPOLLHUP generated?"
+ * https://stackoverflow.com/questions/52976152/tcp-when-is-epollhup-generated/52976327#52976327
+ */
+
+ if (fds.revents & (POLLHUP | POLLRDHUP))
break;
if (fds.revents & (POLLIN | POLLPRI))
@@ -642,7 +757,7 @@ static void *g_db_server_listener(GDbServer *server)
fd = accept(server->fd, (struct sockaddr *)&peer, (socklen_t []) { sizeof(gen_sockaddr_t) });
if (fd == -1)
{
- perror("accept");
+ LOG_ERROR_N("accept");
continue;
}
@@ -667,7 +782,6 @@ static void *g_db_server_listener(GDbServer *server)
/* Initialisation à vide pour les sorties en erreur */
init_dynamic_rle_string(&hash, NULL);
- init_dynamic_rle_string(&user, NULL);
/* Construction d'une représentation */
@@ -678,14 +792,29 @@ static void *g_db_server_listener(GDbServer *server)
{
peer_name = calloc(INET6_ADDRSTRLEN + 1 + 5 + 1, sizeof(char));
- ip = inet_ntop(AF_INET, &peer.inet_addr.sin_addr, peer_name, INET6_ADDRSTRLEN);
+ ip = inet_ntop(AF_INET, &peer.inet4_addr.sin_addr, peer_name, INET6_ADDRSTRLEN);
+ if (ip == NULL)
+ {
+ LOG_ERROR_N("inet_ntop");
+ goto id_error;
+ }
+
+ snprintf(peer_name + strlen(ip), 1 + 5, ":%hu", ntohs(peer.inet4_addr.sin_port));
+
+ }
+
+ else if (*((sa_family_t *)&peer) == AF_INET6)
+ {
+ peer_name = calloc(INET6_ADDRSTRLEN + 1 + 5 + 1, sizeof(char));
+
+ ip = inet_ntop(AF_INET6, &peer.inet6_addr.sin6_addr, peer_name, INET6_ADDRSTRLEN);
if (ip == NULL)
{
- perror("inet_ntop");
+ LOG_ERROR_N("inet_ntop");
goto id_error;
}
- snprintf(peer_name + strlen(ip), 1 + 5, ":%hu", ntohs(peer.inet_addr.sin_port));
+ snprintf(peer_name + strlen(ip), 1 + 5, ":%hu", ntohs(peer.inet6_addr.sin6_port));
}
@@ -695,13 +824,13 @@ static void *g_db_server_listener(GDbServer *server)
error = DBE_NONE;
archive = NULL;
+ iter = NULL;
+
/**
* Le premier "paquet" reçu de la part d'un client doit contenir les informations suivantes :
* - la commande 'DBC_HELO'.
* - le numéro de version du client.
* - l'empreinte du binaire analysé.
- * - l'identifiant de l'utilisateur effectuant des modifications.
- * - la signature de l'empreinte MD5 de l'identifiant.
*
* Tout ceci est à synchroniser avec la fonction g_db_client_start().
*/
@@ -744,24 +873,6 @@ static void *g_db_server_listener(GDbServer *server)
goto error_sending;
}
- status = unpack_rle_string(&user, &in_pbuf);
- if (!status)
- {
- log_variadic_message(LMT_ERROR, _("Error while getting the user name from '%s'..."),
- peer_name);
- error = DBE_BAD_EXCHANGE;
- goto error_sending;
- }
-
- status = extract_packed_buffer(&in_pbuf, sig, RSA_USED_SIZE, false);
- if (!status)
- {
- log_variadic_message(LMT_ERROR, _("Error while getting the signature from '%s'..."),
- peer_name);
- error = DBE_BAD_EXCHANGE;
- goto error_sending;
- }
-
if (cmd != DBC_HELO)
{
log_variadic_message(LMT_ERROR, _("The client from '%s' did not introduce itself!"),
@@ -786,21 +897,6 @@ static void *g_db_server_listener(GDbServer *server)
goto error_sending;
}
- if (is_rle_string_empty(&user))
- {
- log_variadic_message(LMT_ERROR, _("No user is associated with the client from '%s'..."),
- peer_name);
- error = DBE_BAD_EXCHANGE;
- 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 error_sending;
- }
-
/**
* On met en place le maximum ici, de manière à pouvoir indiquer une erreur
* en cas d'échec, et être le plus précis possible dans la courte réponse.
@@ -818,7 +914,19 @@ static void *g_db_server_listener(GDbServer *server)
}
if (iter == NULL)
- archive = g_cdb_archive_new(server->basedir, &hash, &user, &error);
+ {
+ basedir = strdup(server->working);
+ basedir = stradd(basedir, "cdbs" G_DIR_SEPARATOR_S);
+
+ tmpdir = strdup(server->working);
+ tmpdir = stradd(tmpdir, "tmp" G_DIR_SEPARATOR_S);
+
+ archive = g_cdb_archive_new(basedir, tmpdir, &hash, &error);
+
+ free(tmpdir);
+ free(basedir);
+
+ }
/**
* Le serveur doit répondre pour un message type :
@@ -856,14 +964,13 @@ static void *g_db_server_listener(GDbServer *server)
if (iter == NULL)
server->archives = g_list_append(server->archives, archive);
- g_cdb_archive_add_client(archive, tls_fd, &user);
+ g_cdb_archive_add_client(archive, tls_fd);
exit_packed_buffer(&out_pbuf);
free(peer_name);
exit_rle_string(&hash);
- exit_rle_string(&user);
continue;
@@ -884,7 +991,6 @@ static void *g_db_server_listener(GDbServer *server)
free(peer_name);
exit_rle_string(&hash);
- exit_rle_string(&user);
invalid_conn:
@@ -898,6 +1004,8 @@ static void *g_db_server_listener(GDbServer *server)
}
+ g_hub_server_stop(server);
+
return NULL;
}
@@ -905,7 +1013,9 @@ static void *g_db_server_listener(GDbServer *server)
/******************************************************************************
* *
-* Paramètres : server = serveur pour les accès distants à manipuler. *
+* Paramètres : server = serveur pour les accès distants à manipuler. *
+* backlog = nombre de connexions maximal. *
+* keep = conservation du serveur en avant plan. *
* *
* Description : Démarre le serveur de base de données. *
* *
@@ -915,12 +1025,16 @@ static void *g_db_server_listener(GDbServer *server)
* *
******************************************************************************/
-bool g_db_server_start(GDbServer *server)
+ServerStartStatus g_hub_server_start(GHubServer *server, int backlog, bool keep)
{
+ ServerStartStatus result; /* Bilan à retourner */
const SSL_METHOD *method; /* Mode du canal sécurisé */
+ char *filename; /* Fichier PEM à manipuler */
int ret; /* Bilan d'un appel */
+ STACK_OF(X509_NAME) *ca_cert; /* Certificat de l'autorité */
bool status; /* Bilan d'un nettoyage */
- int backlog; /* Nombre de connexions maximal*/
+
+ result = SSS_FAILURE;
/* Définition d'un environnement TLS */
@@ -934,7 +1048,12 @@ bool g_db_server_start(GDbServer *server)
goto quick_error;
}
- ret = SSL_CTX_use_certificate_file(server->tls_ctx, server->cert_file, SSL_FILETYPE_PEM);
+ filename = strdup(server->working);
+ filename = stradd(filename, "server-cert.pem");
+
+ ret = SSL_CTX_use_certificate_file(server->tls_ctx, filename, SSL_FILETYPE_PEM);
+
+ free(filename);
if (ret != 1)
{
@@ -942,7 +1061,12 @@ bool g_db_server_start(GDbServer *server)
goto tls_error;
}
- ret = SSL_CTX_use_PrivateKey_file(server->tls_ctx, server->key_file, SSL_FILETYPE_PEM);
+ filename = strdup(server->working);
+ filename = stradd(filename, "server-key.pem");
+
+ ret = SSL_CTX_use_PrivateKey_file(server->tls_ctx, filename, SSL_FILETYPE_PEM);
+
+ free(filename);
if (ret != 1)
{
@@ -958,52 +1082,99 @@ bool g_db_server_start(GDbServer *server)
goto tls_error;
}
+ /* Validation des certificats */
+
+ if (_ssl_data_index == -1)
+ {
+ _ssl_data_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);
+ assert(_ssl_data_index != -1);
+ }
+
+ ret = SSL_CTX_set_ex_data(server->tls_ctx, _ssl_data_index, server);
+ if (ret != 1)
+ {
+ LOG_ERROR_OPENSSL;
+ goto tls_error;
+ }
+
+ SSL_CTX_set_verify(server->tls_ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, g_hub_server_verify);
+
+ filename = strdup(server->working);
+ filename = stradd(filename, "ca-cert.pem");
+
+ ca_cert = SSL_load_client_CA_file(filename);
+
+ free(filename);
+
+ if (ca_cert == NULL)
+ {
+ LOG_ERROR_OPENSSL;
+ goto tls_error;
+ }
+
+ SSL_CTX_set_client_CA_list(server->tls_ctx, ca_cert);
+
/* Mise en place d'un canal de communication */
server->fd = socket(server->domain, SOCK_STREAM, 0);
if (server->fd == -1)
{
- perror("socket");
+ LOG_ERROR_N("socket");
return false;
}
ret = setsockopt(server->fd, SOL_SOCKET, SO_REUSEADDR, (int []) { 1 }, sizeof(int));
if (ret == -1)
{
- perror("setsockopt");
- goto gdss_error;
+ LOG_ERROR_N("setsockopt");
+ goto network_error;
}
- if (server->clean_socket != NULL)
+ if (server->lock_socket != NULL)
{
- status = server->clean_socket(server);
- if (!status) goto gdss_error;
+ status = server->lock_socket(server);
+ if (!status)
+ {
+ result = SSS_ALREADY_RUNNING;
+ goto network_error;
+ }
+
}
ret = bind(server->fd, (struct sockaddr *)&server->addr, server->sock_len);
if (ret == -1)
{
- perror("bind");
- goto gdss_error;
+ LOG_ERROR_N("bind");
+ goto network_error;
}
- if (!g_generic_config_get_value(get_main_configuration(), MPK_SERVER_BACKLOG, &backlog))
- goto gdss_error;
-
ret = listen(server->fd, backlog);
if (ret == -1)
{
- perror("listen");
- goto gdss_error;
+ LOG_ERROR_N("listen");
+ goto network_error;
}
- server->listener = g_thread_new("cdb_listener", (GThreadFunc)g_db_server_listener, server);
+ if (!keep)
+ {
+ ret = daemon(1, 1);
+ if (ret != 0)
+ {
+ LOG_ERROR_N("daemon");
+ goto network_error;
+ }
+
+ }
+
+ server->listener = g_thread_new("cdb_listener", (GThreadFunc)g_hub_server_listener, server);
log_variadic_message(LMT_PROCESS, _("Server started and listening at %s"), server->desc);
- return true;
+ result = SSS_SUCCESS;
- gdss_error:
+ return result;
+
+ network_error:
close(server->fd);
server->fd = -1;
@@ -1015,7 +1186,30 @@ bool g_db_server_start(GDbServer *server)
quick_error:
- return false;
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : server = serveur pour les accès distants à consulter. *
+* *
+* Description : Attend l'arrête du serveur de base de données. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_hub_server_wait_for_stop(GHubServer *server)
+{
+ g_mutex_lock(&server->wait_mutex);
+
+ g_cond_wait(&server->wait_cond, &server->wait_mutex);
+
+ g_mutex_unlock(&server->wait_mutex);
}
@@ -1032,34 +1226,52 @@ bool g_db_server_start(GDbServer *server)
* *
******************************************************************************/
-void g_db_server_stop(GDbServer *server)
+void g_hub_server_stop(GHubServer *server)
{
+ int fd; /* Canal à clôturer */
int ret; /* Bilan d'un appel */
/* Canal de communication */
if (server->fd == -1)
{
- assert(server->tls_ctx == NULL);
+ /**
+ * Si la fermture est forcée, le thread de traitement va terminer en erreur.
+ * Donc cette fonction sera appelée deux fois. Seule la première va affecter
+ * le contexte, donc on le peut pas s'assurer de la condition suivante dans
+ * tous les cas.
+ */
+
+ /*assert(client->tls_ctx == NULL);*/
return;
}
- ret = shutdown(server->fd, SHUT_RDWR);
- if (ret == -1) perror("shutdown");
+ fd = server->fd;
- g_thread_join(server->listener);
+ server->fd = -1;
- ret = close(server->fd);
- if (ret == -1) perror("close");
+ ret = shutdown(fd, SHUT_RDWR);
+ if (ret == -1) LOG_ERROR_N("shutdown");
- server->fd = -1;
+ ret = close(fd);
+ if (ret == -1) LOG_ERROR_N("close");
+
+ g_thread_join(server->listener);
+
+ /* Verrou d'accès */
- if (server->clean_socket != NULL)
- server->clean_socket(server);
+ if (server->unlock_socket != NULL)
+ server->unlock_socket(server);
/* Environnement TLS */
SSL_CTX_free(server->tls_ctx);
server->tls_ctx = NULL;
+ /* Fin de service */
+
+ g_mutex_lock(&server->wait_mutex);
+ g_cond_signal(&server->wait_cond);
+ g_mutex_unlock(&server->wait_mutex);
+
}
diff --git a/src/analysis/db/server.h b/src/analysis/db/server.h
index 5be7886..44aef54 100644
--- a/src/analysis/db/server.h
+++ b/src/analysis/db/server.h
@@ -30,35 +30,47 @@
-#define G_TYPE_DB_SERVER g_db_server_get_type()
-#define G_DB_SERVER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_DB_SERVER, GDbServer))
-#define G_IS_DB_SERVER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_DB_SERVER))
-#define G_DB_SERVER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_DB_SERVER, GDbServerClass))
-#define G_IS_DB_SERVER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_DB_SERVER))
-#define G_DB_SERVER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_DB_SERVER, GDbServerClass))
+#define G_TYPE_HUB_SERVER g_hub_server_get_type()
+#define G_HUB_SERVER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_HUB_SERVER, GHubServer))
+#define G_IS_HUB_SERVER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_HUB_SERVER))
+#define G_HUB_SERVER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_HUB_SERVER, GHubServerClass))
+#define G_IS_HUB_SERVER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_HUB_SERVER))
+#define G_HUB_SERVER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_HUB_SERVER, GHubServerClass))
/* Description de serveur à l'écoute (instance) */
-typedef struct _GDbServer GDbServer;
+typedef struct _GHubServer GHubServer;
/* Description de serveur à l'écoute (classe) */
-typedef struct _GDbServerClass GDbServerClass;
+typedef struct _GHubServerClass GHubServerClass;
/* Indique le type défini pour une description de serveur à l'écoute. */
-GType g_db_server_get_type(void);
+GType g_hub_server_get_type(void);
/* Prépare un serveur de BD pour les clients internes. */
-GDbServer *g_db_server_new_internal(const char *, char *);
+GHubServer *g_hub_server_new_internal(void);
/* Prépare un serveur de BD pour les clients distants. */
-GDbServer *g_db_server_new_remote(const char *);
+GHubServer *g_hub_server_new_remote(const char *, const char *, bool);
+
+/* Bilan du lancement d'un serveur */
+typedef enum _ServerStartStatus
+{
+ SSS_FAILURE, /* Echec du démarrage */
+ SSS_SUCCESS, /* Serveur démarré */
+ SSS_ALREADY_RUNNING, /* Instance déjà en place */
+
+} ServerStartStatus;
/* Démarre le serveur de base de données. */
-bool g_db_server_start(GDbServer *);
+ServerStartStatus g_hub_server_start(GHubServer *, int, bool);
+
+/* Attend l'arrête du serveur de base de données. */
+void g_hub_server_wait_for_stop(GHubServer *);
/* Arrête le serveur de base de données. */
-void g_db_server_stop(GDbServer *);
+void g_hub_server_stop(GHubServer *);