summaryrefslogtreecommitdiff
path: root/src/analysis/db/server.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/analysis/db/server.c')
-rw-r--r--src/analysis/db/server.c424
1 files changed, 335 insertions, 89 deletions
diff --git a/src/analysis/db/server.c b/src/analysis/db/server.c
index 258a66c..ad7929f 100644
--- a/src/analysis/db/server.c
+++ b/src/analysis/db/server.c
@@ -42,7 +42,9 @@
#include "auth.h"
+#include "backend.h"
#include "cdb.h"
+#include "controller.h"
#include "protocol.h"
#include "misc/rlestr.h"
#include "../../common/extstr.h"
@@ -92,8 +94,10 @@ struct _GHubServer
GThread *listener; /* Procédure de traitement */
- GList *archives; /* Liste des binaires ouverts */
- GMutex mutex; /* Verrou pour l'accès */
+ GList *controllers; /* Liste des administrateurs */
+ GMutex ctrl_mutex; /* Verrou pour l'accès */
+ GList *archives; /* Liste des aanlystes */
+ GMutex ar_mutex; /* Verrou pour l'accès */
GMutex wait_mutex; /* Accès à la condition */
GCond wait_cond; /* Attente de signal */
@@ -136,6 +140,18 @@ static int g_hub_server_verify(int, X509_STORE_CTX *);
/* Assure l'accueil des nouveaux clients. */
static void *g_hub_server_listener(GHubServer *);
+/* Assure l'accueil des nouveaux clients administrateurs. */
+static GServerBackend *g_hub_server_handle_admin(GHubServer *, packed_buffer *, const char *, DBError *, bool *);
+
+/* Assure l'accueil des nouveaux clients analystes. */
+static GServerBackend *g_hub_server_handle_analyst(GHubServer *, packed_buffer *, const char *, DBError *, bool *);
+
+/* Enregistre dans une liste interne un support de suivi. */
+static void g_hub_server_register_backend(GHubServer *, GServerBackend *);
+
+/* Suit les variations du compteur de références d'un greffon. */
+static void on_backend_ref_toggle(GHubServer *, GServerBackend *, gboolean);
+
/* Indique le type défini pour une description de serveur à l'écoute. */
@@ -190,7 +206,10 @@ static void g_hub_server_init(GHubServer *server)
server->unlock_socket = NULL;
server->lock_fd = -1;
- g_mutex_init(&server->mutex);
+ server->controllers = NULL;
+ g_mutex_init(&server->ctrl_mutex);
+ server->archives = NULL;
+ g_mutex_init(&server->ar_mutex);
g_mutex_init(&server->wait_mutex);
g_cond_init(&server->wait_cond);
@@ -216,15 +235,23 @@ static void g_hub_server_dispose(GHubServer *server)
g_hub_server_stop(server);
+ for (iter = g_list_first(server->controllers);
+ iter != NULL;
+ iter = g_list_first(server->controllers))
+ {
+ g_object_unref(G_OBJECT(iter->data));
+ }
+
+ g_mutex_clear(&server->ctrl_mutex);
+
for (iter = g_list_first(server->archives);
iter != NULL;
iter = g_list_first(server->archives))
{
g_object_unref(G_OBJECT(iter->data));
- server->archives = g_list_delete_link(server->archives, iter);
}
- g_mutex_clear(&server->mutex);
+ g_mutex_clear(&server->ar_mutex);
g_mutex_clear(&server->wait_mutex);
g_cond_clear(&server->wait_cond);
@@ -721,18 +748,16 @@ static void *g_hub_server_listener(GHubServer *server)
gen_sockaddr_t peer; /* Adresse cliente */
int fd; /* Canal établi vers un client */
SSL *tls_fd; /* Même canal, mais sécurisé */
- rle_string hash; /* Empreinte du binaire visé */
+ GServerBackend *backend; /* Support de suivi créé */
const char *ip; /* Statut de la conversion */
char *peer_name; /* Désignation du correspondant*/
DBError error; /* Validation de la connexion */
- GCdbArchive *archive; /* Destinataire final du client*/
- GList *iter; /* Boucle de parcours */
packed_buffer in_pbuf; /* Tampon de réception */
bool status; /* Bilan d'une opération */
uint32_t cmd; /* Commande initiale lue */
uint32_t version; /* Version du client lue */
- char *basedir; /* Répertoire de stockage */
- char *tmpdir; /* Répertoire de travail */
+ uint32_t role; /* Rôle visé par le client */
+ bool new; /* Besoin d'ajout à une liste */
packed_buffer out_pbuf; /* Tampon d'émission */
fds.fd = server->fd;
@@ -782,12 +807,10 @@ static void *g_hub_server_listener(GHubServer *server)
goto invalid_conn;
}
- /* Initialisation à vide pour les sorties en erreur */
-
- setup_empty_rle_string(&hash);
-
/* Construction d'une représentation */
+ backend = NULL;
+
if (*((sa_family_t *)&peer) == AF_UNIX)
peer_name = strdup(server->desc);
@@ -799,7 +822,7 @@ static void *g_hub_server_listener(GHubServer *server)
if (ip == NULL)
{
LOG_ERROR_N("inet_ntop");
- goto id_error;
+ goto ip_error;
}
snprintf(peer_name + strlen(ip), 1 + 5, ":%hu", ntohs(peer.inet4_addr.sin_port));
@@ -814,7 +837,7 @@ static void *g_hub_server_listener(GHubServer *server)
if (ip == NULL)
{
LOG_ERROR_N("inet_ntop");
- goto id_error;
+ goto ip_error;
}
snprintf(peer_name + strlen(ip), 1 + 5, ":%hu", ntohs(peer.inet6_addr.sin6_port));
@@ -825,14 +848,12 @@ static void *g_hub_server_listener(GHubServer *server)
goto invalid_conn;
error = DBE_NONE;
- archive = NULL;
-
- iter = NULL;
/**
* Le premier "paquet" reçu de la part d'un client doit contenir les informations suivantes :
- * - la commande 'DBC_HELO'.
- * - le numéro de version du client.
+ * - la commande 'DBC_HELO' ;
+ * - le numéro de version du client ;
+ * - le rôle attendu.
* - l'empreinte du binaire analysé.
*
* Tout ceci est à synchroniser avec la fonction g_db_client_start().
@@ -846,7 +867,7 @@ static void *g_hub_server_listener(GHubServer *server)
log_variadic_message(LMT_ERROR, _("Error while getting the initial packet from '%s'..."),
peer_name);
error = DBE_BAD_EXCHANGE;
- goto error_sending;
+ goto error_receiving;
}
status = extract_packed_buffer(&in_pbuf, &cmd, sizeof(uint32_t), true);
@@ -855,7 +876,7 @@ static void *g_hub_server_listener(GHubServer *server)
log_variadic_message(LMT_ERROR, _("Error while getting the initial command from '%s'..."),
peer_name);
error = DBE_BAD_EXCHANGE;
- goto error_sending;
+ goto error_receiving;
}
status = extract_packed_buffer(&in_pbuf, &version, sizeof(uint32_t), true);
@@ -864,16 +885,16 @@ static void *g_hub_server_listener(GHubServer *server)
log_variadic_message(LMT_ERROR, _("Error while getting the protocol version from '%s'..."),
peer_name);
error = DBE_BAD_EXCHANGE;
- goto error_sending;
+ goto error_receiving;
}
- status = unpack_rle_string(&hash, &in_pbuf);
+ status = extract_packed_buffer(&in_pbuf, &role, sizeof(uint32_t), true);
if (!status)
{
- log_variadic_message(LMT_ERROR, _("Error while getting the binary hash from '%s'..."),
+ log_variadic_message(LMT_ERROR, _("Error while getting the expected role from '%s'..."),
peer_name);
error = DBE_BAD_EXCHANGE;
- goto error_sending;
+ goto error_receiving;
}
if (cmd != DBC_HELO)
@@ -881,65 +902,48 @@ static void *g_hub_server_listener(GHubServer *server)
log_variadic_message(LMT_ERROR, _("The client from '%s' did not introduce itself!"),
peer_name);
error = DBE_BAD_EXCHANGE;
- goto error_sending;
+ goto error_receiving;
}
if (version != CDB_PROTOCOL_VERSION)
{
- log_variadic_message(LMT_ERROR, _("The client from '%s' does not use the same protocol: 0x%08x vs 0x%08x..."),
+ log_variadic_message(LMT_ERROR,
+ _("The client from '%s' does not use the same protocol: 0x%08x vs 0x%08x..."),
peer_name, be32toh(version), CDB_PROTOCOL_VERSION);
error = DBE_WRONG_VERSION;
- goto error_sending;
+ goto error_receiving;
}
- if (is_rle_string_empty(&hash))
+ switch (role)
{
- log_variadic_message(LMT_ERROR, _("The submitted binary hash from '%s' is empty!"),
- peer_name);
- error = DBE_BAD_EXCHANGE;
- goto error_sending;
- }
-
- /**
- * On met en place le maximum ici, de manière à pouvoir indiquer une erreur
- * en cas d'échec, et être le plus précis possible dans la courte réponse.
- */
-
- assert(error == DBE_NONE);
-
- for (iter = g_list_first(server->archives);
- iter != NULL;
- iter = g_list_next(iter))
- {
- archive = G_CDB_ARCHIVE(iter->data);
- if (g_cdb_archive_compare_hash(archive, &hash) == 0)
+ case CRL_ADMIN:
+ backend = g_hub_server_handle_admin(server, &in_pbuf, peer_name, &error, &new);
break;
- }
- if (iter == NULL)
- {
- basedir = strdup(server->working);
- basedir = stradd(basedir, "cdbs" G_DIR_SEPARATOR_S);
+ case CRL_ANALYST:
+ backend = g_hub_server_handle_analyst(server, &in_pbuf, peer_name, &error, &new);
+ break;
- tmpdir = strdup(server->working);
- tmpdir = stradd(tmpdir, "tmp" G_DIR_SEPARATOR_S);
+ default:
+ log_variadic_message(LMT_ERROR, _("Unknown client role requested by '%s'"),
+ peer_name);
+ backend = NULL;
+ error = DBE_BAD_EXCHANGE;
+ new = false;
+ break;
- archive = g_cdb_archive_new(basedir, tmpdir, &hash, &error);
+ }
- free(tmpdir);
- free(basedir);
+ assert((backend == NULL && error != DBE_NONE) || (backend != NULL && error == DBE_NONE));
- }
+ error_receiving:
/**
* Le serveur doit répondre pour un message type :
- * - la commande 'DBC_WELCOME'.
- * - un identifiant d'erreur ('DBE_NONE', 'DBE_BAD_EXCHANGE'
- * ou 'DBE_WRONG_VERSION' ... 'DBE_LOADING_ERROR').
+ * - la commande 'DBC_WELCOME' ;
+ * - un identifiant d'erreur.
*/
- error_sending:
-
exit_packed_buffer(&in_pbuf);
init_packed_buffer(&out_pbuf);
@@ -959,41 +963,28 @@ static void *g_hub_server_listener(GHubServer *server)
* lors des échanges initiaux, car ces derniers seraient alors précédés des mises à jour...
*/
- if (archive != NULL)
+ if (backend != NULL)
{
- assert(error == DBE_NONE);
-
- /* Si l'archive a été créée pour l'occasion... */
- if (iter == NULL)
- server->archives = g_list_append(server->archives, archive);
-
- g_cdb_archive_add_client(archive, tls_fd);
+ if (new)
+ g_hub_server_register_backend(server, backend);
- exit_packed_buffer(&out_pbuf);
-
- free(peer_name);
-
- exit_rle_string(&hash);
-
- continue;
+ g_server_backend_add_client(backend, tls_fd, peer_name);
}
- assert(error != DBE_NONE);
-
out_error:
- exit_packed_buffer(&out_pbuf);
+ if (backend != NULL)
+ g_object_unref(G_OBJECT(backend));
- /* Si l'archive a été créée pour l'occasion... */
- if (iter == NULL && archive != NULL)
- g_object_unref(G_OBJECT(archive));
+ exit_packed_buffer(&out_pbuf);
- id_error:
+ ip_error:
free(peer_name);
- exit_rle_string(&hash);
+ if (backend != NULL)
+ continue;
invalid_conn:
@@ -1016,6 +1007,261 @@ static void *g_hub_server_listener(GHubServer *server)
/******************************************************************************
* *
+* Paramètres : server = serveur pour les accès distants à manipuler. *
+* in_pbuf = reste des premières données reçues. *
+* peer_name = désignation de la connexion entrante. *
+* error = code d'erreur issu du traitement. [OUT] *
+* new = indique si le résultat doit être ajouté. [OUT] *
+* *
+* Description : Assure l'accueil des nouveaux clients administrateurs. *
+* *
+* Retour : Instance de support de suivi mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static GServerBackend *g_hub_server_handle_admin(GHubServer *server, packed_buffer *in_pbuf, const char *peer_name, DBError *error, bool *new)
+{
+ GCdbController *result; /* Support de suivi à retourner*/
+ char *basedir; /* Répertoire de stockage */
+
+ if (has_more_data_in_packed_buffer(in_pbuf))
+ {
+ log_variadic_message(LMT_ERROR, _("The client from '%s' provided to much data!"), peer_name);
+
+ result = NULL;
+
+ *error = DBE_BAD_EXCHANGE;
+ *new = false;
+
+ }
+ else
+ {
+ basedir = strdup(server->working);
+ basedir = stradd(basedir, "cdbs" G_DIR_SEPARATOR_S);
+
+ result = g_cdb_controller_new(basedir, error);
+
+ free(basedir);
+
+ *new = true;
+
+ }
+
+ return G_SERVER_BACKEND(result);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : server = serveur pour les accès distants à manipuler. *
+* in_pbuf = reste des premières données reçues. *
+* peer_name = désignation de la connexion entrante. *
+* error = code d'erreur issu du traitement. [OUT] *
+* new = indique si le résultat doit être ajouté. [OUT] *
+* *
+* Description : Assure l'accueil des nouveaux clients analystes. *
+* *
+* Retour : Instance de support de suivi mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static GServerBackend *g_hub_server_handle_analyst(GHubServer *server, packed_buffer *in_pbuf, const char *peer_name, DBError *error, bool *new)
+{
+ GCdbArchive *result; /* Support de suivi à retourner*/
+ rle_string hash; /* Empreinte du binaire visé */
+ bool status; /* Bilan d'une opération */
+ GList *iter; /* Boucle de parcours */
+ GCdbArchive *archive; /* Destinataire final du client*/
+ char *basedir; /* Répertoire de stockage */
+ char *tmpdir; /* Répertoire de travail */
+
+ result = NULL;
+
+ *error = DBE_BAD_EXCHANGE;
+ *new = false;
+
+ /* Fin de réception des données envoyées */
+
+ status = unpack_rle_string(&hash, in_pbuf);
+ if (!status)
+ {
+ log_variadic_message(LMT_ERROR, _("Error while getting the binary hash from '%s'..."), peer_name);
+ goto error_receiving;
+ }
+
+ if (is_rle_string_empty(&hash))
+ {
+ log_variadic_message(LMT_ERROR, _("The submitted binary hash from '%s' is empty!"), peer_name);
+ goto wrong_receiving;
+ }
+
+ 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;
+ }
+
+ /* Recherche d'un support existant adapté */
+
+ g_mutex_lock(&server->ar_mutex);
+
+ for (iter = g_list_first(server->archives); iter != NULL; iter = g_list_next(iter))
+ {
+ archive = G_CDB_ARCHIVE(iter->data);
+
+ if (g_cdb_archive_compare_hash(archive, &hash) == 0)
+ break;
+
+ }
+
+ if (iter != NULL)
+ {
+ result = archive;
+ g_object_ref(G_OBJECT(result));
+ }
+
+ g_mutex_unlock(&server->ar_mutex);
+
+ /* Nouvelle création au besoin */
+
+ if (result == NULL)
+ {
+ basedir = strdup(server->working);
+ basedir = stradd(basedir, "cdbs" G_DIR_SEPARATOR_S);
+
+ tmpdir = strdup(server->working);
+ tmpdir = stradd(tmpdir, "tmp" G_DIR_SEPARATOR_S);
+
+ result = g_cdb_archive_new(basedir, tmpdir, &hash, error);
+
+ free(tmpdir);
+ free(basedir);
+
+ *new = true;
+
+ }
+
+ wrong_receiving:
+
+ exit_rle_string(&hash);
+
+ error_receiving:
+
+ return (result != NULL ? G_SERVER_BACKEND(result) : NULL);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : server = serveur pour les accès distants à manipuler. *
+* backend = support de suivi de connexion. *
+* *
+* Description : Enregistre dans une liste interne un support de suivi. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_hub_server_register_backend(GHubServer *server, GServerBackend *backend)
+{
+ GList **list; /* Liste à parcourir */
+ GMutex *mutex; /* Verrou à manipuler */
+
+ /* Sélection des éléments concernés */
+
+ if (G_IS_CDB_CONTROLLER(backend))
+ {
+ list = &server->controllers;
+ mutex = &server->ctrl_mutex;
+ }
+ else if (G_IS_CDB_ARCHIVE(backend))
+ {
+ list = &server->archives;
+ mutex = &server->ar_mutex;
+ }
+ else
+ assert(false);
+
+ /* Retrait de l'élément inutilisé */
+
+ g_mutex_lock(mutex);
+
+ g_object_ref(G_OBJECT(backend));
+
+ *list = g_list_append(*list, backend);
+
+ g_object_add_toggle_ref(G_OBJECT(backend), (GToggleNotify)on_backend_ref_toggle, server);
+
+ g_mutex_unlock(mutex);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : server = serveur pour les accès distants à manipuler. *
+* backend = support de suivi de connexion. *
+* last = indication sur la valeur du compteur de références.*
+* *
+* Description : Suit les variations du compteur de références d'un greffon. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void on_backend_ref_toggle(GHubServer *server, GServerBackend *backend, gboolean last)
+{
+ GList **list; /* Liste à parcourir */
+ GMutex *mutex; /* Verrou à manipuler */
+ GList *iter; /* Boucle de parcours */
+
+ if (last)
+ {
+ /* Sélection des éléments concernés */
+
+ if (G_IS_CDB_CONTROLLER(backend))
+ {
+ list = &server->controllers;
+ mutex = &server->ctrl_mutex;
+ }
+ else if (G_IS_CDB_ARCHIVE(backend))
+ {
+ list = &server->archives;
+ mutex = &server->ar_mutex;
+ }
+ else
+ assert(false);
+
+ /* Retrait de l'élément inutilisé */
+
+ g_mutex_lock(mutex);
+
+ for (iter = g_list_first(*list); iter != NULL; iter = g_list_first(*list))
+ {
+ *list = g_list_delete_link(*list, iter);
+ }
+
+ g_object_remove_toggle_ref(G_OBJECT(backend), (GToggleNotify)on_backend_ref_toggle, server);
+
+ g_mutex_unlock(mutex);
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : server = serveur pour les accès distants à manipuler. *
* backlog = nombre de connexions maximal. *
* keep = conservation du serveur en avant plan. *