summaryrefslogtreecommitdiff
path: root/src/analysis/db
diff options
context:
space:
mode:
Diffstat (limited to 'src/analysis/db')
-rw-r--r--src/analysis/db/Makefile.am8
-rw-r--r--src/analysis/db/analyst-int.h76
-rw-r--r--src/analysis/db/analyst.c366
-rw-r--r--src/analysis/db/analyst.h24
-rw-r--r--src/analysis/db/auth.c152
-rw-r--r--src/analysis/db/auth.h5
-rw-r--r--src/analysis/db/cdb.c625
-rw-r--r--src/analysis/db/cdb.h9
-rw-r--r--src/analysis/db/certs.c225
-rw-r--r--src/analysis/db/certs.h6
-rw-r--r--src/analysis/db/client-int.h8
-rw-r--r--src/analysis/db/client.c15
-rw-r--r--src/analysis/db/items/Makefile.am11
-rw-r--r--src/analysis/db/items/comment.c2
-rw-r--r--src/analysis/db/items/move.c12
-rw-r--r--src/analysis/db/misc/Makefile.am11
-rw-r--r--src/analysis/db/misc/rlestr.c15
-rw-r--r--src/analysis/db/protocol.h83
-rw-r--r--src/analysis/db/server.c40
-rw-r--r--src/analysis/db/snapshot.c99
-rw-r--r--src/analysis/db/snapshot.h9
21 files changed, 1529 insertions, 272 deletions
diff --git a/src/analysis/db/Makefile.am b/src/analysis/db/Makefile.am
index 8f8242c..b9325e0 100644
--- a/src/analysis/db/Makefile.am
+++ b/src/analysis/db/Makefile.am
@@ -21,20 +21,16 @@ libanalysisdb_la_SOURCES = \
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/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
index 87a60d3..43fb840 100644
--- a/src/analysis/db/analyst.c
+++ b/src/analysis/db/analyst.c
@@ -26,44 +26,16 @@
#include <assert.h>
#include <poll.h>
+#include <string.h>
-#include "client-int.h"
+#include "analyst-int.h"
+#include "../storage/storage.h"
#include "../../core/logs.h"
-/* Description de client à l'écoute (instance) */
-struct _GAnalystClient
-{
- GHubClient parent; /* A laisser en premier */
-
- rle_string hash; /* Empreinte du binaire lié */
- 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 (* snapshots_updated) (GAnalystClient *);
- void (* snapshot_changed) (GAnalystClient *);
-
-};
+/* ----------------------- DEFINITION D'ANALYSTE COMME CLIENT ----------------------- */
/* Initialise la classe des descriptions de fichier binaire. */
@@ -78,6 +50,9 @@ 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 *);
@@ -89,6 +64,58 @@ static bool g_analyst_client_update_current_snapshot(GAnalystClient *, packed_bu
+/* ------------------------- 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);
@@ -118,8 +145,25 @@ static void g_analyst_client_class_init(GAnalystClientClass *klass)
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,
@@ -153,7 +197,10 @@ static void g_analyst_client_class_init(GAnalystClientClass *klass)
static void g_analyst_client_init(GAnalystClient *client)
{
- setup_empty_rle_string(&client->hash);
+ client->cnt_hash = NULL;
+ client->cnt_class = NULL;
+
+ client->loaded = NULL;
client->collections = NULL;
client->can_get_updates = false;
@@ -189,6 +236,8 @@ static void g_analyst_client_dispose(GAnalystClient *client)
g_mutex_clear(&client->snap_lock);
+ g_clear_object(&client->loaded);
+
G_OBJECT_CLASS(g_analyst_client_parent_class)->dispose(G_OBJECT(client));
}
@@ -210,7 +259,11 @@ static void g_analyst_client_finalize(GAnalystClient *client)
{
size_t i; /* Boucle de parcours */
- unset_rle_string(&client->hash);
+ if (client->cnt_hash != NULL)
+ free(client->cnt_hash);
+
+ if (client->cnt_class != NULL)
+ free(client->cnt_class);
if (client->snapshots != NULL)
{
@@ -229,9 +282,11 @@ static void g_analyst_client_finalize(GAnalystClient *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 : Prépare un client pour une connexion à une BD. *
+* Description : Met en place un client pour une connexion à une BD. *
* *
* Retour : Structure mise en place ou NULL en cas d'échec. *
* *
@@ -239,14 +294,89 @@ static void g_analyst_client_finalize(GAnalystClient *client)
* *
******************************************************************************/
-GAnalystClient *g_analyst_client_new(const char *hash, GList *collections)
+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 */
- result = g_object_new(G_TYPE_HUB_CLIENT, NULL);
+ init_static_rle_string(&str, client->cnt_hash);
- init_static_rle_string(&result->hash, hash);
- result->collections = collections;
+ 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;
@@ -370,6 +500,11 @@ static void *g_analyst_client_update(GAnalystClient *client)
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);
@@ -378,11 +513,10 @@ static void *g_analyst_client_update(GAnalystClient *client)
error = tmp32;
if (error == DBE_NONE)
- log_variadic_message(LMT_INFO, _("Archive saved for binary '%s'"),
- get_rle_string(&client->hash));
+ 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'"),
- get_rle_string(&client->hash));
+ client->cnt_hash);
break;
@@ -607,6 +741,98 @@ static bool g_analyst_client_update_current_snapshot(GAnalystClient *client, pac
/******************************************************************************
* *
+* 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. *
@@ -1134,3 +1360,59 @@ bool g_analyst_client_remove_snapshot(GAnalystClient *client, const snapshot_id_
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
index d9e90c6..ff189ba 100644
--- a/src/analysis/db/analyst.h
+++ b/src/analysis/db/analyst.h
@@ -33,9 +33,26 @@
#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))
@@ -54,8 +71,11 @@ typedef struct _GAnalystClientClass GAnalystClientClass;
/* Indique le type défini pour une description de client à l'écoute. */
GType g_analyst_client_get_type(void);
-/* Prépare un client pour une connexion à une BD. */
-GAnalystClient *g_analyst_client_new(const char *, GList *);
+/* 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 *);
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/cdb.c b/src/analysis/db/cdb.c
index d2997c7..6d4b84d 100644
--- a/src/analysis/db/cdb.c
+++ b/src/analysis/db/cdb.c
@@ -26,6 +26,7 @@
#include <assert.h>
#include <errno.h>
+#include <fcntl.h>
#include <malloc.h>
#include <poll.h>
#include <pthread.h>
@@ -37,17 +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,7 +59,7 @@
-/* ------------------------- COEUR DE LA GESTION D'ARCHIVES ------------------------- */
+/* -------------------------- LIEN VERS UN CLIENT CONNECTE -------------------------- */
/* Informations relatives à un client */
@@ -65,28 +69,51 @@ typedef struct _cdb_client
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 */
@@ -95,7 +122,7 @@ struct _GCdbArchive
/* Description d'une archive d'éléments utilisateur (classe) */
struct _GCdbArchiveClass
{
- GObjectClass parent; /* A laisser en premier */
+ GServerBackendClass parent; /* A laisser en premier */
};
@@ -163,6 +190,118 @@ static bool g_cdb_archive_send_snapshot_change(GCdbArchive *, packed_buffer_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);
+
+}
+
+
+
/* ---------------------------------------------------------------------------------- */
/* COEUR DE LA GESTION D'ARCHIVES */
/* ---------------------------------------------------------------------------------- */
@@ -219,13 +358,19 @@ 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);
@@ -248,9 +393,11 @@ static void g_cdb_archive_dispose(GCdbArchive *archive)
{
g_server_backend_stop(G_SERVER_BACKEND(archive));
+ g_mutex_clear(&archive->clients_access);
+
g_clear_object(&archive->snapshot);
- g_mutex_clear(&archive->clients_access);
+ g_mutex_clear(&archive->loading_access);
G_OBJECT_CLASS(g_cdb_archive_parent_class)->dispose(G_OBJECT(archive));
@@ -285,15 +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);
- if (archive->filename != NULL)
- 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));
@@ -306,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. *
@@ -317,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 */
@@ -326,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))
@@ -345,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 */
@@ -360,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;
@@ -431,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. *
* *
@@ -480,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);
@@ -508,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;
@@ -621,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;
}
@@ -809,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].tls_fd);
+ status = ssl_send_packed_buffer(&pbuf, archive->clients[i]->tls_fd);
if (!status)
LOG_ERROR(LMT_ERROR, _("Failed to send some DB update"));
@@ -838,6 +1038,8 @@ 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 */
@@ -854,20 +1056,38 @@ static void *g_cdb_archive_process(GCdbArchive *archive)
base = G_SERVER_BACKEND(archive);
+ 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 + 2;
+ 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 - 2); i++)
{
- fds[i].fd = SSL_get_fd(archive->clients[i].tls_fd);
+ fds[i].fd = SSL_get_fd(clients[i]->tls_fd);
fds[i].events = POLLIN | POLLPRI;
}
@@ -920,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].tls_fd);
+ status = ssl_recv_packed_buffer(&in_pbuf, clients[i]->tls_fd);
if (!status) goto gcap_bad_exchange;
next_command:
@@ -930,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);
@@ -945,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].tls_fd);
+ status = ssl_send_packed_buffer(&out_pbuf, clients[i]->tls_fd);
if (!status) goto gcap_bad_reply;
exit_packed_buffer(&out_pbuf);
@@ -986,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].tls_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;
@@ -1008,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].tls_fd);
+ status = ssl_send_packed_buffer(&out_pbuf, clients[i]->tls_fd);
if (!status) goto gcap_bad_reply;
exit_packed_buffer(&out_pbuf);
@@ -1020,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].tls_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;
@@ -1032,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].tls_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;
@@ -1110,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)
{
@@ -1154,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;
@@ -1197,6 +1438,12 @@ static void *g_cdb_archive_process(GCdbArchive *archive)
g_server_backend_stop(G_SERVER_BACKEND(archive));
+ for (i = 0; i < last_count; i++)
+ unref_cdb_client(clients[i]);
+
+ if (clients != NULL)
+ free(clients);
+
if (fds != NULL)
free(fds);
@@ -1220,40 +1467,100 @@ static void *g_cdb_archive_process(GCdbArchive *archive)
* *
******************************************************************************/
+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);
/**
- * 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.
+ * Le verrou encadrant les évolutions des contenus initiaux doit englober
+ * l'extension de la liste des clients.
*
- * - soit on intègre le client et celui ci demande des mises à jour
- * collection par collection ; c'est également à lui que revient le rejet
- * des éléments envoyés en solitaires avant la réception de la base
- * complète.
+ * 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).
*
- * 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.
+ * 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);
- archive->clients = realloc(archive->clients, ++archive->count * sizeof(cdb_client));
+ hint = g_cdb_archive_compute_loading_hint(archive);
+
+ if (hint != LSH_READY)
+ hint = (archive->count == 0 ? hint : LSH_ON_WAIT_LIST);
- client = &archive->clients[archive->count - 1];
+ init_packed_buffer(&out_pbuf);
- client->tls_fd = fd;
- client->peer_name = strdup(peer_name);
- client->user = strdup(user);
+ 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);
+
}
@@ -1272,20 +1579,15 @@ static void g_cdb_archive_add_client(GCdbArchive *archive, SSL *fd, const char *
static void _g_cdb_archive_remove_client(GCdbArchive *archive, size_t index)
{
- cdb_client *client; /* Client à traiter */
-
assert(!g_mutex_trylock(&archive->clients_access));
- client = &archive->clients[index];
-
- SSL_free(client->tls_fd);
- free(client->user);
+ 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->count - index - 1) * sizeof(cdb_client *));
- archive->clients = realloc(archive->clients, --archive->count * sizeof(cdb_client));
+ archive->clients = realloc(archive->clients, --archive->count * sizeof(cdb_client *));
}
@@ -1336,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].tls_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);
@@ -1451,3 +1753,188 @@ static bool g_cdb_archive_send_snapshot_change(GCdbArchive *archive, packed_buff
return result;
}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* PRISES EN COMPTE DES COMMANDES */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : cmd = commande à l'origine d'un traitement. *
+* value = valeur à communiquer. *
+* out_pbuf = paquet à consituer pour un retour au client. [OUT]*
+* *
+* Description : Prépare une courte réponse à envoyer à un client connecté. *
+* *
+* Retour : Indication pour le maintien de la communication. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool craft_server_short_answer(DBCommand cmd, uleb128_t value, packed_buffer_t *out_pbuf)
+{
+ bool result; /* Bilan à retourner */
+
+ init_packed_buffer(out_pbuf);
+
+ result = extend_packed_buffer(out_pbuf, (uint32_t []) { cmd }, sizeof(uint32_t), true);
+
+ if (result)
+ result = pack_uleb128((uleb128_t []){ value }, out_pbuf);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* 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 : - *
+* *
+******************************************************************************/
+
+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 */
+
+ result = true;
+ error = DBE_NONE;
+
+ /* 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);
+
+ result = extend_packed_buffer(&test_pbuf, data, data_length, false);
+ if (!result) goto check_failure;
+
+ rewind_packed_buffer(&test_pbuf);
+
+ 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;
+ }
+
+ 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;
+
+ g_object_unref(G_OBJECT(content));
+
+ storage_check_failure:
+
+ g_object_unref(G_OBJECT(storage));
+
+ check_failure:
+
+ exit_packed_buffer(&test_pbuf);
+
+ if (!result) goto free_and_exit;
+
+ /* 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;
+ }
+
+ fd = open(archive->cnt_file, O_WRONLY | O_CREAT, 0600);
+ if (fd == -1)
+ {
+ error = DBE_SYS_ERROR;
+ goto save_error;
+ }
+
+ status = safe_write(fd, data, data_length);
+
+ if (!status)
+ {
+ unlink(archive->cnt_file);
+ free(archive->cnt_file);
+ archive->cnt_file = NULL;
+
+ 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 2dd8118..7a557f2 100644
--- a/src/analysis/db/cdb.h
+++ b/src/analysis/db/cdb.h
@@ -54,13 +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 *);
+/* 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 11d12fd..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é. *
@@ -624,6 +692,64 @@ bool build_keys_and_request(const char *dir, const char *label, const x509_entri
/******************************************************************************
* *
+* 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é */
+
+ result = 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;
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : csr = fichier contenant le certificat à signer. *
* entries = éléments de l'identité constituée. [OUT] *
* *
@@ -641,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;
@@ -666,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;
@@ -734,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);
@@ -742,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;
}
@@ -755,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);
@@ -763,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);
@@ -776,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
index 83c5039..3c140e9 100644
--- a/src/analysis/db/client-int.h
+++ b/src/analysis/db/client-int.h
@@ -28,6 +28,13 @@
#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
@@ -54,6 +61,7 @@ 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 */
};
diff --git a/src/analysis/db/client.c b/src/analysis/db/client.c
index aa1407c..6ce33b0 100644
--- a/src/analysis/db/client.c
+++ b/src/analysis/db/client.c
@@ -99,6 +99,10 @@ static void g_hub_client_class_init(GHubClientClass *klass)
object->dispose = (GObjectFinalizeFunc/* ! */)g_hub_client_dispose;
object->finalize = (GObjectFinalizeFunc)g_hub_client_finalize;
+ klass->role = CRL_UNDEFINED;
+ klass->complete_hello = NULL;
+ klass->recv_func = NULL;
+
}
@@ -485,7 +489,8 @@ static bool g_hub_client_start_common(GHubClient *client, char *desc)
* On réalise l'envoi initial ; le premier paquet doit contenir :
* - la commande 'DBC_HELO' ;
* - le numéro de version du client ;
- * - le rôle attendu de la connexion.
+ * - le rôle attendu de la connexion ;
+ * - des données complémentaires éventuelles.
*
* Tout ceci est à synchroniser avec la fonction g_db_server_listener().
*/
@@ -501,9 +506,11 @@ static bool g_hub_client_start_common(GHubClient *client, char *desc)
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;
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/comment.c b/src/analysis/db/items/comment.c
index da7a4c0..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"
diff --git a/src/analysis/db/items/move.c b/src/analysis/db/items/move.c
index af1c8c1..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
@@ -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/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 bb81b55..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"
+
+
/******************************************************************************
* *
@@ -276,16 +279,16 @@ int cmp_rle_string(const rle_string *s1, const rle_string *s2)
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;
@@ -321,7 +324,7 @@ 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/protocol.h b/src/analysis/db/protocol.h
index 4bef28e..7707058 100644
--- a/src/analysis/db/protocol.h
+++ b/src/analysis/db/protocol.h
@@ -47,15 +47,6 @@
-/* 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;
@@ -71,17 +62,43 @@ typedef enum _ClientRole
} 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 ]
@@ -125,6 +142,8 @@ typedef enum _DBAction
*/
typedef enum _DBCommand
{
+ /* ------------------------- Commandes à portée générale ------------------------- */
+
/**
* Le client envoie un tout premier paquet de la forme suivante :
*
@@ -166,6 +185,49 @@ typedef enum _DBCommand
/* ------------------------ 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'.
*
* Le client connecté envoie un paquet de la forme suivante :
@@ -377,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 f324c74..79d5df1 100644
--- a/src/analysis/db/server.c
+++ b/src/analysis/db/server.c
@@ -925,8 +925,8 @@ static void *g_hub_server_listener(GHubServer *server)
break;
default:
- log_variadic_message(LMT_ERROR, _("Unknown client role requested by '%s'"),
- peer_name);
+ log_variadic_message(LMT_ERROR, _("Unknown client role 0x%x requested by '%s'"),
+ role, peer_name);
backend = NULL;
error = DBE_BAD_EXCHANGE;
new = false;
@@ -1028,7 +1028,7 @@ static GServerBackend *g_hub_server_handle_admin(GHubServer *server, packed_buff
if (has_more_data_in_packed_buffer(in_pbuf))
{
- log_variadic_message(LMT_ERROR, _("The client from '%s' provided to much data!"), peer_name);
+ log_variadic_message(LMT_ERROR, _("The client from '%s' provided too much data!"), peer_name);
result = NULL;
@@ -1074,6 +1074,7 @@ static GServerBackend *g_hub_server_handle_analyst(GHubServer *server, packed_bu
{
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*/
@@ -1087,6 +1088,8 @@ static GServerBackend *g_hub_server_handle_analyst(GHubServer *server, packed_bu
/* Fin de réception des données envoyées */
+ setup_empty_rle_string(&hash);
+
status = unpack_rle_string(&hash, in_pbuf);
if (!status)
{
@@ -1097,13 +1100,28 @@ static GServerBackend *g_hub_server_handle_analyst(GHubServer *server, packed_bu
if (is_rle_string_empty(&hash))
{
log_variadic_message(LMT_ERROR, _("The submitted binary hash from '%s' is empty!"), peer_name);
- goto wrong_receiving;
+ 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 to much data!"), peer_name);
- goto wrong_receiving;
+ 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é */
@@ -1114,7 +1132,7 @@ static GServerBackend *g_hub_server_handle_analyst(GHubServer *server, packed_bu
{
archive = G_CDB_ARCHIVE(iter->data);
- if (g_cdb_archive_compare_hash(archive, &hash) == 0)
+ if (g_cdb_archive_compare_is_suitable_for(archive, &hash, &class))
break;
}
@@ -1137,7 +1155,7 @@ static GServerBackend *g_hub_server_handle_analyst(GHubServer *server, packed_bu
tmpdir = strdup(server->working);
tmpdir = stradd(tmpdir, "tmp" G_DIR_SEPARATOR_S);
- result = g_cdb_archive_new(basedir, tmpdir, &hash, error);
+ result = g_cdb_archive_new(basedir, tmpdir, &hash, &class, error);
free(tmpdir);
free(basedir);
@@ -1146,7 +1164,11 @@ static GServerBackend *g_hub_server_handle_analyst(GHubServer *server, packed_bu
}
- wrong_receiving:
+ wrong_receiving_1:
+
+ exit_rle_string(&class);
+
+ wrong_receiving_0:
exit_rle_string(&hash);
diff --git a/src/analysis/db/snapshot.c b/src/analysis/db/snapshot.c
index 1a92a34..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 *);
@@ -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;
@@ -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;
}
@@ -1482,8 +1456,9 @@ DBError g_db_snapshot_restore(GDbSnapshot *snap, packed_buffer_t *pbuf, bool *re
/******************************************************************************
* *
-* 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_t *pbuf, bool *re
* *
******************************************************************************/
-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;
diff --git a/src/analysis/db/snapshot.h b/src/analysis/db/snapshot.h
index 7f8a82a..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 *);
@@ -87,7 +88,7 @@ DBError g_db_snapshot_set_desc(const GDbSnapshot *, packed_buffer_t *);
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_t *, bool *);