summaryrefslogtreecommitdiff
path: root/src/analysis/db/controller.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/analysis/db/controller.c')
-rw-r--r--src/analysis/db/controller.c449
1 files changed, 449 insertions, 0 deletions
diff --git a/src/analysis/db/controller.c b/src/analysis/db/controller.c
new file mode 100644
index 0000000..46b628d
--- /dev/null
+++ b/src/analysis/db/controller.c
@@ -0,0 +1,449 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * controller.h - prototypes pour la gestion d'un ensemble d'archives au format CDB
+ *
+ * Copyright (C) 2021 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "controller.h"
+
+
+#include <assert.h>
+#include <errno.h>
+#include <malloc.h>
+#include <poll.h>
+#include <pthread.h>
+#include <string.h>
+
+
+#include <i18n.h>
+
+
+#include "backend-int.h"
+#include "../../common/packed.h"
+#include "../../core/logs.h"
+
+
+
+/* Description d'un contrôleur d'archives (instance) */
+struct _GCdbController
+{
+ GServerBackend parent; /* A laisser en premier */
+
+ char *basedir; /* Répertoire du serveur */
+
+ SSL *tls_fd; /* Canal de communication */
+ char *peer_name; /* Désignation du correspondant*/
+ char *user; /* Utilisateur connecté */
+
+};
+
+/* Description d'un contrôleur d'archives (classe) */
+struct _GCdbControllerClass
+{
+ GServerBackendClass parent; /* A laisser en premier */
+
+};
+
+
+/* Initialise la classe des contrôleurs d'archives. */
+static void g_cdb_controller_class_init(GCdbControllerClass *);
+
+/* Initialise un contrôleur d'archives. */
+static void g_cdb_controller_init(GCdbController *);
+
+/* Supprime toutes les références externes. */
+static void g_cdb_controller_dispose(GCdbController *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_cdb_controller_finalize(GCdbController *);
+
+/* Assure le traitement des requêtes de contrôle. */
+static void *g_cdb_controller_process(GCdbController *);
+
+/* Prend en compte une connexion nouvelle d'un utilisateur. */
+static void g_cdb_controller_add_client(GCdbController *, SSL *, const char *, const char *);
+
+
+
+/* Indique le type défini pour une gestion d'archives. */
+G_DEFINE_TYPE(GCdbController, g_cdb_controller, G_TYPE_SERVER_BACKEND);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des contrôleurs d'archives. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_cdb_controller_class_init(GCdbControllerClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GServerBackendClass *backend; /* Classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_cdb_controller_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_cdb_controller_finalize;
+
+ backend = G_SERVER_BACKEND_CLASS(klass);
+
+ backend->thread_name = "cdb_controller";
+ backend->thread_func = (GThreadFunc)g_cdb_controller_process;
+
+ backend->add_client = (add_backend_client_fc)g_cdb_controller_add_client;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : controller = instance à initialiser. *
+* *
+* Description : Initialise un contrôleur d'archives. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_cdb_controller_init(GCdbController *controller)
+{
+ controller->basedir = NULL;
+
+ controller->tls_fd = NULL;
+ controller->peer_name = NULL;
+ controller->user = NULL;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : controller = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_cdb_controller_dispose(GCdbController *controller)
+{
+ g_server_backend_stop(G_SERVER_BACKEND(controller));
+
+ G_OBJECT_CLASS(g_cdb_controller_parent_class)->dispose(G_OBJECT(controller));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : controller = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_cdb_controller_finalize(GCdbController *controller)
+{
+ if (controller->basedir != NULL)
+ free(controller->basedir);
+
+ if (controller->tls_fd != NULL)
+ SSL_free(controller->tls_fd);
+
+ if (controller->peer_name != NULL)
+ free(controller->peer_name);
+
+ if (controller->user != NULL)
+ free(controller->user);
+
+ G_OBJECT_CLASS(g_cdb_controller_parent_class)->finalize(G_OBJECT(controller));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : basedir = répertoire de stockage des enregistrements. *
+* error = indication éventuelle en cas d'échec. [OUT] *
+* *
+* Description : Définit ou ouvre une archive d'éléments utilisateur. *
+* *
+* Retour : Structure mise en plae ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GCdbController *g_cdb_controller_new(const char *basedir, DBError *error)
+{
+ GCdbController *result; /* Adresse à retourner */
+
+ result = g_object_new(G_TYPE_CDB_CONTROLLER, NULL);
+
+ result->basedir = strdup(basedir);
+
+ *error = DBE_NONE;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : controller = centralisation de tous les savoirs. *
+* *
+* Description : Assure le traitement des requêtes de contrôle. *
+* *
+* Retour : NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void *g_cdb_controller_process(GCdbController *controller)
+{
+ GServerBackend *base; /* Base de l'instance */
+ struct pollfd fds[3]; /* Surveillance des flux */
+ int ret; /* Bilan d'un appel */
+ packed_buffer in_pbuf; /* Tampon de réception */
+ uint32_t tmp32; /* Valeur sur 32 bits */
+ bool status; /* Bilan de lecture initiale */
+ uint32_t command; /* Commande de la requête */
+ DBError error; /* Bilan d'une opération */
+ packed_buffer out_pbuf; /* Tampon d'émission */
+ char *msg; /* Erreur à faire remonter */
+
+ base = G_SERVER_BACKEND(controller);
+
+ fds[0].fd = base->stop_ctrl[0];
+ fds[0].events = POLLIN | POLLPRI;
+
+ fds[1].fd = base->refresh_ctrl[0];
+ fds[1].events = POLLIN | POLLPRI;
+
+ fds[2].fd = SSL_get_fd(controller->tls_fd);
+ fds[2].events = POLLIN | POLLPRI;
+
+ while (1)
+ {
+ /* Lancement d'une phase de surveillance */
+
+ ret = poll(fds, 3, -1);
+ if (ret == -1)
+ {
+ if (errno == EINTR) continue;
+
+ LOG_ERROR_N("poll");
+ break;
+
+ }
+
+ /* Demande expresse d'arrêt des procédures */
+ if (fds[0].revents)
+ break;
+
+ /* Demande d'actualisation ?! */
+ assert(fds[1].revents == 0);
+
+ /* Le canal est fermé, une sortie doit être demandée... */
+ if (fds[2].revents & POLLNVAL)
+ goto closed_exchange;
+
+ /**
+ * Même chose, cf. "TCP: When is EPOLLHUP generated?"
+ * https://stackoverflow.com/questions/52976152/tcp-when-is-epollhup-generated/52976327#52976327
+ */
+
+ if (fds[2].revents & (POLLHUP | POLLRDHUP))
+ goto closed_exchange;
+
+ /* Données présentes en entrée */
+ if (fds[2].revents & (POLLIN | POLLPRI))
+ {
+ init_packed_buffer(&in_pbuf);
+
+ status = ssl_recv_packed_buffer(&in_pbuf, controller->tls_fd);
+ if (!status) goto bad_exchange;
+
+ next_command:
+
+ status = extract_packed_buffer(&in_pbuf, &command, sizeof(uint32_t), true);
+ if (!status) goto bad_exchange;
+
+ switch (command)
+ {
+ case DBC_LIST_ARCHIVES:
+
+ /*
+ error = g_cdb_controller_write(archive);
+
+ init_packed_buffer(&out_pbuf);
+
+ status = extend_packed_buffer(&out_pbuf, (uint32_t []) { DBC_SAVE },
+ sizeof(uint32_t), true);
+ if (!status) goto reply_error;
+
+ status = extend_packed_buffer(&out_pbuf, (uint32_t []) { error }, sizeof(uint32_t), true);
+ if (!status) goto reply_error;
+
+ status = ssl_send_packed_buffer(&out_pbuf, controller->tls_fd);
+ if (!status) goto reply_error;
+ */
+
+ exit_packed_buffer(&out_pbuf);
+
+ break;
+
+ default:
+ asprintf(&msg, _("Bad protocol command: 0x%08x"), command);
+ LOG_ERROR(LMT_ERROR, msg);
+ free(msg);
+ goto bad_exchange;
+ break;
+
+ }
+
+ if (has_more_data_in_packed_buffer(&in_pbuf))
+ goto next_command;
+
+ exit_packed_buffer(&in_pbuf);
+
+ continue;
+
+ reply_error:
+
+ exit_packed_buffer(&out_pbuf);
+
+ bad_exchange:
+
+ LOG_ERROR(LMT_ERROR, _("Bad exchange"));
+
+ assert(0);
+
+ exit_packed_buffer(&in_pbuf);
+
+ closed_exchange:
+
+ break;
+
+ }
+
+ }
+
+ /* On disparaît des écrans... */
+
+ g_server_backend_stop(G_SERVER_BACKEND(controller));
+
+ return NULL;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : controller = support pour le suivi d'une connexion. *
+* fd = canal de communication réseau ouvert. *
+* peer_name = désignation de la connexion. *
+* user = désignation de l'utilisateur de la connexion. *
+* *
+* Description : Prend en compte une connexion nouvelle d'un utilisateur. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_cdb_controller_add_client(GCdbController *controller, SSL *fd, const char *peer_name, const char *user)
+{
+ controller->tls_fd = fd;
+
+ controller->peer_name = strdup(peer_name);
+ controller->user = strdup(user);
+
+}
+
+
+
+
+
+#if 0
+/******************************************************************************
+* *
+* Paramètres : controller = archive à connecter avec un utilisateur. *
+* pbuf = paquet à consituer pour un envoi unique. [OUT] *
+* *
+* Description : Envoie à tous les clients la nouvelle liste d'instantanés. *
+* *
+* Retour : Bilan de constitution de la réponse. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_cdb_controller_send_snapshot_update(GCdbController *controller, packed_buffer *pbuf)
+{
+ bool result; /* Bilan à retourner */
+ bool do_send; /* Réalisation de l'émission */
+ packed_buffer out_pbuf; /* Tampon d'émission */
+
+ do_send = (pbuf == NULL);
+
+ if (pbuf == NULL)
+ pbuf = &out_pbuf;
+
+ init_packed_buffer(pbuf);
+
+ result = extend_packed_buffer(pbuf, (uint32_t []) { DBC_SNAPSHOTS_UPDATED },
+ sizeof(uint32_t), true);
+ if (!result) goto bad_reply;
+
+ result = g_db_snapshot_pack_all(archive->snapshot, pbuf);
+ if (!result) goto bad_reply;
+
+ result = extend_packed_buffer(pbuf, SNAPSHOT_END_MARK, SNAP_ID_HEX_SZ, false);
+ if (!result) goto bad_reply;
+
+ bad_reply:
+
+ if (do_send || !result)
+ exit_packed_buffer(pbuf);
+
+ return result;
+
+}
+
+#endif