diff options
Diffstat (limited to 'src/analysis/db/analyst.c')
-rw-r--r-- | src/analysis/db/analyst.c | 366 |
1 files changed, 324 insertions, 42 deletions
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; + +} |