diff options
Diffstat (limited to 'src/analysis/db/cdb.c')
-rw-r--r-- | src/analysis/db/cdb.c | 349 |
1 files changed, 166 insertions, 183 deletions
diff --git a/src/analysis/db/cdb.c b/src/analysis/db/cdb.c index 9e24f84..8d589b3 100644 --- a/src/analysis/db/cdb.c +++ b/src/analysis/db/cdb.c @@ -1,6 +1,6 @@ /* Chrysalide - Outil d'analyse de fichiers binaires - * cdb.h - prototypes pour la manipulation des archives au format CDB + * cdb.c - manipulation des archives au format CDB * * Copyright (C) 2014-2019 Cyrille Bagard * @@ -29,7 +29,6 @@ #include <malloc.h> #include <poll.h> #include <pthread.h> -#include <signal.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> @@ -42,6 +41,7 @@ #include <config.h> +#include "backend-int.h" #include "collection.h" #include "protocol.h" #include "snapshot.h" @@ -61,7 +61,8 @@ /* Informations relatives à un client */ typedef struct _cdb_client { - SSL *ssl_fd; /* Canal de communication */ + SSL *tls_fd; /* Canal de communication */ + char *peer_name; /* Désignation du correspondant*/ char *user; /* Utilisateur à l'autre bout */ uint64_t last_time; /* Date de dernier envoi */ @@ -89,11 +90,6 @@ struct _GCdbArchive size_t count; /* Quantité de clients */ GMutex clients_access; /* Verrou pour l'accès */ - GThread *process; /* Procédure de traitement */ - GMutex id_access; /* Accès à l'identifiant */ - GCond id_cond; /* Condition d'attente */ - pthread_t process_id; /* Identifiant de la procédure */ - }; /* Description d'une archive d'éléments utilisateur (classe) */ @@ -147,6 +143,15 @@ static void on_collection_extended(GDbCollection *, GDbItem *, GCdbArchive *); /* Assure le traitement des requêtes de clients. */ static void *g_cdb_archive_process(GCdbArchive *); +/* Prend en compte une connexion nouvelle d'un utilisateur. */ +static void g_cdb_archive_add_client(GCdbArchive *, SSL *, const char *, const char *); + +/* Dissocie un utilisateur de l'archive. */ +static void _g_cdb_archive_remove_client(GCdbArchive *, size_t); + +/* Dissocie un utilisateur de l'archive. */ +static void g_cdb_archive_remove_client(GCdbArchive *, size_t); + /* Envoie un paquet de données constitué à tous les clients. */ static void g_cdb_archive_send_reply_to_all_clients(GCdbArchive *, packed_buffer *); @@ -156,12 +161,6 @@ static bool g_cdb_archive_send_snapshot_update(GCdbArchive *, packed_buffer *); /* Envoie à tous les clients le nouvel instantané courant. */ static bool g_cdb_archive_send_snapshot_change(GCdbArchive *, packed_buffer *); -/* Dissocie un utilisateur de l'archive. */ -static void _g_cdb_archive_remove_client(GCdbArchive *, size_t); - -/* Dissocie un utilisateur de l'archive. */ -static void g_cdb_archive_remove_client(GCdbArchive *, size_t); - /* ---------------------------------------------------------------------------------- */ @@ -170,7 +169,7 @@ static void g_cdb_archive_remove_client(GCdbArchive *, size_t); /* Indique le type défini pour une une archive d'éléments utilisateur. */ -G_DEFINE_TYPE(GCdbArchive, g_cdb_archive, G_TYPE_OBJECT); +G_DEFINE_TYPE(GCdbArchive, g_cdb_archive, G_TYPE_SERVER_BACKEND); /****************************************************************************** @@ -188,12 +187,20 @@ G_DEFINE_TYPE(GCdbArchive, g_cdb_archive, G_TYPE_OBJECT); static void g_cdb_archive_class_init(GCdbArchiveClass *klass) { GObjectClass *object; /* Autre version de la classe */ + GServerBackendClass *backend; /* Classe parente */ object = G_OBJECT_CLASS(klass); object->dispose = (GObjectFinalizeFunc/* ! */)g_cdb_archive_dispose; object->finalize = (GObjectFinalizeFunc)g_cdb_archive_finalize; + backend = G_SERVER_BACKEND_CLASS(klass); + + backend->thread_name = "cdb_archiver"; + backend->thread_func = (GThreadFunc)g_cdb_archive_process; + + backend->add_client = (add_backend_client_fc)g_cdb_archive_add_client; + } @@ -213,6 +220,7 @@ static void g_cdb_archive_init(GCdbArchive *archive) { setup_empty_rle_string(&archive->hash); + archive->filename = NULL; archive->tmpdir = NULL; archive->collections = create_collections_list(); @@ -221,9 +229,6 @@ static void g_cdb_archive_init(GCdbArchive *archive) g_mutex_init(&archive->clients_access); - g_mutex_init(&archive->id_access); - g_cond_init(&archive->id_cond); - } @@ -241,10 +246,9 @@ static void g_cdb_archive_init(GCdbArchive *archive) static void g_cdb_archive_dispose(GCdbArchive *archive) { - g_clear_object(&archive->snapshot); + g_server_backend_stop(G_SERVER_BACKEND(archive)); - g_cond_clear(&archive->id_cond); - g_mutex_clear(&archive->id_access); + g_clear_object(&archive->snapshot); g_mutex_clear(&archive->clients_access); @@ -284,7 +288,8 @@ static void g_cdb_archive_finalize(GCdbArchive *archive) if (archive->xml_desc != NULL) free(archive->xml_desc); - free(archive->filename); + if (archive->filename != NULL) + free(archive->filename); if (archive->tmpdir != NULL) free(archive->tmpdir); @@ -804,7 +809,7 @@ static void on_collection_extended(GDbCollection *collec, GDbItem *item, GCdbArc for (i = 0; i < archive->count && status; i++) { - status = ssl_send_packed_buffer(&pbuf, archive->clients[i].ssl_fd); + status = ssl_send_packed_buffer(&pbuf, archive->clients[i].tls_fd); if (!status) LOG_ERROR(LMT_ERROR, _("Failed to send some DB update")); @@ -832,6 +837,7 @@ static void on_collection_extended(GDbCollection *collec, GDbItem *item, GCdbArc static void *g_cdb_archive_process(GCdbArchive *archive) { + GServerBackend *base; /* Base de l'instance */ struct pollfd *fds; /* Surveillance des flux */ nfds_t nfds; /* Quantité de ces flux */ nfds_t i; /* Boucle de parcours */ @@ -846,14 +852,7 @@ static void *g_cdb_archive_process(GCdbArchive *archive) bool reload; /* Besoin de rechargement */ char *msg; /* Erreur à faire remonter */ - void interrupt_poll_with_sigusr1(int sig) { }; - - signal(SIGUSR1, interrupt_poll_with_sigusr1); - - g_mutex_lock(&archive->id_access); - archive->process_id = pthread_self(); - g_cond_signal(&archive->id_cond); - g_mutex_unlock(&archive->id_access); + base = G_SERVER_BACKEND(archive); fds = NULL; @@ -863,35 +862,46 @@ static void *g_cdb_archive_process(GCdbArchive *archive) g_mutex_lock(&archive->clients_access); - nfds = archive->count; + nfds = archive->count + 2; fds = realloc(fds, nfds * sizeof(struct pollfd)); - for (i = 0; i < nfds; i++) + for (i = 0; i < (nfds - 2); i++) { - fds[i].fd = SSL_get_fd(archive->clients[i].ssl_fd); + fds[i].fd = SSL_get_fd(archive->clients[i].tls_fd); fds[i].events = POLLIN | POLLPRI; } g_mutex_unlock(&archive->clients_access); - if (nfds == 0) + if (nfds == 2) goto gcap_no_more_clients; + fds[nfds - 2].fd = base->stop_ctrl[0]; + fds[nfds - 2].events = POLLIN | POLLPRI; + + fds[nfds - 1].fd = base->refresh_ctrl[0]; + fds[nfds - 1].events = POLLIN | POLLPRI; + /* Lancement d'une phase de surveillance */ ret = poll(fds, nfds, -1); if (ret == -1) { - if (errno == EINTR) continue; - LOG_ERROR_N("poll"); break; - } + /* Demande expresse d'arrêt des procédures */ + if (fds[nfds - 2].revents) + break; + + /* Demande d'actualisation */ + if (fds[nfds - 1].revents) + continue; + /* Traitement des requêtes reçues */ - for (i = 0; i < nfds; i++) + for (i = 0; i < (nfds - 1); i++) { /* Le canal est fermé, une sortie doit être demandée... */ if (fds[i].revents & POLLNVAL) @@ -910,7 +920,7 @@ static void *g_cdb_archive_process(GCdbArchive *archive) { init_packed_buffer(&in_pbuf); - status = ssl_recv_packed_buffer(&in_pbuf, archive->clients[i].ssl_fd); + status = ssl_recv_packed_buffer(&in_pbuf, archive->clients[i].tls_fd); if (!status) goto gcap_bad_exchange; next_command: @@ -935,7 +945,7 @@ static void *g_cdb_archive_process(GCdbArchive *archive) status = extend_packed_buffer(&out_pbuf, (uint32_t []) { error }, sizeof(uint32_t), true); if (!status) goto gcap_bad_reply; - status = ssl_send_packed_buffer(&out_pbuf, archive->clients[i].ssl_fd); + status = ssl_send_packed_buffer(&out_pbuf, archive->clients[i].tls_fd); if (!status) goto gcap_bad_reply; exit_packed_buffer(&out_pbuf); @@ -976,7 +986,7 @@ static void *g_cdb_archive_process(GCdbArchive *archive) status = extend_packed_buffer(&out_pbuf, (uint8_t []) { 0x0 }, sizeof(uint8_t), true); if (!status) goto gcap_bad_reply; - status = ssl_send_packed_buffer(&out_pbuf, archive->clients[i].ssl_fd); + status = ssl_send_packed_buffer(&out_pbuf, archive->clients[i].tls_fd); if (!status) goto gcap_bad_reply; exit_packed_buffer(&out_pbuf); @@ -998,7 +1008,7 @@ static void *g_cdb_archive_process(GCdbArchive *archive) &in_pbuf, &out_pbuf, archive->db); if (!status) goto gcap_bad_reply; - status = ssl_send_packed_buffer(&out_pbuf, archive->clients[i].ssl_fd); + status = ssl_send_packed_buffer(&out_pbuf, archive->clients[i].tls_fd); if (!status) goto gcap_bad_reply; exit_packed_buffer(&out_pbuf); @@ -1010,7 +1020,7 @@ static void *g_cdb_archive_process(GCdbArchive *archive) if (!g_cdb_archive_send_snapshot_update(archive, &out_pbuf)) goto critical_error; - status = ssl_send_packed_buffer(&out_pbuf, archive->clients[i].ssl_fd); + status = ssl_send_packed_buffer(&out_pbuf, archive->clients[i].tls_fd); if (!status) goto gcap_bad_reply; exit_packed_buffer(&out_pbuf); @@ -1022,7 +1032,7 @@ static void *g_cdb_archive_process(GCdbArchive *archive) if (!g_cdb_archive_send_snapshot_change(archive, &out_pbuf)) goto critical_error; - status = ssl_send_packed_buffer(&out_pbuf, archive->clients[i].ssl_fd); + status = ssl_send_packed_buffer(&out_pbuf, archive->clients[i].tls_fd); if (!status) goto gcap_bad_reply; exit_packed_buffer(&out_pbuf); @@ -1185,12 +1195,7 @@ static void *g_cdb_archive_process(GCdbArchive *archive) gcap_no_more_clients: - archive->process = NULL; - - g_mutex_lock(&archive->id_access); - archive->process_id = 0; - g_cond_signal(&archive->id_cond); - g_mutex_unlock(&archive->id_access); + g_server_backend_stop(G_SERVER_BACKEND(archive)); if (fds != NULL) free(fds); @@ -1202,6 +1207,115 @@ static void *g_cdb_archive_process(GCdbArchive *archive) /****************************************************************************** * * +* Paramètres : archive = support pour le suivi d'une connexion. * +* fd = canal de communication réseau ouvert. * +* peer_name = désignation de la connexion. * +* user = désignation de l'utilisateur de la connexion. * +* * +* Description : Prend en compte une connexion nouvelle d'un utilisateur. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_cdb_archive_add_client(GCdbArchive *archive, SSL *fd, const char *peer_name, const char *user) +{ + cdb_client *client; /* Nouvelle fiche d'entité */ + + /** + * La situation est un peu compliquée lors de l'accueil d'un nouveau client : + * + * - soit on envoie tous les éléments à prendre en compte, mais on doit + * bloquer la base de données jusqu'à l'intégration pleine et entière + * du client, afin que ce dernier ne loupe pas l'envoi d'un nouvel + * élément entre temps. + * + * - soit on intègre le client et celui ci demande des mises à jour + * collection par collection ; c'est également à lui que revient le rejet + * des éléments envoyés en solitaires avant la réception de la base + * complète. + * + * On fait le choix du second scenario ici, du fait de la difficulté + * de maîtriser facilement la reconstitution d'une liste de clients dans + * g_cdb_archive_process() depuis un autre flot d'exécution. + */ + + g_mutex_lock(&archive->clients_access); + + archive->clients = realloc(archive->clients, ++archive->count * sizeof(cdb_client)); + + client = &archive->clients[archive->count - 1]; + + client->tls_fd = fd; + client->peer_name = strdup(peer_name); + client->user = strdup(user); + + g_mutex_unlock(&archive->clients_access); + +} + + +/****************************************************************************** +* * +* Paramètres : archive = archive à connecter avec un utilisateur. * +* index = indice de l'utilisateur concerné. * +* * +* Description : Dissocie un utilisateur de l'archive. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void _g_cdb_archive_remove_client(GCdbArchive *archive, size_t index) +{ + cdb_client *client; /* Client à traiter */ + + assert(!g_mutex_trylock(&archive->clients_access)); + + client = &archive->clients[index]; + + SSL_free(client->tls_fd); + free(client->user); + + if ((index + 1) < archive->count) + memmove(&archive->clients[index], &archive->clients[index + 1], + (archive->count - index - 1) * sizeof(cdb_client)); + + archive->clients = realloc(archive->clients, --archive->count * sizeof(cdb_client)); + +} + + +/****************************************************************************** +* * +* Paramètres : archive = archive à connecter avec un utilisateur. * +* index = indice de l'utilisateur concerné. * +* * +* Description : Dissocie un utilisateur de l'archive. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_cdb_archive_remove_client(GCdbArchive *archive, size_t index) +{ + g_mutex_lock(&archive->clients_access); + + _g_cdb_archive_remove_client(archive, index); + + g_mutex_unlock(&archive->clients_access); + +} + + +/****************************************************************************** +* * * Paramètres : archive = archive à connecter avec un utilisateur. * * pbuf = paquet de données à émettre. * * * @@ -1222,7 +1336,7 @@ static void g_cdb_archive_send_reply_to_all_clients(GCdbArchive *archive, packed for (i = 0; i < archive->count; i++) { - status = ssl_send_packed_buffer(pbuf, archive->clients[i].ssl_fd); + status = ssl_send_packed_buffer(pbuf, archive->clients[i].tls_fd); if (!status) { log_variadic_message(LMT_ERROR, _("Error while replying to client %zu"), i); @@ -1337,134 +1451,3 @@ static bool g_cdb_archive_send_snapshot_change(GCdbArchive *archive, packed_buff return result; } - - -/****************************************************************************** -* * -* Paramètres : archive = archive à connecter avec un utilisateur. * -* fd = canal de communication réseau ouvert. * -* * -* Description : Associe un nouvel utilisateur à l'archive. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_cdb_archive_add_client(GCdbArchive *archive, SSL *fd) -{ - X509 *peer_cert; /* Certificat présenté */ - volatile pthread_t *process_id; /* Identifiant de la procédure */ - - /** - * La situation est un peu compliquée lors de l'accueil d'un nouveau client : - * - * - soit on envoie tous les éléments à prendre en compte, mais on doit - * bloquer la base de données jusqu'à l'intégration pleine et entière - * du client, afin que ce dernier ne loupe pas l'envoi d'un nouvel - * élément entre temps. - * - * - soit on intègre le client et celui ci demande des mises à jour - * collection par collection ; c'est également à lui qui revient le rejet - * des éléments envoyés en solitaires avant la réception de la base - * complète. - * - * On fait le choix du second scenario ici, du fait de la difficulté - * de maîtriser facilement la reconstitution d'une liste de clients dans - * g_cdb_archive_process() depuis un autre flot d'exécution. - */ - - /* Ajout dans la liste officielle */ - - g_mutex_lock(&archive->clients_access); - - archive->clients = realloc(archive->clients, ++archive->count * sizeof(cdb_client)); - - archive->clients[archive->count - 1].ssl_fd = fd; - - peer_cert = SSL_get_peer_certificate(fd); - - archive->clients[archive->count - 1].user = X509_NAME_oneline(X509_get_subject_name(peer_cert), NULL, -1); - - X509_free(peer_cert); - - /* Démarrage ou redémarrage du processus d'écoute */ - - if (archive->process == NULL) - { - archive->process = g_thread_new("cdb_process", (GThreadFunc)g_cdb_archive_process, archive); - - /* On attend que le processus parallèle soit prêt */ - - process_id = &archive->process_id; - - g_mutex_lock(&archive->id_access); - while (process_id == 0) - g_cond_wait(&archive->id_cond, &archive->id_access); - g_mutex_unlock(&archive->id_access); - - } - else - pthread_kill(archive->process_id, SIGUSR1); - - g_mutex_unlock(&archive->clients_access); - -} - - -/****************************************************************************** -* * -* Paramètres : archive = archive à connecter avec un utilisateur. * -* index = indice de l'utilisateur concerné. * -* * -* Description : Dissocie un utilisateur de l'archive. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void _g_cdb_archive_remove_client(GCdbArchive *archive, size_t index) -{ - cdb_client *client; /* Client à traiter */ - - assert(!g_mutex_trylock(&archive->clients_access)); - - client = &archive->clients[index]; - - SSL_free(client->ssl_fd); - free(client->user); - - if ((index + 1) < archive->count) - memmove(&archive->clients[index], &archive->clients[index + 1], - (archive->count - index - 1) * sizeof(cdb_client)); - - archive->clients = realloc(archive->clients, --archive->count * sizeof(cdb_client)); - -} - - -/****************************************************************************** -* * -* Paramètres : archive = archive à connecter avec un utilisateur. * -* index = indice de l'utilisateur concerné. * -* * -* Description : Dissocie un utilisateur de l'archive. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_cdb_archive_remove_client(GCdbArchive *archive, size_t index) -{ - g_mutex_lock(&archive->clients_access); - - _g_cdb_archive_remove_client(archive, index); - - g_mutex_unlock(&archive->clients_access); - -} |