summaryrefslogtreecommitdiff
path: root/src/analysis/db
diff options
context:
space:
mode:
Diffstat (limited to 'src/analysis/db')
-rw-r--r--src/analysis/db/Makefile.am14
-rw-r--r--src/analysis/db/admin.c501
-rw-r--r--src/analysis/db/admin.h68
-rw-r--r--src/analysis/db/analyst-int.h76
-rw-r--r--src/analysis/db/analyst.c1418
-rw-r--r--src/analysis/db/analyst.h115
-rw-r--r--src/analysis/db/auth.c152
-rw-r--r--src/analysis/db/auth.h5
-rw-r--r--src/analysis/db/backend-int.h68
-rw-r--r--src/analysis/db/backend.c267
-rw-r--r--src/analysis/db/backend.h56
-rw-r--r--src/analysis/db/cdb.c822
-rw-r--r--src/analysis/db/cdb.h18
-rw-r--r--src/analysis/db/certs.c317
-rw-r--r--src/analysis/db/certs.h6
-rw-r--r--src/analysis/db/client-int.h79
-rw-r--r--src/analysis/db/client.c1090
-rw-r--r--src/analysis/db/client.h39
-rw-r--r--src/analysis/db/collection.c16
-rw-r--r--src/analysis/db/collection.h16
-rw-r--r--src/analysis/db/controller.c481
-rw-r--r--src/analysis/db/controller.h59
-rw-r--r--src/analysis/db/item-int.h4
-rw-r--r--src/analysis/db/item.c12
-rw-r--r--src/analysis/db/item.h4
-rw-r--r--src/analysis/db/items/Makefile.am11
-rw-r--r--src/analysis/db/items/bookmark.c8
-rw-r--r--src/analysis/db/items/comment.c10
-rw-r--r--src/analysis/db/items/move.c20
-rw-r--r--src/analysis/db/items/switcher.c8
-rw-r--r--src/analysis/db/misc/Makefile.am11
-rw-r--r--src/analysis/db/misc/rlestr.c19
-rw-r--r--src/analysis/db/misc/rlestr.h4
-rw-r--r--src/analysis/db/misc/snapshot.c8
-rw-r--r--src/analysis/db/misc/snapshot.h8
-rw-r--r--src/analysis/db/misc/timestamp.c4
-rw-r--r--src/analysis/db/misc/timestamp.h4
-rw-r--r--src/analysis/db/protocol.h131
-rw-r--r--src/analysis/db/server.c450
-rw-r--r--src/analysis/db/snapshot.c113
-rw-r--r--src/analysis/db/snapshot.h19
41 files changed, 4938 insertions, 1593 deletions
diff --git a/src/analysis/db/Makefile.am b/src/analysis/db/Makefile.am
index 3edfb09..b9325e0 100644
--- a/src/analysis/db/Makefile.am
+++ b/src/analysis/db/Makefile.am
@@ -3,32 +3,34 @@ noinst_LTLIBRARIES = libanalysisdb.la
libanalysisdb_la_SOURCES = \
+ admin.h admin.c \
+ analyst.h analyst.c \
auth.h auth.c \
+ backend-int.h \
+ backend.h backend.c \
cdb.h cdb.c \
certs.h certs.c \
+ client-int.h \
client.h client.c \
collection-int.h \
collection.h collection.c \
+ controller.h controller.c \
item-int.h \
item.h item.c \
protocol.h \
server.h server.c \
snapshot.h snapshot.c
+libanalysisdb_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBARCHIVE_CFLAGS) $(LIBSQLITE_CFLAGS) $(LIBSSL_CFLAGS)
+
libanalysisdb_la_LIBADD = \
items/libanalysisdbitems.la \
misc/libanalysisdbmisc.la
-libanalysisdb_la_LDFLAGS = $(LIBSSL_LIBS)
-
devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
dev_HEADERS = $(libanalysisdb_la_SOURCES:%c=)
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBARCHIVE_CFLAGS) $(LIBSQLITE_CFLAGS) $(LIBSSL_CFLAGS)
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
SUBDIRS = items misc
diff --git a/src/analysis/db/admin.c b/src/analysis/db/admin.c
new file mode 100644
index 0000000..024cbed
--- /dev/null
+++ b/src/analysis/db/admin.c
@@ -0,0 +1,501 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * admin.c - connexion en administrateur à un serveur Chrysalide
+ *
+ * Copyright (C) 2014-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 "admin.h"
+
+
+#include <assert.h>
+#include <malloc.h>
+#include <poll.h>
+#include <string.h>
+
+
+#include "client-int.h"
+#include "../../common/leb128.h"
+#include "../../core/logs.h"
+
+
+
+/* Description de client à l'écoute (instance) */
+struct _GAdminClient
+{
+ GHubClient parent; /* A laisser en premier */
+
+ char **binaries; /* Liste de binaires existants*/
+ size_t binaries_count; /* Taille de cette liste */
+ GMutex binaries_lock; /* Concurrence des accès */
+
+};
+
+/* Description de client à l'écoute (classe) */
+struct _GAdminClientClass
+{
+ GHubClientClass parent; /* A laisser en premier */
+
+ /* Signaux */
+
+ void (* existing_binaries_updated) (GAdminClient *);
+
+};
+
+
+/* Initialise la classe des descriptions de fichier binaire. */
+static void g_admin_client_class_init(GAdminClientClass *);
+
+/* Initialise une description de fichier binaire. */
+static void g_admin_client_init(GAdminClient *);
+
+/* Supprime toutes les références externes. */
+static void g_admin_client_dispose(GAdminClient *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_admin_client_finalize(GAdminClient *);
+
+/* Assure l'accueil des nouvelles mises à jour. */
+static void *g_admin_client_update(GAdminClient *);
+
+/* Met à jour la liste des binaires existants. */
+static bool g_admin_client_update_existing_binaries(GAdminClient *, packed_buffer_t *);
+
+
+
+/* Indique le type défini pour une description de client à l'écoute. */
+G_DEFINE_TYPE(GAdminClient, g_admin_client, G_TYPE_HUB_CLIENT);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des descriptions de fichier binaire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_admin_client_class_init(GAdminClientClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GHubClientClass *client; /* Classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_admin_client_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_admin_client_finalize;
+
+ client = G_HUB_CLIENT_CLASS(klass);
+
+ client->role = CRL_ADMIN;
+ client->recv_func = (GThreadFunc)g_admin_client_update;
+
+ g_signal_new("existing-binaries-updated",
+ G_TYPE_ADMIN_CLIENT,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(GAdminClientClass, existing_binaries_updated),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : client = instance à initialiser. *
+* *
+* Description : Initialise une description de fichier binaire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_admin_client_init(GAdminClient *client)
+{
+ client->binaries = NULL;
+ client->binaries_count = 0;
+ g_mutex_init(&client->binaries_lock);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : archive = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_admin_client_dispose(GAdminClient *client)
+{
+ g_hub_client_stop(G_HUB_CLIENT(client));
+
+ G_OBJECT_CLASS(g_admin_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. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_admin_client_finalize(GAdminClient *client)
+{
+ size_t i; /* Boucle de parcours */
+
+ if (client->binaries != NULL)
+ {
+ for (i = 0; i < client->binaries_count; i++)
+ free(client->binaries[i]);
+
+ free(client->binaries);
+
+ }
+
+ g_mutex_clear(&client->binaries_lock);
+
+ G_OBJECT_CLASS(g_admin_client_parent_class)->finalize(G_OBJECT(client));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Prépare un client pour une connexion à une BD. *
+* *
+* Retour : Structure mise en place ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GAdminClient *g_admin_client_new(void)
+{
+ GAdminClient *result; /* Adresse à retourner */
+
+ result = g_object_new(G_TYPE_ADMIN_CLIENT, NULL);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : client = client pour les accès distants à manipuler. *
+* *
+* Description : Assure l'accueil des nouvelles mises à jour. *
+* *
+* Retour : NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void *g_admin_client_update(GAdminClient *client)
+{
+ GHubClient *base; /* Base de l'instance */
+ struct pollfd fds[2]; /* Surveillance des flux */
+ packed_buffer_t in_pbuf; /* Tampon de réception */
+ int ret; /* Bilan d'un appel */
+ bool status; /* Bilan d'une opération */
+ uint32_t command; /* Commande de la requête */
+ //packed_buffer_t out_pbuf; /* Tampon d'émission */
+ char *msg; /* Message d'erreur à imprimer */
+
+ base = G_HUB_CLIENT(client);
+
+ /**
+ * Phase d'écoute continue...
+ */
+
+ fds[0].fd = base->stop_ctrl[0];
+ fds[0].events = POLLIN | POLLPRI;
+
+ fds[1].fd = SSL_get_fd(base->tls_fd);
+ fds[1].events = POLLIN | POLLPRI;
+
+ init_packed_buffer(&in_pbuf);
+
+ while (true)
+ {
+ ret = poll(fds, 2, -1);
+ if (ret == -1)
+ {
+ LOG_ERROR_N("poll");
+ break;
+ }
+
+ /* Demande expresse d'arrêt des procédures */
+ if (fds[0].revents)
+ break;
+
+ /* Le canal est fermé, une sortie doit être demandée... */
+ if (fds[1].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[1].revents & (POLLHUP | POLLRDHUP))
+ break;
+
+ if (fds[1].revents & (POLLIN | POLLPRI))
+ {
+ reset_packed_buffer(&in_pbuf);
+
+ status = ssl_recv_packed_buffer(&in_pbuf, base->tls_fd);
+ if (!status) goto bad_exchange;
+
+ next_command:
+
+ status = extract_packed_buffer(&in_pbuf, &command, sizeof(uint32_t), true);
+ if (!status) goto bad_exchange;
+
+ switch (command)
+ {
+ case DBC_EXISTING_BINARIES:
+ status = g_admin_client_update_existing_binaries(client, &in_pbuf);
+ if (!status) goto bad_exchange;
+ break;
+
+ default:
+ log_variadic_message(LMT_INFO,
+ _("This command is not available on this side: 0x%08x"), command);
+ goto bad_exchange;
+ break;
+
+ }
+
+ if (has_more_data_in_packed_buffer(&in_pbuf))
+ goto next_command;
+
+ continue;
+
+ bad_exchange:
+
+ asprintf(&msg, _("Bad reception from %s"), base->desc);
+
+ LOG_ERROR(LMT_ERROR, msg);
+
+ free(msg);
+
+ break;
+
+ }
+
+ }
+
+ g_hub_client_stop(G_HUB_CLIENT(client));
+
+ exit_packed_buffer(&in_pbuf);
+
+ return NULL;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : client = client pour les accès distants à manipuler. *
+* *
+* Description : Effectue une demande de liste de binaires existants. *
+* *
+* Retour : true si la commande a bien été envoyée, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_admin_client_request_existing_binaries(GAdminClient *client)
+{
+ bool result; /* Bilan partiel à remonter */
+ packed_buffer_t out_pbuf; /* Tampon d'émission */
+ SSL *tls_fd; /* Canal de communication SSL */
+
+ init_packed_buffer(&out_pbuf);
+
+ tls_fd = g_hub_client_get_ssl_fd(G_HUB_CLIENT(client));
+
+ if (tls_fd == NULL)
+ result = false;
+
+ else
+ {
+ result = extend_packed_buffer(&out_pbuf, (uint32_t []) { DBC_LIST_BINARIES }, sizeof(uint32_t), true);
+
+ if (result)
+ result = ssl_send_packed_buffer(&out_pbuf, tls_fd);
+
+ g_hub_client_put_ssl_fd(G_HUB_CLIENT(client), tls_fd);
+
+ }
+
+ exit_packed_buffer(&out_pbuf);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : client = client pour les accès distants à manipuler. *
+* pbuf = données présentes à traiter. *
+* *
+* Description : Met à jour la liste des binaires existants. *
+* *
+* Retour : true si l'opération s'est déroulée sans encombre, ou false. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_admin_client_update_existing_binaries(GAdminClient *client, packed_buffer_t *pbuf)
+{
+ bool result; /* Validité à retourner */
+ size_t i; /* Boucle de parcours */
+ uleb128_t count; /* Nombre d'éléments détectés */
+ rle_string name; /* Nom à exporter */
+
+ result = true;
+
+ g_mutex_lock(&client->binaries_lock);
+
+ if (client->binaries != NULL)
+ {
+ for (i = 0; i < client->binaries_count; i++)
+ free(client->binaries[i]);
+
+ free(client->binaries);
+
+ client->binaries = NULL;
+ client->binaries_count = 0;
+
+ }
+
+ result = unpack_uleb128(&count, pbuf);
+ if (!result) goto exit;
+
+ client->binaries_count = count;
+
+ if (count > 0)
+ {
+ client->binaries = calloc(client->binaries_count, sizeof(char *));
+
+ for (i = 0; i < client->binaries_count; i++)
+ {
+ result = unpack_rle_string(&name, pbuf);
+ if (!result) break;
+
+ client->binaries[i] = strdup(name.data);
+
+ exit_rle_string(&name);
+
+ }
+
+ if (i < client->binaries_count)
+ {
+ for (i = 0; i < client->binaries_count; i++)
+ if (client->binaries[i] != NULL)
+ free(client->binaries[i]);
+
+ free(client->binaries);
+
+ client->binaries = NULL;
+ client->binaries_count = 0;
+
+ }
+
+ }
+
+ exit:
+
+ g_mutex_unlock(&client->binaries_lock);
+
+ if (result)
+ g_signal_emit_by_name(client, "existing-binaries-updated");
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : client = client pour les accès distants à manipuler. *
+* count = taille de la liste retournée. [OUT] *
+* *
+* Description : Fournit la liste des instantanés existants. *
+* *
+* Retour : Liste de binaires en place ou NULL si aucun. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+char **g_admin_client_get_existing_binaries(GAdminClient *client, size_t *count)
+{
+ char **result; /* Liste à retourner */
+ size_t i; /* Boucle de parcours */
+
+ result = NULL;
+ *count = 0;
+
+ g_mutex_lock(&client->binaries_lock);
+
+ if (client->binaries_count > 0)
+ {
+ result = malloc(client->binaries_count * sizeof(char *));
+ *count = client->binaries_count;
+
+ for (i = 0; i < client->binaries_count; i++)
+ result[i] = strdup(client->binaries[i]);
+
+ }
+
+ g_mutex_unlock(&client->binaries_lock);
+
+ return result;
+
+}
diff --git a/src/analysis/db/admin.h b/src/analysis/db/admin.h
new file mode 100644
index 0000000..31366ae
--- /dev/null
+++ b/src/analysis/db/admin.h
@@ -0,0 +1,68 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * admin.h - prototypes pour la connexion en administrateur à un serveur Chrysalide
+ *
+ * Copyright (C) 2021 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_ADMIN_H
+#define _ANALYSIS_DB_ADMIN_H
+
+
+#include <glib-object.h>
+#include <stdbool.h>
+#include <openssl/ssl.h>
+
+
+#include "client.h"
+#include "collection.h"
+#include "misc/snapshot.h"
+
+
+
+#define G_TYPE_ADMIN_CLIENT g_admin_client_get_type()
+#define G_ADMIN_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_ADMIN_CLIENT, GAdminClient))
+#define G_IS_ADMIN_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_ADMIN_CLIENT))
+#define G_ADMIN_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_ADMIN_CLIENT, GAdminClientClass))
+#define G_IS_ADMIN_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_ADMIN_CLIENT))
+#define G_ADMIN_CLIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_ADMIN_CLIENT, GAdminClientClass))
+
+
+/* Description de client à l'écoute (instance) */
+typedef struct _GAdminClient GAdminClient;
+
+/* Description de client à l'écoute (classe) */
+typedef struct _GAdminClientClass GAdminClientClass;
+
+
+/* Indique le type défini pour une description de client à l'écoute. */
+GType g_admin_client_get_type(void);
+
+/* Prépare un client pour une connexion à une BD. */
+GAdminClient *g_admin_client_new(void);
+
+/* Effectue une demande de liste de binaires existants. */
+bool g_admin_client_request_existing_binaries(GAdminClient *);
+
+/* Fournit la liste des instantanés existants. */
+char **g_admin_client_get_existing_binaries(GAdminClient *, size_t *);
+
+
+
+#endif /* _ANALYSIS_DB_ADMIN_H */
diff --git a/src/analysis/db/analyst-int.h b/src/analysis/db/analyst-int.h
new file mode 100644
index 0000000..4f76eff
--- /dev/null
+++ b/src/analysis/db/analyst-int.h
@@ -0,0 +1,76 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * analyst-int.h - prototypes pour la définition interne des connexions en analyste à un serveur Chrysalide
+ *
+ * Copyright (C) 2022 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_ANALYST_INT_H
+#define _ANALYSIS_DB_ANALYST_INT_H
+
+
+#include "analyst.h"
+#include "client-int.h"
+
+
+
+/* Description de client à l'écoute (instance) */
+struct _GAnalystClient
+{
+ GHubClient parent; /* A laisser en premier */
+
+ char *cnt_hash; /* Empreinte du binaire lié */
+ char *cnt_class; /* Interprétation du contenu */
+
+ GLoadedContent *loaded; /* Contenu chargé */
+ GList *collections; /* Collections d'un binaire */
+
+ bool can_get_updates; /* Réception de maj possibles ?*/
+
+ snapshot_info_t *snapshots; /* Liste des instantanés */
+ size_t snap_count; /* Taille de cette liste */
+ GMutex snap_lock; /* Concurrence des accès */
+
+ snapshot_id_t current; /* Instantané courant */
+ bool has_current; /* Validité de l'identifiant */
+ GMutex cur_lock; /* Concurrence des accès */
+
+};
+
+/* Description de client à l'écoute (classe) */
+struct _GAnalystClientClass
+{
+ GHubClientClass parent; /* A laisser en premier */
+
+ /* Signaux */
+
+ void (* ready) (GAnalystClient *);
+ void (* server_status_changed) (GAnalystClient *, LoadingStatusHint);
+ void (* snapshots_updated) (GAnalystClient *);
+ void (* snapshot_changed) (GAnalystClient *);
+
+};
+
+
+/* Prépare un client pour une connexion à une BD. */
+bool g_analyst_client_setup(GAnalystClient *, const char *, const char *, GList *, GLoadedContent *);
+
+
+
+#endif /* _ANALYSIS_DB_ANALYST_INT_H */
diff --git a/src/analysis/db/analyst.c b/src/analysis/db/analyst.c
new file mode 100644
index 0000000..43fb840
--- /dev/null
+++ b/src/analysis/db/analyst.c
@@ -0,0 +1,1418 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * analyst.c - connexion en analyste à un serveur Chrysalide
+ *
+ * Copyright (C) 2014-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 "analyst.h"
+
+
+#include <assert.h>
+#include <poll.h>
+#include <string.h>
+
+
+#include "analyst-int.h"
+#include "../storage/storage.h"
+#include "../../core/logs.h"
+
+
+
+/* ----------------------- DEFINITION D'ANALYSTE COMME CLIENT ----------------------- */
+
+
+/* Initialise la classe des descriptions de fichier binaire. */
+static void g_analyst_client_class_init(GAnalystClientClass *);
+
+/* Initialise une description de fichier binaire. */
+static void g_analyst_client_init(GAnalystClient *);
+
+/* Supprime toutes les références externes. */
+static void g_analyst_client_dispose(GAnalystClient *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_analyst_client_finalize(GAnalystClient *);
+
+/* Termine la constitution des données initiales à présenter. */
+static bool g_analyst_client_complete_hello(GAnalystClient *, packed_buffer_t *);
+
+/* Assure l'accueil des nouvelles mises à jour. */
+static void *g_analyst_client_update(GAnalystClient *);
+
+/* Met à jour la liste des instantanés courants. */
+static bool g_analyst_client_update_snapshots(GAnalystClient *, packed_buffer_t *);
+
+/* Met à jour l'identifiant de l'instantané courant. */
+static bool g_analyst_client_update_current_snapshot(GAnalystClient *, packed_buffer_t *);
+
+
+
+/* ------------------------- PRISES EN COMPTE DES COMMANDES ------------------------- */
+
+
+/* Prend en compte une évolution du statut côté serveur. */
+static bool g_analyst_client_handle_loading_hints(GAnalystClient *, packed_buffer_t *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* GLUES POUR LA GLIB */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Définit un type GLib pour l'énumération "LoadingStatusHint". *
+* *
+* Retour : Type GLib enregistré. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GType g_loading_status_hint_type(void)
+{
+ static GType result = 0;
+
+ static const GEnumValue values[] = {
+ { LSH_READY, "LSH_READY", "ready" },
+ { LSH_ON_WAIT_LIST, "LSH_ON_WAIT_LIST", "on_wait_list" },
+ { LSH_NEED_CONTENT, "LSH_NEED_CONTENT", "need_content" },
+ { LSH_NEED_FORMAT, "LSH_NEED_FORMAT", "need_format" },
+ { LSH_NEED_ARCH, "LSH_NEED_ARCH", "need_arch" },
+ { 0, NULL, NULL }
+ };
+
+ if (result == 0)
+ result = g_enum_register_static(g_intern_static_string("LoadingStatusHint"), values);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* DEFINITION D'ANALYSTE COMME CLIENT */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une description de client à l'écoute. */
+G_DEFINE_TYPE(GAnalystClient, g_analyst_client, G_TYPE_HUB_CLIENT);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des descriptions de fichier binaire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_analyst_client_class_init(GAnalystClientClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GHubClientClass *client; /* Classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_analyst_client_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_analyst_client_finalize;
+
+ client = G_HUB_CLIENT_CLASS(klass);
+
+ client->role = CRL_ANALYST;
+ client->complete_hello = (complete_client_hello_fc)g_analyst_client_complete_hello;
+ client->recv_func = (GThreadFunc)g_analyst_client_update;
+
+ g_signal_new("ready",
+ G_TYPE_ANALYST_CLIENT,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(GAnalystClientClass, ready),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ g_signal_new("server-status-changed",
+ G_TYPE_ANALYST_CLIENT,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(GAnalystClientClass, server_status_changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__ENUM,
+ G_TYPE_NONE, 1, G_TYPE_LOADING_STATUS_HINT);
+
+ g_signal_new("snapshots-updated",
+ G_TYPE_ANALYST_CLIENT,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(GAnalystClientClass, snapshots_updated),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ g_signal_new("snapshot-changed",
+ G_TYPE_ANALYST_CLIENT,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(GAnalystClientClass, snapshot_changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : client = instance à initialiser. *
+* *
+* Description : Initialise une description de fichier binaire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_analyst_client_init(GAnalystClient *client)
+{
+ client->cnt_hash = NULL;
+ client->cnt_class = NULL;
+
+ client->loaded = NULL;
+ client->collections = NULL;
+
+ client->can_get_updates = false;
+
+ client->snapshots = NULL;
+ client->snap_count = 0;
+ g_mutex_init(&client->snap_lock);
+
+ setup_empty_snapshot_id(&client->current);
+ client->has_current = false;
+ g_mutex_init(&client->cur_lock);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : archive = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_analyst_client_dispose(GAnalystClient *client)
+{
+ g_hub_client_stop(G_HUB_CLIENT(client));
+
+ g_mutex_clear(&client->cur_lock);
+
+ g_mutex_clear(&client->snap_lock);
+
+ g_clear_object(&client->loaded);
+
+ G_OBJECT_CLASS(g_analyst_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. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_analyst_client_finalize(GAnalystClient *client)
+{
+ size_t i; /* Boucle de parcours */
+
+ if (client->cnt_hash != NULL)
+ free(client->cnt_hash);
+
+ if (client->cnt_class != NULL)
+ free(client->cnt_class);
+
+ if (client->snapshots != NULL)
+ {
+ for (i = 0; i < client->snap_count; i++)
+ exit_snapshot_info(&client->snapshots[i]);
+
+ free(client->snapshots);
+
+ }
+
+ G_OBJECT_CLASS(g_analyst_client_parent_class)->finalize(G_OBJECT(client));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : hash = empreinte d'un binaire en cours d'analyse. *
+* class = nature de l'interprétation de ce contenu. *
+* collections = ensemble de collections existantes. *
+* loaded = éventuel élément local préchargé. *
+* *
+* Description : Met en place un client pour une connexion à une BD. *
+* *
+* Retour : Structure mise en place ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GAnalystClient *g_analyst_client_new(const char *hash, const char *class, GList *collections, GLoadedContent *loaded)
+{
+ GAnalystClient *result; /* Adresse à retourner */
+ bool status; /* Bilan de l'initialisation */
+
+ result = g_object_new(G_TYPE_ANALYST_CLIENT, NULL);
+
+ status = g_analyst_client_setup(result, hash, class, collections, loaded);
+
+ assert(status);
+
+ if (!status)
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : client = client pour les accès distants à initialiser. *
+* hash = empreinte d'un binaire en cours d'analyse. *
+* class = nature de l'interprétation de ce contenu. *
+* collections = ensemble de collections existantes. *
+* loaded = éventuel élément local préchargé. *
+* *
+* Description : Prépare un client pour une connexion à une BD. *
+* *
+* Retour : Structure mise en place ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_analyst_client_setup(GAnalystClient *client, const char *hash, const char *class, GList *collections, GLoadedContent *loaded)
+{
+ bool result; /* Bilan à retourner */
+
+ result = true;
+
+ client->cnt_hash = strdup(hash);
+ client->cnt_class = strdup(class);
+
+ client->loaded = loaded;
+ if (loaded != NULL) g_object_ref(G_OBJECT(loaded));
+
+ client->collections = collections;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : client = client pour les accès distants à manipuler. *
+* pbuf = tampon d'émission initial à compléter. *
+* *
+* Description : Termine la constitution des données initiales à présenter. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_analyst_client_complete_hello(GAnalystClient *client, packed_buffer_t *pbuf)
+{
+ bool result; /* Bilan à retourner */
+ rle_string str; /* Chaîne à communiquer */
+
+ init_static_rle_string(&str, client->cnt_hash);
+
+ result = pack_rle_string(&str, pbuf);
+
+ exit_rle_string(&str);
+
+ init_static_rle_string(&str, client->cnt_class);
+
+ result = pack_rle_string(&str, pbuf);
+
+ exit_rle_string(&str);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : client = client pour les accès distants à manipuler. *
+* *
+* Description : Assure l'accueil des nouvelles mises à jour. *
+* *
+* Retour : NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void *g_analyst_client_update(GAnalystClient *client)
+{
+ GHubClient *base; /* Base de l'instance */
+ packed_buffer_t out_pbuf; /* Tampon d'émission */
+ bool status; /* Bilan d'une opération */
+ struct pollfd fds[2]; /* Surveillance des flux */
+ packed_buffer_t in_pbuf; /* Tampon de réception */
+ int ret; /* Bilan d'un appel */
+ uint32_t tmp32; /* Valeur sur 32 bits */
+ uint32_t command; /* Commande de la requête */
+ DBError error; /* Bilan d'une commande passée */
+ GDbCollection *collec; /* Collection visée au final */
+ uint8_t tmp8; /* Valeur sur 8 bits */
+ char *msg; /* Message d'erreur à imprimer */
+
+ base = G_HUB_CLIENT(client);
+
+ /**
+ * Avant toute chose, on demande un stage d'actualisation !
+ */
+
+ init_packed_buffer(&out_pbuf);
+
+ status = extend_packed_buffer(&out_pbuf, (uint32_t []) { DBC_GET_SNAPSHOTS }, sizeof(uint32_t), true);
+ if (!status)
+ {
+ exit_packed_buffer(&out_pbuf);
+ goto exit;
+ }
+
+ status = extend_packed_buffer(&out_pbuf, (uint32_t []) { DBC_GET_CUR_SNAPSHOT }, sizeof(uint32_t), true);
+ if (!status)
+ {
+ exit_packed_buffer(&out_pbuf);
+ goto exit;
+ }
+
+ status = extend_packed_buffer(&out_pbuf, (uint32_t []) { DBC_GET_ALL_ITEMS }, sizeof(uint32_t), true);
+ if (!status)
+ {
+ exit_packed_buffer(&out_pbuf);
+ goto exit;
+ }
+
+ status = ssl_send_packed_buffer(&out_pbuf, base->tls_fd);
+ if (!status)
+ {
+ log_simple_message(LMT_INFO, _("Failed to get all updates"));
+ exit_packed_buffer(&out_pbuf);
+ goto exit;
+ }
+
+ exit_packed_buffer(&out_pbuf);
+
+ /**
+ * Phase d'écoute continue...
+ */
+
+ fds[0].fd = base->stop_ctrl[0];
+ fds[0].events = POLLIN | POLLPRI;
+
+ fds[1].fd = SSL_get_fd(base->tls_fd);
+ fds[1].events = POLLIN | POLLPRI;
+
+ init_packed_buffer(&in_pbuf);
+
+ while (true)
+ {
+ ret = poll(fds, 2, -1);
+ if (ret == -1)
+ {
+ LOG_ERROR_N("poll");
+ break;
+ }
+
+ /* Demande expresse d'arrêt des procédures */
+ if (fds[0].revents)
+ break;
+
+ /* Le canal est fermé, une sortie doit être demandée... */
+ if (fds[1].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[1].revents & (POLLHUP | POLLRDHUP))
+ break;
+
+ if (fds[1].revents & (POLLIN | POLLPRI))
+ {
+ reset_packed_buffer(&in_pbuf);
+
+ status = ssl_recv_packed_buffer(&in_pbuf, base->tls_fd);
+ if (!status) goto gdcu_bad_exchange;
+
+ next_command:
+
+ status = extract_packed_buffer(&in_pbuf, &command, sizeof(uint32_t), true);
+ if (!status) goto gdcu_bad_exchange;
+
+ switch (command)
+ {
+ case DBC_LOADING_STATUS:
+ status = g_analyst_client_handle_loading_hints(client, &in_pbuf);
+ if (!status) goto gdcu_bad_exchange;
+ break;
+
+ case DBC_SAVE:
+
+ status = extract_packed_buffer(&in_pbuf, &tmp32, sizeof(uint32_t), true);
+ if (!status) goto gdcu_bad_exchange;
+
+ error = tmp32;
+
+ if (error == DBE_NONE)
+ log_variadic_message(LMT_INFO, _("Archive saved for binary '%s'"), client->cnt_hash);
+ else
+ log_variadic_message(LMT_ERROR, _("Failed to save the archive for binary '%s'"),
+ client->cnt_hash);
+
+ break;
+
+ case DBC_COLLECTION:
+
+ status = extract_packed_buffer(&in_pbuf, &tmp32, sizeof(uint32_t), true);
+ if (!status) goto gdcu_bad_exchange;
+
+ collec = find_collection_in_list(client->collections, tmp32);
+ if (collec == NULL) goto gdcu_bad_exchange;
+
+ if (client->can_get_updates)
+ status = g_db_collection_unpack(collec, &in_pbuf, NULL);
+ else
+ status = _g_db_collection_unpack(collec, &in_pbuf, (DBAction []) { 0 }, NULL);
+
+ if (!status) goto gdcu_bad_exchange;
+
+ break;
+
+ case DBC_GET_ALL_ITEMS:
+ log_variadic_message(LMT_INFO,
+ _("This command is not available on this side: 0x%08x"), command);
+ goto gdcu_bad_exchange;
+ break;
+
+ case DBC_SET_ALL_ITEMS:
+
+ status = extract_packed_buffer(&in_pbuf, &tmp8, sizeof(uint8_t), true);
+ if (!status) goto gdcu_bad_exchange;
+
+ client->can_get_updates = (tmp8 == 0x1);
+ break;
+
+ case DBC_GET_SNAPSHOTS:
+ log_variadic_message(LMT_INFO,
+ _("This command is not available on this side: 0x%08x"), command);
+ goto gdcu_bad_exchange;
+ break;
+
+ case DBC_SNAPSHOTS_UPDATED:
+
+ status = g_analyst_client_update_snapshots(client, &in_pbuf);
+ if (!status) goto gdcu_bad_exchange;
+
+ break;
+
+ case DBC_GET_CUR_SNAPSHOT:
+ log_variadic_message(LMT_INFO,
+ _("This command is not available on this side: 0x%08x"), command);
+ goto gdcu_bad_exchange;
+ break;
+
+ case DBC_CUR_SNAPSHOT_UPDATED:
+
+ status = g_analyst_client_update_current_snapshot(client, &in_pbuf);
+ if (!status) goto gdcu_bad_exchange;
+
+ break;
+
+ case DBC_SET_CUR_SNAPSHOT:
+ case DBC_SET_SNAPSHOT_NAME:
+ case DBC_SET_SNAPSHOT_DESC:
+ case DBC_CREATE_SNAPSHOT:
+ case DBC_REMOVE_SNAPSHOT:
+ log_variadic_message(LMT_INFO,
+ _("This command is not available on this side: 0x%08x"), command);
+ goto gdcu_bad_exchange;
+ break;
+
+ }
+
+ if (has_more_data_in_packed_buffer(&in_pbuf))
+ goto next_command;
+
+ client->can_get_updates = true;
+ continue;
+
+ gdcu_bad_exchange:
+
+ asprintf(&msg, _("Bad reception from %s"), base->desc);
+
+ LOG_ERROR(LMT_ERROR, msg);
+
+ free(msg);
+
+ break;
+
+ }
+
+ }
+
+ exit:
+
+ g_hub_client_stop(G_HUB_CLIENT(client));
+
+ exit_packed_buffer(&in_pbuf);
+
+ return NULL;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : client = client pour les accès distants à manipuler. *
+* pbuf = données présentes à traiter. *
+* *
+* Description : Met à jour la liste des instantanés courants. *
+* *
+* Retour : true si l'opération s'est déroulée sans encombre, ou false. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_analyst_client_update_snapshots(GAnalystClient *client, packed_buffer_t *pbuf)
+{
+ bool result; /* Validité à retourner */
+ size_t i; /* Boucle de parcours */
+ char id[SNAP_ID_HEX_SZ]; /* Caractères hexadécimaux */
+ snapshot_info_t info; /* Description d'instantané */
+ snapshot_info_t *dest; /* Destination de description */
+
+ result = true;
+
+ g_mutex_lock(&client->snap_lock);
+
+ if (client->snapshots != NULL)
+ {
+ for (i = 0; i < client->snap_count; i++)
+ exit_snapshot_info(&client->snapshots[i]);
+
+ free(client->snapshots);
+
+ client->snapshots = NULL;
+ client->snap_count = 0;
+
+ }
+
+ do
+ {
+ result = peek_packed_buffer(pbuf, id, SNAP_ID_HEX_SZ, false);
+ if (!result) break;
+
+ if (strncmp(id, SNAPSHOT_END_MARK, SNAP_ID_HEX_SZ) == 0)
+ {
+ advance_packed_buffer(pbuf, SNAP_ID_HEX_SZ);
+ break;
+ }
+
+ else
+ {
+ setup_empty_snapshot_info(&info);
+
+ result = unpack_snapshot_info(&info, pbuf);
+ if (!result) break;
+
+ client->snapshots = realloc(client->snapshots, ++client->snap_count * sizeof(snapshot_info_t));
+
+ dest = &client->snapshots[client->snap_count - 1];
+
+ setup_empty_snapshot_info(dest);
+ copy_snapshot_info(dest, &info);
+
+ exit_snapshot_info(&info);
+
+ }
+
+ }
+ while (true);
+
+ g_mutex_unlock(&client->snap_lock);
+
+ if (result)
+ g_signal_emit_by_name(client, "snapshots-updated");
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : client = client pour les accès distants à manipuler. *
+* pbuf = données présentes à traiter. *
+* *
+* Description : Met à jour l'identifiant de l'instantané courant. *
+* *
+* Retour : true si l'opération s'est déroulée sans encombre, ou false. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_analyst_client_update_current_snapshot(GAnalystClient *client, packed_buffer_t *pbuf)
+{
+ bool result; /* Validité à retourner */
+ snapshot_id_t id; /* Identifiant d'instantané */
+
+ setup_empty_snapshot_id(&id);
+
+ result = unpack_snapshot_id(&id, pbuf);
+
+ if (result)
+ {
+ g_mutex_lock(&client->cur_lock);
+
+ copy_snapshot_id(&client->current, &id);
+ client->has_current = true;
+
+ g_mutex_unlock(&client->cur_lock);
+
+ g_signal_emit_by_name(client, "snapshot-changed");
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : client = client pour les accès distants à manipuler. *
+* content = contenu binaire à envoyer. *
+* *
+* Description : Envoie un contenu binaire pour conservation côté serveur. *
+* *
+* Retour : true si la commande a bien été envoyée, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_analyst_client_send_content(GAnalystClient *client, GBinContent *content)
+{
+ bool result; /* Bilan partiel à remonter */
+ const gchar *hash; /* Empreinte du contenu fourni */
+ packed_buffer_t cnt_pbuf; /* Tampon de stockage */
+ GObjectStorage *storage; /* Gestionnaire de stockage */
+ off64_t pos; /* Emplacement du binaire */
+ SSL *tls_fd; /* Canal de communication SSL */
+ packed_buffer_t out_pbuf; /* Tampon d'émission */
+
+ result = false;
+
+ /* Validation de la conformité du contenu */
+
+ hash = g_binary_content_get_checksum(content);
+
+ if (strcmp(hash, client->cnt_hash) != 0)
+ {
+ log_variadic_message(LMT_ERROR, _("Provided ontent does not match client content (hash: '%s')"),
+ client->cnt_hash);
+ goto exit;
+ }
+
+ /* Conversion en format de stockage */
+
+ init_packed_buffer(&cnt_pbuf);
+
+ storage = g_object_storage_new(client->cnt_hash);
+
+ result = g_object_storage_store_object(storage, "contents", G_SERIALIZABLE_OBJECT(content), &pos);
+ if (!result) goto exit_with_failure;
+
+ result = pack_uleb128((uleb128_t []){ pos }, &cnt_pbuf);
+ if (!result) goto exit_with_failure;
+
+ result = g_object_storage_store(storage, &cnt_pbuf);
+ if (!result) goto exit_with_failure;
+
+ /* Transmission */
+
+ tls_fd = g_hub_client_get_ssl_fd(G_HUB_CLIENT(client));
+
+ if (tls_fd == NULL)
+ result = false;
+
+ else
+ {
+ init_packed_buffer(&out_pbuf);
+
+ result = extend_packed_buffer(&out_pbuf, (uint32_t []) { DBC_SET_CONTENT }, sizeof(uint32_t), true);
+
+ if (result)
+ result = pack_uleb128((uleb128_t []){ get_packed_buffer_payload_length(&cnt_pbuf) }, &out_pbuf);
+
+ if (result)
+ result = include_packed_buffer(&out_pbuf, &cnt_pbuf);
+
+ if (result)
+ result = ssl_send_packed_buffer(&out_pbuf, tls_fd);
+
+ g_hub_client_put_ssl_fd(G_HUB_CLIENT(client), tls_fd);
+
+ exit_packed_buffer(&out_pbuf);
+
+ }
+
+ exit_with_failure:
+
+ g_object_unref(G_OBJECT(storage));
+
+ exit_packed_buffer(&cnt_pbuf);
+
+ exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : client = client pour les accès distants à manipuler. *
+* *
+* Description : Effectue une demande de sauvegarde de l'état courant. *
+* *
+* Retour : true si la commande a bien été envoyée, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_analyst_client_save(GAnalystClient *client)
+{
+ bool result; /* Bilan partiel à remonter */
+ packed_buffer_t out_pbuf; /* Tampon d'émission */
+ SSL *tls_fd; /* Canal de communication SSL */
+
+ init_packed_buffer(&out_pbuf);
+
+ tls_fd = g_hub_client_get_ssl_fd(G_HUB_CLIENT(client));
+
+ if (tls_fd == NULL)
+ result = false;
+
+ else
+ {
+ result = extend_packed_buffer(&out_pbuf, (uint32_t []) { DBC_SAVE }, sizeof(uint32_t), true);
+
+ if (result)
+ result = ssl_send_packed_buffer(&out_pbuf, tls_fd);
+
+ g_hub_client_put_ssl_fd(G_HUB_CLIENT(client), tls_fd);
+
+ }
+
+ exit_packed_buffer(&out_pbuf);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : client = client pour les accès distants à manipuler. *
+* item = élémnent à pousser vers un serveur de collection. *
+* *
+* Description : Ajoute un élément à la collection d'un serveur. *
+* *
+* Retour : true si la commande a bien été envoyée, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_analyst_client_add_item(GAnalystClient *client, const GDbItem *item)
+{
+ bool result; /* Bilan partiel à remonter */
+ packed_buffer_t out_pbuf; /* Tampon d'émission */
+ SSL *tls_fd; /* Canal de communication SSL */
+ DBFeatures feature; /* Domaine de fonctionnalité */
+ GDbCollection *collec; /* Collection visée au final */
+
+ init_packed_buffer(&out_pbuf);
+
+ tls_fd = g_hub_client_get_ssl_fd(G_HUB_CLIENT(client));
+
+ if (tls_fd == NULL)
+ result = false;
+
+ else
+ {
+ feature = g_db_item_get_feature(item);
+
+ collec = find_collection_in_list(client->collections, feature);
+ if (collec == NULL)
+ {
+ result = false;
+ goto bad_item_feature;
+ }
+
+ result = g_db_collection_pack(collec, &out_pbuf, DBA_ADD_ITEM, item);
+
+ if (result)
+ result = ssl_send_packed_buffer(&out_pbuf, tls_fd);
+
+ bad_item_feature:
+
+ g_hub_client_put_ssl_fd(G_HUB_CLIENT(client), tls_fd);
+
+ }
+
+ exit_packed_buffer(&out_pbuf);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : client = client pour les accès distants à manipuler. *
+* timestamp = date du dernier élément à garder comme actif. *
+* *
+* Description : Active les éléments en amont d'un horodatage donné. *
+* *
+* Retour : true si la commande a bien été envoyée, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_analyst_client_set_last_active(GAnalystClient *client, timestamp_t timestamp)
+{
+ bool result; /* Bilan partiel à remonter */
+ packed_buffer_t out_pbuf; /* Tampon d'émission */
+ SSL *tls_fd; /* Canal de communication SSL */
+
+ init_packed_buffer(&out_pbuf);
+
+ tls_fd = g_hub_client_get_ssl_fd(G_HUB_CLIENT(client));
+
+ if (tls_fd == NULL)
+ result = false;
+
+ else
+ {
+ result = extend_packed_buffer(&out_pbuf, (uint32_t []) { DBC_SET_LAST_ACTIVE }, sizeof(uint32_t), true);
+
+ if (result)
+ result = pack_timestamp(&timestamp, &out_pbuf);
+
+ if (result)
+ result = ssl_send_packed_buffer(&out_pbuf, tls_fd);
+
+ g_hub_client_put_ssl_fd(G_HUB_CLIENT(client), tls_fd);
+
+ }
+
+ exit_packed_buffer(&out_pbuf);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : client = client pour les accès distants à manipuler. *
+* info = description des instantanés présents. [OUT] *
+* count = taille de la liste retournée. [OUT] *
+* *
+* Description : Fournit la liste des instantanés existants. *
+* *
+* Retour : true si la liste retournée est valide, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_analyst_client_get_snapshots(GAnalystClient *client, snapshot_info_t **info, size_t *count)
+{
+ bool result; /* Validité à retourner */
+ size_t i; /* Boucle de parcours */
+ snapshot_info_t *dest; /* Destination de description */
+
+ g_mutex_lock(&client->snap_lock);
+
+ result = (client->snap_count > 0);
+
+ if (result)
+ {
+ *info = malloc(client->snap_count * sizeof(snapshot_info_t));
+ *count = client->snap_count;
+
+ for (i = 0; i < client->snap_count; i++)
+ {
+ dest = &(*info)[i];
+
+ setup_empty_snapshot_info(dest);
+ copy_snapshot_info(dest, &client->snapshots[i]);
+
+ }
+
+ }
+
+ g_mutex_unlock(&client->snap_lock);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : client = client pour les accès distants à manipuler. *
+* id = identifiant d'instantané à renseigner. [OUT] *
+* *
+* Description : Fournit l'identifiant de l'instantané courant. *
+* *
+* Retour : true si l'identifiant retourné est valide, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_analyst_client_get_current_snapshot(GAnalystClient *client, snapshot_id_t *id)
+{
+ bool result; /* Validité à retourner */
+
+ g_mutex_lock(&client->cur_lock);
+
+ result = client->has_current;
+
+ if (result)
+ copy_snapshot_id(id, &client->current);
+
+ g_mutex_unlock(&client->cur_lock);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : client = client pour les accès distants à manipuler. *
+* id = identifiant d'instantané à activer. *
+* *
+* Description : Définit l'identifiant de l'instantané courant. *
+* *
+* Retour : true si la commande a bien été envoyée, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_analyst_client_set_current_snapshot(GAnalystClient *client, const snapshot_id_t *id)
+{
+ bool result; /* Bilan partiel à remonter */
+ packed_buffer_t out_pbuf; /* Tampon d'émission */
+ SSL *tls_fd; /* Canal de communication SSL */
+
+ init_packed_buffer(&out_pbuf);
+
+ tls_fd = g_hub_client_get_ssl_fd(G_HUB_CLIENT(client));
+
+ if (tls_fd == NULL)
+ result = false;
+
+ else
+ {
+ result = extend_packed_buffer(&out_pbuf, (uint32_t []) { DBC_SET_CUR_SNAPSHOT }, sizeof(uint32_t), true);
+
+ if (result)
+ result = pack_snapshot_id(id, &out_pbuf);
+
+ if (result)
+ result = ssl_send_packed_buffer(&out_pbuf, tls_fd);
+
+ g_hub_client_put_ssl_fd(G_HUB_CLIENT(client), tls_fd);
+
+ }
+
+ exit_packed_buffer(&out_pbuf);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : client = client pour les accès distants à manipuler. *
+* id = identifiant d'instantané à traiter. *
+* name = désignation humaine pour l'instantané. *
+* *
+* Description : Définit la désignation d'un instantané donné. *
+* *
+* Retour : true si la commande a bien été envoyée, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_analyst_client_set_snapshot_name(GAnalystClient *client, const snapshot_id_t *id, const char *name)
+{
+ bool result; /* Bilan partiel à remonter */
+ packed_buffer_t out_pbuf; /* Tampon d'émission */
+ SSL *tls_fd; /* Canal de communication SSL */
+ rle_string string; /* Chaîne à transmettre */
+
+ init_packed_buffer(&out_pbuf);
+
+ tls_fd = g_hub_client_get_ssl_fd(G_HUB_CLIENT(client));
+
+ if (tls_fd == NULL)
+ result = false;
+
+ else
+ {
+ result = extend_packed_buffer(&out_pbuf, (uint32_t []) { DBC_SET_SNAPSHOT_NAME }, sizeof(uint32_t), true);
+
+ if (result)
+ result = pack_snapshot_id(id, &out_pbuf);
+
+ if (result)
+ {
+ init_static_rle_string(&string, name);
+
+ result = pack_rle_string(&string, &out_pbuf);
+
+ exit_rle_string(&string);
+
+ }
+
+ if (result)
+ result = ssl_send_packed_buffer(&out_pbuf, tls_fd);
+
+ g_hub_client_put_ssl_fd(G_HUB_CLIENT(client), tls_fd);
+
+ }
+
+ exit_packed_buffer(&out_pbuf);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : client = client pour les accès distants à manipuler. *
+* id = identifiant d'instantané à traiter. *
+* desc = description humaine pour l'instantané. *
+* *
+* Description : Définit la description d'un instantané donné. *
+* *
+* Retour : true si la commande a bien été envoyée, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_analyst_client_set_snapshot_desc(GAnalystClient *client, const snapshot_id_t *id, const char *desc)
+{
+ bool result; /* Bilan partiel à remonter */
+ packed_buffer_t out_pbuf; /* Tampon d'émission */
+ SSL *tls_fd; /* Canal de communication SSL */
+ rle_string string; /* Chaîne à transmettre */
+
+ init_packed_buffer(&out_pbuf);
+
+ tls_fd = g_hub_client_get_ssl_fd(G_HUB_CLIENT(client));
+
+ if (tls_fd == NULL)
+ result = false;
+
+ else
+ {
+ result = extend_packed_buffer(&out_pbuf, (uint32_t []) { DBC_SET_SNAPSHOT_DESC }, sizeof(uint32_t), true);
+
+ if (result)
+ result = pack_snapshot_id(id, &out_pbuf);
+
+ if (result)
+ {
+ init_static_rle_string(&string, desc);
+
+ result = pack_rle_string(&string, &out_pbuf);
+
+ exit_rle_string(&string);
+
+ }
+
+ if (result)
+ result = ssl_send_packed_buffer(&out_pbuf, tls_fd);
+
+ g_hub_client_put_ssl_fd(G_HUB_CLIENT(client), tls_fd);
+
+ }
+
+ exit_packed_buffer(&out_pbuf);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : client = client pour les accès distants à manipuler. *
+* id = identifiant d'instantané à traiter. *
+* *
+* Description : Restaure un ancien instantané. *
+* *
+* Retour : true si la commande a bien été envoyée, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_analyst_client_restore_snapshot(GAnalystClient *client, const snapshot_id_t *id)
+{
+ bool result; /* Bilan partiel à remonter */
+ packed_buffer_t out_pbuf; /* Tampon d'émission */
+ SSL *tls_fd; /* Canal de communication SSL */
+
+ init_packed_buffer(&out_pbuf);
+
+ tls_fd = g_hub_client_get_ssl_fd(G_HUB_CLIENT(client));
+
+ if (tls_fd == NULL)
+ result = false;
+
+ else
+ {
+ result = extend_packed_buffer(&out_pbuf, (uint32_t []) { DBC_SET_CUR_SNAPSHOT }, sizeof(uint32_t), true);
+
+ if (result)
+ result = pack_snapshot_id(id, &out_pbuf);
+
+ if (result)
+ result = ssl_send_packed_buffer(&out_pbuf, tls_fd);
+
+ g_hub_client_put_ssl_fd(G_HUB_CLIENT(client), tls_fd);
+
+ }
+
+ exit_packed_buffer(&out_pbuf);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : client = client pour les accès distants à manipuler. *
+* *
+* Description : Crée un nouvel instantané à partir d'un autre. *
+* *
+* Retour : true si la commande a bien été envoyée, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_analyst_client_create_snapshot(GAnalystClient *client)
+{
+ bool result; /* Bilan partiel à remonter */
+ packed_buffer_t out_pbuf; /* Tampon d'émission */
+ SSL *tls_fd; /* Canal de communication SSL */
+
+ init_packed_buffer(&out_pbuf);
+
+ tls_fd = g_hub_client_get_ssl_fd(G_HUB_CLIENT(client));
+
+ if (tls_fd == NULL)
+ result = false;
+
+ else
+ {
+ result = extend_packed_buffer(&out_pbuf, (uint32_t []) { DBC_CREATE_SNAPSHOT }, sizeof(uint32_t), true);
+
+ if (result)
+ result = ssl_send_packed_buffer(&out_pbuf, tls_fd);
+
+ g_hub_client_put_ssl_fd(G_HUB_CLIENT(client), tls_fd);
+
+ }
+
+ exit_packed_buffer(&out_pbuf);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : client = client pour les accès distants à manipuler. *
+* id = identifiant d'instantané à traiter. *
+* rec = programme une suppression récursive. *
+* *
+* Description : Supprime un ancien instantané. *
+* *
+* Retour : true si la commande a bien été envoyée, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_analyst_client_remove_snapshot(GAnalystClient *client, const snapshot_id_t *id, bool rec)
+{
+ bool result; /* Bilan partiel à remonter */
+ packed_buffer_t out_pbuf; /* Tampon d'émission */
+ SSL *tls_fd; /* Canal de communication SSL */
+
+ init_packed_buffer(&out_pbuf);
+
+ tls_fd = g_hub_client_get_ssl_fd(G_HUB_CLIENT(client));
+
+ if (tls_fd == NULL)
+ result = false;
+
+ else
+ {
+ result = extend_packed_buffer(&out_pbuf, (uint32_t []) { DBC_REMOVE_SNAPSHOT }, sizeof(uint32_t), true);
+
+ if (result)
+ result = pack_snapshot_id(id, &out_pbuf);
+
+ if (result)
+ result = extend_packed_buffer(&out_pbuf, (uint8_t []) { rec ? 0x1 : 0x0 }, sizeof(uint8_t), false);
+
+ if (result)
+ result = ssl_send_packed_buffer(&out_pbuf, tls_fd);
+
+ g_hub_client_put_ssl_fd(G_HUB_CLIENT(client), tls_fd);
+
+ }
+
+ exit_packed_buffer(&out_pbuf);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* PRISES EN COMPTE DES COMMANDES */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : archive = archive à connecter avec un utilisateur. *
+* in_pbuf = paquet à consulter. *
+* *
+* Description : Prend en compte une évolution du statut côté serveur. *
+* *
+* Retour : Indication pour le maintien de la communication. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_analyst_client_handle_loading_hints(GAnalystClient *client, packed_buffer_t *in_pbuf)
+{
+ bool result; /* Bilan à retourner */
+ uleb128_t hint; /* Indication du serveur */
+
+ result = unpack_uleb128(&hint, in_pbuf);
+
+ switch (hint)
+ {
+ case LSH_READY:
+ g_signal_emit_by_name(client, "ready");
+ break;
+
+ case LSH_ON_WAIT_LIST:
+ log_simple_message(LMT_INFO, _("Waiting for content from server..."));
+ break;
+
+ case LSH_NEED_CONTENT:
+ case LSH_NEED_FORMAT:
+ case LSH_NEED_ARCH:
+ g_signal_emit_by_name(client, "server-status-changed", hint);
+ break;
+
+ default:
+ log_variadic_message(LMT_ERROR,
+ _("Unknown loaded hint received (%x); unsupported newer protocol?"),
+ hint);
+ result = false;
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/src/analysis/db/analyst.h b/src/analysis/db/analyst.h
new file mode 100644
index 0000000..ff189ba
--- /dev/null
+++ b/src/analysis/db/analyst.h
@@ -0,0 +1,115 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * analyst.h - prototypes pour la connexion en analyste à un serveur Chrysalide
+ *
+ * Copyright (C) 2014-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_ANALYST_H
+#define _ANALYSIS_DB_ANALYST_H
+
+
+#include <glib-object.h>
+#include <stdbool.h>
+#include <openssl/ssl.h>
+
+
+#include "client.h"
+#include "collection.h"
+#include "misc/snapshot.h"
+#include "../content.h"
+#include "../loaded.h"
+
+
+
+
+/* ------------------------------- GLUES POUR LA GLIB ------------------------------- */
+
+
+#define G_TYPE_LOADING_STATUS_HINT g_loading_status_hint_type()
+
+
+/* Définit un type GLib pour l'énumération "LoadingStatusHint". */
+GType g_loading_status_hint_type(void);
+
+
+
+/* ----------------------- DEFINITION D'ANALYSTE COMME CLIENT ----------------------- */
+
+
+#define G_TYPE_ANALYST_CLIENT g_analyst_client_get_type()
+#define G_ANALYST_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_ANALYST_CLIENT, GAnalystClient))
+#define G_IS_ANALYST_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_ANALYST_CLIENT))
+#define G_ANALYST_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_ANALYST_CLIENT, GAnalystClientClass))
+#define G_IS_ANALYST_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_ANALYST_CLIENT))
+#define G_ANALYST_CLIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_ANALYST_CLIENT, GAnalystClientClass))
+
+
+/* Description de client à l'écoute (instance) */
+typedef struct _GAnalystClient GAnalystClient;
+
+/* Description de client à l'écoute (classe) */
+typedef struct _GAnalystClientClass GAnalystClientClass;
+
+
+/* Indique le type défini pour une description de client à l'écoute. */
+GType g_analyst_client_get_type(void);
+
+/* Met en place un client pour une connexion à une BD. */
+GAnalystClient *g_analyst_client_new(const char *, const char *, GList *, GLoadedContent *);
+
+/* Envoie un contenu binaire pour conservation côté serveur. */
+bool g_analyst_client_send_content(GAnalystClient *, GBinContent *);
+
+/* Effectue une demande de sauvegarde de l'état courant. */
+bool g_analyst_client_save(GAnalystClient *);
+
+/* Ajoute un élément à la collection d'un serveur. */
+bool g_analyst_client_add_item(GAnalystClient *, const GDbItem *);
+
+/* Active les éléments en amont d'un horodatage donné. */
+bool g_analyst_client_set_last_active(GAnalystClient *, timestamp_t);
+
+/* Fournit la liste des instantanés existants. */
+bool g_analyst_client_get_snapshots(GAnalystClient *, snapshot_info_t **, size_t *);
+
+/* Fournit l'identifiant de l'instantané courant. */
+bool g_analyst_client_get_current_snapshot(GAnalystClient *, snapshot_id_t *);
+
+/* Définit l'identifiant de l'instantané courant. */
+bool g_analyst_client_set_current_snapshot(GAnalystClient *, const snapshot_id_t *);
+
+/* Définit la désignation d'un instantané donné. */
+bool g_analyst_client_set_snapshot_name(GAnalystClient *, const snapshot_id_t *, const char *);
+
+/* Définit la description d'un instantané donné. */
+bool g_analyst_client_set_snapshot_desc(GAnalystClient *, const snapshot_id_t *, const char *);
+
+/* Restaure un ancien instantané. */
+bool g_analyst_client_restore_snapshot(GAnalystClient *, const snapshot_id_t *);
+
+/* Crée un nouvel instantané à partir d'un autre. */
+bool g_analyst_client_create_snapshot(GAnalystClient *);
+
+/* Supprime un ancien instantané. */
+bool g_analyst_client_remove_snapshot(GAnalystClient *, const snapshot_id_t *, bool);
+
+
+
+#endif /* _ANALYSIS_DB_ANALYST_H */
diff --git a/src/analysis/db/auth.c b/src/analysis/db/auth.c
index 5e62f58..5869794 100644
--- a/src/analysis/db/auth.c
+++ b/src/analysis/db/auth.c
@@ -38,6 +38,7 @@
#include "../../common/io.h"
#include "../../common/pathname.h"
#include "../../common/xdg.h"
+#include "../../common/xml.h"
#include "../../core/logs.h"
@@ -48,6 +49,14 @@ 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 *);
+/* Renvoie un accès à la configuration XML des privilèges. */
+static bool open_server_priv_config(const char *, const char *, xmlDocPtr *, xmlXPathContextPtr *);
+
+/* Assure la présence d'au moins un administrateur. */
+static bool ensure_one_admin_is_registered(const char *, const char *, const char *);
+
+/* Enregistre et clôture la configuration XML des privilèges. */
+static bool close_server_priv_config(const char *, const char *, xmlDocPtr, xmlXPathContextPtr);
/******************************************************************************
@@ -458,6 +467,8 @@ bool add_client_to_server(const char *host, const char *port, unsigned long vali
char *cakey; /* Clef de cette autorité */
char *storage; /* Répertoire de stockage */
char *dest; /* Destination d'une copie */
+ x509_entries entries; /* Identitié du client */
+ char *id; /* Identifiant associé */
result = false;
@@ -517,6 +528,22 @@ bool add_client_to_server(const char *host, const char *port, unsigned long vali
}
+ if (result)
+ {
+ result = load_identity_from_cert(hash, &entries);
+
+ if (result)
+ {
+ id = translate_x509_entries(&entries);
+
+ result = ensure_one_admin_is_registered(host, port, id);
+
+ free_x509_entries(&entries);
+
+ }
+
+ }
+
free(storage);
}
@@ -539,9 +566,132 @@ bool add_client_to_server(const char *host, const char *port, unsigned long vali
/******************************************************************************
* *
+* Paramètres : host = désignation du serveur à contacter. *
+* port = port d'écoute correspondant. *
+* xdoc = document XML prêt à emploi. [OUT] *
+* context = contexte de recherche XPath. [OUT] *
+* *
+* Description : Renvoie un accès à la configuration XML des privilèges. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool open_server_priv_config(const char *host, const char *port, xmlDocPtr *xdoc, xmlXPathContextPtr *context)
+{
+ bool result; /* Bilan à retourner */
+ char *filename; /* Chemin d'accès à la config. */
+ int ret; /* Test de présence de fichier */
+
+ filename = get_db_working_directory("servers", host, port, NULL);
+ filename = stradd(filename, "privs.xml");
+
+ ret = access(filename, F_OK);
+
+ if (ret == 0)
+ result = open_xml_file(filename, xdoc, context);
+
+ else
+ {
+ result = create_new_xml_file(xdoc, context);
+
+ if (result)
+ result = (ensure_node_exist(*xdoc, *context, "/ServerPrivLevels") != NULL);
+
+ }
+
+ free(filename);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : host = désignation du serveur à contacter. *
+* port = port d'écoute correspondant. *
+* id = identification d'un utilisateur. *
+* *
+* Description : Assure la présence d'au moins un administrateur. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool ensure_one_admin_is_registered(const char *host, const char *port, const char *id)
+{
+ bool result; /* Bilan à retourner */
+ xmlDocPtr xdoc; /* Document XML de configurat° */
+ xmlXPathContextPtr context; /* Contexte de recherche XPath */
+ xmlXPathObjectPtr xobject; /* Cible d'une recherche */
+ size_t count; /* Nombre de contenus premiers */
+
+ result = open_server_priv_config(host, port, &xdoc, &context);
+ if (!result) goto exit;
+
+ xobject = get_node_xpath_object(context, "/ServerPrivLevels/Administrators/User");
+
+ count = XPATH_OBJ_NODES_COUNT(xobject);
+
+ if (count == 0)
+ result = add_content_to_node(xdoc, context, "/ServerPrivLevels/Administrators/User", id);
+
+ if(xobject != NULL)
+ xmlXPathFreeObject(xobject);
+
+ result = close_server_priv_config(host, port, xdoc, context);
+
+ exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : host = désignation du serveur à contacter. *
+* port = port d'écoute correspondant. *
+* xdoc = document XML prêt à emploi. *
+* context = contexte de recherche XPath. *
+* *
+* Description : Enregistre et clôture la configuration XML des privilèges. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool close_server_priv_config(const char *host, const char *port, xmlDocPtr xdoc, xmlXPathContextPtr context)
+{
+ bool result; /* Bilan à retourner */
+ char *filename; /* Chemin d'accès à la config. */
+
+ filename = get_db_working_directory("servers", host, port, NULL);
+ filename = stradd(filename, "privs.xml");
+
+ result = save_xml_file(xdoc, filename);
+
+ close_xml_file(xdoc, context);
+
+ free(filename);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : - *
* *
-* Description : Assure la présence d'unenvironnement pour serveur interne. *
+* Description : Assure la présence d'un environnement pour serveur interne. *
* *
* Retour : Bilan de l'opération. *
* *
diff --git a/src/analysis/db/auth.h b/src/analysis/db/auth.h
index 4464244..70b8a9e 100644
--- a/src/analysis/db/auth.h
+++ b/src/analysis/db/auth.h
@@ -30,7 +30,7 @@
#include "certs.h"
-
+#include "protocol.h"
/* Met en place un canal UNIX pour un serveur interne. */
@@ -51,6 +51,9 @@ bool setup_server_identity(const char *, const char *, unsigned long, x509_entri
/* 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);
diff --git a/src/analysis/db/backend-int.h b/src/analysis/db/backend-int.h
new file mode 100644
index 0000000..c74192c
--- /dev/null
+++ b/src/analysis/db/backend-int.h
@@ -0,0 +1,68 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * backend-int.h - prototypes internes pour le suivi d'une connexion à un serveur
+ *
+ * Copyright (C) 2021 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_BACKEND_INT_H
+#define _ANALYSIS_DB_BACKEND_INT_H
+
+
+#include <stdbool.h>
+
+
+#include "backend.h"
+
+
+
+/* Prend en compte une connexion nouvelle d'un utilisateur. */
+typedef void (* add_backend_client_fc) (GServerBackend *, SSL *, const char *, const char *);
+
+
+/* Support pour un suivi de connexion à un serveur (instance) */
+struct _GServerBackend
+{
+ GObject parent; /* A laisser en premier */
+
+ int stop_ctrl[2]; /* Commande d'arrêt */
+ int refresh_ctrl[2]; /* Commande d'actualisation */
+ GThread *process; /* Procédure de traitement */
+
+};
+
+/* Support pour un suivi de connexion à un serveur (classe) */
+struct _GServerBackendClass
+{
+ GObjectClass parent; /* A laisser en premier */
+
+ const char *thread_name; /* Désignation de processus */
+ GThreadFunc thread_func; /* Traitement des échanges */
+
+ add_backend_client_fc add_client; /* Intégration d'un client */
+
+};
+
+
+/* Met fin à un support de suivi. */
+void g_server_backend_stop(GServerBackend *);
+
+
+
+#endif /* _ANALYSIS_DB_BACKEND_INT_H */
diff --git a/src/analysis/db/backend.c b/src/analysis/db/backend.c
new file mode 100644
index 0000000..3a5f46e
--- /dev/null
+++ b/src/analysis/db/backend.c
@@ -0,0 +1,267 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * backend.c - suivi d'une connexion à un serveur
+ *
+ * Copyright (C) 2021 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 "backend.h"
+
+
+#include <unistd.h>
+
+
+#include "backend-int.h"
+#include "../../core/logs.h"
+
+
+
+/* Initialise la classe des supports pour suivi de connexion. */
+static void g_server_backend_class_init(GServerBackendClass *);
+
+/* Initialise un support pour suivi de connexion. */
+static void g_server_backend_init(GServerBackend *);
+
+/* Supprime toutes les références externes. */
+static void g_server_backend_dispose(GServerBackend *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_server_backend_finalize(GServerBackend *);
+
+
+
+/* Indique le type défini pour un Support de suivi de connexion. */
+G_DEFINE_TYPE(GServerBackend, g_server_backend, G_TYPE_OBJECT);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des supports pour suivi de connexion. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_server_backend_class_init(GServerBackendClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_server_backend_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_server_backend_finalize;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : backend = instance à initialiser. *
+* *
+* Description : Initialise un support pour suivi de connexion. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_server_backend_init(GServerBackend *backend)
+{
+ backend->stop_ctrl[0] = -1;
+ backend->stop_ctrl[1] = -1;
+ backend->refresh_ctrl[0] = -1;
+ backend->refresh_ctrl[1] = -1;
+ backend->process = NULL;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : backend = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_server_backend_dispose(GServerBackend *backend)
+{
+ G_OBJECT_CLASS(g_server_backend_parent_class)->dispose(G_OBJECT(backend));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : backend = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_server_backend_finalize(GServerBackend *backend)
+{
+ G_OBJECT_CLASS(g_server_backend_parent_class)->finalize(G_OBJECT(backend));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : backend = support pour le suivi d'une connexion. *
+* fd = canal de communication réseau ouvert. *
+* peer_name = désignation de la connexion. *
+* *
+* Description : Prend en compte une connexion nouvelle d'un utilisateur. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_server_backend_add_client(GServerBackend *backend, SSL *fd, const char *peer_name)
+{
+ GServerBackendClass *class; /* Classe du support manipulé */
+ X509 *peer_cert; /* Certificat présenté */
+ char *user; /* Nom d'utilisateur associé */
+ int ret; /* Bilan d'un appel */
+ ssize_t sent; /* Quantité de données émises */
+
+ class = G_SERVER_BACKEND_GET_CLASS(backend);
+
+ /* Ajout dans la liste officielle */
+
+ peer_cert = SSL_get_peer_certificate(fd);
+
+ user = X509_NAME_oneline(X509_get_subject_name(peer_cert), NULL, -1);
+
+ X509_free(peer_cert);
+
+ class->add_client(backend, fd, peer_name, user);
+
+ free(user);
+
+ /* Démarrage ou redémarrage du processus d'écoute */
+
+ if (backend->process == NULL)
+ {
+ ret = pipe(backend->stop_ctrl);
+ if (ret != 0)
+ {
+ LOG_ERROR_N("pipe");
+ g_object_unref(G_OBJECT(backend));
+ goto sys_error;
+ }
+
+ ret = pipe(backend->refresh_ctrl);
+ if (ret != 0)
+ {
+ LOG_ERROR_N("pipe");
+ g_object_unref(G_OBJECT(backend));
+ goto sys_error;
+ }
+
+ backend->process = g_thread_new(class->thread_name, class->thread_func, backend);
+
+ sys_error:
+
+ ;
+
+ }
+
+ else
+ {
+ sent = write(backend->refresh_ctrl[1], "\xf0", 1);
+ if (sent != 1) LOG_ERROR_N("write");
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : backend = support pour le suivi d'une connexion. *
+* *
+* Description : Met fin à un support de suivi. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_server_backend_stop(GServerBackend *backend)
+{
+ GThread *process; /* Procédure à terminer */
+ int ret; /* Bilan d'un appel */
+ ssize_t sent; /* Quantité de données émises */
+
+ /* Gestion du double appel */
+
+ if (backend->process == NULL)
+ return;
+
+ process = backend->process;
+
+ backend->process = NULL;
+
+ /* Ordre d'arrêt */
+
+ if (g_thread_self() != process)
+ {
+ sent = write(backend->stop_ctrl[1], "\xf0", 1);
+ if (sent != 1) LOG_ERROR_N("write");
+
+ g_thread_join(process);
+
+ }
+
+ /* Fermeture des flux */
+
+ ret = close(backend->stop_ctrl[0]);
+ if (ret == -1) LOG_ERROR_N("close");
+ backend->stop_ctrl[0] = -1;
+
+ ret = close(backend->stop_ctrl[1]);
+ if (ret == -1) LOG_ERROR_N("close");
+ backend->stop_ctrl[1] = -1;
+
+ ret = close(backend->refresh_ctrl[0]);
+ if (ret == -1) LOG_ERROR_N("close");
+ backend->refresh_ctrl[0] = -1;
+
+ ret = close(backend->refresh_ctrl[1]);
+ if (ret == -1) LOG_ERROR_N("close");
+ backend->refresh_ctrl[1] = -1;
+
+}
diff --git a/src/analysis/db/backend.h b/src/analysis/db/backend.h
new file mode 100644
index 0000000..0aad651
--- /dev/null
+++ b/src/analysis/db/backend.h
@@ -0,0 +1,56 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * backend.h - prototypes pour le suivi d'une connexion à un serveur
+ *
+ * Copyright (C) 2021 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_BACKEND_H
+#define _ANALYSIS_DB_BACKEND_H
+
+
+#include <glib-object.h>
+#include <openssl/ssl.h>
+
+
+
+#define G_TYPE_SERVER_BACKEND g_server_backend_get_type()
+#define G_SERVER_BACKEND(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SERVER_BACKEND, GServerBackend))
+#define G_IS_SERVER_BACKEND(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SERVER_BACKEND))
+#define G_SERVER_BACKEND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SERVER_BACKEND, GServerBackendClass))
+#define G_IS_SERVER_BACKEND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SERVER_BACKEND))
+#define G_SERVER_BACKEND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SERVER_BACKEND, GServerBackendClass))
+
+
+/* Support pour un suivi de connexion à un serveur (instance) */
+typedef struct _GServerBackend GServerBackend;
+
+/* Support pour un suivi de connexion à un serveur (classe) */
+typedef struct _GServerBackendClass GServerBackendClass;
+
+
+/* Indique le type défini pour un Support de suivi de connexion. */
+GType g_server_backend_get_type(void);
+
+/* Prend en compte une connexion nouvelle d'un utilisateur. */
+void g_server_backend_add_client(GServerBackend *, SSL *, const char *);
+
+
+
+#endif /* _ANALYSIS_DB_BACKEND_H */
diff --git a/src/analysis/db/cdb.c b/src/analysis/db/cdb.c
index 9e24f84..6d4b84d 100644
--- a/src/analysis/db/cdb.c
+++ b/src/analysis/db/cdb.c
@@ -1,6 +1,6 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
- * cdb.h - prototypes pour la manipulation des archives au format CDB
+ * cdb.c - manipulation des archives au format CDB
*
* Copyright (C) 2014-2019 Cyrille Bagard
*
@@ -26,10 +26,10 @@
#include <assert.h>
#include <errno.h>
+#include <fcntl.h>
#include <malloc.h>
#include <poll.h>
#include <pthread.h>
-#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
@@ -38,16 +38,20 @@
#include <sys/stat.h>
-#include <i18n.h>
#include <config.h>
+#include <i18n.h>
+#include "backend-int.h"
#include "collection.h"
#include "protocol.h"
#include "snapshot.h"
+#include "../content.h"
+#include "../storage/storage.h"
#include "../../common/compression.h"
#include "../../common/cpp.h"
#include "../../common/extstr.h"
+#include "../../common/io.h"
#include "../../common/pathname.h"
#include "../../common/xml.h"
#include "../../core/collections.h"
@@ -55,51 +59,70 @@
-/* ------------------------- COEUR DE LA GESTION D'ARCHIVES ------------------------- */
+/* -------------------------- LIEN VERS UN CLIENT CONNECTE -------------------------- */
/* Informations relatives à un client */
typedef struct _cdb_client
{
- SSL *ssl_fd; /* Canal de communication */
+ SSL *tls_fd; /* Canal de communication */
+ char *peer_name; /* Désignation du correspondant*/
char *user; /* Utilisateur à l'autre bout */
- uint64_t last_time; /* Date de dernier envoi */
+ gint ref_count; /* Décompte d'utilisation */
} cdb_client;
+/* Met en place le suivi d'une connexion de client. */
+static cdb_client *create_cdb_client(SSL *, const char *, const char *);
+
+/* Supprime le suivi d'une connexion de client. */
+static void delete_cdb_client(cdb_client *);
+
+/* Augmente le décompte d'utilisation d'un suivi de connexion. */
+static void ref_cdb_client(cdb_client *);
+
+/* Diminue le décompte d'utilisation d'un suivi de connexion. */
+static void unref_cdb_client(cdb_client *);
+
+
+
+/* ------------------------- COEUR DE LA GESTION D'ARCHIVES ------------------------- */
+
+
/* Description d'une archive d'éléments utilisateur (instance) */
struct _GCdbArchive
{
- GObject parent; /* A laisser en premier */
+ GServerBackend parent; /* A laisser en premier */
rle_string hash; /* Empreinte cryptographique */
+ rle_string class; /* Nature du contenu analysé */
char *filename; /* Chemin d'accès à l'archive */
char *tmpdir; /* Répertoire de travail */
char *xml_desc; /* Fichier de description */
+ char *cnt_file; /* Fichier de contenu binaire */
+
+ GMutex loading_access; /* Verrou pour l'accès */
+
+
GList *collections; /* Ensemble de modifications */
GDbSnapshot *snapshot; /* Instantanés de bases SQL */
sqlite3 *db; /* Base de données à manipuler */
- cdb_client *clients; /* Connexions en place */
+ cdb_client **clients; /* Connexions en place */
size_t count; /* Quantité de clients */
GMutex clients_access; /* Verrou pour l'accès */
- GThread *process; /* Procédure de traitement */
- GMutex id_access; /* Accès à l'identifiant */
- GCond id_cond; /* Condition d'attente */
- pthread_t process_id; /* Identifiant de la procédure */
-
};
/* Description d'une archive d'éléments utilisateur (classe) */
struct _GCdbArchiveClass
{
- GObjectClass parent; /* A laisser en premier */
+ GServerBackendClass parent; /* A laisser en premier */
};
@@ -147,20 +170,135 @@ static void on_collection_extended(GDbCollection *, GDbItem *, GCdbArchive *);
/* Assure le traitement des requêtes de clients. */
static void *g_cdb_archive_process(GCdbArchive *);
+/* Prend en compte une connexion nouvelle d'un utilisateur. */
+static void g_cdb_archive_add_client(GCdbArchive *, SSL *, const char *, const char *);
+
+/* Dissocie un utilisateur de l'archive. */
+static void _g_cdb_archive_remove_client(GCdbArchive *, size_t);
+
+/* Dissocie un utilisateur de l'archive. */
+static void g_cdb_archive_remove_client(GCdbArchive *, size_t);
+
/* Envoie un paquet de données constitué à tous les clients. */
-static void g_cdb_archive_send_reply_to_all_clients(GCdbArchive *, packed_buffer *);
+static void g_cdb_archive_send_reply_to_all_clients(GCdbArchive *, packed_buffer_t *);
/* Envoie à tous les clients la nouvelle liste d'instantanés. */
-static bool g_cdb_archive_send_snapshot_update(GCdbArchive *, packed_buffer *);
+static bool g_cdb_archive_send_snapshot_update(GCdbArchive *, packed_buffer_t *);
/* Envoie à tous les clients le nouvel instantané courant. */
-static bool g_cdb_archive_send_snapshot_change(GCdbArchive *, packed_buffer *);
+static bool g_cdb_archive_send_snapshot_change(GCdbArchive *, packed_buffer_t *);
-/* Dissocie un utilisateur de l'archive. */
-static void _g_cdb_archive_remove_client(GCdbArchive *, size_t);
-/* Dissocie un utilisateur de l'archive. */
-static void g_cdb_archive_remove_client(GCdbArchive *, size_t);
+
+/* ------------------------- PRISES EN COMPTE DES COMMANDES ------------------------- */
+
+
+/* Prépare une courte réponse à envoyer à un client connecté. */
+static bool craft_server_short_answer(DBCommand, uleb128_t, packed_buffer_t *);
+
+/* Enregistre le contenu binaire lié à une analyse. */
+static bool g_cdb_archive_set_content(GCdbArchive *, packed_buffer_t *, packed_buffer_t *);
+
+
+
+/* -------------------------- LIEN VERS UN CLIENT CONNECTE -------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : fd = canal de communication réseau ouvert. *
+* peer_name = désignation de la connexion. *
+* user = désignation de l'utilisateur de la connexion. *
+* *
+* Description : Met en place le suivi d'une connexion de client. *
+* *
+* Retour : Structure dédiée construite. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static cdb_client *create_cdb_client(SSL *fd, const char *peer_name, const char *user)
+{
+ cdb_client *result; /* Fiche d'entité à retourner */
+
+ result = malloc(sizeof(cdb_client));
+
+ result->tls_fd = fd;
+
+ result->peer_name = strdup(peer_name);
+ result->user = strdup(user);
+
+ g_atomic_int_set(&result->ref_count, 1);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : client = informations de suivi à libérer de la mémoire. *
+* *
+* Description : Supprime le suivi d'une connexion de client. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void delete_cdb_client(cdb_client *client)
+{
+ assert(g_atomic_int_get(&client->ref_count) == 0);
+
+ SSL_free(client->tls_fd);
+
+ free(client->peer_name);
+ free(client->user);
+
+ free(client);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : client = informations de suivi à libérer de la mémoire. *
+* *
+* Description : Augmente le décompte d'utilisation d'un suivi de connexion. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void ref_cdb_client(cdb_client *client)
+{
+ g_atomic_int_inc(&client->ref_count);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : client = informations de suivi à libérer de la mémoire. *
+* *
+* Description : Diminue le décompte d'utilisation d'un suivi de connexion. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void unref_cdb_client(cdb_client *client)
+{
+ if (g_atomic_int_dec_and_test(&client->ref_count))
+ delete_cdb_client(client);
+
+}
@@ -170,7 +308,7 @@ static void g_cdb_archive_remove_client(GCdbArchive *, size_t);
/* Indique le type défini pour une une archive d'éléments utilisateur. */
-G_DEFINE_TYPE(GCdbArchive, g_cdb_archive, G_TYPE_OBJECT);
+G_DEFINE_TYPE(GCdbArchive, g_cdb_archive, G_TYPE_SERVER_BACKEND);
/******************************************************************************
@@ -188,12 +326,20 @@ G_DEFINE_TYPE(GCdbArchive, g_cdb_archive, G_TYPE_OBJECT);
static void g_cdb_archive_class_init(GCdbArchiveClass *klass)
{
GObjectClass *object; /* Autre version de la classe */
+ GServerBackendClass *backend; /* Classe parente */
object = G_OBJECT_CLASS(klass);
object->dispose = (GObjectFinalizeFunc/* ! */)g_cdb_archive_dispose;
object->finalize = (GObjectFinalizeFunc)g_cdb_archive_finalize;
+ backend = G_SERVER_BACKEND_CLASS(klass);
+
+ backend->thread_name = "cdb_archiver";
+ backend->thread_func = (GThreadFunc)g_cdb_archive_process;
+
+ backend->add_client = (add_backend_client_fc)g_cdb_archive_add_client;
+
}
@@ -212,18 +358,22 @@ static void g_cdb_archive_class_init(GCdbArchiveClass *klass)
static void g_cdb_archive_init(GCdbArchive *archive)
{
setup_empty_rle_string(&archive->hash);
+ setup_empty_rle_string(&archive->class);
+ archive->filename = NULL;
archive->tmpdir = NULL;
+ archive->xml_desc = NULL;
+
+ archive->cnt_file = NULL;
+ g_mutex_init(&archive->loading_access);
archive->collections = create_collections_list();
archive->snapshot = NULL;
+ archive->db = NULL;
g_mutex_init(&archive->clients_access);
- g_mutex_init(&archive->id_access);
- g_cond_init(&archive->id_cond);
-
}
@@ -241,13 +391,14 @@ static void g_cdb_archive_init(GCdbArchive *archive)
static void g_cdb_archive_dispose(GCdbArchive *archive)
{
- g_clear_object(&archive->snapshot);
-
- g_cond_clear(&archive->id_cond);
- g_mutex_clear(&archive->id_access);
+ g_server_backend_stop(G_SERVER_BACKEND(archive));
g_mutex_clear(&archive->clients_access);
+ g_clear_object(&archive->snapshot);
+
+ g_mutex_clear(&archive->loading_access);
+
G_OBJECT_CLASS(g_cdb_archive_parent_class)->dispose(G_OBJECT(archive));
}
@@ -281,14 +432,19 @@ static void g_cdb_archive_finalize(GCdbArchive *archive)
#endif
}
+ if (archive->cnt_file != NULL)
+ free(archive->cnt_file);
+
if (archive->xml_desc != NULL)
free(archive->xml_desc);
- free(archive->filename);
-
if (archive->tmpdir != NULL)
free(archive->tmpdir);
+ if (archive->filename != NULL)
+ free(archive->filename);
+
+ exit_rle_string(&archive->class);
exit_rle_string(&archive->hash);
G_OBJECT_CLASS(g_cdb_archive_parent_class)->finalize(G_OBJECT(archive));
@@ -301,6 +457,7 @@ 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. *
+* class = nature du contenu analysé associé. *
* error = indication éventuelle en cas d'échec. [OUT] *
* *
* Description : Définit ou ouvre une archive d'éléments utilisateur. *
@@ -312,7 +469,7 @@ static void g_cdb_archive_finalize(GCdbArchive *archive)
* *
******************************************************************************/
-GCdbArchive *g_cdb_archive_new(const char *basedir, const char *tmpdir, const rle_string *hash, DBError *error)
+GCdbArchive *g_cdb_archive_new(const char *basedir, const char *tmpdir, const rle_string *hash, const rle_string *class, DBError *error)
{
GCdbArchive *result; /* Adresse à retourner */
int ret; /* Retour d'un appel */
@@ -321,13 +478,16 @@ GCdbArchive *g_cdb_archive_new(const char *basedir, const char *tmpdir, const rl
result = g_object_new(G_TYPE_CDB_ARCHIVE, NULL);
dup_into_rle_string(&result->hash, get_rle_string(hash));
+ dup_into_rle_string(&result->class, get_rle_string(class));
*error = DBE_SYS_ERROR;
/* Chemin de l'archive */
result->filename = strdup(basedir);
- result->filename = stradd(result->filename, hash->data);
+ result->filename = stradd(result->filename, get_rle_string(hash));
+ result->filename = stradd(result->filename, "-");
+ result->filename = stradd(result->filename, get_rle_string(class));
result->filename = stradd(result->filename, ".cdb.tar.xz");
if (!mkpath(result->filename))
@@ -340,11 +500,8 @@ GCdbArchive *g_cdb_archive_new(const char *basedir, const char *tmpdir, const rl
if (!mkpath(tmpdir))
goto error;
- ret = asprintf(&result->xml_desc, "%s" G_DIR_SEPARATOR_S "%s_desc.xml", tmpdir, get_rle_string(hash));
- if (ret == -1) goto no_tmp;
-
- ret = ensure_path_exists(result->xml_desc);
- if (ret == -1) goto no_tmp;
+ result->xml_desc = g_cdb_archive_get_tmp_filename(result, "desc.xml");
+ if (result->xml_desc == NULL) goto no_tmp;
/* Création de l'archive si elle n'existe pas */
@@ -355,7 +512,7 @@ GCdbArchive *g_cdb_archive_new(const char *basedir, const char *tmpdir, const rl
/* Le soucis ne vient pas de l'absence du fichier... */
if (errno != ENOENT) goto error;
- result->snapshot = g_db_snapshot_new_empty(tmpdir, get_rle_string(hash), result->collections);
+ result->snapshot = g_db_snapshot_new_empty(result, result->collections);
if (result->snapshot == NULL)
goto error;
@@ -426,6 +583,47 @@ GCdbArchive *g_cdb_archive_new(const char *basedir, const char *tmpdir, const rl
/******************************************************************************
* *
* Paramètres : archive = informations quant à l'archive à interpréter. *
+* suffix = fin du nom de fichier à définir. *
+* *
+* Description : Construit un chemin pour un fichier propre à l'archive. *
+* *
+* Retour : Chemin de fichier à utiliser ou NULL en cas d'erreur. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+char *g_cdb_archive_get_tmp_filename(const GCdbArchive *archive, const char *suffix)
+{
+ char *result; /* Chemin à retourner */
+ int ret; /* Retour d'un appel */
+
+ ret = asprintf(&result, "%s" G_DIR_SEPARATOR_S "%s_%s",
+ archive->tmpdir, get_rle_string(&archive->hash), suffix);
+
+ if (ret == -1)
+ result = NULL;
+
+ else
+ {
+ ret = ensure_path_exists(result);
+
+ if (ret == -1)
+ {
+ free(result);
+ result = NULL;
+ }
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : archive = informations quant à l'archive à interpréter. *
* *
* Description : Ouvre une archive avec tous les éléments à conserver. *
* *
@@ -475,8 +673,7 @@ static DBError g_cdb_archive_read(GCdbArchive *archive)
goto load_error;
}
- archive->snapshot = g_db_snapshot_new_from_xml(archive->tmpdir, get_rle_string(&archive->hash),
- xdoc, context);
+ archive->snapshot = g_db_snapshot_new_from_xml(archive, xdoc, context);
close_xml_file(xdoc, context);
@@ -503,7 +700,7 @@ static DBError g_cdb_archive_read(GCdbArchive *archive)
ret = archive_read_open_filename(in, archive->filename, 10240 /* ?! */);
if (ret != ARCHIVE_OK) goto bad_archive;
- status = g_db_snapshot_fill(archive->snapshot, in);
+ status = g_db_snapshot_fill(archive->snapshot, in, archive);
if (!status) goto load_error;
result = DBE_NONE;
@@ -616,18 +813,26 @@ DBError g_cdb_archive_write(const GCdbArchive *archive)
* *
* Paramètres : archive = informations quant à l'archive à consulter. *
* hash = empreinte extérieure à comparer. *
+* class = nature du contenu analysé. *
* *
-* Description : Détermine si une empreinte correspond à celle d'une archive. *
+* Description : Détermine l'archive correspond à une cible recherchée. *
* *
-* Retour : Résultat de la comparaison : -1, 0 ou 1. *
+* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
-int g_cdb_archive_compare_hash(const GCdbArchive *archive, const rle_string *hash)
+bool g_cdb_archive_compare_is_suitable_for(const GCdbArchive *archive, const rle_string *hash, const rle_string *class)
{
- return cmp_rle_string(&archive->hash, hash);
+ bool result; /* Bilan à retourner */
+
+ result = (cmp_rle_string(&archive->hash, hash) == 0);
+
+ if (result)
+ result = (cmp_rle_string(&archive->class, class) == 0);
+
+ return result;
}
@@ -792,7 +997,7 @@ static void g_cdb_archive_register_signals(GCdbArchive *archive)
static void on_collection_extended(GDbCollection *collec, GDbItem *item, GCdbArchive *archive)
{
- packed_buffer pbuf; /* Tampon d'émission */
+ packed_buffer_t pbuf; /* Tampon d'émission */
size_t i; /* Boucle de parcours */
bool status; /* Bilan d'un envoi de retour */
@@ -804,7 +1009,7 @@ static void on_collection_extended(GDbCollection *collec, GDbItem *item, GCdbArc
for (i = 0; i < archive->count && status; i++)
{
- status = ssl_send_packed_buffer(&pbuf, archive->clients[i].ssl_fd);
+ status = ssl_send_packed_buffer(&pbuf, archive->clients[i]->tls_fd);
if (!status)
LOG_ERROR(LMT_ERROR, _("Failed to send some DB update"));
@@ -832,66 +1037,91 @@ static void on_collection_extended(GDbCollection *collec, GDbItem *item, GCdbArc
static void *g_cdb_archive_process(GCdbArchive *archive)
{
+ GServerBackend *base; /* Base de l'instance */
+ cdb_client **clients; /* Clients surveillés */
+ size_t last_count; /* Quantité de ces clients */
struct pollfd *fds; /* Surveillance des flux */
nfds_t nfds; /* Quantité de ces flux */
nfds_t i; /* Boucle de parcours */
int ret; /* Bilan d'un appel */
- packed_buffer in_pbuf; /* Tampon de réception */
+ packed_buffer_t in_pbuf; /* Tampon de réception */
uint32_t tmp32; /* Valeur sur 32 bits */
bool status; /* Bilan de lecture initiale */
uint32_t command; /* Commande de la requête */
DBError error; /* Bilan d'une opération */
- packed_buffer out_pbuf; /* Tampon d'émission */
+ packed_buffer_t out_pbuf; /* Tampon d'émission */
GDbCollection *collec; /* Collection visée au final */
bool reload; /* Besoin de rechargement */
char *msg; /* Erreur à faire remonter */
- void interrupt_poll_with_sigusr1(int sig) { };
+ base = G_SERVER_BACKEND(archive);
- signal(SIGUSR1, interrupt_poll_with_sigusr1);
-
- g_mutex_lock(&archive->id_access);
- archive->process_id = pthread_self();
- g_cond_signal(&archive->id_cond);
- g_mutex_unlock(&archive->id_access);
+ clients = NULL;
+ last_count = 0;
fds = NULL;
while (1)
{
+ /* Réinitialisation ? */
+
+ for (i = 0; i < last_count; i++)
+ unref_cdb_client(clients[i]);
+
/* Reconstitution d'une liste à jour */
g_mutex_lock(&archive->clients_access);
- nfds = archive->count;
+ last_count = archive->count;
+
+ clients = realloc(clients, last_count * sizeof(cdb_client));
+
+ for (i = 0; i < last_count; i++)
+ {
+ clients[i] = archive->clients[i];
+ ref_cdb_client(clients[i]);
+ }
+
+ nfds = last_count + 2;
fds = realloc(fds, nfds * sizeof(struct pollfd));
- for (i = 0; i < nfds; i++)
+ for (i = 0; i < (nfds - 2); i++)
{
- fds[i].fd = SSL_get_fd(archive->clients[i].ssl_fd);
+ fds[i].fd = SSL_get_fd(clients[i]->tls_fd);
fds[i].events = POLLIN | POLLPRI;
}
g_mutex_unlock(&archive->clients_access);
- if (nfds == 0)
+ if (nfds == 2)
goto gcap_no_more_clients;
+ fds[nfds - 2].fd = base->stop_ctrl[0];
+ fds[nfds - 2].events = POLLIN | POLLPRI;
+
+ fds[nfds - 1].fd = base->refresh_ctrl[0];
+ fds[nfds - 1].events = POLLIN | POLLPRI;
+
/* Lancement d'une phase de surveillance */
ret = poll(fds, nfds, -1);
if (ret == -1)
{
- if (errno == EINTR) continue;
-
LOG_ERROR_N("poll");
break;
-
}
+ /* Demande expresse d'arrêt des procédures */
+ if (fds[nfds - 2].revents)
+ break;
+
+ /* Demande d'actualisation */
+ if (fds[nfds - 1].revents)
+ continue;
+
/* Traitement des requêtes reçues */
- for (i = 0; i < nfds; i++)
+ for (i = 0; i < (nfds - 1); i++)
{
/* Le canal est fermé, une sortie doit être demandée... */
if (fds[i].revents & POLLNVAL)
@@ -910,7 +1140,7 @@ static void *g_cdb_archive_process(GCdbArchive *archive)
{
init_packed_buffer(&in_pbuf);
- status = ssl_recv_packed_buffer(&in_pbuf, archive->clients[i].ssl_fd);
+ status = ssl_recv_packed_buffer(&in_pbuf, clients[i]->tls_fd);
if (!status) goto gcap_bad_exchange;
next_command:
@@ -920,13 +1150,21 @@ static void *g_cdb_archive_process(GCdbArchive *archive)
command = tmp32;
+ init_packed_buffer(&out_pbuf);
+
switch (command)
{
+ case DBC_SET_CONTENT:
+ status = g_cdb_archive_set_content(archive, &in_pbuf, &out_pbuf);
+ break;
+
+
+
case DBC_SAVE:
error = g_cdb_archive_write(archive);
- init_packed_buffer(&out_pbuf);
+ //init_packed_buffer(&out_pbuf);
status = extend_packed_buffer(&out_pbuf, (uint32_t []) { DBC_SAVE },
sizeof(uint32_t), true);
@@ -935,7 +1173,7 @@ static void *g_cdb_archive_process(GCdbArchive *archive)
status = extend_packed_buffer(&out_pbuf, (uint32_t []) { error }, sizeof(uint32_t), true);
if (!status) goto gcap_bad_reply;
- status = ssl_send_packed_buffer(&out_pbuf, archive->clients[i].ssl_fd);
+ status = ssl_send_packed_buffer(&out_pbuf, clients[i]->tls_fd);
if (!status) goto gcap_bad_reply;
exit_packed_buffer(&out_pbuf);
@@ -976,10 +1214,10 @@ static void *g_cdb_archive_process(GCdbArchive *archive)
status = extend_packed_buffer(&out_pbuf, (uint8_t []) { 0x0 }, sizeof(uint8_t), true);
if (!status) goto gcap_bad_reply;
- status = ssl_send_packed_buffer(&out_pbuf, archive->clients[i].ssl_fd);
- if (!status) goto gcap_bad_reply;
+ //status = ssl_send_packed_buffer(&out_pbuf, clients[i]->tls_fd);
+ //if (!status) goto gcap_bad_reply;
- exit_packed_buffer(&out_pbuf);
+ //exit_packed_buffer(&out_pbuf);
break;
@@ -998,7 +1236,7 @@ static void *g_cdb_archive_process(GCdbArchive *archive)
&in_pbuf, &out_pbuf, archive->db);
if (!status) goto gcap_bad_reply;
- status = ssl_send_packed_buffer(&out_pbuf, archive->clients[i].ssl_fd);
+ status = ssl_send_packed_buffer(&out_pbuf, clients[i]->tls_fd);
if (!status) goto gcap_bad_reply;
exit_packed_buffer(&out_pbuf);
@@ -1010,10 +1248,12 @@ static void *g_cdb_archive_process(GCdbArchive *archive)
if (!g_cdb_archive_send_snapshot_update(archive, &out_pbuf))
goto critical_error;
- status = ssl_send_packed_buffer(&out_pbuf, archive->clients[i].ssl_fd);
- if (!status) goto gcap_bad_reply;
+ status = true;
- exit_packed_buffer(&out_pbuf);
+ //status = ssl_send_packed_buffer(&out_pbuf, clients[i]->tls_fd);
+ //if (!status) goto gcap_bad_reply;
+
+ //exit_packed_buffer(&out_pbuf);
break;
@@ -1022,10 +1262,10 @@ static void *g_cdb_archive_process(GCdbArchive *archive)
if (!g_cdb_archive_send_snapshot_change(archive, &out_pbuf))
goto critical_error;
- status = ssl_send_packed_buffer(&out_pbuf, archive->clients[i].ssl_fd);
- if (!status) goto gcap_bad_reply;
+ //status = ssl_send_packed_buffer(&out_pbuf, clients[i]->tls_fd);
+ //if (!status) goto gcap_bad_reply;
- exit_packed_buffer(&out_pbuf);
+ //exit_packed_buffer(&out_pbuf);
break;
@@ -1100,7 +1340,7 @@ static void *g_cdb_archive_process(GCdbArchive *archive)
case DBC_CREATE_SNAPSHOT:
- error = g_db_snapshot_create(archive->snapshot, archive->db);
+ error = g_db_snapshot_create(archive->snapshot, archive->db, archive);
if (error == DBE_NONE)
{
@@ -1144,6 +1384,17 @@ static void *g_cdb_archive_process(GCdbArchive *archive)
}
+ if (!status)
+ goto gcap_bad_reply;
+
+ if (get_packed_buffer_payload_length(&out_pbuf) > 0)
+ {
+ status = ssl_send_packed_buffer(&out_pbuf, clients[i]->tls_fd);
+ if (!status) goto gcap_bad_reply;
+ }
+
+ exit_packed_buffer(&out_pbuf);
+
if (has_more_data_in_packed_buffer(&in_pbuf))
goto next_command;
@@ -1185,12 +1436,13 @@ static void *g_cdb_archive_process(GCdbArchive *archive)
gcap_no_more_clients:
- archive->process = NULL;
+ g_server_backend_stop(G_SERVER_BACKEND(archive));
+
+ for (i = 0; i < last_count; i++)
+ unref_cdb_client(clients[i]);
- g_mutex_lock(&archive->id_access);
- archive->process_id = 0;
- g_cond_signal(&archive->id_cond);
- g_mutex_unlock(&archive->id_access);
+ if (clients != NULL)
+ free(clients);
if (fds != NULL)
free(fds);
@@ -1202,6 +1454,170 @@ static void *g_cdb_archive_process(GCdbArchive *archive)
/******************************************************************************
* *
+* Paramètres : archive = support pour le suivi d'une connexion. *
+* fd = canal de communication réseau ouvert. *
+* peer_name = désignation de la connexion. *
+* user = désignation de l'utilisateur de la connexion. *
+* *
+* Description : Prend en compte une connexion nouvelle d'un utilisateur. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static LoadingStatusHint g_cdb_archive_compute_loading_hint(GCdbArchive *archive)
+{
+ LoadingStatusHint result; /* Statut à retourner */
+
+
+ // Try
+ // g_mutex_lock(&archive->loading_access);
+
+
+
+ // cnt_file
+
+ if (archive->cnt_file == NULL)
+ result = LSH_NEED_CONTENT;
+
+ else
+ result = LSH_NEED_FORMAT;
+
+
+
+
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : archive = support pour le suivi d'une connexion. *
+* fd = canal de communication réseau ouvert. *
+* peer_name = désignation de la connexion. *
+* user = désignation de l'utilisateur de la connexion. *
+* *
+* Description : Prend en compte une connexion nouvelle d'un utilisateur. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_cdb_archive_add_client(GCdbArchive *archive, SSL *fd, const char *peer_name, const char *user)
+{
+ cdb_client *client; /* Nouvelle fiche d'entité */
+ packed_buffer_t out_pbuf; /* Tampon d'émission */
+ LoadingStatusHint hint; /* Statut de chargement */
+ bool status; /* Bilan de lecture initiale */
+
+ client = create_cdb_client(fd, peer_name, user);
+
+ /**
+ * Le verrou encadrant les évolutions des contenus initiaux doit englober
+ * l'extension de la liste des clients.
+ *
+ * En effet, une évolution partielle peut intervenir dans la fonction
+ * g_cdb_archive_process(), à un moment au seul le verrou dans les
+ * évolutions sera posé (g_cdb_archive_set_content() par exemple).
+ *
+ * Or g_cdb_archive_compute_loading_hint() doit fournir ici un état qui ne
+ * varie pas entre le calcul et l'envoi. Donc verrous sur les clients et
+ * l'état de l'archive doivent englover l'ensemble des traitements ci-après.
+ */
+
+ g_mutex_lock(&archive->loading_access);
+
+ g_mutex_lock(&archive->clients_access);
+
+ hint = g_cdb_archive_compute_loading_hint(archive);
+
+ if (hint != LSH_READY)
+ hint = (archive->count == 0 ? hint : LSH_ON_WAIT_LIST);
+
+ init_packed_buffer(&out_pbuf);
+
+ status = craft_server_short_answer(DBC_LOADING_STATUS, hint, &out_pbuf);
+
+ if (status)
+ status = ssl_send_packed_buffer(&out_pbuf, fd);
+
+ exit_packed_buffer(&out_pbuf);
+
+ if (status)
+ {
+ archive->clients = realloc(archive->clients, ++archive->count * sizeof(cdb_client *));
+
+ archive->clients[archive->count - 1] = client;
+
+ }
+
+ g_mutex_unlock(&archive->clients_access);
+
+ g_mutex_unlock(&archive->loading_access);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : archive = archive à connecter avec un utilisateur. *
+* index = indice de l'utilisateur concerné. *
+* *
+* Description : Dissocie un utilisateur de l'archive. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void _g_cdb_archive_remove_client(GCdbArchive *archive, size_t index)
+{
+ assert(!g_mutex_trylock(&archive->clients_access));
+
+ unref_cdb_client(archive->clients[index]);
+
+ if ((index + 1) < archive->count)
+ memmove(&archive->clients[index], &archive->clients[index + 1],
+ (archive->count - index - 1) * sizeof(cdb_client *));
+
+ archive->clients = realloc(archive->clients, --archive->count * sizeof(cdb_client *));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : archive = archive à connecter avec un utilisateur. *
+* index = indice de l'utilisateur concerné. *
+* *
+* Description : Dissocie un utilisateur de l'archive. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_cdb_archive_remove_client(GCdbArchive *archive, size_t index)
+{
+ g_mutex_lock(&archive->clients_access);
+
+ _g_cdb_archive_remove_client(archive, index);
+
+ g_mutex_unlock(&archive->clients_access);
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : archive = archive à connecter avec un utilisateur. *
* pbuf = paquet de données à émettre. *
* *
@@ -1213,7 +1629,7 @@ static void *g_cdb_archive_process(GCdbArchive *archive)
* *
******************************************************************************/
-static void g_cdb_archive_send_reply_to_all_clients(GCdbArchive *archive, packed_buffer *pbuf)
+static void g_cdb_archive_send_reply_to_all_clients(GCdbArchive *archive, packed_buffer_t *pbuf)
{
size_t i; /* Boucle de parcours */
bool status; /* Bilan d'une émission */
@@ -1222,7 +1638,7 @@ static void g_cdb_archive_send_reply_to_all_clients(GCdbArchive *archive, packed
for (i = 0; i < archive->count; i++)
{
- status = ssl_send_packed_buffer(pbuf, archive->clients[i].ssl_fd);
+ status = ssl_send_packed_buffer(pbuf, archive->clients[i]->tls_fd);
if (!status)
{
log_variadic_message(LMT_ERROR, _("Error while replying to client %zu"), i);
@@ -1252,11 +1668,11 @@ static void g_cdb_archive_send_reply_to_all_clients(GCdbArchive *archive, packed
* *
******************************************************************************/
-static bool g_cdb_archive_send_snapshot_update(GCdbArchive *archive, packed_buffer *pbuf)
+static bool g_cdb_archive_send_snapshot_update(GCdbArchive *archive, packed_buffer_t *pbuf)
{
bool result; /* Bilan à retourner */
bool do_send; /* Réalisation de l'émission */
- packed_buffer out_pbuf; /* Tampon d'émission */
+ packed_buffer_t out_pbuf; /* Tampon d'émission */
do_send = (pbuf == NULL);
@@ -1301,11 +1717,11 @@ static bool g_cdb_archive_send_snapshot_update(GCdbArchive *archive, packed_buff
* *
******************************************************************************/
-static bool g_cdb_archive_send_snapshot_change(GCdbArchive *archive, packed_buffer *pbuf)
+static bool g_cdb_archive_send_snapshot_change(GCdbArchive *archive, packed_buffer_t *pbuf)
{
bool result; /* Bilan à retourner */
bool do_send; /* Réalisation de l'émission */
- packed_buffer out_pbuf; /* Tampon d'émission */
+ packed_buffer_t out_pbuf; /* Tampon d'émission */
snapshot_id_t id; /* Identifiant d'instantané */
do_send = (pbuf == NULL);
@@ -1339,132 +1755,186 @@ static bool g_cdb_archive_send_snapshot_change(GCdbArchive *archive, packed_buff
}
+
+/* ---------------------------------------------------------------------------------- */
+/* PRISES EN COMPTE DES COMMANDES */
+/* ---------------------------------------------------------------------------------- */
+
+
/******************************************************************************
* *
-* Paramètres : archive = archive à connecter avec un utilisateur. *
-* fd = canal de communication réseau ouvert. *
+* Paramètres : cmd = commande à l'origine d'un traitement. *
+* value = valeur à communiquer. *
+* out_pbuf = paquet à consituer pour un retour au client. [OUT]*
* *
-* Description : Associe un nouvel utilisateur à l'archive. *
+* Description : Prépare une courte réponse à envoyer à un client connecté. *
* *
-* Retour : - *
+* Retour : Indication pour le maintien de la communication. *
* *
* Remarques : - *
* *
******************************************************************************/
-void g_cdb_archive_add_client(GCdbArchive *archive, SSL *fd)
+static bool craft_server_short_answer(DBCommand cmd, uleb128_t value, packed_buffer_t *out_pbuf)
{
- X509 *peer_cert; /* Certificat présenté */
- volatile pthread_t *process_id; /* Identifiant de la procédure */
+ bool result; /* Bilan à retourner */
- /**
- * La situation est un peu compliquée lors de l'accueil d'un nouveau client :
- *
- * - soit on envoie tous les éléments à prendre en compte, mais on doit
- * bloquer la base de données jusqu'à l'intégration pleine et entière
- * du client, afin que ce dernier ne loupe pas l'envoi d'un nouvel
- * élément entre temps.
- *
- * - soit on intègre le client et celui ci demande des mises à jour
- * collection par collection ; c'est également à lui qui revient le rejet
- * des éléments envoyés en solitaires avant la réception de la base
- * complète.
- *
- * On fait le choix du second scenario ici, du fait de la difficulté
- * de maîtriser facilement la reconstitution d'une liste de clients dans
- * g_cdb_archive_process() depuis un autre flot d'exécution.
- */
+ init_packed_buffer(out_pbuf);
- /* Ajout dans la liste officielle */
+ result = extend_packed_buffer(out_pbuf, (uint32_t []) { cmd }, sizeof(uint32_t), true);
- g_mutex_lock(&archive->clients_access);
+ if (result)
+ result = pack_uleb128((uleb128_t []){ value }, out_pbuf);
- archive->clients = realloc(archive->clients, ++archive->count * sizeof(cdb_client));
+ return result;
- archive->clients[archive->count - 1].ssl_fd = fd;
+}
- peer_cert = SSL_get_peer_certificate(fd);
- archive->clients[archive->count - 1].user = X509_NAME_oneline(X509_get_subject_name(peer_cert), NULL, -1);
+/******************************************************************************
+* *
+* Paramètres : archive = archive à connecter avec un utilisateur. *
+* in_pbuf = paquet à consulter. *
+* out_pbuf = paquet à consituer pour un retour au client. [OUT]*
+* *
+* Description : Enregistre le contenu binaire lié à une analyse. *
+* *
+* Retour : Indication pour le maintien de la communication. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
- X509_free(peer_cert);
+static bool g_cdb_archive_set_content(GCdbArchive *archive, packed_buffer_t *in_pbuf, packed_buffer_t *out_pbuf)
+{
+ bool result; /* Bilan à retourner */
+ DBError error; /* Bilan d'une opération */
+ uleb128_t data_length; /* Taille du contenu stocké */
+ void *data; /* Données du stockage */
+ packed_buffer_t test_pbuf; /* Copie des données pour test */
+ uleb128_t pos; /* Position du contenu */
+ GObjectStorage *storage; /* Gestionnaire de stockage */
+ GSerializableObject *content; /* Contenu restitué */
+ const gchar *hash; /* Empreinte de ce contenu */
+ int fd; /* Flux ouvert en écriture */
+ bool status; /* Bilan d'une écriture */
+ LoadingStatusHint hint; /* Statut de chargement */
- /* Démarrage ou redémarrage du processus d'écoute */
+ result = true;
+ error = DBE_NONE;
- if (archive->process == NULL)
- {
- archive->process = g_thread_new("cdb_process", (GThreadFunc)g_cdb_archive_process, archive);
+ /* Récupération de la charge utile */
+
+ result = unpack_uleb128(&data_length, in_pbuf);
+ if (!result) goto exit;
+
+ data = malloc(data_length);
+
+ result = extract_packed_buffer(in_pbuf, data, data_length, false);
+ if (!result) goto free_and_exit;
+
+ /* Validation de l'empreinte du contenu */
+
+ init_packed_buffer(&test_pbuf);
- /* On attend que le processus parallèle soit prêt */
+ result = extend_packed_buffer(&test_pbuf, data, data_length, false);
+ if (!result) goto check_failure;
- process_id = &archive->process_id;
+ rewind_packed_buffer(&test_pbuf);
- g_mutex_lock(&archive->id_access);
- while (process_id == 0)
- g_cond_wait(&archive->id_cond, &archive->id_access);
- g_mutex_unlock(&archive->id_access);
+ result = unpack_uleb128(&pos, &test_pbuf);
+ if (!result) goto check_failure;
+ storage = g_object_storage_load(&test_pbuf);
+ if (storage == NULL)
+ {
+ result = false;
+ goto check_failure;
}
- else
- pthread_kill(archive->process_id, SIGUSR1);
- g_mutex_unlock(&archive->clients_access);
+ content = g_object_storage_load_object(storage, "contents", pos);
+ if (!G_IS_BIN_CONTENT(content))
+ {
+ result = false;
+ goto storage_check_failure;
+ }
-}
+ hash = g_binary_content_get_checksum(G_BIN_CONTENT(content));
+ if (strcmp(hash, get_rle_string(&archive->hash)) != 0)
+ error = DBE_WRONG_HASH;
-/******************************************************************************
-* *
-* Paramètres : archive = archive à connecter avec un utilisateur. *
-* index = indice de l'utilisateur concerné. *
-* *
-* Description : Dissocie un utilisateur de l'archive. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
+ g_object_unref(G_OBJECT(content));
-static void _g_cdb_archive_remove_client(GCdbArchive *archive, size_t index)
-{
- cdb_client *client; /* Client à traiter */
+ storage_check_failure:
- assert(!g_mutex_trylock(&archive->clients_access));
+ g_object_unref(G_OBJECT(storage));
- client = &archive->clients[index];
+ check_failure:
- SSL_free(client->ssl_fd);
- free(client->user);
+ exit_packed_buffer(&test_pbuf);
- if ((index + 1) < archive->count)
- memmove(&archive->clients[index], &archive->clients[index + 1],
- (archive->count - index - 1) * sizeof(cdb_client));
+ if (!result) goto free_and_exit;
- archive->clients = realloc(archive->clients, --archive->count * sizeof(cdb_client));
+ /* Enregistrement sur disque */
-}
+ if (error == DBE_NONE)
+ {
+ if (archive->cnt_file != NULL)
+ free(archive->cnt_file);
+ archive->cnt_file = g_cdb_archive_get_tmp_filename(archive, "storedcontent.bin");
+ if (archive->cnt_file == NULL)
+ {
+ error = DBE_SYS_ERROR;
+ goto save_error;
+ }
-/******************************************************************************
-* *
-* Paramètres : archive = archive à connecter avec un utilisateur. *
-* index = indice de l'utilisateur concerné. *
-* *
-* Description : Dissocie un utilisateur de l'archive. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
+ fd = open(archive->cnt_file, O_WRONLY | O_CREAT, 0600);
+ if (fd == -1)
+ {
+ error = DBE_SYS_ERROR;
+ goto save_error;
+ }
-static void g_cdb_archive_remove_client(GCdbArchive *archive, size_t index)
-{
- g_mutex_lock(&archive->clients_access);
+ status = safe_write(fd, data, data_length);
- _g_cdb_archive_remove_client(archive, index);
+ if (!status)
+ {
+ unlink(archive->cnt_file);
+ free(archive->cnt_file);
+ archive->cnt_file = NULL;
- g_mutex_unlock(&archive->clients_access);
+ error = DBE_SYS_ERROR;
+
+ }
+
+ close(fd);
+
+ save_error:
+
+ ;
+
+ }
+
+ /* Formulation de la réponse */
+
+ result = craft_server_short_answer(DBC_SET_CONTENT, error, out_pbuf);
+
+ if (result && error == DBE_NONE)
+ {
+ hint = g_cdb_archive_compute_loading_hint(archive);
+
+ result = craft_server_short_answer(DBC_LOADING_STATUS, hint, out_pbuf);
+
+ }
+
+ free_and_exit:
+
+ free(data);
+
+ exit:
+
+ return result;
}
diff --git a/src/analysis/db/cdb.h b/src/analysis/db/cdb.h
index 58bb781..7a557f2 100644
--- a/src/analysis/db/cdb.h
+++ b/src/analysis/db/cdb.h
@@ -54,22 +54,16 @@ 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 char *, const rle_string *, DBError *);
+GCdbArchive *g_cdb_archive_new(const char *, const char *, const rle_string *, const rle_string *, DBError *);
+
+/* Construit un chemin pour un fichier propre à l'archive. */
+char *g_cdb_archive_get_tmp_filename(const GCdbArchive *, const char *);
/* Enregistre une archive avec tous les éléments à conserver. */
DBError g_cdb_archive_write(const GCdbArchive *);
-/* Détermine si une empreinte correspond à celle d'une archive. */
-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 *);
-
-
+/* Détermine l'archive correspond à une cible recherchée. */
+bool g_cdb_archive_compare_is_suitable_for(const GCdbArchive *, const rle_string *, const rle_string *);
diff --git a/src/analysis/db/certs.c b/src/analysis/db/certs.c
index dabc127..22ff397 100644
--- a/src/analysis/db/certs.c
+++ b/src/analysis/db/certs.c
@@ -39,6 +39,7 @@
#include <i18n.h>
+#include "../../common/extstr.h"
#include "../../core/logs.h"
@@ -52,6 +53,9 @@ static bool add_extension_to_req(STACK_OF(X509_EXTENSION) *, int, /*const */char
/* Crée une paire de clefs RSA. */
static RSA *generate_rsa_key(unsigned int, unsigned long);
+/* Recharge l'identité inscrite dans un élément X509. */
+static bool load_identity_from_x509(/*const */X509_NAME *, x509_entries *);
+
/******************************************************************************
@@ -97,6 +101,70 @@ bool are_x509_entries_empty(const x509_entries *entries)
/******************************************************************************
* *
+* Paramètres : entries = éléments d'identité à convertir. *
+* *
+* Description : Traduit en chaîne de caractères une définition d'identité. *
+* *
+* Retour : Chaîne de caractères ou NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+char *translate_x509_entries(const x509_entries *entries)
+{
+ char *result; /* Description à retourner */
+
+ result = NULL;
+
+ if (entries->country != NULL)
+ {
+ result = stradd(result, "C=");
+ result = stradd(result, entries->country);
+ }
+
+ if (entries->state != NULL)
+ {
+ if (result != NULL) result = stradd(result, "/");
+ result = stradd(result, "ST=");
+ result = stradd(result, entries->state);
+ }
+
+ if (entries->locality != NULL)
+ {
+ if (result != NULL) result = stradd(result, "/");
+ result = stradd(result, "L=");
+ result = stradd(result, entries->locality);
+ }
+
+ if (entries->organisation != NULL)
+ {
+ if (result != NULL) result = stradd(result, "/");
+ result = stradd(result, "O=");
+ result = stradd(result, entries->organisation);
+ }
+
+ if (entries->organisational_unit != NULL)
+ {
+ if (result != NULL) result = stradd(result, "/");
+ result = stradd(result, "OU=");
+ result = stradd(result, entries->organisational_unit);
+ }
+
+ if (entries->common_name != NULL)
+ {
+ if (result != NULL) result = stradd(result, "/");
+ result = stradd(result, "CN=");
+ result = stradd(result, entries->common_name);
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : entries = éléments d'identité à supprimer de la mémoire. *
* *
* Description : Libère la mémoire occupée par une définition d'identité. *
@@ -255,6 +323,7 @@ static RSA *generate_rsa_key(unsigned int bits, unsigned long e)
bool build_keys_and_ca(const char *dir, const char *label, unsigned long valid, const x509_entries *entries)
{
+ bool result; /* Bilan à retourner */
RSA *rsa; /* Clef RSA pour le certificat */
EVP_PKEY *pk; /* Enveloppe pour clef publique*/
int ret; /* Bilan d'un appel */
@@ -263,20 +332,30 @@ bool build_keys_and_ca(const char *dir, const char *label, unsigned long valid,
char *filename; /* Chemin d'accès à un fichier */
FILE *stream; /* Flux ouvert en écriture */
+ result = false;
+
rsa = generate_rsa_key(4096, 17);
if (rsa == NULL) goto rsa_failed;
pk = EVP_PKEY_new();
- if (pk == NULL) goto pk_failed;
+ if (pk == NULL)
+ {
+ RSA_free(rsa);
+ goto pk_failed;
+ }
ret = EVP_PKEY_assign_RSA(pk, rsa);
- if (ret != 1) goto asign_failed;
+ if (ret != 1)
+ {
+ RSA_free(rsa);
+ goto asign_failed;
+ }
x509 = X509_new();
if (x509 == NULL) goto x509_failed;
ret = X509_set_pubkey(x509, pk);
- if (ret != 1) goto ca_failed;
+ if (ret != 1) goto ca_asign_failed;
ret = X509_set_version(x509, 2);
if (ret != 1) goto ca_failed;
@@ -344,7 +423,11 @@ bool build_keys_and_ca(const char *dir, const char *label, unsigned long valid,
asprintf(&filename, "%s%c%s-key.pem", dir, G_DIR_SEPARATOR, label);
stream = fopen(filename, "wb");
- if (stream == NULL) goto ca_failed;
+ if (stream == NULL)
+ {
+ free(filename);
+ goto ca_failed;
+ }
ret = PEM_write_PrivateKey(stream, pk, NULL, NULL, 0, NULL, NULL);
@@ -361,7 +444,11 @@ bool build_keys_and_ca(const char *dir, const char *label, unsigned long valid,
asprintf(&filename, "%s%c%s-cert.pem", dir, G_DIR_SEPARATOR, label);
stream = fopen(filename, "wb");
- if (stream == NULL) goto ca_failed;
+ if (stream == NULL)
+ {
+ free(filename);
+ goto ca_failed;
+ }
ret = PEM_write_X509(stream, x509);
@@ -375,34 +462,24 @@ bool build_keys_and_ca(const char *dir, const char *label, unsigned long valid,
if (ret != 1)
goto ca_failed;
- /* Libérations finales */
-
- X509_free(x509);
- EVP_PKEY_free(pk);
+ result = true;
- return true;
+ /* Libérations finales */
ca_failed:
+ ca_asign_failed:
X509_free(x509);
x509_failed:
-
- EVP_PKEY_free(pk);
-
- return false;
-
asign_failed:
EVP_PKEY_free(pk);
pk_failed:
-
- RSA_free(rsa);
-
rsa_failed:
- return false;
+ return result;
}
@@ -458,6 +535,7 @@ static bool add_extension_to_req(STACK_OF(X509_EXTENSION) *sk, int nid, /*const
bool build_keys_and_request(const char *dir, const char *label, const x509_entries *entries)
{
+ bool result; /* Bilan à retourner */
RSA *rsa; /* Clef RSA pour le certificat */
EVP_PKEY *pk; /* Enveloppe pour clef publique*/
int ret; /* Bilan d'un appel */
@@ -467,20 +545,30 @@ bool build_keys_and_request(const char *dir, const char *label, const x509_entri
char *filename; /* Chemin d'accès à un fichier */
FILE *stream; /* Flux ouvert en écriture */
+ result = false;
+
rsa = generate_rsa_key(2048, 17);
if (rsa == NULL) goto rsa_failed;
pk = EVP_PKEY_new();
- if (pk == NULL) goto pk_failed;
+ if (pk == NULL)
+ {
+ RSA_free(rsa);
+ goto pk_failed;
+ }
ret = EVP_PKEY_assign_RSA(pk, rsa);
- if (ret != 1) goto asign_failed;
+ if (ret != 1)
+ {
+ RSA_free(rsa);
+ goto asign_failed;
+ }
x509 = X509_REQ_new();
if (x509 == NULL) goto x509_failed;
ret = X509_REQ_set_pubkey(x509, pk);
- if (ret != 1) goto asign_failed;
+ if (ret != 1) goto req_asign_failed;
/* Etablissement d'une identité */
@@ -523,8 +611,6 @@ bool build_keys_and_request(const char *dir, const char *label, const x509_entri
ret = X509_REQ_add_extensions(x509, exts);
if (ret != 1) goto exts_failed;
- sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
-
/* Signature */
ret = X509_REQ_sign(x509, pk, EVP_sha256());
@@ -538,7 +624,11 @@ bool build_keys_and_request(const char *dir, const char *label, const x509_entri
asprintf(&filename, "%s%c%s-key.pem", dir, G_DIR_SEPARATOR, label);
stream = fopen(filename, "wb");
- if (stream == NULL) goto req_failed_2;
+ if (stream == NULL)
+ {
+ free(filename);
+ goto req_failed_2;
+ }
ret = PEM_write_PrivateKey(stream, pk, NULL, NULL, 0, NULL, NULL);
@@ -555,7 +645,11 @@ bool build_keys_and_request(const char *dir, const char *label, const x509_entri
asprintf(&filename, "%s%c%s-csr.pem", dir, G_DIR_SEPARATOR, label);
stream = fopen(filename, "wb");
- if (stream == NULL) goto req_failed_2;
+ if (stream == NULL)
+ {
+ free(filename);
+ goto req_failed_2;
+ }
ret = PEM_write_X509_REQ(stream, x509);
@@ -569,35 +663,87 @@ bool build_keys_and_request(const char *dir, const char *label, const x509_entri
if (ret != 1)
goto req_failed_2;
- return true;
+ result = true;
- req_failed_2:
+ /* Libérations finales */
+ req_failed_2:
exts_failed:
- sk_X509_EXTENSION_free(exts);
+ sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
req_failed:
+ req_asign_failed:
X509_REQ_free(x509);
x509_failed:
+ asign_failed:
EVP_PKEY_free(pk);
- return false;
+ pk_failed:
+ rsa_failed:
- asign_failed:
+ return result;
- EVP_PKEY_free(pk);
+}
- pk_failed:
- RSA_free(rsa);
+/******************************************************************************
+* *
+* Paramètres : subject = sujet d'un élément X509. *
+* entries = éléments de l'identité constituée. [OUT] *
+* *
+* Description : Recharge l'identité inscrite dans un élément X509. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool load_identity_from_x509(/*const */X509_NAME *subject, x509_entries *entries)
+{
+ bool result; /* Bilan à retourner */
+ int length; /* Taille du champ visé */
- rsa_failed:
+ result = false;
- return false;
+#define GET_NAME_ENTRY(key, value) \
+ do \
+ { \
+ length = X509_NAME_get_text_by_NID(subject, key, NULL, -1); \
+ if (length != -1) \
+ { \
+ entries->value = malloc((length + 1) * sizeof(char)); \
+ length = X509_NAME_get_text_by_NID(subject, key, entries->value, length + 1); \
+ assert(length != -1); \
+ if (length == -1) \
+ goto copy_failed; \
+ } \
+ } \
+ while (0)
+
+ GET_NAME_ENTRY(NID_countryName, country);
+
+ GET_NAME_ENTRY(NID_stateOrProvinceName, state);
+
+ GET_NAME_ENTRY(NID_localityName, locality);
+
+ GET_NAME_ENTRY(NID_organizationName, organisation);
+
+ GET_NAME_ENTRY(NID_organizationalUnitName, organisational_unit);
+
+ GET_NAME_ENTRY(NID_commonName, common_name);
+
+#undef GET_NAME_ENTRY
+
+ result = true;
+
+ copy_failed:
+
+ return result;
}
@@ -621,7 +767,6 @@ bool load_identity_from_request(const char *csr, x509_entries *entries)
FILE *stream; /* Flux ouvert en lecture */
X509_REQ *req; /* Certificat X509 à signer */
X509_NAME *subject; /* Sujet du certificat */
- int length; /* Taille du champ visé */
result = false;
@@ -646,38 +791,65 @@ bool load_identity_from_request(const char *csr, x509_entries *entries)
subject = X509_REQ_get_subject_name(req);
-#define GET_NAME_ENTRY(key, value) \
- do \
- { \
- length = X509_NAME_get_text_by_NID(subject, key, NULL, -1); \
- if (length != -1) \
- { \
- entries->value = malloc((length + 1) * sizeof(char)); \
- length = X509_NAME_get_text_by_NID(subject, key, entries->value, length + 1); \
- assert(length != -1); \
- } \
- } \
- while (0)
+ result = load_identity_from_x509(subject, entries);
- GET_NAME_ENTRY(NID_countryName, country);
+ X509_REQ_free(req);
- GET_NAME_ENTRY(NID_stateOrProvinceName, state);
+ csr_read_failed:
- GET_NAME_ENTRY(NID_localityName, locality);
+ return result;
- GET_NAME_ENTRY(NID_organizationName, organisation);
+}
- GET_NAME_ENTRY(NID_organizationalUnitName, organisational_unit);
- GET_NAME_ENTRY(NID_commonName, common_name);
+/******************************************************************************
+* *
+* Paramètres : crt = fichier contenant un certificat signé. *
+* entries = éléments de l'identité constituée. [OUT] *
+* *
+* Description : Recharge l'identité inscrite dans un certificat signé. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
-#undef GET_NAME_ENTRY
+bool load_identity_from_cert(const char *crt, x509_entries *entries)
+{
+ bool result; /* Bilan à retourner */
+ FILE *stream; /* Flux ouvert en lecture */
+ X509 *x; /* Certificat X509 signé */
+ X509_NAME *subject; /* Sujet du certificat */
- X509_REQ_free(req);
+ result = false;
- result = true;
+ memset(entries, 0, sizeof(*entries));
- csr_read_failed:
+ /* Chargement de la requête */
+
+ stream = fopen(crt, "rb");
+ if (stream == NULL) goto crt_read_failed;
+
+ x = PEM_read_X509(stream, NULL, NULL, NULL);
+
+ fclose(stream);
+
+ if (x == NULL)
+ {
+ log_variadic_message(LMT_ERROR, _("Unable to read the signed certificate from '%s'"), crt);
+ goto crt_read_failed;
+ }
+
+ /* Recherche des éléments */
+
+ subject = X509_get_subject_name(x);
+
+ result = load_identity_from_x509(subject, entries);
+
+ X509_free(x);
+
+ crt_read_failed:
return result;
@@ -714,7 +886,12 @@ bool sign_cert(const char *csr, const char *cacert, const char *cakey, const cha
/* Chargement de la requête */
stream = fopen(csr, "rb");
- if (stream == NULL) goto csr_read_failed;
+
+ if (stream == NULL)
+ {
+ log_variadic_message(LMT_ERROR, _("Unable to open the certificate signing request file '%s'"), csr);
+ goto csr_read_failed;
+ }
req = PEM_read_X509_REQ(stream, NULL, NULL, NULL);
@@ -722,7 +899,7 @@ bool sign_cert(const char *csr, const char *cacert, const char *cakey, const cha
if (req == NULL)
{
- log_variadic_message(LMT_ERROR, _("Unable to read the certificate signing request from '%s'"), cert);
+ log_variadic_message(LMT_ERROR, _("Unable to read the certificate signing request from '%s'"), csr);
goto csr_read_failed;
}
@@ -735,7 +912,12 @@ bool sign_cert(const char *csr, const char *cacert, const char *cakey, const cha
/* Chargement des éléments de l'autorité */
stream = fopen(cacert, "rb");
- if (stream == NULL) goto cacert_read_failed;
+
+ if (stream == NULL)
+ {
+ log_variadic_message(LMT_ERROR, _("Unable to open the CA certificate file '%s'"), cacert);
+ goto cacert_read_failed;
+ }
ca_cert = PEM_read_X509(stream, NULL, NULL, NULL);
@@ -743,12 +925,17 @@ bool sign_cert(const char *csr, const char *cacert, const char *cakey, const cha
if (ca_cert == NULL)
{
- log_variadic_message(LMT_ERROR, _("Unable to read the certificate from '%s'"), cert);
+ log_variadic_message(LMT_ERROR, _("Unable to read the CA certificate from '%s'"), cacert);
goto cacert_read_failed;
}
stream = fopen(cakey, "rb");
- if (stream == NULL) goto cakey_read_failed;
+
+ if (stream == NULL)
+ {
+ log_variadic_message(LMT_ERROR, _("Unable to open the CA private key file '%s'"), cakey);
+ goto cakey_read_failed;
+ }
ca_pk = PEM_read_PrivateKey(stream, NULL, NULL, NULL);
@@ -756,7 +943,7 @@ bool sign_cert(const char *csr, const char *cacert, const char *cakey, const cha
if (ca_pk == NULL)
{
- log_variadic_message(LMT_ERROR, _("Unable to read the CA private key from %s"), cakey);
+ log_variadic_message(LMT_ERROR, _("Unable to read the CA private key from '%s'"), cakey);
goto cakey_read_failed;
}
diff --git a/src/analysis/db/certs.h b/src/analysis/db/certs.h
index 51a2e34..359b3d3 100644
--- a/src/analysis/db/certs.h
+++ b/src/analysis/db/certs.h
@@ -45,6 +45,9 @@ typedef struct _x509_entries
/* Indique si une définition existe dans l'identité. */
bool are_x509_entries_empty(const x509_entries *);
+/* Traduit en chaîne de caractères une définition d'identité. */
+char *translate_x509_entries(const x509_entries *);
+
/* Libère la mémoire occupée par une définition d'identité. */
void free_x509_entries(x509_entries *);
@@ -57,6 +60,9 @@ bool build_keys_and_request(const char *, const char *, const x509_entries *);
/* Recharge l'identité inscrite dans une requête de signature. */
bool load_identity_from_request(const char *, x509_entries *);
+/* Recharge l'identité inscrite dans un certificat signé. */
+bool load_identity_from_cert(const char *, 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-int.h b/src/analysis/db/client-int.h
new file mode 100644
index 0000000..3c140e9
--- /dev/null
+++ b/src/analysis/db/client-int.h
@@ -0,0 +1,79 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * client.h - prototypes pour la connexion à un serveur Chrysalide
+ *
+ * Copyright (C) 2014-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_CLIENT_INT_H
+#define _ANALYSIS_DB_CLIENT_INT_H
+
+
+#include "client.h"
+
+
+#include "../../common/packed.h"
+
+
+
+/* Termine la constitution des données initiales à présenter. */
+typedef bool (* complete_client_hello_fc) (GHubClient *, packed_buffer_t *);
+
+
+/* Description de client à l'écoute (instance) */
+struct _GHubClient
+{
+ GObject parent; /* A laisser en premier */
+
+ char *working; /* Répertoire de travail */
+
+ SSL_CTX *tls_ctx; /* Contexte du chiffrement */
+
+ int fd; /* Canal de communication */
+ SSL *tls_fd; /* Même canal, mais sécurisé */
+ char *desc; /* Description du lien */
+
+ GMutex sending_lock; /* Concurrence des envois */
+ int stop_ctrl[2]; /* Commande d'arrêt */
+ GThread *update; /* Procédure de traitement */
+
+};
+
+/* Description de client à l'écoute (classe) */
+struct _GHubClientClass
+{
+ GObjectClass parent; /* A laisser en premier */
+
+ uint32_t role; /* Rôle associé aux clients */
+ complete_client_hello_fc complete_hello;/* Finalisation de l'intro */
+ GThreadFunc recv_func; /* Réception de données */
+
+};
+
+
+
+/* Identifie le canal de communication pour envois au serveur. */
+SSL *g_hub_client_get_ssl_fd(GHubClient *);
+
+/* Marque le canal de communication comme disponible. */
+void g_hub_client_put_ssl_fd(GHubClient *, SSL *);
+
+
+
+#endif /* _ANALYSIS_DB_CLIENT_INT_H */
diff --git a/src/analysis/db/client.c b/src/analysis/db/client.c
index ba0fec8..6ce33b0 100644
--- a/src/analysis/db/client.c
+++ b/src/analysis/db/client.c
@@ -37,6 +37,7 @@
#include <i18n.h>
+#include "client-int.h"
#include "auth.h"
#include "protocol.h"
#include "misc/rlestr.h"
@@ -47,59 +48,6 @@
-/* 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 _GHubClient
-{
- GObject parent; /* A laisser en premier */
-
- 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 */
-
- int fd; /* Canal de communication */
- SSL *tls_fd; /* Même canal, mais sécurisé */
- char *desc; /* Description du lien */
-
- GMutex sending_lock; /* Concurrence des envois */
- bool can_get_updates; /* Réception de maj possibles ?*/
- GThread *update; /* Procédure de traitement */
-
- snapshot_info_t *snapshots; /* Liste des instantanés */
- size_t snap_count; /* Taille de cette liste */
- GMutex snap_lock; /* Concurrence des accès */
-
- snapshot_id_t current; /* Instantané courant */
- bool has_current; /* Validité de l'identifiant */
- GMutex cur_lock; /* Concurrence des accès */
-
-};
-
-/* Description de client à l'écoute (classe) */
-struct _GHubClientClass
-{
- GObjectClass parent; /* A laisser en premier */
-
- /* Signaux */
-
- void (* snapshots_updated) (GHubClient *);
- void (* snapshot_changed) (GHubClient *);
-
-};
-
-
/* Initialise la classe des descriptions de fichier binaire. */
static void g_hub_client_class_init(GHubClientClass *);
@@ -112,23 +60,17 @@ static void g_hub_client_dispose(GHubClient *);
/* Procède à la libération totale de la mémoire. */
static void g_hub_client_finalize(GHubClient *);
-/* Démarre réellement la connexion à la base de données. */
-static bool g_hub_client_start_common(GHubClient *, char *);
-
-/* Assure l'accueil des nouvelles mises à jour. */
-static void *g_hub_client_update(GHubClient *);
-
-/* Met à jour la liste des instantanés courants. */
-static bool g_hub_client_update_snapshots(GHubClient *, packed_buffer *);
-
-/* Met à jour l'identifiant de l'instantané courant. */
-static bool g_hub_client_update_current_snapshot(GHubClient *, packed_buffer *);
+/* 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 */
-/* Identifie le canal de communication pour envois au serveur. */
-static SSL *g_hub_client_get_ssl_fd(GHubClient *);
+} gen_sockaddr_t;
-/* Marque le canal de communication comme disponible. */
-static void g_hub_client_put_ssl_fd(GHubClient *, SSL *);
+/* Démarre réellement la connexion à la base de données. */
+static bool g_hub_client_start_common(GHubClient *, char *);
@@ -157,21 +99,9 @@ static void g_hub_client_class_init(GHubClientClass *klass)
object->dispose = (GObjectFinalizeFunc/* ! */)g_hub_client_dispose;
object->finalize = (GObjectFinalizeFunc)g_hub_client_finalize;
- g_signal_new("snapshots-updated",
- G_TYPE_HUB_CLIENT,
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET(GHubClientClass, snapshots_updated),
- NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
-
- g_signal_new("snapshot-changed",
- G_TYPE_HUB_CLIENT,
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET(GHubClientClass, snapshot_changed),
- NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
+ klass->role = CRL_UNDEFINED;
+ klass->complete_hello = NULL;
+ klass->recv_func = NULL;
}
@@ -190,9 +120,6 @@ static void g_hub_client_class_init(GHubClientClass *klass)
static void g_hub_client_init(GHubClient *client)
{
- setup_empty_rle_string(&client->hash);
- client->collections = NULL;
-
client->working = NULL;
client->tls_ctx = NULL;
@@ -202,17 +129,10 @@ static void g_hub_client_init(GHubClient *client)
client->desc = NULL;
g_mutex_init(&client->sending_lock);
- client->can_get_updates = false;
+ client->stop_ctrl[0] = -1;
+ client->stop_ctrl[1] = -1;
client->update = NULL;
- client->snapshots = NULL;
- client->snap_count = 0;
- g_mutex_init(&client->snap_lock);
-
- setup_empty_snapshot_id(&client->current);
- client->has_current = false;
- g_mutex_init(&client->cur_lock);
-
}
@@ -230,12 +150,6 @@ static void g_hub_client_init(GHubClient *client)
static void g_hub_client_dispose(GHubClient *client)
{
- g_hub_client_stop(client);
-
- g_mutex_clear(&client->cur_lock);
-
- g_mutex_clear(&client->snap_lock);
-
g_mutex_clear(&client->sending_lock);
G_OBJECT_CLASS(g_hub_client_parent_class)->dispose(G_OBJECT(client));
@@ -257,10 +171,6 @@ static void g_hub_client_dispose(GHubClient *client)
static void g_hub_client_finalize(GHubClient *client)
{
- size_t i; /* Boucle de parcours */
-
- unset_rle_string(&client->hash);
-
if (client->working != NULL)
free(client->working);
@@ -270,15 +180,6 @@ static void g_hub_client_finalize(GHubClient *client)
if (client->desc != NULL)
free(client->desc);
- if (client->snapshots != NULL)
- {
- for (i = 0; i < client->snap_count; i++)
- exit_snapshot_info(&client->snapshots[i]);
-
- free(client->snapshots);
-
- }
-
G_OBJECT_CLASS(g_hub_client_parent_class)->finalize(G_OBJECT(client));
}
@@ -286,33 +187,6 @@ static void g_hub_client_finalize(GHubClient *client)
/******************************************************************************
* *
-* 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. *
-* *
-* Retour : Structure mise en place ou NULL en cas d'échec. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-GHubClient *g_hub_client_new(const char *hash, GList *collections)
-{
- GHubClient *result; /* Adresse à retourner */
-
- result = g_object_new(G_TYPE_HUB_CLIENT, NULL);
-
- init_static_rle_string(&result->hash, hash);
- result->collections = collections;
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
* Paramètres : client = client pour les accès distants à manipuler. *
* *
* Description : Démarre la connexion à la base de données interne. *
@@ -522,9 +396,10 @@ static bool g_hub_client_start_common(GHubClient *client, char *desc)
char *filename; /* Fichier PEM à manipuler */
int ret; /* Bilan d'un appel */
char *rootdir; /* Racine pour le client */
- packed_buffer out_pbuf; /* Tampon d'émission */
+ GHubClientClass *class; /* Classe du client connecté */
+ packed_buffer_t out_pbuf; /* Tampon d'émission */
bool status; /* Bilan d'une opération */
- packed_buffer in_pbuf; /* Tampon de réception */
+ packed_buffer_t in_pbuf; /* Tampon de réception */
uint32_t data; /* Mot de données lues */
DBError error; /* Validation de la connexion */
@@ -608,11 +483,14 @@ static bool g_hub_client_start_common(GHubClient *client, char *desc)
goto ssl_error;
}
+ class = G_HUB_CLIENT_GET_CLASS(client);
+
/**
* On réalise l'envoi initial ; le premier paquet doit contenir :
- * - la commande 'DBC_HELO'.
- * - le numéro de version du client.
- * - l'empreinte du binaire analysé.
+ * - la commande 'DBC_HELO' ;
+ * - le numéro de version du client ;
+ * - le rôle attendu de la connexion ;
+ * - des données complémentaires éventuelles.
*
* Tout ceci est à synchroniser avec la fonction g_db_server_listener().
*/
@@ -625,15 +503,21 @@ static bool g_hub_client_start_common(GHubClient *client, char *desc)
status = extend_packed_buffer(&out_pbuf, (uint32_t []) { CDB_PROTOCOL_VERSION }, sizeof(uint32_t), true);
if (!status) goto setup_error;
- status = pack_rle_string(&client->hash, &out_pbuf);
+ status = extend_packed_buffer(&out_pbuf, &class->role, sizeof(uint32_t), true);
if (!status) goto setup_error;
+ if (class->complete_hello != NULL)
+ {
+ status = class->complete_hello(client, &out_pbuf);
+ if (!status) goto setup_error;
+ }
+
status = ssl_send_packed_buffer(&out_pbuf, client->tls_fd);
if (!status) goto setup_error;
/**
* Le serveur doit répondre pour un message type :
- * - la commande 'DBC_WELCOME'.
+ * - la commande 'DBC_WELCOME' ;
* - un identifiant d'erreur ('DBE_NONE', 'DBE_BAD_EXCHANGE'
* ou 'DBE_WRONG_VERSION' ... 'DBE_LOADING_ERROR').
*/
@@ -689,14 +573,19 @@ static bool g_hub_client_start_common(GHubClient *client, char *desc)
}
- client->can_get_updates = false;
+ ret = pipe(client->stop_ctrl);
+ if (ret != 0)
+ {
+ LOG_ERROR_N("pipe");
+ goto sys_error;
+ }
- client->update = g_thread_try_new("cdb_client", (GThreadFunc)g_hub_client_update, client, NULL);
+ client->update = g_thread_try_new("cdb_client", class->recv_func, client, NULL);
if (client->update == NULL)
{
log_variadic_message(LMT_ERROR, _("Failed to start a listening thread for the server '%s'!"),
desc);
- goto comm_error;
+ goto sys_error;
}
exit_packed_buffer(&out_pbuf);
@@ -704,6 +593,7 @@ static bool g_hub_client_start_common(GHubClient *client, char *desc)
return true;
+ sys_error:
comm_error:
exit_packed_buffer(&in_pbuf);
@@ -733,344 +623,6 @@ static bool g_hub_client_start_common(GHubClient *client, char *desc)
* *
* Paramètres : client = client pour les accès distants à manipuler. *
* *
-* Description : Assure l'accueil des nouvelles mises à jour. *
-* *
-* Retour : NULL. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void *g_hub_client_update(GHubClient *client)
-{
- packed_buffer out_pbuf; /* Tampon d'émission */
- bool status; /* Bilan d'une opération */
- struct pollfd fds; /* Surveillance des flux */
- packed_buffer in_pbuf; /* Tampon de réception */
- int ret; /* Bilan d'un appel */
- uint32_t tmp32; /* Valeur sur 32 bits */
- uint32_t command; /* Commande de la requête */
- DBError error; /* Bilan d'une commande passée */
- GDbCollection *collec; /* Collection visée au final */
- uint8_t tmp8; /* Valeur sur 8 bits */
- char *msg; /* Message d'erreur à imprimer */
-
- /**
- * Avant toute chose, on demande un stage d'actualisation !
- */
-
- init_packed_buffer(&out_pbuf);
-
- status = extend_packed_buffer(&out_pbuf, (uint32_t []) { DBC_GET_SNAPSHOTS }, sizeof(uint32_t), true);
- if (!status)
- {
- exit_packed_buffer(&out_pbuf);
- goto exit;
- }
-
- status = extend_packed_buffer(&out_pbuf, (uint32_t []) { DBC_GET_CUR_SNAPSHOT }, sizeof(uint32_t), true);
- if (!status)
- {
- exit_packed_buffer(&out_pbuf);
- goto exit;
- }
-
- status = extend_packed_buffer(&out_pbuf, (uint32_t []) { DBC_GET_ALL_ITEMS }, sizeof(uint32_t), true);
- if (!status)
- {
- exit_packed_buffer(&out_pbuf);
- goto exit;
- }
-
- status = ssl_send_packed_buffer(&out_pbuf, client->tls_fd);
- if (!status)
- {
- log_simple_message(LMT_INFO, _("Failed to get all updates"));
- exit_packed_buffer(&out_pbuf);
- goto exit;
- }
-
- exit_packed_buffer(&out_pbuf);
-
- /**
- * Phase d'écoute continue...
- */
-
- fds.fd = client->fd;
- fds.events = POLLIN | POLLPRI;
-
- init_packed_buffer(&in_pbuf);
-
- while (client->fd != -1)
- {
- ret = poll(&fds, 1, -1);
- if (ret != 1) continue;
-
- /* Le canal est fermé, une sortie doit être demandée... */
- 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);
-
- status = ssl_recv_packed_buffer(&in_pbuf, client->tls_fd);
- if (!status) goto gdcu_bad_exchange;
-
- next_command:
-
- status = extract_packed_buffer(&in_pbuf, &command, sizeof(uint32_t), true);
- if (!status) goto gdcu_bad_exchange;
-
- switch (command)
- {
- case DBC_SAVE:
-
- status = extract_packed_buffer(&in_pbuf, &tmp32, sizeof(uint32_t), true);
- if (!status) goto gdcu_bad_exchange;
-
- error = tmp32;
-
- if (error == DBE_NONE)
- log_variadic_message(LMT_INFO, _("Archive saved for binary '%s'"),
- get_rle_string(&client->hash));
- else
- log_variadic_message(LMT_ERROR, _("Failed to save the archive for binary '%s'"),
- get_rle_string(&client->hash));
-
- break;
-
- case DBC_COLLECTION:
-
- status = extract_packed_buffer(&in_pbuf, &tmp32, sizeof(uint32_t), true);
- if (!status) goto gdcu_bad_exchange;
-
- collec = find_collection_in_list(client->collections, tmp32);
- if (collec == NULL) goto gdcu_bad_exchange;
-
- if (client->can_get_updates)
- status = g_db_collection_unpack(collec, &in_pbuf, NULL);
- else
- status = _g_db_collection_unpack(collec, &in_pbuf, (DBAction []) { 0 }, NULL);
-
- if (!status) goto gdcu_bad_exchange;
-
- break;
-
- case DBC_GET_ALL_ITEMS:
- log_variadic_message(LMT_INFO,
- _("This command is not available on this side: 0x%08x"), command);
- goto gdcu_bad_exchange;
- break;
-
- case DBC_SET_ALL_ITEMS:
-
- status = extract_packed_buffer(&in_pbuf, &tmp8, sizeof(uint8_t), true);
- if (!status) goto gdcu_bad_exchange;
-
- client->can_get_updates = (tmp8 == 0x1);
- break;
-
- case DBC_GET_SNAPSHOTS:
- log_variadic_message(LMT_INFO,
- _("This command is not available on this side: 0x%08x"), command);
- goto gdcu_bad_exchange;
- break;
-
- case DBC_SNAPSHOTS_UPDATED:
-
- status = g_hub_client_update_snapshots(client, &in_pbuf);
- if (!status) goto gdcu_bad_exchange;
-
- break;
-
- case DBC_GET_CUR_SNAPSHOT:
- log_variadic_message(LMT_INFO,
- _("This command is not available on this side: 0x%08x"), command);
- goto gdcu_bad_exchange;
- break;
-
- case DBC_CUR_SNAPSHOT_UPDATED:
-
- status = g_hub_client_update_current_snapshot(client, &in_pbuf);
- if (!status) goto gdcu_bad_exchange;
-
- break;
-
- case DBC_SET_CUR_SNAPSHOT:
- case DBC_SET_SNAPSHOT_NAME:
- case DBC_SET_SNAPSHOT_DESC:
- case DBC_CREATE_SNAPSHOT:
- case DBC_REMOVE_SNAPSHOT:
- log_variadic_message(LMT_INFO,
- _("This command is not available on this side: 0x%08x"), command);
- goto gdcu_bad_exchange;
- break;
-
- }
-
- if (has_more_data_in_packed_buffer(&in_pbuf))
- goto next_command;
-
- client->can_get_updates = true;
- continue;
-
- gdcu_bad_exchange:
-
- asprintf(&msg, _("Bad reception from %s"), client->desc);
-
- LOG_ERROR(LMT_ERROR, msg);
-
- free(msg);
-
- break;
-
- }
-
- }
-
- exit:
-
- g_hub_client_stop(client);
-
- exit_packed_buffer(&in_pbuf);
-
- return NULL;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : client = client pour les accès distants à manipuler. *
-* pbuf = données présentes à traiter. *
-* *
-* Description : Met à jour la liste des instantanés courants. *
-* *
-* Retour : true si l'opération s'est déroulée sans encombre, ou false. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static bool g_hub_client_update_snapshots(GHubClient *client, packed_buffer *pbuf)
-{
- bool result; /* Validité à retourner */
- size_t i; /* Boucle de parcours */
- char id[SNAP_ID_HEX_SZ]; /* Caractères hexadécimaux */
- snapshot_info_t info; /* Description d'instantané */
- snapshot_info_t *dest; /* Destination de description */
-
- result = true;
-
- g_mutex_lock(&client->snap_lock);
-
- if (client->snapshots != NULL)
- {
- for (i = 0; i < client->snap_count; i++)
- exit_snapshot_info(&client->snapshots[i]);
-
- free(client->snapshots);
-
- client->snapshots = NULL;
- client->snap_count = 0;
-
- }
-
- do
- {
- result = peek_packed_buffer(pbuf, id, SNAP_ID_HEX_SZ, false);
- if (!result) break;
-
- if (strncmp(id, SNAPSHOT_END_MARK, SNAP_ID_HEX_SZ) == 0)
- {
- advance_packed_buffer(pbuf, SNAP_ID_HEX_SZ);
- break;
- }
-
- else
- {
- setup_empty_snapshot_info(&info);
-
- result = unpack_snapshot_info(&info, pbuf);
- if (!result) break;
-
- client->snapshots = realloc(client->snapshots, ++client->snap_count * sizeof(snapshot_info_t));
-
- dest = &client->snapshots[client->snap_count - 1];
-
- setup_empty_snapshot_info(dest);
- copy_snapshot_info(dest, &info);
-
- exit_snapshot_info(&info);
-
- }
-
- }
- while (true);
-
- g_mutex_unlock(&client->snap_lock);
-
- if (result)
- g_signal_emit_by_name(client, "snapshots-updated");
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : client = client pour les accès distants à manipuler. *
-* pbuf = données présentes à traiter. *
-* *
-* Description : Met à jour l'identifiant de l'instantané courant. *
-* *
-* Retour : true si l'opération s'est déroulée sans encombre, ou false. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static bool g_hub_client_update_current_snapshot(GHubClient *client, packed_buffer *pbuf)
-{
- bool result; /* Validité à retourner */
- snapshot_id_t id; /* Identifiant d'instantané */
-
- setup_empty_snapshot_id(&id);
-
- result = unpack_snapshot_id(&id, pbuf);
-
- if (result)
- {
- g_mutex_lock(&client->cur_lock);
-
- copy_snapshot_id(&client->current, &id);
- client->has_current = true;
-
- g_mutex_unlock(&client->cur_lock);
-
- g_signal_emit_by_name(client, "snapshot-changed");
-
- }
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : client = client pour les accès distants à manipuler. *
-* *
* Description : Arrête la connexion à la base de données. *
* *
* Retour : - *
@@ -1083,8 +635,9 @@ void g_hub_client_stop(GHubClient *client)
{
int fd; /* Canal à clôturer */
int ret; /* Bilan d'un appel */
+ ssize_t sent; /* Quantité de données émises */
- /* Canal de communication */
+ /* Gestion du double appel */
if (client->fd == -1)
{
@@ -1103,13 +656,18 @@ void g_hub_client_stop(GHubClient *client)
client->fd = -1;
- ret = close(fd);
- if (ret == -1) LOG_ERROR_N("close");
+ /* Ordre d'arrêt */
if (g_thread_self() != client->update)
+ {
+ sent = write(client->stop_ctrl[1], "\xf0", 1);
+ if (sent != 1) LOG_ERROR_N("write");
+
g_thread_join(client->update);
- /* Environnement TLS */
+ }
+
+ /* Fermeture des flux */
SSL_free(client->tls_fd);
client->tls_fd = NULL;
@@ -1117,6 +675,17 @@ void g_hub_client_stop(GHubClient *client)
SSL_CTX_free(client->tls_ctx);
client->tls_ctx = NULL;
+ ret = close(fd);
+ if (ret == -1) LOG_ERROR_N("close");
+
+ ret = close(client->stop_ctrl[0]);
+ if (ret == -1) LOG_ERROR_N("close");
+ client->stop_ctrl[0] = -1;
+
+ ret = close(client->stop_ctrl[1]);
+ if (ret == -1) LOG_ERROR_N("close");
+ client->stop_ctrl[1] = -1;
+
}
@@ -1132,7 +701,7 @@ void g_hub_client_stop(GHubClient *client)
* *
******************************************************************************/
-static SSL *g_hub_client_get_ssl_fd(GHubClient *client)
+SSL *g_hub_client_get_ssl_fd(GHubClient *client)
{
SSL *result; /* Canal à retourner */
#ifndef NDEBUG
@@ -1174,541 +743,10 @@ static SSL *g_hub_client_get_ssl_fd(GHubClient *client)
* *
******************************************************************************/
-static void g_hub_client_put_ssl_fd(GHubClient *client, SSL *tls_fd)
+void g_hub_client_put_ssl_fd(GHubClient *client, SSL *tls_fd)
{
g_mutex_unlock(&client->sending_lock);
SSL_free(tls_fd);
}
-
-
-/******************************************************************************
-* *
-* Paramètres : client = client pour les accès distants à manipuler. *
-* *
-* Description : Effectue une demande de sauvegarde de l'état courant. *
-* *
-* Retour : true si la commande a bien été envoyée, false sinon. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-bool g_hub_client_save(GHubClient *client)
-{
- bool result; /* Bilan partiel à remonter */
- packed_buffer out_pbuf; /* Tampon d'émission */
- SSL *tls_fd; /* Canal de communication SSL */
-
- init_packed_buffer(&out_pbuf);
-
- tls_fd = g_hub_client_get_ssl_fd(client);
-
- if (tls_fd == NULL)
- result = false;
-
- else
- {
- result = extend_packed_buffer(&out_pbuf, (uint32_t []) { DBC_SAVE }, sizeof(uint32_t), true);
-
- if (result)
- result = ssl_send_packed_buffer(&out_pbuf, tls_fd);
-
- g_hub_client_put_ssl_fd(client, tls_fd);
-
- }
-
- exit_packed_buffer(&out_pbuf);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : client = client pour les accès distants à manipuler. *
-* item = élémnent à pousser vers un serveur de collection. *
-* *
-* Description : Ajoute un élément à la collection d'un serveur. *
-* *
-* Retour : true si la commande a bien été envoyée, false sinon. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-bool g_hub_client_add_item(GHubClient *client, const GDbItem *item)
-{
- bool result; /* Bilan partiel à remonter */
- packed_buffer out_pbuf; /* Tampon d'émission */
- SSL *tls_fd; /* Canal de communication SSL */
- DBFeatures feature; /* Domaine de fonctionnalité */
- GDbCollection *collec; /* Collection visée au final */
-
- init_packed_buffer(&out_pbuf);
-
- tls_fd = g_hub_client_get_ssl_fd(client);
-
- if (tls_fd == NULL)
- result = false;
-
- else
- {
- feature = g_db_item_get_feature(item);
-
- collec = find_collection_in_list(client->collections, feature);
- if (collec == NULL)
- {
- result = false;
- goto bad_item_feature;
- }
-
- result = g_db_collection_pack(collec, &out_pbuf, DBA_ADD_ITEM, item);
-
- if (result)
- result = ssl_send_packed_buffer(&out_pbuf, tls_fd);
-
- bad_item_feature:
-
- g_hub_client_put_ssl_fd(client, tls_fd);
-
- }
-
- exit_packed_buffer(&out_pbuf);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : client = client pour les accès distants à manipuler. *
-* timestamp = date du dernier élément à garder comme actif. *
-* *
-* Description : Active les éléments en amont d'un horodatage donné. *
-* *
-* Retour : true si la commande a bien été envoyée, false sinon. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-bool g_hub_client_set_last_active(GHubClient *client, timestamp_t timestamp)
-{
- bool result; /* Bilan partiel à remonter */
- packed_buffer out_pbuf; /* Tampon d'émission */
- SSL *tls_fd; /* Canal de communication SSL */
-
- init_packed_buffer(&out_pbuf);
-
- tls_fd = g_hub_client_get_ssl_fd(client);
-
- if (tls_fd == NULL)
- result = false;
-
- else
- {
- result = extend_packed_buffer(&out_pbuf, (uint32_t []) { DBC_SET_LAST_ACTIVE }, sizeof(uint32_t), true);
-
- if (result)
- result = pack_timestamp(&timestamp, &out_pbuf);
-
- if (result)
- result = ssl_send_packed_buffer(&out_pbuf, tls_fd);
-
- g_hub_client_put_ssl_fd(client, tls_fd);
-
- }
-
- exit_packed_buffer(&out_pbuf);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : client = client pour les accès distants à manipuler. *
-* info = description des instantanés présents. [OUT] *
-* count = taille de la liste retournée. [OUT] *
-* *
-* Description : Fournit la liste des instantanés existants. *
-* *
-* Retour : true si la liste retournée est valide, false sinon. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-bool g_hub_client_get_snapshots(GHubClient *client, snapshot_info_t **info, size_t *count)
-{
- bool result; /* Validité à retourner */
- size_t i; /* Boucle de parcours */
- snapshot_info_t *dest; /* Destination de description */
-
- g_mutex_lock(&client->snap_lock);
-
- result = (client->snap_count > 0);
-
- if (result)
- {
- *info = malloc(client->snap_count * sizeof(snapshot_info_t));
- *count = client->snap_count;
-
- for (i = 0; i < client->snap_count; i++)
- {
- dest = &(*info)[i];
-
- setup_empty_snapshot_info(dest);
- copy_snapshot_info(dest, &client->snapshots[i]);
-
- }
-
- }
-
- g_mutex_unlock(&client->snap_lock);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : client = client pour les accès distants à manipuler. *
-* id = identifiant d'instantané à renseigner. [OUT] *
-* *
-* Description : Fournit l'identifiant de l'instantané courant. *
-* *
-* Retour : true si l'identifiant retourné est valide, false sinon. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-bool g_hub_client_get_current_snapshot(GHubClient *client, snapshot_id_t *id)
-{
- bool result; /* Validité à retourner */
-
- g_mutex_lock(&client->cur_lock);
-
- result = client->has_current;
-
- if (result)
- copy_snapshot_id(id, &client->current);
-
- g_mutex_unlock(&client->cur_lock);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : client = client pour les accès distants à manipuler. *
-* id = identifiant d'instantané à activer. *
-* *
-* Description : Définit l'identifiant de l'instantané courant. *
-* *
-* Retour : true si la commande a bien été envoyée, false sinon. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-bool g_hub_client_set_current_snapshot(GHubClient *client, const snapshot_id_t *id)
-{
- bool result; /* Bilan partiel à remonter */
- packed_buffer out_pbuf; /* Tampon d'émission */
- SSL *tls_fd; /* Canal de communication SSL */
-
- init_packed_buffer(&out_pbuf);
-
- tls_fd = g_hub_client_get_ssl_fd(client);
-
- if (tls_fd == NULL)
- result = false;
-
- else
- {
- result = extend_packed_buffer(&out_pbuf, (uint32_t []) { DBC_SET_CUR_SNAPSHOT }, sizeof(uint32_t), true);
-
- if (result)
- result = pack_snapshot_id(id, &out_pbuf);
-
- if (result)
- result = ssl_send_packed_buffer(&out_pbuf, tls_fd);
-
- g_hub_client_put_ssl_fd(client, tls_fd);
-
- }
-
- exit_packed_buffer(&out_pbuf);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : client = client pour les accès distants à manipuler. *
-* id = identifiant d'instantané à traiter. *
-* name = désignation humaine pour l'instantané. *
-* *
-* Description : Définit la désignation d'un instantané donné. *
-* *
-* Retour : true si la commande a bien été envoyée, false sinon. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-bool g_hub_client_set_snapshot_name(GHubClient *client, const snapshot_id_t *id, const char *name)
-{
- bool result; /* Bilan partiel à remonter */
- packed_buffer out_pbuf; /* Tampon d'émission */
- SSL *tls_fd; /* Canal de communication SSL */
- rle_string string; /* Chaîne à transmettre */
-
- init_packed_buffer(&out_pbuf);
-
- tls_fd = g_hub_client_get_ssl_fd(client);
-
- if (tls_fd == NULL)
- result = false;
-
- else
- {
- result = extend_packed_buffer(&out_pbuf, (uint32_t []) { DBC_SET_SNAPSHOT_NAME }, sizeof(uint32_t), true);
-
- if (result)
- result = pack_snapshot_id(id, &out_pbuf);
-
- if (result)
- {
- init_static_rle_string(&string, name);
-
- result = pack_rle_string(&string, &out_pbuf);
-
- exit_rle_string(&string);
-
- }
-
- if (result)
- result = ssl_send_packed_buffer(&out_pbuf, tls_fd);
-
- g_hub_client_put_ssl_fd(client, tls_fd);
-
- }
-
- exit_packed_buffer(&out_pbuf);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : client = client pour les accès distants à manipuler. *
-* id = identifiant d'instantané à traiter. *
-* desc = description humaine pour l'instantané. *
-* *
-* Description : Définit la description d'un instantané donné. *
-* *
-* Retour : true si la commande a bien été envoyée, false sinon. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-bool g_hub_client_set_snapshot_desc(GHubClient *client, const snapshot_id_t *id, const char *desc)
-{
- bool result; /* Bilan partiel à remonter */
- packed_buffer out_pbuf; /* Tampon d'émission */
- SSL *tls_fd; /* Canal de communication SSL */
- rle_string string; /* Chaîne à transmettre */
-
- init_packed_buffer(&out_pbuf);
-
- tls_fd = g_hub_client_get_ssl_fd(client);
-
- if (tls_fd == NULL)
- result = false;
-
- else
- {
- result = extend_packed_buffer(&out_pbuf, (uint32_t []) { DBC_SET_SNAPSHOT_DESC }, sizeof(uint32_t), true);
-
- if (result)
- result = pack_snapshot_id(id, &out_pbuf);
-
- if (result)
- {
- init_static_rle_string(&string, desc);
-
- result = pack_rle_string(&string, &out_pbuf);
-
- exit_rle_string(&string);
-
- }
-
- if (result)
- result = ssl_send_packed_buffer(&out_pbuf, tls_fd);
-
- g_hub_client_put_ssl_fd(client, tls_fd);
-
- }
-
- exit_packed_buffer(&out_pbuf);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : client = client pour les accès distants à manipuler. *
-* id = identifiant d'instantané à traiter. *
-* *
-* Description : Restaure un ancien instantané. *
-* *
-* Retour : true si la commande a bien été envoyée, false sinon. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-bool g_hub_client_restore_snapshot(GHubClient *client, const snapshot_id_t *id)
-{
- bool result; /* Bilan partiel à remonter */
- packed_buffer out_pbuf; /* Tampon d'émission */
- SSL *tls_fd; /* Canal de communication SSL */
-
- init_packed_buffer(&out_pbuf);
-
- tls_fd = g_hub_client_get_ssl_fd(client);
-
- if (tls_fd == NULL)
- result = false;
-
- else
- {
- result = extend_packed_buffer(&out_pbuf, (uint32_t []) { DBC_SET_CUR_SNAPSHOT }, sizeof(uint32_t), true);
-
- if (result)
- result = pack_snapshot_id(id, &out_pbuf);
-
- if (result)
- result = ssl_send_packed_buffer(&out_pbuf, tls_fd);
-
- g_hub_client_put_ssl_fd(client, tls_fd);
-
- }
-
- exit_packed_buffer(&out_pbuf);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : client = client pour les accès distants à manipuler. *
-* *
-* Description : Crée un nouvel instantané à partir d'un autre. *
-* *
-* Retour : true si la commande a bien été envoyée, false sinon. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-bool g_hub_client_create_snapshot(GHubClient *client)
-{
- bool result; /* Bilan partiel à remonter */
- packed_buffer out_pbuf; /* Tampon d'émission */
- SSL *tls_fd; /* Canal de communication SSL */
-
- init_packed_buffer(&out_pbuf);
-
- tls_fd = g_hub_client_get_ssl_fd(client);
-
- if (tls_fd == NULL)
- result = false;
-
- else
- {
- result = extend_packed_buffer(&out_pbuf, (uint32_t []) { DBC_CREATE_SNAPSHOT }, sizeof(uint32_t), true);
-
- if (result)
- result = ssl_send_packed_buffer(&out_pbuf, tls_fd);
-
- g_hub_client_put_ssl_fd(client, tls_fd);
-
- }
-
- exit_packed_buffer(&out_pbuf);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : client = client pour les accès distants à manipuler. *
-* id = identifiant d'instantané à traiter. *
-* rec = programme une suppression récursive. *
-* *
-* Description : Supprime un ancien instantané. *
-* *
-* Retour : true si la commande a bien été envoyée, false sinon. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-bool g_hub_client_remove_snapshot(GHubClient *client, const snapshot_id_t *id, bool rec)
-{
- bool result; /* Bilan partiel à remonter */
- packed_buffer out_pbuf; /* Tampon d'émission */
- SSL *tls_fd; /* Canal de communication SSL */
-
- init_packed_buffer(&out_pbuf);
-
- tls_fd = g_hub_client_get_ssl_fd(client);
-
- if (tls_fd == NULL)
- result = false;
-
- else
- {
- result = extend_packed_buffer(&out_pbuf, (uint32_t []) { DBC_REMOVE_SNAPSHOT }, sizeof(uint32_t), true);
-
- if (result)
- result = pack_snapshot_id(id, &out_pbuf);
-
- if (result)
- result = extend_packed_buffer(&out_pbuf, (uint8_t []) { rec ? 0x1 : 0x0 }, sizeof(uint8_t), false);
-
- if (result)
- result = ssl_send_packed_buffer(&out_pbuf, tls_fd);
-
- g_hub_client_put_ssl_fd(client, tls_fd);
-
- }
-
- exit_packed_buffer(&out_pbuf);
-
- return result;
-
-}
diff --git a/src/analysis/db/client.h b/src/analysis/db/client.h
index 9a95163..0ec40e6 100644
--- a/src/analysis/db/client.h
+++ b/src/analysis/db/client.h
@@ -30,9 +30,6 @@
#include <openssl/ssl.h>
-#include "collection.h"
-#include "misc/snapshot.h"
-
#define G_TYPE_HUB_CLIENT g_hub_client_get_type()
@@ -53,9 +50,6 @@ typedef struct _GHubClientClass GHubClientClass;
/* Indique le type défini pour une description de client à l'écoute. */
GType g_hub_client_get_type(void);
-/* Prépare un client pour une connexion à une BD. */
-GHubClient *g_hub_client_new(const char *, GList *);
-
/* Démarre la connexion à la base de données interne. */
bool g_hub_client_start_internal(GHubClient *);
@@ -65,39 +59,6 @@ bool g_hub_client_start_remote(GHubClient *, const char *, const char *, bool);
/* Arrête la connexion à la base de données. */
void g_hub_client_stop(GHubClient *);
-/* Effectue une demande de sauvegarde de l'état courant. */
-bool g_hub_client_save(GHubClient *);
-
-/* Ajoute un élément à la collection d'un serveur. */
-bool g_hub_client_add_item(GHubClient *, const GDbItem *);
-
-/* Active les éléments en amont d'un horodatage donné. */
-bool g_hub_client_set_last_active(GHubClient *, timestamp_t);
-
-/* Fournit la liste des instantanés existants. */
-bool g_hub_client_get_snapshots(GHubClient *, snapshot_info_t **, size_t *);
-
-/* Fournit l'identifiant de l'instantané courant. */
-bool g_hub_client_get_current_snapshot(GHubClient *, snapshot_id_t *);
-
-/* Définit l'identifiant de l'instantané courant. */
-bool g_hub_client_set_current_snapshot(GHubClient *, const snapshot_id_t *);
-
-/* Définit la désignation d'un instantané donné. */
-bool g_hub_client_set_snapshot_name(GHubClient *, const snapshot_id_t *, const char *);
-
-/* Définit la description d'un instantané donné. */
-bool g_hub_client_set_snapshot_desc(GHubClient *, const snapshot_id_t *, const char *);
-
-/* Restaure un ancien instantané. */
-bool g_hub_client_restore_snapshot(GHubClient *, const snapshot_id_t *);
-
-/* Crée un nouvel instantané à partir d'un autre. */
-bool g_hub_client_create_snapshot(GHubClient *);
-
-/* Supprime un ancien instantané. */
-bool g_hub_client_remove_snapshot(GHubClient *, const snapshot_id_t *, bool);
-
#endif /* _ANALYSIS_DB_CLIENT_H */
diff --git a/src/analysis/db/collection.c b/src/analysis/db/collection.c
index dcab73e..52476dd 100644
--- a/src/analysis/db/collection.c
+++ b/src/analysis/db/collection.c
@@ -324,7 +324,7 @@ const char *g_db_collection_get_name(const GDbCollection *collec)
* *
******************************************************************************/
-bool _g_db_collection_unpack(GDbCollection *collec, packed_buffer *pbuf, DBAction *action, GDbItem **dest)
+bool _g_db_collection_unpack(GDbCollection *collec, packed_buffer_t *pbuf, DBAction *action, GDbItem **dest)
{
bool result; /* Bilan à faire remonter */
uint32_t tmp32; /* Valeur sur 32 bits */
@@ -376,7 +376,7 @@ bool _g_db_collection_unpack(GDbCollection *collec, packed_buffer *pbuf, DBActio
* *
******************************************************************************/
-bool g_db_collection_unpack(GDbCollection *collec, packed_buffer *pbuf, sqlite3 *db)
+bool g_db_collection_unpack(GDbCollection *collec, packed_buffer_t *pbuf, sqlite3 *db)
{
bool result; /* Bilan à faire remonter */
DBAction action; /* Commande de la requête */
@@ -460,7 +460,7 @@ bool g_db_collection_unpack(GDbCollection *collec, packed_buffer *pbuf, sqlite3
* *
******************************************************************************/
-bool g_db_collection_pack(GDbCollection *collec, packed_buffer *pbuf, DBAction action, const GDbItem *item)
+bool g_db_collection_pack(GDbCollection *collec, packed_buffer_t *pbuf, DBAction action, const GDbItem *item)
{
bool result; /* Bilan à retourner */
@@ -493,7 +493,7 @@ bool g_db_collection_pack(GDbCollection *collec, packed_buffer *pbuf, DBAction a
* *
******************************************************************************/
-bool g_db_collection_pack_all_updates(GDbCollection *collec, packed_buffer *pbuf)
+bool g_db_collection_pack_all_updates(GDbCollection *collec, packed_buffer_t *pbuf)
{
bool result; /* Bilan à renvoyer */
size_t i; /* Boucle de parcours */
@@ -779,7 +779,7 @@ bool g_db_collection_add_item(GDbCollection *collec, GDbItem *item)
* *
******************************************************************************/
-bool g_db_collection_drop_disabled_items(GDbCollection *collec, packed_buffer *pbuf)
+bool g_db_collection_drop_disabled_items(GDbCollection *collec, packed_buffer_t *pbuf)
{
bool result; /* Bilan à retourner */
size_t i; /* Boucle de parcours */
@@ -1021,7 +1021,7 @@ static size_t g_db_collection_find_by_timestamp(GDbCollection *collec, timestamp
* *
******************************************************************************/
-bool g_db_collection_disable_at(GDbCollection *collec, timestamp_t timestamp, sqlite3 *db, packed_buffer *pbuf)
+bool g_db_collection_disable_at(GDbCollection *collec, timestamp_t timestamp, sqlite3 *db, packed_buffer_t *pbuf)
{
bool result; /* Bilan à retourner */
size_t start; /* Début de la zone à changer */
@@ -1450,7 +1450,7 @@ void lock_unlock_collections(GList *list, bool write, bool lock)
* *
******************************************************************************/
-bool pack_all_collection_updates(GList *list, packed_buffer *pbuf)
+bool pack_all_collection_updates(GList *list, packed_buffer_t *pbuf)
{
bool result; /* Bilan à retourner */
GList *iter; /* Boucle de parcours */
@@ -1496,7 +1496,7 @@ bool pack_all_collection_updates(GList *list, packed_buffer *pbuf)
* *
******************************************************************************/
-bool update_activity_in_collections(GList *list, packed_buffer *inbuf, packed_buffer *outbuf, sqlite3 *db)
+bool update_activity_in_collections(GList *list, packed_buffer_t *inbuf, packed_buffer_t *outbuf, sqlite3 *db)
{
bool result; /* Résultat global à renvoyer */
bool status; /* Bilan de lecture initiale */
diff --git a/src/analysis/db/collection.h b/src/analysis/db/collection.h
index 6c14624..6d7b369 100644
--- a/src/analysis/db/collection.h
+++ b/src/analysis/db/collection.h
@@ -69,16 +69,16 @@ const char *g_db_collection_get_name(const GDbCollection *);
/* Réceptionne un élément depuis une requête réseau. */
-bool _g_db_collection_unpack(GDbCollection *, packed_buffer *, DBAction *, GDbItem **);
+bool _g_db_collection_unpack(GDbCollection *, packed_buffer_t *, DBAction *, GDbItem **);
/* Réceptionne et traite une requête réseau pour collection. */
-bool g_db_collection_unpack(GDbCollection *, packed_buffer *, sqlite3 *);
+bool g_db_collection_unpack(GDbCollection *, packed_buffer_t *, sqlite3 *);
/* Envoie pour traitement une requête réseau pour collection. */
-bool g_db_collection_pack(GDbCollection *, packed_buffer *, DBAction, const GDbItem *);
+bool g_db_collection_pack(GDbCollection *, packed_buffer_t *, DBAction, const GDbItem *);
/* Envoie pour mise à jour tous les éléments courants. */
-bool g_db_collection_pack_all_updates(GDbCollection *, packed_buffer *);
+bool g_db_collection_pack_all_updates(GDbCollection *, packed_buffer_t *);
@@ -111,13 +111,13 @@ typedef enum _ActiveItemChange
bool g_db_collection_add_item(GDbCollection *, GDbItem *);
/* Procède au retrait des éléments désactivés de la collection. */
-bool g_db_collection_drop_disabled_items(GDbCollection *, packed_buffer *);
+bool g_db_collection_drop_disabled_items(GDbCollection *, packed_buffer_t *);
/* Procède au retrait d'un élément dans la collection. */
bool g_db_collection_remove_item(GDbCollection *, const GDbItem *);
/* Désactive les éléments en aval d'un horodatage donné. */
-bool g_db_collection_disable_at(GDbCollection *, timestamp_t, sqlite3 *, packed_buffer *);
+bool g_db_collection_disable_at(GDbCollection *, timestamp_t, sqlite3 *, packed_buffer_t *);
/* Prend acte d'un changement d'état d'un élément de collection. */
bool g_db_collection_update_item_state(GDbCollection *, const GDbItem *);
@@ -154,10 +154,10 @@ void lock_unlock_collections(GList *, bool, bool);
#define runlock_collections(lst) lock_unlock_collections(lst, false, false);
/* Collecte les informations utiles pour un nouvel arrivant. */
-bool pack_all_collection_updates(GList *, packed_buffer *);
+bool pack_all_collection_updates(GList *, packed_buffer_t *);
/* Met à jour les statuts d'activité des éléments. */
-bool update_activity_in_collections(GList *, packed_buffer *, packed_buffer *, sqlite3 *);
+bool update_activity_in_collections(GList *, packed_buffer_t *, packed_buffer_t *, sqlite3 *);
diff --git a/src/analysis/db/controller.c b/src/analysis/db/controller.c
new file mode 100644
index 0000000..a27c20a
--- /dev/null
+++ b/src/analysis/db/controller.c
@@ -0,0 +1,481 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * controller.h - prototypes pour la gestion d'un ensemble d'archives au format CDB
+ *
+ * Copyright (C) 2021 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 "controller.h"
+
+
+#include <assert.h>
+#include <errno.h>
+#include <dirent.h>
+#include <malloc.h>
+#include <poll.h>
+#include <pthread.h>
+#include <string.h>
+
+
+#include <i18n.h>
+
+
+#include "backend-int.h"
+#include "misc/rlestr.h"
+#include "../../common/leb128.h"
+#include "../../common/packed.h"
+#include "../../core/logs.h"
+
+
+
+/* Description d'un contrôleur d'archives (instance) */
+struct _GCdbController
+{
+ GServerBackend parent; /* A laisser en premier */
+
+ char *basedir; /* Répertoire du serveur */
+
+ SSL *tls_fd; /* Canal de communication */
+ char *peer_name; /* Désignation du correspondant*/
+ char *user; /* Utilisateur connecté */
+
+};
+
+/* Description d'un contrôleur d'archives (classe) */
+struct _GCdbControllerClass
+{
+ GServerBackendClass parent; /* A laisser en premier */
+
+};
+
+
+/* Initialise la classe des contrôleurs d'archives. */
+static void g_cdb_controller_class_init(GCdbControllerClass *);
+
+/* Initialise un contrôleur d'archives. */
+static void g_cdb_controller_init(GCdbController *);
+
+/* Supprime toutes les références externes. */
+static void g_cdb_controller_dispose(GCdbController *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_cdb_controller_finalize(GCdbController *);
+
+/* Assure le traitement des requêtes de contrôle. */
+static void *g_cdb_controller_process(GCdbController *);
+
+/* Prend en compte une connexion nouvelle d'un utilisateur. */
+static void g_cdb_controller_add_client(GCdbController *, SSL *, const char *, const char *);
+
+/* Envoie au client la liste des binaires présents. */
+static bool g_cdb_controller_send_existing_binaries(GCdbController *, packed_buffer_t *);
+
+
+
+/* Indique le type défini pour une gestion d'archives. */
+G_DEFINE_TYPE(GCdbController, g_cdb_controller, G_TYPE_SERVER_BACKEND);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des contrôleurs d'archives. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_cdb_controller_class_init(GCdbControllerClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GServerBackendClass *backend; /* Classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_cdb_controller_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_cdb_controller_finalize;
+
+ backend = G_SERVER_BACKEND_CLASS(klass);
+
+ backend->thread_name = "cdb_controller";
+ backend->thread_func = (GThreadFunc)g_cdb_controller_process;
+
+ backend->add_client = (add_backend_client_fc)g_cdb_controller_add_client;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : controller = instance à initialiser. *
+* *
+* Description : Initialise un contrôleur d'archives. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_cdb_controller_init(GCdbController *controller)
+{
+ controller->basedir = NULL;
+
+ controller->tls_fd = NULL;
+ controller->peer_name = NULL;
+ controller->user = NULL;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : controller = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_cdb_controller_dispose(GCdbController *controller)
+{
+ g_server_backend_stop(G_SERVER_BACKEND(controller));
+
+ G_OBJECT_CLASS(g_cdb_controller_parent_class)->dispose(G_OBJECT(controller));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : controller = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_cdb_controller_finalize(GCdbController *controller)
+{
+ if (controller->basedir != NULL)
+ free(controller->basedir);
+
+ if (controller->tls_fd != NULL)
+ SSL_free(controller->tls_fd);
+
+ if (controller->peer_name != NULL)
+ free(controller->peer_name);
+
+ if (controller->user != NULL)
+ free(controller->user);
+
+ G_OBJECT_CLASS(g_cdb_controller_parent_class)->finalize(G_OBJECT(controller));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : basedir = répertoire de stockage des enregistrements. *
+* error = indication éventuelle en cas d'échec. [OUT] *
+* *
+* Description : Définit ou ouvre une archive d'éléments utilisateur. *
+* *
+* Retour : Structure mise en plae ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GCdbController *g_cdb_controller_new(const char *basedir, DBError *error)
+{
+ GCdbController *result; /* Adresse à retourner */
+
+ result = g_object_new(G_TYPE_CDB_CONTROLLER, NULL);
+
+ result->basedir = strdup(basedir);
+
+ *error = DBE_NONE;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : controller = centralisation de tous les savoirs. *
+* *
+* Description : Assure le traitement des requêtes de contrôle. *
+* *
+* Retour : NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void *g_cdb_controller_process(GCdbController *controller)
+{
+ GServerBackend *base; /* Base de l'instance */
+ struct pollfd fds[3]; /* Surveillance des flux */
+ int ret; /* Bilan d'un appel */
+ packed_buffer_t in_pbuf; /* Tampon de réception */
+ bool status; /* Bilan de lecture initiale */
+ uint32_t command; /* Commande de la requête */
+ packed_buffer_t out_pbuf; /* Tampon d'émission */
+ char *msg; /* Erreur à faire remonter */
+
+ base = G_SERVER_BACKEND(controller);
+
+ fds[0].fd = base->stop_ctrl[0];
+ fds[0].events = POLLIN | POLLPRI;
+
+ fds[1].fd = base->refresh_ctrl[0];
+ fds[1].events = POLLIN | POLLPRI;
+
+ fds[2].fd = SSL_get_fd(controller->tls_fd);
+ fds[2].events = POLLIN | POLLPRI;
+
+ while (1)
+ {
+ /* Lancement d'une phase de surveillance */
+
+ ret = poll(fds, 3, -1);
+ if (ret == -1)
+ {
+ if (errno == EINTR) continue;
+
+ LOG_ERROR_N("poll");
+ break;
+
+ }
+
+ /* Demande expresse d'arrêt des procédures */
+ if (fds[0].revents)
+ break;
+
+ /* Demande d'actualisation ?! */
+ assert(fds[1].revents == 0);
+
+ /* Le canal est fermé, une sortie doit être demandée... */
+ if (fds[2].revents & POLLNVAL)
+ 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[2].revents & (POLLHUP | POLLRDHUP))
+ goto closed_exchange;
+
+ /* Données présentes en entrée */
+ if (fds[2].revents & (POLLIN | POLLPRI))
+ {
+ init_packed_buffer(&in_pbuf);
+
+ status = ssl_recv_packed_buffer(&in_pbuf, controller->tls_fd);
+ if (!status) goto bad_exchange;
+
+ next_command:
+
+ status = extract_packed_buffer(&in_pbuf, &command, sizeof(uint32_t), true);
+ if (!status) goto bad_exchange;
+
+ switch (command)
+ {
+ case DBC_LIST_BINARIES:
+
+ init_packed_buffer(&out_pbuf);
+
+ status = extend_packed_buffer(&out_pbuf, (uint32_t []) { DBC_EXISTING_BINARIES },
+ sizeof(uint32_t), true);
+ if (!status) goto reply_error;
+
+ status = g_cdb_controller_send_existing_binaries(controller, &out_pbuf);
+ if (!status) goto reply_error;
+
+ status = ssl_send_packed_buffer(&out_pbuf, controller->tls_fd);
+ if (!status) goto reply_error;
+
+ exit_packed_buffer(&out_pbuf);
+
+ break;
+
+ default:
+ asprintf(&msg, _("Bad protocol command: 0x%08x"), command);
+ LOG_ERROR(LMT_ERROR, msg);
+ free(msg);
+ goto bad_exchange;
+ break;
+
+ }
+
+ if (has_more_data_in_packed_buffer(&in_pbuf))
+ goto next_command;
+
+ exit_packed_buffer(&in_pbuf);
+
+ continue;
+
+ reply_error:
+
+ exit_packed_buffer(&out_pbuf);
+
+ bad_exchange:
+
+ LOG_ERROR(LMT_ERROR, _("Bad exchange"));
+
+ assert(0);
+
+ exit_packed_buffer(&in_pbuf);
+
+ closed_exchange:
+
+ break;
+
+ }
+
+ }
+
+ /* On disparaît des écrans... */
+
+ g_server_backend_stop(G_SERVER_BACKEND(controller));
+
+ return NULL;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : controller = support pour le suivi d'une connexion. *
+* fd = canal de communication réseau ouvert. *
+* peer_name = désignation de la connexion. *
+* user = désignation de l'utilisateur de la connexion. *
+* *
+* Description : Prend en compte une connexion nouvelle d'un utilisateur. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_cdb_controller_add_client(GCdbController *controller, SSL *fd, const char *peer_name, const char *user)
+{
+ controller->tls_fd = fd;
+
+ controller->peer_name = strdup(peer_name);
+ controller->user = strdup(user);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : controller = administration d'archives d'analyse. *
+* pbuf = paquet à consituer pour un envoi unique. [OUT] *
+* *
+* Description : Envoie au client la liste des binaires présents. *
+* *
+* Retour : Bilan de constitution de la réponse. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_cdb_controller_send_existing_binaries(GCdbController *controller, packed_buffer_t *pbuf)
+{
+ bool result; /* Bilan à retourner */
+ DIR *directory; /* Répertoire de travail */
+ uleb128_t count; /* Nombre d'éléments détectés */
+ packed_buffer_t items; /* Liste des éléments trouvés */
+ struct dirent *item; /* Propriétés d'un élément */
+ rle_string name; /* Nom à exporter */
+ bool status; /* Bilan d'une inscription */
+ int ret; /* Bilan de fermture */
+
+ result = false;
+
+ directory = opendir(controller->basedir);
+ if (directory == NULL)
+ {
+ LOG_ERROR_N("opendir");
+
+ if (errno == ENOENT)
+ {
+ count = 0;
+ result = pack_uleb128(&count, pbuf);
+ }
+
+ goto bad_dir;
+
+ }
+
+ count = 0;
+ init_packed_buffer(&items);
+
+ for (item = readdir(directory); item != NULL; item = readdir(directory))
+ {
+ if (item->d_type != DT_DIR)
+ continue;
+
+ if (strcmp(item->d_name, ".") == 0 || strcmp(item->d_name, "..") == 0)
+ continue;
+
+ init_static_rle_string(&name, item->d_name);
+
+ status = pack_rle_string(&name, &items);
+
+ exit_rle_string(&name);
+
+ if (!status)
+ goto reg_error;
+
+ count++;
+
+ }
+
+ result = pack_uleb128(&count, pbuf);
+
+ if (result)
+ result = include_packed_buffer(pbuf, &items);
+
+ reg_error:
+
+ exit_packed_buffer(&items);
+
+ ret = closedir(directory);
+ if (ret == -1) LOG_ERROR_N("closedir");
+
+ bad_dir:
+
+ return result;
+
+}
diff --git a/src/analysis/db/controller.h b/src/analysis/db/controller.h
new file mode 100644
index 0000000..adeee2b
--- /dev/null
+++ b/src/analysis/db/controller.h
@@ -0,0 +1,59 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * controller.h - prototypes pour la gestion d'un ensemble d'archives au format CDB
+ *
+ * Copyright (C) 2014-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_CONTROLLER_H
+#define _ANALYSIS_DB_CONTROLLER_H
+
+
+#include <glib-object.h>
+#include <stdbool.h>
+
+
+#include "protocol.h"
+
+
+
+#define G_TYPE_CDB_CONTROLLER g_cdb_controller_get_type()
+#define G_CDB_CONTROLLER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_CDB_CONTROLLER, GCdbController))
+#define G_IS_CDB_CONTROLLER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_CDB_CONTROLLER))
+#define G_CDB_CONTROLLER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_CDB_CONTROLLER, GCdbControllerClass))
+#define G_IS_CDB_CONTROLLER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_CDB_CONTROLLER))
+#define G_CDB_CONTROLLER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_CDB_CONTROLLER, GCdbControllerClass))
+
+
+/* Description d'un contrôleur d'archives (instance) */
+typedef struct _GCdbController GCdbController;
+
+/* Description d'un contrôleur d'archives (classe) */
+typedef struct _GCdbControllerClass GCdbControllerClass;
+
+
+/* Indique le type défini pour une gestion d'archives. */
+GType g_cdb_controller_get_type(void);
+
+/* Prépare un client pour une connexion à une BD. */
+GCdbController *g_cdb_controller_new(const char *, DBError *);
+
+
+
+#endif /* _ANALYSIS_DB_CONTROLLER_H */
diff --git a/src/analysis/db/item-int.h b/src/analysis/db/item-int.h
index 4b37844..871a65e 100644
--- a/src/analysis/db/item-int.h
+++ b/src/analysis/db/item-int.h
@@ -46,10 +46,10 @@ typedef gboolean (* cmp_db_item_key_fc) (const GDbItem *, const GDbItem *);
typedef gint (* cmp_db_item_fc) (const GDbItem *, const GDbItem *);
/* Importe la définition d'une base d'éléments pour collection. */
-typedef bool (* unpack_db_item_fc) (GDbItem *, packed_buffer *);
+typedef bool (* unpack_db_item_fc) (GDbItem *, packed_buffer_t *);
/* Exporte la définition d'une base d'éléments pour collection. */
-typedef bool (* pack_db_item_fc) (const GDbItem *, packed_buffer *);
+typedef bool (* pack_db_item_fc) (const GDbItem *, packed_buffer_t *);
/* Construit la description humaine d'un signet sur un tampon. */
typedef char * (* build_item_label_fc) (const GDbItem *);
diff --git a/src/analysis/db/item.c b/src/analysis/db/item.c
index 16866ab..6ee59a7 100644
--- a/src/analysis/db/item.c
+++ b/src/analysis/db/item.c
@@ -49,10 +49,10 @@ static void g_db_item_dispose(GDbItem *);
static void g_db_item_finalize(GDbItem *);
/* Importe la définition d'une base d'éléments pour collection. */
-static bool _g_db_item_unpack(GDbItem *, packed_buffer *);
+static bool _g_db_item_unpack(GDbItem *, packed_buffer_t *);
/* Exporte la définition d'une base d'éléments pour collection. */
-static bool _g_db_item_pack(const GDbItem *, packed_buffer *);
+static bool _g_db_item_pack(const GDbItem *, packed_buffer_t *);
@@ -376,7 +376,7 @@ gint g_db_item_cmp(const GDbItem *a, const GDbItem *b)
* *
******************************************************************************/
-static bool _g_db_item_unpack(GDbItem *item, packed_buffer *pbuf)
+static bool _g_db_item_unpack(GDbItem *item, packed_buffer_t *pbuf)
{
bool result; /* Bilan à retourner */
uint32_t flags; /* Propriétés de l'élément */
@@ -410,7 +410,7 @@ static bool _g_db_item_unpack(GDbItem *item, packed_buffer *pbuf)
* *
******************************************************************************/
-bool g_db_item_unpack(GDbItem *item, packed_buffer *pbuf)
+bool g_db_item_unpack(GDbItem *item, packed_buffer_t *pbuf)
{
bool result; /* Bilan à retourner */
@@ -434,7 +434,7 @@ bool g_db_item_unpack(GDbItem *item, packed_buffer *pbuf)
* *
******************************************************************************/
-static bool _g_db_item_pack(const GDbItem *item, packed_buffer *pbuf)
+static bool _g_db_item_pack(const GDbItem *item, packed_buffer_t *pbuf)
{
bool result; /* Bilan à retourner */
DbItemFlags flags; /* Propriétés de l'élément */
@@ -468,7 +468,7 @@ static bool _g_db_item_pack(const GDbItem *item, packed_buffer *pbuf)
* *
******************************************************************************/
-bool g_db_item_pack(const GDbItem *item, packed_buffer *pbuf)
+bool g_db_item_pack(const GDbItem *item, packed_buffer_t *pbuf)
{
return G_DB_ITEM_GET_CLASS(item)->pack(item, pbuf);
diff --git a/src/analysis/db/item.h b/src/analysis/db/item.h
index a4eaffa..e34523c 100644
--- a/src/analysis/db/item.h
+++ b/src/analysis/db/item.h
@@ -93,10 +93,10 @@ int g_db_item_cmp_with_timestamp(const timestamp_t *, const GDbItem **);
gint g_db_item_cmp(const GDbItem *, const GDbItem *);
/* Importe la définition d'une base d'éléments pour collection. */
-bool g_db_item_unpack(GDbItem *, packed_buffer *);
+bool g_db_item_unpack(GDbItem *, packed_buffer_t *);
/* Exporte la définition d'une base d'éléments pour collection. */
-bool g_db_item_pack(const GDbItem *, packed_buffer *);
+bool g_db_item_pack(const GDbItem *, packed_buffer_t *);
/* Applique un élément de collection sur un binaire. */
bool g_db_item_apply(GDbItem *, GLoadedBinary *);
diff --git a/src/analysis/db/items/Makefile.am b/src/analysis/db/items/Makefile.am
index b9ce117..f8f70d5 100644
--- a/src/analysis/db/items/Makefile.am
+++ b/src/analysis/db/items/Makefile.am
@@ -7,18 +7,9 @@ libanalysisdbitems_la_SOURCES = \
move.h move.c \
switcher.h switcher.c
-libanalysisdbitems_la_LIBADD =
-
-libanalysisdbitems_la_LDFLAGS =
+libanalysisdbitems_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBSQLITE_CFLAGS)
devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
dev_HEADERS = $(libanalysisdbitems_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBARCHIVE_CFLAGS) $(LIBSQLITE_CFLAGS)
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
-SUBDIRS =
diff --git a/src/analysis/db/items/bookmark.c b/src/analysis/db/items/bookmark.c
index 0a64c89..3610d96 100644
--- a/src/analysis/db/items/bookmark.c
+++ b/src/analysis/db/items/bookmark.c
@@ -81,10 +81,10 @@ static gboolean g_db_bookmark_cmp_key(const GDbBookmark *, const GDbBookmark *);
static gint g_db_bookmark_cmp(const GDbBookmark *, const GDbBookmark *);
/* Importe la définition d'un signet dans un flux réseau. */
-static bool g_db_bookmark_unpack(GDbBookmark *, packed_buffer *);
+static bool g_db_bookmark_unpack(GDbBookmark *, packed_buffer_t *);
/* Exporte la définition d'un signet dans un flux réseau. */
-static bool g_db_bookmark_pack(const GDbBookmark *, packed_buffer *);
+static bool g_db_bookmark_pack(const GDbBookmark *, packed_buffer_t *);
/* Construit la description humaine d'un signet sur un tampon. */
static char *g_db_bookmark_build_label(const GDbBookmark *);
@@ -412,7 +412,7 @@ static gint g_db_bookmark_cmp(const GDbBookmark *a, const GDbBookmark *b)
* *
******************************************************************************/
-static bool g_db_bookmark_unpack(GDbBookmark *bookmark, packed_buffer *pbuf)
+static bool g_db_bookmark_unpack(GDbBookmark *bookmark, packed_buffer_t *pbuf)
{
bool result; /* Bilan à retourner */
@@ -442,7 +442,7 @@ static bool g_db_bookmark_unpack(GDbBookmark *bookmark, packed_buffer *pbuf)
* *
******************************************************************************/
-static bool g_db_bookmark_pack(const GDbBookmark *bookmark, packed_buffer *pbuf)
+static bool g_db_bookmark_pack(const GDbBookmark *bookmark, packed_buffer_t *pbuf)
{
bool result; /* Bilan à retourner */
diff --git a/src/analysis/db/items/comment.c b/src/analysis/db/items/comment.c
index bdff3a6..fb27f60 100644
--- a/src/analysis/db/items/comment.c
+++ b/src/analysis/db/items/comment.c
@@ -39,9 +39,9 @@
#include "../../human/asm/lang.h"
#include "../../../common/array.h"
#include "../../../common/extstr.h"
+#include "../../../core/columns.h"
#include "../../../glibext/gbinarycursor.h"
#include "../../../glibext/linegen-int.h"
-#include "../../../gtkext/gtkblockdisplay.h"
@@ -94,10 +94,10 @@ static gboolean g_db_comment_cmp_key(const GDbComment *, const GDbComment *);
static gint g_db_comment_cmp(const GDbComment *, const GDbComment *);
/* Importe la définition d'un commentaire dans un flux réseau. */
-static bool g_db_comment_unpack(GDbComment *, packed_buffer *);
+static bool g_db_comment_unpack(GDbComment *, packed_buffer_t *);
/* Exporte la définition d'un commentaire dans un flux réseau. */
-static bool g_db_comment_pack(GDbComment *, packed_buffer *);
+static bool g_db_comment_pack(GDbComment *, packed_buffer_t *);
/* Construit la description humaine d'un commentaire. */
static char *g_db_comment_build_label(GDbComment *);
@@ -570,7 +570,7 @@ static gint g_db_comment_cmp(const GDbComment *a, const GDbComment *b)
* *
******************************************************************************/
-static bool g_db_comment_unpack(GDbComment *comment, packed_buffer *pbuf)
+static bool g_db_comment_unpack(GDbComment *comment, packed_buffer_t *pbuf)
{
bool result; /* Bilan à retourner */
uint8_t tmp8; /* Valeur sur 8 bits */
@@ -623,7 +623,7 @@ static bool g_db_comment_unpack(GDbComment *comment, packed_buffer *pbuf)
* *
******************************************************************************/
-static bool g_db_comment_pack(GDbComment *comment, packed_buffer *pbuf)
+static bool g_db_comment_pack(GDbComment *comment, packed_buffer_t *pbuf)
{
bool result; /* Bilan à retourner */
rle_string text; /* Texte brut récupéré */
diff --git a/src/analysis/db/items/move.c b/src/analysis/db/items/move.c
index f70de6f..e4f503b 100644
--- a/src/analysis/db/items/move.c
+++ b/src/analysis/db/items/move.c
@@ -35,9 +35,13 @@
#include "../collection-int.h"
#include "../item-int.h"
-#include "../../../gui/core/global.h"
+#ifdef INCLUDE_GTK_SUPPORT
+# include "../../../gui/core/global.h"
+#endif
#include "../../../glibext/gbinarycursor.h"
-#include "../../../glibext/gloadedpanel.h"
+#ifdef INCLUDE_GTK_SUPPORT
+# include "../../../glibext/gloadedpanel.h"
+#endif
@@ -78,10 +82,10 @@ static void g_db_move_finalize(GDbMove *);
static gint g_db_move_cmp(const GDbMove *, const GDbMove *);
/* Importe la définition d'un déplacement depuis un flux réseau. */
-static bool g_db_move_unpack(GDbMove *, packed_buffer *);
+static bool g_db_move_unpack(GDbMove *, packed_buffer_t *);
/* Exporte la définition d'un déplacement dans un flux réseau. */
-static bool g_db_move_pack(const GDbMove *, packed_buffer *);
+static bool g_db_move_pack(const GDbMove *, packed_buffer_t *);
/* Construit la description humaine d'un déplacement. */
static char *g_db_move_build_label(GDbMove *);
@@ -314,7 +318,7 @@ static gint g_db_move_cmp(const GDbMove *a, const GDbMove *b)
* *
******************************************************************************/
-static bool g_db_move_unpack(GDbMove *move, packed_buffer *pbuf)
+static bool g_db_move_unpack(GDbMove *move, packed_buffer_t *pbuf)
{
bool result; /* Bilan à retourner */
@@ -347,7 +351,7 @@ static bool g_db_move_unpack(GDbMove *move, packed_buffer *pbuf)
* *
******************************************************************************/
-static bool g_db_move_pack(const GDbMove *move, packed_buffer *pbuf)
+static bool g_db_move_pack(const GDbMove *move, packed_buffer_t *pbuf)
{
bool result; /* Bilan à retourner */
@@ -410,6 +414,8 @@ static char *g_db_move_build_label(GDbMove *move)
static bool g_db_move_run(const GDbMove *move, GLineCursor *cursor)
{
+#ifdef INCLUDE_GTK_SUPPORT
+
GLoadedPanel *panel; /* Afficheur effectif de code */
typedef struct _move_params
@@ -465,6 +471,8 @@ static bool g_db_move_run(const GDbMove *move, GLineCursor *cursor)
if (panel != NULL)
g_object_unref(G_OBJECT(panel));
+#endif
+
return true;
}
diff --git a/src/analysis/db/items/switcher.c b/src/analysis/db/items/switcher.c
index 090b8ce..885406c 100644
--- a/src/analysis/db/items/switcher.c
+++ b/src/analysis/db/items/switcher.c
@@ -84,10 +84,10 @@ static gboolean g_db_switcher_cmp_key(const GDbSwitcher *, const GDbSwitcher *);
static gint g_db_switcher_cmp(const GDbSwitcher *, const GDbSwitcher *);
/* Importe la définition d'un signet depuis un flux réseau. */
-static bool g_db_switcher_unpack(GDbSwitcher *, packed_buffer *);
+static bool g_db_switcher_unpack(GDbSwitcher *, packed_buffer_t *);
/* Exporte la définition d'un signet dans un flux réseau. */
-static bool g_db_switcher_pack(const GDbSwitcher *, packed_buffer *);
+static bool g_db_switcher_pack(const GDbSwitcher *, packed_buffer_t *);
/* Construit la description humaine d'un signet sur un tampon. */
static char *g_db_switcher_build_label(GDbSwitcher *);
@@ -448,7 +448,7 @@ static gint g_db_switcher_cmp(const GDbSwitcher *a, const GDbSwitcher *b)
* *
******************************************************************************/
-static bool g_db_switcher_unpack(GDbSwitcher *switcher, packed_buffer *pbuf)
+static bool g_db_switcher_unpack(GDbSwitcher *switcher, packed_buffer_t *pbuf)
{
bool result; /* Bilan à retourner */
uint32_t tmp32; /* Valeur sur 32 bits */
@@ -489,7 +489,7 @@ static bool g_db_switcher_unpack(GDbSwitcher *switcher, packed_buffer *pbuf)
* *
******************************************************************************/
-static bool g_db_switcher_pack(const GDbSwitcher *switcher, packed_buffer *pbuf)
+static bool g_db_switcher_pack(const GDbSwitcher *switcher, packed_buffer_t *pbuf)
{
bool result; /* Bilan à retourner */
diff --git a/src/analysis/db/misc/Makefile.am b/src/analysis/db/misc/Makefile.am
index 6d4af6c..fc3cab2 100644
--- a/src/analysis/db/misc/Makefile.am
+++ b/src/analysis/db/misc/Makefile.am
@@ -6,18 +6,7 @@ libanalysisdbmisc_la_SOURCES = \
snapshot.h snapshot.c \
timestamp.h timestamp.c
-libanalysisdbmisc_la_LIBADD =
-
-libanalysisdbmisc_la_LDFLAGS =
-
devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
dev_HEADERS = $(libanalysisdbmisc_la_SOURCES:%c=)
-
-
-AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBARCHIVE_CFLAGS) $(LIBSQLITE_CFLAGS)
-
-AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
-
-SUBDIRS =
diff --git a/src/analysis/db/misc/rlestr.c b/src/analysis/db/misc/rlestr.c
index 7b1e705..a211723 100644
--- a/src/analysis/db/misc/rlestr.c
+++ b/src/analysis/db/misc/rlestr.c
@@ -29,6 +29,9 @@
#include <string.h>
+#include "../../../common/leb128.h"
+
+
/******************************************************************************
* *
@@ -273,19 +276,19 @@ int cmp_rle_string(const rle_string *s1, const rle_string *s2)
* *
******************************************************************************/
-bool unpack_rle_string(rle_string *str, packed_buffer *pbuf)
+bool unpack_rle_string(rle_string *str, packed_buffer_t *pbuf)
{
bool result; /* Bilan à retourner */
- uint32_t tmp32; /* Valeur sur 32 bits */
+ uleb128_t len; /* Quantité de caractères */
unset_rle_string(str);
- result = extract_packed_buffer(pbuf, &tmp32, sizeof(uint32_t), true);
-
- str->length = tmp32;
+ result = unpack_uleb128(&len, pbuf);
- if (result && str->length > 0)
+ if (result && len > 0)
{
+ str->length = len;
+
str->data = malloc(str->length + 1);
str->dynamic = true;
@@ -317,11 +320,11 @@ bool unpack_rle_string(rle_string *str, packed_buffer *pbuf)
* *
******************************************************************************/
-bool pack_rle_string(const rle_string *str, packed_buffer *pbuf)
+bool pack_rle_string(const rle_string *str, packed_buffer_t *pbuf)
{
bool result; /* Bilan à retourner */
- result = extend_packed_buffer(pbuf, (uint32_t []) { str->length }, sizeof(uint32_t), true);
+ result = pack_uleb128((uleb128_t []){ str->length }, pbuf);
if (result && str->length > 0)
result = extend_packed_buffer(pbuf, str->data, str->length + 1, false);
diff --git a/src/analysis/db/misc/rlestr.h b/src/analysis/db/misc/rlestr.h
index 63effda..aa2aa73 100644
--- a/src/analysis/db/misc/rlestr.h
+++ b/src/analysis/db/misc/rlestr.h
@@ -83,10 +83,10 @@ void unset_rle_string(rle_string *);
int cmp_rle_string(const rle_string *, const rle_string *);
/* Importe la définition d'une chaîne de caractères. */
-bool unpack_rle_string(rle_string *, packed_buffer *);
+bool unpack_rle_string(rle_string *, packed_buffer_t *);
/* Exporte la définition d'une chaîne de caractères. */
-bool pack_rle_string(const rle_string *, packed_buffer *);
+bool pack_rle_string(const rle_string *, packed_buffer_t *);
diff --git a/src/analysis/db/misc/snapshot.c b/src/analysis/db/misc/snapshot.c
index 23fe15c..b116b3c 100644
--- a/src/analysis/db/misc/snapshot.c
+++ b/src/analysis/db/misc/snapshot.c
@@ -188,7 +188,7 @@ int cmp_snapshot_id(const snapshot_id_t *id1, const snapshot_id_t *id2)
* *
******************************************************************************/
-bool unpack_snapshot_id(snapshot_id_t *id, packed_buffer *pbuf)
+bool unpack_snapshot_id(snapshot_id_t *id, packed_buffer_t *pbuf)
{
bool result; /* Bilan à retourner */
@@ -212,7 +212,7 @@ bool unpack_snapshot_id(snapshot_id_t *id, packed_buffer *pbuf)
* *
******************************************************************************/
-bool pack_snapshot_id(const snapshot_id_t *id, packed_buffer *pbuf)
+bool pack_snapshot_id(const snapshot_id_t *id, packed_buffer_t *pbuf)
{
bool result; /* Bilan à retourner */
@@ -411,7 +411,7 @@ void copy_snapshot_info(snapshot_info_t *dest, const snapshot_info_t *src)
* *
******************************************************************************/
-bool unpack_snapshot_info(snapshot_info_t *info, packed_buffer *pbuf)
+bool unpack_snapshot_info(snapshot_info_t *info, packed_buffer_t *pbuf)
{
bool result; /* Bilan à retourner */
rle_string string; /* Chaîne à transmettre */
@@ -473,7 +473,7 @@ bool unpack_snapshot_info(snapshot_info_t *info, packed_buffer *pbuf)
* *
******************************************************************************/
-bool pack_snapshot_info(const snapshot_info_t *info, packed_buffer *pbuf)
+bool pack_snapshot_info(const snapshot_info_t *info, packed_buffer_t *pbuf)
{
bool result; /* Bilan à retourner */
rle_string string; /* Chaîne à transmettre */
diff --git a/src/analysis/db/misc/snapshot.h b/src/analysis/db/misc/snapshot.h
index 3f55b50..f6a84f1 100644
--- a/src/analysis/db/misc/snapshot.h
+++ b/src/analysis/db/misc/snapshot.h
@@ -71,10 +71,10 @@ void copy_snapshot_id(snapshot_id_t *, const snapshot_id_t *);
int cmp_snapshot_id(const snapshot_id_t *, const snapshot_id_t *);
/* Importe la définition d'un identifiant d'instantané. */
-bool unpack_snapshot_id(snapshot_id_t *, packed_buffer *);
+bool unpack_snapshot_id(snapshot_id_t *, packed_buffer_t *);
/* Exporte la définition d'un identifiant d'instantané. */
-bool pack_snapshot_id(const snapshot_id_t *, packed_buffer *);
+bool pack_snapshot_id(const snapshot_id_t *, packed_buffer_t *);
@@ -117,10 +117,10 @@ void exit_snapshot_info(snapshot_info_t *);
void copy_snapshot_info(snapshot_info_t *, const snapshot_info_t *);
/* Importe la description d'un identifiant d'instantané. */
-bool unpack_snapshot_info(snapshot_info_t *, packed_buffer *);
+bool unpack_snapshot_info(snapshot_info_t *, packed_buffer_t *);
/* Exporte la description d'un identifiant d'instantané. */
-bool pack_snapshot_info(const snapshot_info_t *, packed_buffer *);
+bool pack_snapshot_info(const snapshot_info_t *, packed_buffer_t *);
/* Change la désignation dans les informations d'un instantané. */
void set_snapshot_info_name(snapshot_info_t *, const char *);
diff --git a/src/analysis/db/misc/timestamp.c b/src/analysis/db/misc/timestamp.c
index 5f49997..1790e2b 100644
--- a/src/analysis/db/misc/timestamp.c
+++ b/src/analysis/db/misc/timestamp.c
@@ -203,7 +203,7 @@ int cmp_timestamp(const timestamp_t *t1, const timestamp_t *t2)
* *
******************************************************************************/
-bool unpack_timestamp(timestamp_t *timestamp, packed_buffer *pbuf)
+bool unpack_timestamp(timestamp_t *timestamp, packed_buffer_t *pbuf)
{
bool result; /* Bilan à retourner */
@@ -227,7 +227,7 @@ bool unpack_timestamp(timestamp_t *timestamp, packed_buffer *pbuf)
* *
******************************************************************************/
-bool pack_timestamp(const timestamp_t *timestamp, packed_buffer *pbuf)
+bool pack_timestamp(const timestamp_t *timestamp, packed_buffer_t *pbuf)
{
bool result; /* Bilan à retourner */
diff --git a/src/analysis/db/misc/timestamp.h b/src/analysis/db/misc/timestamp.h
index f41a529..bdb9d3e 100644
--- a/src/analysis/db/misc/timestamp.h
+++ b/src/analysis/db/misc/timestamp.h
@@ -57,10 +57,10 @@ void copy_timestamp(timestamp_t *, const timestamp_t *);
int cmp_timestamp(const timestamp_t *, const timestamp_t *);
/* Importe la définition d'un horodatage. */
-bool unpack_timestamp(timestamp_t *, packed_buffer *);
+bool unpack_timestamp(timestamp_t *, packed_buffer_t *);
/* Exporte la définition d'un horodatage. */
-bool pack_timestamp(const timestamp_t *, packed_buffer *);
+bool pack_timestamp(const timestamp_t *, packed_buffer_t *);
diff --git a/src/analysis/db/protocol.h b/src/analysis/db/protocol.h
index f673c4b..7707058 100644
--- a/src/analysis/db/protocol.h
+++ b/src/analysis/db/protocol.h
@@ -29,8 +29,12 @@
/**
* Version de la définition courante du protocole.
*/
-#define CDB_PROTOCOL_VERSION 0xc0de0004
+#define CDB_PROTOCOL_VERSION 0xc0de0005
+/**
+ * 0xc0de0005 :
+ * - création des rôles d'aministrateur et d'analyste
+ */
@@ -43,34 +47,58 @@
-/* Comportement vis à vis des éléments */
-typedef enum _DBStorage
-{
- DBS_ALL_LOCAL = 0x00, /* Enregistrements locaux */
- DBS_ALL_REMOTE = 0x01, /* Enregistrements distants */
- DBS_MAX = 0x01
-
-} DBStorage;
+/* Rôle à envoyer lors des présentations */
+typedef enum _ClientRole
+{
+ CRL_UNDEFINED = 0, /* Rôle non défini */
+ CRL_ADMIN = 1, /* Rôle d'administrateur */
+ CRL_ANALYST = 2, /* Rôle d'analyste */
+} ClientRole;
+/* Niveaux de privilèges */
+typedef enum _ServerPrivLevels
+{
+ SPV_UNDEFINED = 0, /* Rôle non défini */
+ SPV_ADMINISTRATOR = 1, /* Pleins pouvoirs */
+ SPV_MANAGER = 2, /* Gestionnaire de comptes */
+ SPV_CREATOR = 3, /* Gestionnaire d'analyses */
+ SPV_ANALYST = 4, /* Analyste de binaires */
+} ServerPrivLevels;
/**
- * Une fois la connexion établie, les paquets ont tous la forme suivante :
+ * Précisions pour la commande DBC_LOADING_STATUS.
+ */
+/* Eléments de base nécessaires */
+typedef enum _LoadingStatusHint
+{
+ LSH_READY = 0, /* (Plus) rien n'est requis */
+ LSH_ON_WAIT_LIST = 1, /* Concurrence des connexions */
+ LSH_NEED_CONTENT = 2, /* Suppléments nécessaires */
+ LSH_NEED_FORMAT = 3, /* Suppléments nécessaires */
+ LSH_NEED_ARCH = 4, /* Suppléments nécessaires */
+} LoadingStatusHint;
+
+
+
+
+/**
+ * Une fois la connexion établie, les paquets ont tous la forme suivante :
*
* [ type de collection visée ; cf. DBFeatures ]
* [ action à mener ; cf. DBAction ]
@@ -114,9 +142,91 @@ typedef enum _DBAction
*/
typedef enum _DBCommand
{
+ /* ------------------------- Commandes à portée générale ------------------------- */
+
+ /**
+ * Le client envoie un tout premier paquet de la forme suivante :
+ *
+ * [ Ordre de sauvegarde : DBC_HELO ]
+ * [ Protocole supporté : CDB_PROTOCOL_VERSION ]
+ * [ Rôle visé ; cf ClientRole ]
+ * [ Compléments selon le rôle visé ]
+ *
+ * Le serveur effectue les validations et renvoie un bilan :
+ *
+ * [ Ordre de sauvegarde : DBC_WELCOME ]
+ * [ Statut d'exécution ; cf. DBError ]
+ *
+ */
+
DBC_HELO, /* Connexion initiale C -> S */
DBC_WELCOME, /* Réponse initiale S -> C */
+
+ /* ------------------------ Commandes pour administrateur ------------------------ */
+
+ /**
+ * Le client envoie une requête pour lister les binaires de la forme suivante :
+ *
+ * [ Demande de liste : DBC_LIST_BINARIES ]
+ *
+ * Le serveur liste tous les répertoires présents et renvoie cette liste :
+ *
+ * [ Marqueur de liste : DBC_EXISTING_BINARIES ]
+ * [ Quantité d'éléments en ULEB128 ]
+ * [ Noms en chaîne RLE... ]
+ *
+ */
+
+ DBC_LIST_BINARIES, /* Fourniture des identifiants */
+ DBC_EXISTING_BINARIES, /* Eléments présents */
+
+
+ /* ------------------------ Commandes pour analyste ------------------------ */
+
+ /**
+ * Gestion de la commande 'DBC_LOADING_STATUS'.
+ *
+ * Le serveur envoie un statut de prise en charge au début d'une connexion :
+ *
+ * [ Indication du serveur : DBC_LOADING_STATUS]
+ * [ Statut courant ; cf. LoadingStatusHint ]
+ *
+ */
+
+ DBC_LOADING_STATUS, /* Indications initiales */
+
+ /**
+ * Gestion de la commande 'DBC_SET_CONTENT'.
+ *
+ * Le client connecté envoie un paquet de la forme suivante :
+ *
+ * [ Ordre de sauvegarde : DBC_SET_CONTENT ]
+ * [ Quantité des données suivantes ]
+ * [ Position du contenu + données de stockage ]
+ *
+ * Le serveur s'exécute et renvoie un bilan :
+ *
+ * [ Ordre de sauvegarde : DBC_SET_CONTENT ]
+ * [ Statut d'exécution ; cf. DBError ]
+ *
+ */
+
+ DBC_SET_CONTENT,
+
+
+
+
+
+
+
+
+
+
+
+
+
+
/**
* Gestion de la commande 'DBC_SAVE'.
*
@@ -329,6 +439,7 @@ typedef enum _DBError
DBE_XML_VERSION_ERROR, /* Vieille archive présente */
DBE_DB_LOADING_ERROR, /* Erreur pendant le chargement*/
+ DBE_WRONG_HASH, /* Empreinte inattendue */
DBE_XML_ERROR, /* Erreur lors d'une définition*/
DBE_SNAPSHOT_NOT_FOUND, /* Instantané non trouvé */
DBE_SNAPSHOT_RESTORE_FAILURE, /* Echec d'une restauration */
diff --git a/src/analysis/db/server.c b/src/analysis/db/server.c
index 258a66c..79d5df1 100644
--- a/src/analysis/db/server.c
+++ b/src/analysis/db/server.c
@@ -42,7 +42,9 @@
#include "auth.h"
+#include "backend.h"
#include "cdb.h"
+#include "controller.h"
#include "protocol.h"
#include "misc/rlestr.h"
#include "../../common/extstr.h"
@@ -92,8 +94,10 @@ struct _GHubServer
GThread *listener; /* Procédure de traitement */
- GList *archives; /* Liste des binaires ouverts */
- GMutex mutex; /* Verrou pour l'accès */
+ GList *controllers; /* Liste des administrateurs */
+ GMutex ctrl_mutex; /* Verrou pour l'accès */
+ GList *archives; /* Liste des aanlystes */
+ GMutex ar_mutex; /* Verrou pour l'accès */
GMutex wait_mutex; /* Accès à la condition */
GCond wait_cond; /* Attente de signal */
@@ -136,6 +140,18 @@ static int g_hub_server_verify(int, X509_STORE_CTX *);
/* Assure l'accueil des nouveaux clients. */
static void *g_hub_server_listener(GHubServer *);
+/* Assure l'accueil des nouveaux clients administrateurs. */
+static GServerBackend *g_hub_server_handle_admin(GHubServer *, packed_buffer_t *, const char *, DBError *, bool *);
+
+/* Assure l'accueil des nouveaux clients analystes. */
+static GServerBackend *g_hub_server_handle_analyst(GHubServer *, packed_buffer_t *, const char *, DBError *, bool *);
+
+/* Enregistre dans une liste interne un support de suivi. */
+static void g_hub_server_register_backend(GHubServer *, GServerBackend *);
+
+/* Suit les variations du compteur de références d'un greffon. */
+static void on_backend_ref_toggle(GHubServer *, GServerBackend *, gboolean);
+
/* Indique le type défini pour une description de serveur à l'écoute. */
@@ -190,7 +206,10 @@ static void g_hub_server_init(GHubServer *server)
server->unlock_socket = NULL;
server->lock_fd = -1;
- g_mutex_init(&server->mutex);
+ server->controllers = NULL;
+ g_mutex_init(&server->ctrl_mutex);
+ server->archives = NULL;
+ g_mutex_init(&server->ar_mutex);
g_mutex_init(&server->wait_mutex);
g_cond_init(&server->wait_cond);
@@ -216,15 +235,23 @@ static void g_hub_server_dispose(GHubServer *server)
g_hub_server_stop(server);
+ for (iter = g_list_first(server->controllers);
+ iter != NULL;
+ iter = g_list_first(server->controllers))
+ {
+ g_object_unref(G_OBJECT(iter->data));
+ }
+
+ g_mutex_clear(&server->ctrl_mutex);
+
for (iter = g_list_first(server->archives);
iter != NULL;
iter = g_list_first(server->archives))
{
g_object_unref(G_OBJECT(iter->data));
- server->archives = g_list_delete_link(server->archives, iter);
}
- g_mutex_clear(&server->mutex);
+ g_mutex_clear(&server->ar_mutex);
g_mutex_clear(&server->wait_mutex);
g_cond_clear(&server->wait_cond);
@@ -721,19 +748,17 @@ static void *g_hub_server_listener(GHubServer *server)
gen_sockaddr_t peer; /* Adresse cliente */
int fd; /* Canal établi vers un client */
SSL *tls_fd; /* Même canal, mais sécurisé */
- rle_string hash; /* Empreinte du binaire visé */
+ GServerBackend *backend; /* Support de suivi créé */
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 */
+ packed_buffer_t 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 */
- char *basedir; /* Répertoire de stockage */
- char *tmpdir; /* Répertoire de travail */
- packed_buffer out_pbuf; /* Tampon d'émission */
+ uint32_t role; /* Rôle visé par le client */
+ bool new; /* Besoin d'ajout à une liste */
+ packed_buffer_t out_pbuf; /* Tampon d'émission */
fds.fd = server->fd;
fds.events = POLLIN | POLLPRI;
@@ -782,12 +807,10 @@ static void *g_hub_server_listener(GHubServer *server)
goto invalid_conn;
}
- /* Initialisation à vide pour les sorties en erreur */
-
- setup_empty_rle_string(&hash);
-
/* Construction d'une représentation */
+ backend = NULL;
+
if (*((sa_family_t *)&peer) == AF_UNIX)
peer_name = strdup(server->desc);
@@ -799,7 +822,7 @@ static void *g_hub_server_listener(GHubServer *server)
if (ip == NULL)
{
LOG_ERROR_N("inet_ntop");
- goto id_error;
+ goto ip_error;
}
snprintf(peer_name + strlen(ip), 1 + 5, ":%hu", ntohs(peer.inet4_addr.sin_port));
@@ -814,7 +837,7 @@ static void *g_hub_server_listener(GHubServer *server)
if (ip == NULL)
{
LOG_ERROR_N("inet_ntop");
- goto id_error;
+ goto ip_error;
}
snprintf(peer_name + strlen(ip), 1 + 5, ":%hu", ntohs(peer.inet6_addr.sin6_port));
@@ -825,14 +848,12 @@ static void *g_hub_server_listener(GHubServer *server)
goto invalid_conn;
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.
+ * - la commande 'DBC_HELO' ;
+ * - le numéro de version du client ;
+ * - le rôle attendu.
* - l'empreinte du binaire analysé.
*
* Tout ceci est à synchroniser avec la fonction g_db_client_start().
@@ -846,7 +867,7 @@ static void *g_hub_server_listener(GHubServer *server)
log_variadic_message(LMT_ERROR, _("Error while getting the initial packet from '%s'..."),
peer_name);
error = DBE_BAD_EXCHANGE;
- goto error_sending;
+ goto error_receiving;
}
status = extract_packed_buffer(&in_pbuf, &cmd, sizeof(uint32_t), true);
@@ -855,7 +876,7 @@ static void *g_hub_server_listener(GHubServer *server)
log_variadic_message(LMT_ERROR, _("Error while getting the initial command from '%s'..."),
peer_name);
error = DBE_BAD_EXCHANGE;
- goto error_sending;
+ goto error_receiving;
}
status = extract_packed_buffer(&in_pbuf, &version, sizeof(uint32_t), true);
@@ -864,16 +885,16 @@ static void *g_hub_server_listener(GHubServer *server)
log_variadic_message(LMT_ERROR, _("Error while getting the protocol version from '%s'..."),
peer_name);
error = DBE_BAD_EXCHANGE;
- goto error_sending;
+ goto error_receiving;
}
- status = unpack_rle_string(&hash, &in_pbuf);
+ status = extract_packed_buffer(&in_pbuf, &role, sizeof(uint32_t), true);
if (!status)
{
- log_variadic_message(LMT_ERROR, _("Error while getting the binary hash from '%s'..."),
+ log_variadic_message(LMT_ERROR, _("Error while getting the expected role from '%s'..."),
peer_name);
error = DBE_BAD_EXCHANGE;
- goto error_sending;
+ goto error_receiving;
}
if (cmd != DBC_HELO)
@@ -881,65 +902,48 @@ static void *g_hub_server_listener(GHubServer *server)
log_variadic_message(LMT_ERROR, _("The client from '%s' did not introduce itself!"),
peer_name);
error = DBE_BAD_EXCHANGE;
- goto error_sending;
+ goto error_receiving;
}
if (version != CDB_PROTOCOL_VERSION)
{
- log_variadic_message(LMT_ERROR, _("The client from '%s' does not use the same protocol: 0x%08x vs 0x%08x..."),
+ log_variadic_message(LMT_ERROR,
+ _("The client from '%s' does not use the same protocol: 0x%08x vs 0x%08x..."),
peer_name, be32toh(version), CDB_PROTOCOL_VERSION);
error = DBE_WRONG_VERSION;
- goto error_sending;
+ goto error_receiving;
}
- if (is_rle_string_empty(&hash))
+ switch (role)
{
- log_variadic_message(LMT_ERROR, _("The submitted binary hash from '%s' is empty!"),
- peer_name);
- 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.
- */
-
- assert(error == DBE_NONE);
+ case CRL_ADMIN:
+ backend = g_hub_server_handle_admin(server, &in_pbuf, peer_name, &error, &new);
+ break;
- for (iter = g_list_first(server->archives);
- iter != NULL;
- iter = g_list_next(iter))
- {
- archive = G_CDB_ARCHIVE(iter->data);
- if (g_cdb_archive_compare_hash(archive, &hash) == 0)
+ case CRL_ANALYST:
+ backend = g_hub_server_handle_analyst(server, &in_pbuf, peer_name, &error, &new);
break;
- }
- if (iter == NULL)
- {
- basedir = strdup(server->working);
- basedir = stradd(basedir, "cdbs" G_DIR_SEPARATOR_S);
+ default:
+ log_variadic_message(LMT_ERROR, _("Unknown client role 0x%x requested by '%s'"),
+ role, peer_name);
+ backend = NULL;
+ error = DBE_BAD_EXCHANGE;
+ new = false;
+ break;
- tmpdir = strdup(server->working);
- tmpdir = stradd(tmpdir, "tmp" G_DIR_SEPARATOR_S);
+ }
- archive = g_cdb_archive_new(basedir, tmpdir, &hash, &error);
+ assert((backend == NULL && error != DBE_NONE) || (backend != NULL && error == DBE_NONE));
- free(tmpdir);
- free(basedir);
-
- }
+ error_receiving:
/**
* Le serveur doit répondre pour un message type :
- * - la commande 'DBC_WELCOME'.
- * - un identifiant d'erreur ('DBE_NONE', 'DBE_BAD_EXCHANGE'
- * ou 'DBE_WRONG_VERSION' ... 'DBE_LOADING_ERROR').
+ * - la commande 'DBC_WELCOME' ;
+ * - un identifiant d'erreur.
*/
- error_sending:
-
exit_packed_buffer(&in_pbuf);
init_packed_buffer(&out_pbuf);
@@ -959,41 +963,28 @@ static void *g_hub_server_listener(GHubServer *server)
* lors des échanges initiaux, car ces derniers seraient alors précédés des mises à jour...
*/
- if (archive != NULL)
+ if (backend != NULL)
{
- assert(error == DBE_NONE);
-
- /* Si l'archive a été créée pour l'occasion... */
- if (iter == NULL)
- server->archives = g_list_append(server->archives, archive);
-
- g_cdb_archive_add_client(archive, tls_fd);
-
- exit_packed_buffer(&out_pbuf);
-
- free(peer_name);
+ if (new)
+ g_hub_server_register_backend(server, backend);
- exit_rle_string(&hash);
-
- continue;
+ g_server_backend_add_client(backend, tls_fd, peer_name);
}
- assert(error != DBE_NONE);
-
out_error:
- exit_packed_buffer(&out_pbuf);
+ if (backend != NULL)
+ g_object_unref(G_OBJECT(backend));
- /* Si l'archive a été créée pour l'occasion... */
- if (iter == NULL && archive != NULL)
- g_object_unref(G_OBJECT(archive));
+ exit_packed_buffer(&out_pbuf);
- id_error:
+ ip_error:
free(peer_name);
- exit_rle_string(&hash);
+ if (backend != NULL)
+ continue;
invalid_conn:
@@ -1016,6 +1007,283 @@ static void *g_hub_server_listener(GHubServer *server)
/******************************************************************************
* *
+* Paramètres : server = serveur pour les accès distants à manipuler. *
+* in_pbuf = reste des premières données reçues. *
+* peer_name = désignation de la connexion entrante. *
+* error = code d'erreur issu du traitement. [OUT] *
+* new = indique si le résultat doit être ajouté. [OUT] *
+* *
+* Description : Assure l'accueil des nouveaux clients administrateurs. *
+* *
+* Retour : Instance de support de suivi mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static GServerBackend *g_hub_server_handle_admin(GHubServer *server, packed_buffer_t *in_pbuf, const char *peer_name, DBError *error, bool *new)
+{
+ GCdbController *result; /* Support de suivi à retourner*/
+ char *basedir; /* Répertoire de stockage */
+
+ if (has_more_data_in_packed_buffer(in_pbuf))
+ {
+ log_variadic_message(LMT_ERROR, _("The client from '%s' provided too much data!"), peer_name);
+
+ result = NULL;
+
+ *error = DBE_BAD_EXCHANGE;
+ *new = false;
+
+ }
+ else
+ {
+ basedir = strdup(server->working);
+ basedir = stradd(basedir, "cdbs" G_DIR_SEPARATOR_S);
+
+ result = g_cdb_controller_new(basedir, error);
+
+ free(basedir);
+
+ *new = true;
+
+ }
+
+ return G_SERVER_BACKEND(result);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : server = serveur pour les accès distants à manipuler. *
+* in_pbuf = reste des premières données reçues. *
+* peer_name = désignation de la connexion entrante. *
+* error = code d'erreur issu du traitement. [OUT] *
+* new = indique si le résultat doit être ajouté. [OUT] *
+* *
+* Description : Assure l'accueil des nouveaux clients analystes. *
+* *
+* Retour : Instance de support de suivi mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static GServerBackend *g_hub_server_handle_analyst(GHubServer *server, packed_buffer_t *in_pbuf, const char *peer_name, DBError *error, bool *new)
+{
+ GCdbArchive *result; /* Support de suivi à retourner*/
+ rle_string hash; /* Empreinte du binaire visé */
+ rle_string class; /* Nature du contenu visé */
+ bool status; /* Bilan d'une opération */
+ GList *iter; /* Boucle de parcours */
+ GCdbArchive *archive; /* Destinataire final du client*/
+ char *basedir; /* Répertoire de stockage */
+ char *tmpdir; /* Répertoire de travail */
+
+ result = NULL;
+
+ *error = DBE_BAD_EXCHANGE;
+ *new = false;
+
+ /* Fin de réception des données envoyées */
+
+ setup_empty_rle_string(&hash);
+
+ status = unpack_rle_string(&hash, in_pbuf);
+ if (!status)
+ {
+ log_variadic_message(LMT_ERROR, _("Error while getting the binary hash from '%s'..."), peer_name);
+ goto error_receiving;
+ }
+
+ if (is_rle_string_empty(&hash))
+ {
+ log_variadic_message(LMT_ERROR, _("The submitted binary hash from '%s' is empty!"), peer_name);
+ goto wrong_receiving_0;
+ }
+
+ setup_empty_rle_string(&class);
+
+ status = unpack_rle_string(&class, in_pbuf);
+ if (!status)
+ {
+ log_variadic_message(LMT_ERROR, _("Error while getting the content class from '%s'..."), peer_name);
+ goto wrong_receiving_0;
+ }
+
+ if (is_rle_string_empty(&class))
+ {
+ log_variadic_message(LMT_ERROR, _("The submitted content class from '%s' is empty!"), peer_name);
+ goto wrong_receiving_1;
+ }
+
+ if (has_more_data_in_packed_buffer(in_pbuf))
+ {
+ log_variadic_message(LMT_ERROR, _("The client from '%s' provided too much data!"), peer_name);
+ goto wrong_receiving_1;
+ }
+
+ /* Recherche d'un support existant adapté */
+
+ g_mutex_lock(&server->ar_mutex);
+
+ for (iter = g_list_first(server->archives); iter != NULL; iter = g_list_next(iter))
+ {
+ archive = G_CDB_ARCHIVE(iter->data);
+
+ if (g_cdb_archive_compare_is_suitable_for(archive, &hash, &class))
+ break;
+
+ }
+
+ if (iter != NULL)
+ {
+ result = archive;
+ g_object_ref(G_OBJECT(result));
+ }
+
+ g_mutex_unlock(&server->ar_mutex);
+
+ /* Nouvelle création au besoin */
+
+ if (result == NULL)
+ {
+ basedir = strdup(server->working);
+ basedir = stradd(basedir, "cdbs" G_DIR_SEPARATOR_S);
+
+ tmpdir = strdup(server->working);
+ tmpdir = stradd(tmpdir, "tmp" G_DIR_SEPARATOR_S);
+
+ result = g_cdb_archive_new(basedir, tmpdir, &hash, &class, error);
+
+ free(tmpdir);
+ free(basedir);
+
+ *new = true;
+
+ }
+
+ wrong_receiving_1:
+
+ exit_rle_string(&class);
+
+ wrong_receiving_0:
+
+ exit_rle_string(&hash);
+
+ error_receiving:
+
+ return (result != NULL ? G_SERVER_BACKEND(result) : NULL);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : server = serveur pour les accès distants à manipuler. *
+* backend = support de suivi de connexion. *
+* *
+* Description : Enregistre dans une liste interne un support de suivi. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_hub_server_register_backend(GHubServer *server, GServerBackend *backend)
+{
+ GList **list; /* Liste à parcourir */
+ GMutex *mutex; /* Verrou à manipuler */
+
+ /* Sélection des éléments concernés */
+
+ if (G_IS_CDB_CONTROLLER(backend))
+ {
+ list = &server->controllers;
+ mutex = &server->ctrl_mutex;
+ }
+ else if (G_IS_CDB_ARCHIVE(backend))
+ {
+ list = &server->archives;
+ mutex = &server->ar_mutex;
+ }
+ else
+ assert(false);
+
+ /* Retrait de l'élément inutilisé */
+
+ g_mutex_lock(mutex);
+
+ g_object_ref(G_OBJECT(backend));
+
+ *list = g_list_append(*list, backend);
+
+ g_object_add_toggle_ref(G_OBJECT(backend), (GToggleNotify)on_backend_ref_toggle, server);
+
+ g_mutex_unlock(mutex);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : server = serveur pour les accès distants à manipuler. *
+* backend = support de suivi de connexion. *
+* last = indication sur la valeur du compteur de références.*
+* *
+* Description : Suit les variations du compteur de références d'un greffon. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void on_backend_ref_toggle(GHubServer *server, GServerBackend *backend, gboolean last)
+{
+ GList **list; /* Liste à parcourir */
+ GMutex *mutex; /* Verrou à manipuler */
+ GList *iter; /* Boucle de parcours */
+
+ if (last)
+ {
+ /* Sélection des éléments concernés */
+
+ if (G_IS_CDB_CONTROLLER(backend))
+ {
+ list = &server->controllers;
+ mutex = &server->ctrl_mutex;
+ }
+ else if (G_IS_CDB_ARCHIVE(backend))
+ {
+ list = &server->archives;
+ mutex = &server->ar_mutex;
+ }
+ else
+ assert(false);
+
+ /* Retrait de l'élément inutilisé */
+
+ g_mutex_lock(mutex);
+
+ for (iter = g_list_first(*list); iter != NULL; iter = g_list_first(*list))
+ {
+ *list = g_list_delete_link(*list, iter);
+ }
+
+ g_object_remove_toggle_ref(G_OBJECT(backend), (GToggleNotify)on_backend_ref_toggle, server);
+
+ g_mutex_unlock(mutex);
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : server = serveur pour les accès distants à manipuler. *
* backlog = nombre de connexions maximal. *
* keep = conservation du serveur en avant plan. *
diff --git a/src/analysis/db/snapshot.c b/src/analysis/db/snapshot.c
index e07129e..170cab5 100644
--- a/src/analysis/db/snapshot.c
+++ b/src/analysis/db/snapshot.c
@@ -37,7 +37,6 @@
#include "collection.h"
#include "../../common/compression.h"
#include "../../common/extstr.h"
-#include "../../common/io.h"
#include "../../common/sqlite.h"
#include "../../common/xml.h"
#include "../../core/logs.h"
@@ -69,7 +68,7 @@ static snapshot_node_t *create_snapshot_node(const char *, uint64_t, const char
static void destroy_snapshot_node(snapshot_node_t *);
/* Définit le chemin vers une base de données pour un noeud. */
-static bool setup_snapshot_node_db_path(snapshot_node_t *, const char *, const char *);
+static bool setup_snapshot_node_db_path(snapshot_node_t *, const GCdbArchive *);
/* Valide la présence d'une base de données pour chaque noeud. */
static bool check_snapshot_nodes(const snapshot_node_t *);
@@ -90,7 +89,7 @@ static void add_snapshot_node(snapshot_node_t *, snapshot_node_t *);
static void remove_snapshot_node(snapshot_node_t *, bool);
/* Collecte les descriptions d'une arborescence d'instantanés. */
-static bool pack_snapshot_node(const snapshot_node_t *, packed_buffer *);
+static bool pack_snapshot_node(const snapshot_node_t *, packed_buffer_t *);
@@ -102,9 +101,6 @@ struct _GDbSnapshot
{
GObject parent; /* A laisser en premier */
- char *tmpdir; /* Répertoire de travail */
- char *hash; /* Empreinte de binaire */
-
snapshot_node_t *nodes; /* Instantanés présents */
snapshot_node_t *current; /* Instantané courant */
@@ -133,7 +129,7 @@ static void g_db_snapshot_dispose(GDbSnapshot *);
static void g_db_snapshot_finalize(GDbSnapshot *);
/* Prépare un gestionnaire d'instantanés de bases de données. */
-static GDbSnapshot *g_db_snapshot_new(const char *, const char *);
+static GDbSnapshot *g_db_snapshot_new(const GCdbArchive *);
@@ -231,9 +227,8 @@ static void destroy_snapshot_node(snapshot_node_t *node)
/******************************************************************************
* *
-* Paramètres : node = noeud d'instantané à traiter. *
-* tmpdir = répertoire de travail temporaire. *
-* hash = empreinte du binaire à représenter. *
+* Paramètres : node = noeud d'instantané à traiter. *
+* archive = archive concernée par l'instantané. *
* *
* Description : Définit le chemin vers une base de données pour un noeud. *
* *
@@ -243,23 +238,26 @@ static void destroy_snapshot_node(snapshot_node_t *node)
* *
******************************************************************************/
-static bool setup_snapshot_node_db_path(snapshot_node_t *node, const char *tmpdir, const char *hash)
+static bool setup_snapshot_node_db_path(snapshot_node_t *node, const GCdbArchive *archive)
{
bool result; /* Bilan à retourner */
snapshot_id_t *id; /* Identifiant attribué */
+ char *suffix; /* Fin du fichier temporaire */
int ret; /* Bilan d'une génération */
id = get_snapshot_info_id(&node->info);
- ret = asprintf(&node->path, "%s" G_DIR_SEPARATOR_S "%s_%s_db.sql",
- tmpdir, hash, snapshot_id_as_string(id));
-
+ ret = asprintf(&suffix, "%s_db.sql", snapshot_id_as_string(id));
result = (ret > 0);
if (result)
{
- ret = ensure_path_exists(node->path);
- result = (ret != -1);
+ node->path = g_cdb_archive_get_tmp_filename(archive, suffix);
+
+ free(suffix);
+
+ result = (node->path != NULL);
+
}
return result;
@@ -639,7 +637,7 @@ static void remove_snapshot_node(snapshot_node_t *node, bool rec)
* *
******************************************************************************/
-static bool pack_snapshot_node(const snapshot_node_t *node, packed_buffer *pbuf)
+static bool pack_snapshot_node(const snapshot_node_t *node, packed_buffer_t *pbuf)
{
bool result; /* Bilan à retourner */
size_t i; /* Boucle de parcours */
@@ -702,9 +700,6 @@ static void g_db_snapshot_class_init(GDbSnapshotClass *klass)
static void g_db_snapshot_init(GDbSnapshot *snap)
{
- snap->tmpdir = NULL;
- snap->hash = NULL;
-
snap->nodes = NULL;
snap->current = NULL;
@@ -746,12 +741,6 @@ static void g_db_snapshot_dispose(GDbSnapshot *snap)
static void g_db_snapshot_finalize(GDbSnapshot *snap)
{
- if (snap->tmpdir != NULL)
- free(snap->tmpdir);
-
- if (snap->hash != NULL)
- free(snap->hash);
-
if (snap->nodes != NULL)
destroy_snapshot_node(snap->nodes);
@@ -765,8 +754,7 @@ static void g_db_snapshot_finalize(GDbSnapshot *snap)
/******************************************************************************
* *
-* Paramètres : tmpdir = répertoire de travail temporaire. *
-* hash = empreinte du binaire à représenter. *
+* Paramètres : archive = archive associée à l'instantané. *
* *
* Description : Prépare un gestionnaire d'instantanés de bases de données. *
* *
@@ -776,28 +764,15 @@ static void g_db_snapshot_finalize(GDbSnapshot *snap)
* *
******************************************************************************/
-static GDbSnapshot *g_db_snapshot_new(const char *tmpdir, const char *hash)
+static GDbSnapshot *g_db_snapshot_new(const GCdbArchive *archive)
{
GDbSnapshot *result; /* Adresse à retourner */
- int ret; /* Bilan d'une génération */
- bool status; /* Bilan de la création */
result = g_object_new(G_TYPE_DB_SNAPSHOT, NULL);
- result->tmpdir = strdup(tmpdir);
- result->hash = strdup(hash);
+ result->current_db = g_cdb_archive_get_tmp_filename(archive, "current_db.sql");
- ret = asprintf(&result->current_db, "%s" G_DIR_SEPARATOR_S "%s_current_db.sql", tmpdir, hash);
-
- status = (ret > 0);
-
- if (status)
- {
- ret = ensure_path_exists(result->current_db);
- status = (ret != -1);
- }
-
- if (!status)
+ if (result->current_db == NULL)
{
g_object_unref(G_OBJECT(result));
result = NULL;
@@ -810,8 +785,7 @@ static GDbSnapshot *g_db_snapshot_new(const char *tmpdir, const char *hash)
/******************************************************************************
* *
-* Paramètres : tmpdir = répertoire de travail temporaire. *
-* hash = empreinte du binaire à représenter. *
+* Paramètres : archive = archive associée à l'instantané. *
* collections = ensemble de modifications par catégories. *
* *
* Description : Prépare un gestionnaire d'instantanés de bases de données. *
@@ -822,7 +796,7 @@ static GDbSnapshot *g_db_snapshot_new(const char *tmpdir, const char *hash)
* *
******************************************************************************/
-GDbSnapshot *g_db_snapshot_new_empty(const char *tmpdir, const char *hash, GList *collections)
+GDbSnapshot *g_db_snapshot_new_empty(const GCdbArchive *archive, GList *collections)
{
GDbSnapshot *result; /* Adresse à retourner */
sqlite3 *db; /* Base de données à manipuler */
@@ -831,12 +805,12 @@ GDbSnapshot *g_db_snapshot_new_empty(const char *tmpdir, const char *hash, GList
GList *iter; /* Boucle de parcours */
GDbCollection *collec; /* Collection visée manipulée */
- result = g_db_snapshot_new(tmpdir, hash);
+ result = g_db_snapshot_new(archive);
if (result == NULL) goto exit;
result->nodes = create_snapshot_node(NULL, 0, NULL, NULL);
- status = setup_snapshot_node_db_path(result->nodes, tmpdir, hash);
+ status = setup_snapshot_node_db_path(result->nodes, archive);
if (!status) goto error;
result->current = result->nodes;
@@ -886,8 +860,7 @@ GDbSnapshot *g_db_snapshot_new_empty(const char *tmpdir, const char *hash, GList
/******************************************************************************
* *
-* Paramètres : tmpdir = répertoire de travail temporaire. *
-* hash = empreinte du binaire à représenter. *
+* Paramètres : archive = archive associée à l'instantané. *
* xdoc = document XML à compléter. *
* context = contexte pour les recherches. *
* *
@@ -899,7 +872,7 @@ GDbSnapshot *g_db_snapshot_new_empty(const char *tmpdir, const char *hash, GList
* *
******************************************************************************/
-GDbSnapshot *g_db_snapshot_new_from_xml(const char *tmpdir, const char *hash, xmlDocPtr xdoc, xmlXPathContextPtr context)
+GDbSnapshot *g_db_snapshot_new_from_xml(const GCdbArchive *archive, xmlDocPtr xdoc, xmlXPathContextPtr context)
{
GDbSnapshot *result; /* Adresse à retourner */
xmlXPathObjectPtr xobject; /* Cible d'une recherche */
@@ -916,7 +889,7 @@ GDbSnapshot *g_db_snapshot_new_from_xml(const char *tmpdir, const char *hash, xm
snapshot_node_t *node; /* Instantané nouveau constitué*/
snapshot_id_t node_id; /* Identifiant de noeud courant*/
- result = g_db_snapshot_new(tmpdir, hash);
+ result = g_db_snapshot_new(archive);
if (result == NULL) goto exit;
/* Chargement de l'ensemble des instantanés */
@@ -1042,7 +1015,8 @@ GDbSnapshot *g_db_snapshot_new_from_xml(const char *tmpdir, const char *hash, xm
/******************************************************************************
* *
* Paramètres : snap = gestionnaire d'instantanés à constituer. *
-* archive = archive en cours de lecture. *
+* ar = archive en cours de lecture. *
+* archive = archive associée à l'instantané. *
* *
* Description : Associe une base de données aux instantanés chargés. *
* *
@@ -1052,7 +1026,7 @@ GDbSnapshot *g_db_snapshot_new_from_xml(const char *tmpdir, const char *hash, xm
* *
******************************************************************************/
-bool g_db_snapshot_fill(GDbSnapshot *snap, struct archive *archive)
+bool g_db_snapshot_fill(GDbSnapshot *snap, struct archive *ar, const GCdbArchive *archive)
{
bool result; /* Bilan à retourner */
struct archive_entry *entry; /* Elément de l'archive */
@@ -1066,9 +1040,9 @@ bool g_db_snapshot_fill(GDbSnapshot *snap, struct archive *archive)
result = false;
- for (ret = archive_read_next_header(archive, &entry);
+ for (ret = archive_read_next_header(ar, &entry);
ret == ARCHIVE_OK;
- ret = archive_read_next_header(archive, &entry))
+ ret = archive_read_next_header(ar, &entry))
{
path = archive_entry_pathname(entry);
@@ -1077,7 +1051,7 @@ bool g_db_snapshot_fill(GDbSnapshot *snap, struct archive *archive)
if (strcmp(path, "current.db") == 0)
{
- if (!dump_archive_entry_into_file(archive, entry, snap->current_db))
+ if (!dump_archive_entry_into_file(ar, entry, snap->current_db))
break;
continue;
@@ -1098,10 +1072,10 @@ bool g_db_snapshot_fill(GDbSnapshot *snap, struct archive *archive)
if (node == NULL)
break;
- if (!setup_snapshot_node_db_path(node, snap->tmpdir, snap->hash))
+ if (!setup_snapshot_node_db_path(node, archive))
break;
- if (!dump_archive_entry_into_file(archive, entry, node->path))
+ if (!dump_archive_entry_into_file(ar, entry, node->path))
break;
}
@@ -1263,7 +1237,7 @@ sqlite3 *g_db_snapshot_get_database(const GDbSnapshot *snap)
* *
******************************************************************************/
-bool g_db_snapshot_pack_all(const GDbSnapshot *snap, packed_buffer *pbuf)
+bool g_db_snapshot_pack_all(const GDbSnapshot *snap, packed_buffer_t *pbuf)
{
bool result; /* Bilan à retourner */
@@ -1287,7 +1261,7 @@ bool g_db_snapshot_pack_all(const GDbSnapshot *snap, packed_buffer *pbuf)
* *
******************************************************************************/
-DBError g_db_snapshot_set_name(const GDbSnapshot *snap, packed_buffer *pbuf)
+DBError g_db_snapshot_set_name(const GDbSnapshot *snap, packed_buffer_t *pbuf)
{
DBError result; /* Conclusion à retourner */
snapshot_id_t id; /* Identifiant d'instantané */
@@ -1352,7 +1326,7 @@ DBError g_db_snapshot_set_name(const GDbSnapshot *snap, packed_buffer *pbuf)
* *
******************************************************************************/
-DBError g_db_snapshot_set_desc(const GDbSnapshot *snap, packed_buffer *pbuf)
+DBError g_db_snapshot_set_desc(const GDbSnapshot *snap, packed_buffer_t *pbuf)
{
DBError result; /* Conclusion à retourner */
snapshot_id_t id; /* Identifiant d'instantané */
@@ -1418,7 +1392,7 @@ DBError g_db_snapshot_set_desc(const GDbSnapshot *snap, packed_buffer *pbuf)
* *
******************************************************************************/
-DBError g_db_snapshot_restore(GDbSnapshot *snap, packed_buffer *pbuf, bool *reload)
+DBError g_db_snapshot_restore(GDbSnapshot *snap, packed_buffer_t *pbuf, bool *reload)
{
DBError result; /* Conclusion à retourner */
snapshot_id_t id; /* Identifiant d'instantané */
@@ -1482,8 +1456,9 @@ DBError g_db_snapshot_restore(GDbSnapshot *snap, packed_buffer *pbuf, bool *relo
/******************************************************************************
* *
-* Paramètres : snap = gestionnaire d'instantanés à consulter. *
-* db = base de données courante. *
+* Paramètres : snap = gestionnaire d'instantanés à consulter. *
+* db = base de données courante. *
+* archive = archive associée à l'instantané. *
* *
* Description : Crée un nouvel instantanés dans l'arborescence. *
* *
@@ -1493,7 +1468,7 @@ DBError g_db_snapshot_restore(GDbSnapshot *snap, packed_buffer *pbuf, bool *relo
* *
******************************************************************************/
-DBError g_db_snapshot_create(GDbSnapshot *snap, sqlite3 *db)
+DBError g_db_snapshot_create(GDbSnapshot *snap, sqlite3 *db, const GCdbArchive *archive)
{
DBError result; /* Conclusion à retourner */
snapshot_node_t *new; /* Nouvel instantané */
@@ -1503,7 +1478,7 @@ DBError g_db_snapshot_create(GDbSnapshot *snap, sqlite3 *db)
new = create_snapshot_node(NULL, 0, NULL, NULL);
- status = setup_snapshot_node_db_path(new, snap->tmpdir, snap->hash);
+ status = setup_snapshot_node_db_path(new, archive);
if (!status)
{
result = DBE_SYS_ERROR;
@@ -1544,7 +1519,7 @@ DBError g_db_snapshot_create(GDbSnapshot *snap, sqlite3 *db)
* *
******************************************************************************/
-DBError g_db_snapshot_remove(GDbSnapshot *snap, packed_buffer *pbuf, bool *changed)
+DBError g_db_snapshot_remove(GDbSnapshot *snap, packed_buffer_t *pbuf, bool *changed)
{
DBError result; /* Conclusion à retourner */
snapshot_id_t id; /* Identifiant d'instantané */
diff --git a/src/analysis/db/snapshot.h b/src/analysis/db/snapshot.h
index 8737f8c..59a2ba7 100644
--- a/src/analysis/db/snapshot.h
+++ b/src/analysis/db/snapshot.h
@@ -33,6 +33,7 @@
#include <libxml/xpath.h>
+#include "cdb.h"
#include "protocol.h"
#include "misc/snapshot.h"
@@ -57,13 +58,13 @@ typedef struct _GDbSnapshotClass GDbSnapshotClass;
GType g_db_snapshot_get_type(void);
/* Prépare un gestionnaire d'instantanés de bases de données. */
-GDbSnapshot *g_db_snapshot_new_empty(const char *, const char *, GList *);
+GDbSnapshot *g_db_snapshot_new_empty(const GCdbArchive *, GList *);
/* Charge un gestionnaire d'instantanés de bases de données. */
-GDbSnapshot *g_db_snapshot_new_from_xml(const char *, const char *, xmlDocPtr, xmlXPathContextPtr);
+GDbSnapshot *g_db_snapshot_new_from_xml(const GCdbArchive *, xmlDocPtr, xmlXPathContextPtr);
/* Associe une base de données aux instantanés chargés. */
-bool g_db_snapshot_fill(GDbSnapshot *, struct archive *);
+bool g_db_snapshot_fill(GDbSnapshot *, struct archive *, const GCdbArchive *);
/* Enregistre tous les éléments associés aux instantanés. */
DBError g_db_snapshot_save(const GDbSnapshot *, xmlDocPtr, xmlXPathContextPtr, struct archive *);
@@ -75,22 +76,22 @@ bool g_db_snapshot_get_current_id(const GDbSnapshot *, snapshot_id_t *);
sqlite3 *g_db_snapshot_get_database(const GDbSnapshot *);
/* Collecte les descriptions de l'ensemble des instantanés. */
-bool g_db_snapshot_pack_all(const GDbSnapshot *, packed_buffer *);
+bool g_db_snapshot_pack_all(const GDbSnapshot *, packed_buffer_t *);
/* Actualise la désignation d'un instantané donné. */
-DBError g_db_snapshot_set_name(const GDbSnapshot *, packed_buffer *);
+DBError g_db_snapshot_set_name(const GDbSnapshot *, packed_buffer_t *);
/* Actualise la description d'un instantané donné. */
-DBError g_db_snapshot_set_desc(const GDbSnapshot *, packed_buffer *);
+DBError g_db_snapshot_set_desc(const GDbSnapshot *, packed_buffer_t *);
/* Restaure un instantané de l'arborescence. */
-DBError g_db_snapshot_restore(GDbSnapshot *, packed_buffer *, bool *);
+DBError g_db_snapshot_restore(GDbSnapshot *, packed_buffer_t *, bool *);
/* Crée un nouvel instantanés dans l'arborescence. */
-DBError g_db_snapshot_create(GDbSnapshot *, sqlite3 *);
+DBError g_db_snapshot_create(GDbSnapshot *, sqlite3 *, const GCdbArchive *);
/* Supprime un instantané dans l'arborescence. */
-DBError g_db_snapshot_remove(GDbSnapshot *, packed_buffer *, bool *);
+DBError g_db_snapshot_remove(GDbSnapshot *, packed_buffer_t *, bool *);