summaryrefslogtreecommitdiff
path: root/src/analysis
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2021-08-01 16:46:12 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2021-08-01 16:46:12 (GMT)
commit2ea2e6080eec1b06bbd4607203d34f38b75c80f3 (patch)
tree75cd34437eef2a055616a4554211c96c4e7f9d41 /src/analysis
parent76227d352c21332d1f19e812e157307bdc6c9cf5 (diff)
Extend the protocol to store the analyzed binary content.
Diffstat (limited to 'src/analysis')
-rw-r--r--src/analysis/db/analyst.c115
-rw-r--r--src/analysis/db/analyst.h4
-rw-r--r--src/analysis/db/auth.c152
-rw-r--r--src/analysis/db/auth.h5
-rw-r--r--src/analysis/db/cdb.c218
-rw-r--r--src/analysis/db/protocol.h64
6 files changed, 534 insertions, 24 deletions
diff --git a/src/analysis/db/analyst.c b/src/analysis/db/analyst.c
index dff073a..49585c2 100644
--- a/src/analysis/db/analyst.c
+++ b/src/analysis/db/analyst.c
@@ -26,9 +26,11 @@
#include <assert.h>
#include <poll.h>
+#include <string.h>
#include "client-int.h"
+#include "../storage/storage.h"
#include "../../core/logs.h"
@@ -38,7 +40,7 @@ struct _GAnalystClient
{
GHubClient parent; /* A laisser en premier */
- rle_string hash; /* Empreinte du binaire lié */
+ char *hash; /* Empreinte du binaire lié */
GList *collections; /* Collections d'un binaire */
bool can_get_updates; /* Réception de maj possibles ?*/
@@ -157,7 +159,7 @@ static void g_analyst_client_class_init(GAnalystClientClass *klass)
static void g_analyst_client_init(GAnalystClient *client)
{
- setup_empty_rle_string(&client->hash);
+ client->hash = NULL;
client->collections = NULL;
client->can_get_updates = false;
@@ -214,7 +216,8 @@ static void g_analyst_client_finalize(GAnalystClient *client)
{
size_t i; /* Boucle de parcours */
- unset_rle_string(&client->hash);
+ if (client->hash != NULL)
+ free(client->hash);
if (client->snapshots != NULL)
{
@@ -249,7 +252,7 @@ GAnalystClient *g_analyst_client_new(const char *hash, GList *collections)
result = g_object_new(G_TYPE_ANALYST_CLIENT, NULL);
- init_static_rle_string(&result->hash, hash);
+ result->hash = strdup(hash);
result->collections = collections;
return result;
@@ -273,8 +276,13 @@ GAnalystClient *g_analyst_client_new(const char *hash, GList *collections)
static bool g_analyst_client_complete_hello(GAnalystClient *client, packed_buffer_t *pbuf)
{
bool result; /* Bilan à retourner */
+ rle_string str; /* Chaîne à communiquer */
- result = pack_rle_string(&client->hash, pbuf);
+ init_static_rle_string(&str, client->hash);
+
+ result = pack_rle_string(&str, pbuf);
+
+ exit_rle_string(&str);
return result;
@@ -406,11 +414,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->hash);
else
log_variadic_message(LMT_ERROR, _("Failed to save the archive for binary '%s'"),
- get_rle_string(&client->hash));
+ client->hash);
break;
@@ -635,6 +642,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->hash) != 0)
+ {
+ log_variadic_message(LMT_ERROR, _("Provided ontent does not match client content (hash: '%s')"),
+ client->hash);
+ goto exit;
+ }
+
+ /* Conversion en format de stockage */
+
+ init_packed_buffer(&cnt_pbuf);
+
+ storage = g_object_storage_new(client->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. *
diff --git a/src/analysis/db/analyst.h b/src/analysis/db/analyst.h
index d9e90c6..7b11f53 100644
--- a/src/analysis/db/analyst.h
+++ b/src/analysis/db/analyst.h
@@ -33,6 +33,7 @@
#include "client.h"
#include "collection.h"
#include "misc/snapshot.h"
+#include "../content.h"
@@ -57,6 +58,9 @@ GType g_analyst_client_get_type(void);
/* Prépare un client pour une connexion à une BD. */
GAnalystClient *g_analyst_client_new(const char *, GList *);
+/* 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 4da55fd..e4179d3 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>
@@ -45,9 +46,12 @@
#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"
@@ -79,6 +83,7 @@ struct _GCdbArchive
char *filename; /* Chemin d'accès à l'archive */
char *tmpdir; /* Répertoire de travail */
+ char *cnt_file; /* Fichier de contenu binaire */
char *xml_desc; /* Fichier de description */
GList *collections; /* Ensemble de modifications */
@@ -163,6 +168,17 @@ static bool g_cdb_archive_send_snapshot_change(GCdbArchive *, packed_buffer_t *)
+/* ------------------------- PRISES EN COMPTE DES COMMANDES ------------------------- */
+
+
+/* Prépare la réponse à envoyer à un client connecté. */
+static bool setup_server_answer(DBCommand, DBError, packed_buffer_t *);
+
+/* Enregistre le contenu binaire lié à une analyse. */
+static bool g_cdb_archive_set_content(GCdbArchive *, packed_buffer_t *, packed_buffer_t *);
+
+
+
/* ---------------------------------------------------------------------------------- */
/* COEUR DE LA GESTION D'ARCHIVES */
/* ---------------------------------------------------------------------------------- */
@@ -222,6 +238,8 @@ static void g_cdb_archive_init(GCdbArchive *archive)
archive->filename = NULL;
archive->tmpdir = NULL;
+ archive->cnt_file = NULL;
+ archive->xml_desc = NULL;
archive->collections = create_collections_list();
@@ -285,15 +303,18 @@ 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->hash);
G_OBJECT_CLASS(g_cdb_archive_parent_class)->finalize(G_OBJECT(archive));
@@ -932,6 +953,19 @@ static void *g_cdb_archive_process(GCdbArchive *archive)
switch (command)
{
+ case DBC_SET_CONTENT:
+
+ status = g_cdb_archive_set_content(archive, &in_pbuf, &out_pbuf);
+ if (!status) goto gcap_bad_reply;
+
+ status = ssl_send_packed_buffer(&out_pbuf, archive->clients[i].tls_fd);
+ if (!status) goto gcap_bad_reply;
+
+ exit_packed_buffer(&out_pbuf);
+ break;
+
+
+
case DBC_SAVE:
error = g_cdb_archive_write(archive);
@@ -1451,3 +1485,181 @@ 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. *
+* error = bilan de traitement à communiquer. *
+* out_pbuf = paquet à consituer pour un retour au client. [OUT]*
+* *
+* Description : Prépare la réponse à envoyer à un client connecté. *
+* *
+* Retour : Indication pour le maintien de la communication. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool setup_server_answer(DBCommand cmd, DBError error, 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 = extend_packed_buffer(out_pbuf, (uint32_t []) { error }, sizeof(uint32_t), true);
+
+ 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 ret; /* Retour d'un appel */
+ int fd; /* Flux ouvert en écriture */
+ bool status; /* Bilan d'une écriture */
+
+ 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);
+
+ ret = asprintf(&archive->cnt_file, "%s" G_DIR_SEPARATOR_S "%s_storedcontent.bin",
+ archive->tmpdir, get_rle_string(&archive->hash));
+ if (ret == -1)
+ {
+ 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 = setup_server_answer(DBC_SET_CONTENT, error, out_pbuf);
+
+ free_and_exit:
+
+ free(data);
+
+ exit:
+
+ return result;
+
+}
diff --git a/src/analysis/db/protocol.h b/src/analysis/db/protocol.h
index 4bef28e..17263c8 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,36 @@ 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 :
+
+/* Eléments de base nécessaires */
+typedef enum _RequiredBasics
+{
+ RBS_NONE = 0x0, /* (Plus) rien n'est requis */
+ RBS_CONTENT = 0x1, /* Contenu binaire à analyser */
+ RBS_LOADED = 0x2, /* Contenu binaire analysé */
+
+} RequiredBasics;
+
+/**
+ * Une fois la connexion établie, les paquets ont tous la forme suivante :
*
* [ type de collection visée ; cf. DBFeatures ]
* [ action à mener ; cf. DBAction ]
@@ -166,6 +176,37 @@ typedef enum _DBCommand
/* ------------------------ Commandes pour analyste ------------------------ */
/**
+ * 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 +418,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 */