summaryrefslogtreecommitdiff
path: root/src/analysis/db/client.c
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2019-08-29 21:43:47 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2019-08-29 21:43:47 (GMT)
commitfa40856e942a7e1bd1cb2729645182c1fa717468 (patch)
tree954db169d2b734e661d904e502cd1c803f51c6ea /src/analysis/db/client.c
parent7f973e015eb59b626edc584a19a1ad3ffddf4867 (diff)
Defined a new way to launch updates share servers.
Diffstat (limited to 'src/analysis/db/client.c')
-rw-r--r--src/analysis/db/client.c373
1 files changed, 243 insertions, 130 deletions
diff --git a/src/analysis/db/client.c b/src/analysis/db/client.c
index 24198f6..c608bfa 100644
--- a/src/analysis/db/client.c
+++ b/src/analysis/db/client.c
@@ -37,31 +37,39 @@
#include <i18n.h>
-#include "keymgn.h"
+#include "auth.h"
#include "protocol.h"
#include "misc/rlestr.h"
+#include "../../common/extstr.h"
#include "../../common/io.h"
#include "../../common/xdg.h"
#include "../../core/logs.h"
+/* Format générique des adresses de connexion */
+typedef union _gen_sockaddr_t
+{
+ struct sockaddr_in inet4_addr; /* Adresse d'écoute IPv4 */
+ struct sockaddr_in6 inet6_addr; /* Adresse d'écoute IPv6 */
+ struct sockaddr inet_4_6_addr; /* Adresse d'écoute IPv4/6 */
+
+} gen_sockaddr_t;
+
+
/* Description de client à l'écoute (instance) */
-struct _GDbClient
+struct _GHubClient
{
GObject parent; /* A laisser en premier */
- char *author; /* Utilisateur représenté */
- //char *key_file; /* Accès sa la clef privée */
-
const char *name; /* Désignation du binaire */
rle_string hash; /* Empreinte du binaire lié */
GList *collections; /* Collections d'un binaire */
+ char *working; /* Répertoire de travail */
+
SSL_CTX *tls_ctx; /* Contexte du chiffrement */
- char *cert_file; /* Fichier du certificat */
- char *key_file; /* Fichier de la clef privée */
int fd; /* Canal de communication */
SSL *tls_fd; /* Même canal, mais sécurisé */
@@ -74,7 +82,7 @@ struct _GDbClient
};
/* Description de client à l'écoute (classe) */
-struct _GDbClientClass
+struct _GHubClientClass
{
GObjectClass parent; /* A laisser en premier */
@@ -82,24 +90,27 @@ struct _GDbClientClass
/* Initialise la classe des descriptions de fichier binaire. */
-static void g_db_client_class_init(GDbClientClass *);
+static void g_hub_client_class_init(GHubClientClass *);
/* Initialise une description de fichier binaire. */
-static void g_db_client_init(GDbClient *);
+static void g_hub_client_init(GHubClient *);
+
+/* Supprime toutes les références externes. */
+static void g_hub_client_dispose(GHubClient *);
/* Procède à la libération totale de la mémoire. */
-static void g_db_client_finalize(GDbClient *);
+static void g_hub_client_finalize(GHubClient *);
/* Démarre réellement la connexion à la base de données. */
-static bool g_db_client_start_common(GDbClient *, char *);
+static bool g_hub_client_start_common(GHubClient *, char *);
/* Assure l'accueil des nouvelles mises à jour. */
-static void *g_db_client_update(GDbClient *);
+static void *g_hub_client_update(GHubClient *);
/* Indique le type défini pour une description de client à l'écoute. */
-G_DEFINE_TYPE(GDbClient, g_db_client, G_TYPE_OBJECT);
+G_DEFINE_TYPE(GHubClient, g_hub_client, G_TYPE_OBJECT);
/******************************************************************************
@@ -114,13 +125,14 @@ G_DEFINE_TYPE(GDbClient, g_db_client, G_TYPE_OBJECT);
* *
******************************************************************************/
-static void g_db_client_class_init(GDbClientClass *klass)
+static void g_hub_client_class_init(GHubClientClass *klass)
{
GObjectClass *object; /* Autre version de la classe */
object = G_OBJECT_CLASS(klass);
- object->finalize = (GObjectFinalizeFunc)g_db_client_finalize;
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_hub_client_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_hub_client_finalize;
}
@@ -137,11 +149,11 @@ static void g_db_client_class_init(GDbClientClass *klass)
* *
******************************************************************************/
-static void g_db_client_init(GDbClient *client)
+static void g_hub_client_init(GHubClient *client)
{
+ client->working = NULL;
+
client->tls_ctx = NULL;
- client->cert_file = NULL;
- client->key_file = NULL;
client->fd = -1;
client->tls_fd = NULL;
@@ -152,6 +164,27 @@ static void g_db_client_init(GDbClient *client)
/******************************************************************************
* *
+* Paramètres : archive = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_hub_client_dispose(GHubClient *client)
+{
+ g_hub_client_stop(client);
+
+ G_OBJECT_CLASS(g_hub_client_parent_class)->dispose(G_OBJECT(client));
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : client = instance d'objet GLib à traiter. *
* *
* Description : Procède à la libération totale de la mémoire. *
@@ -162,36 +195,28 @@ static void g_db_client_init(GDbClient *client)
* *
******************************************************************************/
-static void g_db_client_finalize(GDbClient *client)
+static void g_hub_client_finalize(GHubClient *client)
{
- free(client->author);
-
unset_rle_string(&client->hash);
- assert(client->tls_ctx == NULL);
-
- if (client->cert_file != NULL)
- free(client->cert_file);
+ if (client->working != NULL)
+ free(client->working);
- if (client->key_file != NULL)
- free(client->key_file);
+ assert(client->tls_ctx == NULL);
assert(client->tls_fd == NULL);
if (client->desc != NULL)
free(client->desc);
- G_OBJECT_CLASS(g_db_client_parent_class)->finalize(G_OBJECT(client));
+ G_OBJECT_CLASS(g_hub_client_parent_class)->finalize(G_OBJECT(client));
}
/******************************************************************************
* *
-* Paramètres : author = utilisateur à représenter via le client. *
-* kfile = clef menant à sa clef privée. *
-* name = désignation humaine du binaire associé. *
-* hash = empreinte d'un binaire en cours d'analyse. *
+* Paramètres : hash = empreinte d'un binaire en cours d'analyse. *
* collections = ensemble de collections existantes. *
* *
* Description : Prépare un client pour une connexion à une BD. *
@@ -202,16 +227,11 @@ static void g_db_client_finalize(GDbClient *client)
* *
******************************************************************************/
-GDbClient *g_db_client_new(char *author, char *kfile, const char *name, const char *hash, GList *collections)
+GHubClient *g_hub_client_new(const char *hash, GList *collections)
{
- GDbClient *result; /* Adresse à retourner */
+ GHubClient *result; /* Adresse à retourner */
- result = g_object_new(G_TYPE_DB_CLIENT, NULL);
-
- result->author = author;
- result->key_file = kfile;
-
- result->name = name;
+ result = g_object_new(G_TYPE_HUB_CLIENT, NULL);
init_static_rle_string(&result->hash, hash);
result->collections = collections;
@@ -233,7 +253,7 @@ GDbClient *g_db_client_new(char *author, char *kfile, const char *name, const ch
* *
******************************************************************************/
-bool g_db_client_start_internal(GDbClient *client)
+bool g_hub_client_start_internal(GHubClient *client)
{
bool status; /* Bilan de la connexion */
struct sockaddr_un addr; /* Adresse de transmission */
@@ -242,42 +262,43 @@ bool g_db_client_start_internal(GDbClient *client)
/* Identification du serveur à contacter */
- status = build_tmp_socket("internal-server", &addr);
- if (!status) goto gdcni_error;
+ status = build_internal_server_socket(&addr);
+ if (!status) goto fs_error;
/* Création d'un canal de communication */
client->fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (client->fd == -1)
{
- perror("socket");
- goto gdcni_error;
+ LOG_ERROR_N("socket");
+ goto fs_error;
}
ret = connect(client->fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_un));
if (ret == -1)
{
- perror("connect");
- goto gdcsi_no_listening;
+ LOG_ERROR_N("connect");
+ goto no_listening;
}
asprintf(&desc, "unix://%s", addr.sun_path);
- status = g_db_client_start_common(client, desc);
+ client->working = get_db_working_directory("clients", "standalone", NULL, NULL);
+
+ status = g_hub_client_start_common(client, desc);
if (!status)
- goto gdcsi_no_listening;
+ goto no_listening;
return true;
- gdcsi_no_listening:
+ no_listening:
close(client->fd);
-
- gdcni_error:
-
client->fd = -1;
+ fs_error:
+
return false;
}
@@ -288,6 +309,7 @@ bool g_db_client_start_internal(GDbClient *client)
* Paramètres : client = client pour les accès distants à manipuler. *
* host = hôte à représenter pour le service. *
* port = port de connexion pour les clients. *
+* ipv6 = adopte une préférence pour les adresses IPv6. *
* *
* Description : Démarre la connexion à la base de données distante. *
* *
@@ -297,54 +319,114 @@ bool g_db_client_start_internal(GDbClient *client)
* *
******************************************************************************/
-bool g_db_client_start_remote(GDbClient *client, const char *host, unsigned short port)
+bool g_hub_client_start_remote(GHubClient *client, const char *host, const char *port, bool ipv6)
{
- struct hostent *hp; /* Informations sur l'hôte */
- struct sockaddr_in addr; /* Adresse de transmission */
- int ret; /* Bilan d'un appel */
+ struct addrinfo hints; /* Cadre de connexion souhaité */
+ struct addrinfo *available; /* Cadres de connexion dispos */
+ int ret; /* Bilan d'une consultation */
+ int domain; /* Domaine du canal */
+ struct addrinfo *iter; /* Boucle de parcours */
+ gen_sockaddr_t addr; /* Adresse d'écoute générique */
+ socklen_t sock_len; /* Taille de cette adresse */
char *desc; /* Description du serveur ciblé*/
bool status; /* Bilan de la connexion */
- /* Identification du serveur à contacter */
+ /* Détermination du point d'écoute */
+
+ memset(&hints, 0, sizeof(hints));
+
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
+
+ ret = getaddrinfo(host, port, &hints, &available);
+ if (ret != 0)
+ {
+ LOG_ERROR_GAI_N("getaddrinfo", ret);
+ goto no_target;
+ }
+
+ domain = AF_UNSPEC;
+
+ /**
+ * Premier tour : on essaie de se plier à la demande.
+ */
+
+ for (iter = available; iter != NULL && domain == AF_UNSPEC; iter = iter->ai_next)
+ {
+ if (ipv6 && iter->ai_family != AF_INET6)
+ continue;
- hp = gethostbyname(host);
- if (hp == NULL) return false;
+ if (!ipv6 && iter->ai_family != AF_INET)
+ continue;
+
+ domain = iter->ai_family;
+
+ memcpy(&addr.inet_4_6_addr, iter->ai_addr, iter->ai_addrlen);
+ sock_len = iter->ai_addrlen;
+
+ }
+
+ /**
+ * Second tour : on fait avec ce qu'on a.
+ */
+
+ for (iter = available; iter != NULL && domain == AF_UNSPEC; iter = iter->ai_next)
+ {
+ if (iter->ai_family != AF_INET6 && iter->ai_family != AF_INET)
+ continue;
+
+ domain = iter->ai_family;
+
+ memcpy(&addr.inet_4_6_addr, iter->ai_addr, iter->ai_addrlen);
+ sock_len = iter->ai_addrlen;
+
+ }
- addr.sin_family = hp->h_addrtype;
- memcpy(&addr.sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
+ if (available != NULL)
+ freeaddrinfo(available);
- addr.sin_port = htons(port);
+ if (domain == AF_UNSPEC)
+ {
+ log_variadic_message(LMT_ERROR, _("No suitable address found for %s:%s"), host, port);
+ goto no_target;
+ }
/* Création d'un canal de communication */
- client->fd = socket(AF_INET, SOCK_STREAM, 0);
+ client->fd = socket(domain, SOCK_STREAM, 0);
if (client->fd == -1)
{
- perror("socket");
- return false;
+ LOG_ERROR_N("socket");
+ goto error_socket;
}
- ret = connect(client->fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in));
+ ret = connect(client->fd, (struct sockaddr *)&addr, sock_len);
if (ret == -1)
{
- perror("connect");
- goto gdcsr_no_listening;
+ LOG_ERROR_N("connect");
+ goto no_listening;
}
- asprintf(&desc, "%s:%hu", host, port);
+ asprintf(&desc, "%s:%s", host, port);
- status = g_db_client_start_common(client, desc);
+ client->working = get_db_working_directory("clients", host, port, NULL);
+
+ status = g_hub_client_start_common(client, desc);
if (!status)
- goto gdcsr_no_listening;
+ goto no_listening;
return true;
- gdcsr_no_listening:
+ no_listening:
close(client->fd);
client->fd = -1;
+ error_socket:
+ no_target:
+
return false;
}
@@ -364,26 +446,21 @@ bool g_db_client_start_remote(GDbClient *client, const char *host, unsigned shor
* *
******************************************************************************/
-static bool g_db_client_start_common(GDbClient *client, char *desc)
+static bool g_hub_client_start_common(GHubClient *client, char *desc)
{
const SSL_METHOD *method; /* Mode du canal sécurisé */
+ char *filename; /* Fichier PEM à manipuler */
int ret; /* Bilan d'un appel */
+ char *rootdir; /* Racine pour le client */
packed_buffer out_pbuf; /* Tampon d'émission */
bool status; /* Bilan d'une opération */
- rle_string user; /* Nom d'utilisateur associé */
- GChecksum *checksum; /* Empreinte MD5 à signer */
- unsigned char md5_digest[16]; /* Empreinte MD5 calculée */
- RSA *key; /* Clef pour la signature */
- unsigned char sig[RSA_USED_SIZE]; /* Signature effectuée */
packed_buffer in_pbuf; /* Tampon de réception */
uint32_t data; /* Mot de données lues */
DBError error; /* Validation de la connexion */
client->desc = desc;
- /**
- * Mise en place d'un environnement sécurisé.
- */
+ /* Définition d'un environnement TLS */
method = TLS_client_method();
@@ -395,6 +472,54 @@ static bool g_db_client_start_common(GDbClient *client, char *desc)
goto quick_error;
}
+ filename = strdup(client->working);
+ filename = stradd(filename, "client-cert.pem");
+
+ ret = SSL_CTX_use_certificate_file(client->tls_ctx, filename, SSL_FILETYPE_PEM);
+
+ free(filename);
+
+ if (ret != 1)
+ {
+ LOG_ERROR_OPENSSL;
+ goto tls_error;
+ }
+
+ rootdir = get_db_working_directory("clients", NULL, NULL, NULL);
+
+ filename = strdup(rootdir);
+ filename = stradd(filename, "client-key.pem");
+
+ ret = SSL_CTX_use_PrivateKey_file(client->tls_ctx, filename, SSL_FILETYPE_PEM);
+
+ free(filename);
+ free(rootdir);
+
+ if (ret != 1)
+ {
+ LOG_ERROR_OPENSSL;
+ goto tls_error;
+ }
+
+ /* Validation des certificats */
+
+ SSL_CTX_set_verify(client->tls_ctx, SSL_VERIFY_PEER, NULL);
+
+ filename = strdup(client->working);
+ filename = stradd(filename, "ca-cert.pem");
+
+ ret = SSL_CTX_load_verify_locations(client->tls_ctx, filename, NULL);
+
+ free(filename);
+
+ if (ret != 1)
+ {
+ LOG_ERROR_OPENSSL;
+ goto tls_error;
+ }
+
+ /* Mise en place d'un canal de communication */
+
client->tls_fd = SSL_new(client->tls_ctx);
if (client->tls_fd == NULL)
@@ -410,7 +535,7 @@ static bool g_db_client_start_common(GDbClient *client, char *desc)
if (ret != 1)
{
LOG_ERROR_OPENSSL;
- goto tls_error;
+ goto ssl_error;
}
/**
@@ -418,8 +543,6 @@ static bool g_db_client_start_common(GDbClient *client, char *desc)
* - la commande 'DBC_HELO'.
* - le numéro de version du client.
* - l'empreinte du binaire analysé.
- * - l'identifiant de l'utilisateur effectuant des modifications.
- * - la signature de l'empreinte MD5 de l'identifiant.
*
* Tout ceci est à synchroniser avec la fonction g_db_server_listener().
*/
@@ -435,30 +558,6 @@ static bool g_db_client_start_common(GDbClient *client, char *desc)
status = pack_rle_string(&client->hash, &out_pbuf);
if (!status) goto setup_error;
- dup_into_rle_string(&user, client->author);
-
- status = pack_rle_string(&user, &out_pbuf);
- if (!status) goto setup_error;
-
- checksum = g_checksum_new(G_CHECKSUM_MD5);
- g_checksum_update(checksum, (guchar *)get_rle_string(&user), get_rle_length(&user));
- g_checksum_get_digest(checksum, (guint8 *)md5_digest, (gsize []) { sizeof(md5_digest) });
- g_checksum_free(checksum);
-
- key = load_rsa_key(client->key_file, true);
- if (key == NULL) goto setup_error;
-
- if (!sign_md5_hash(key, md5_digest, sig))
- {
- RSA_free(key);
- goto setup_error;
- }
-
- RSA_free(key);
-
- status = extend_packed_buffer(&out_pbuf, sig, RSA_USED_SIZE, false);
- if (!status) goto setup_error;
-
status = ssl_send_packed_buffer(&out_pbuf, client->tls_fd);
if (!status) goto setup_error;
@@ -522,7 +621,7 @@ static bool g_db_client_start_common(GDbClient *client, char *desc)
client->can_get_updates = false;
- client->update = g_thread_try_new("cdb_client", (GThreadFunc)g_db_client_update, client, NULL);
+ client->update = g_thread_try_new("cdb_client", (GThreadFunc)g_hub_client_update, client, NULL);
if (client->update == NULL)
{
log_variadic_message(LMT_ERROR, _("Failed to start a listening thread for the server '%s'!"),
@@ -543,7 +642,10 @@ static bool g_db_client_start_common(GDbClient *client, char *desc)
exit_packed_buffer(&out_pbuf);
- unset_rle_string(&user);
+ ssl_error:
+
+ SSL_free(client->tls_fd);
+ client->tls_fd = NULL;
tls_error:
@@ -552,9 +654,6 @@ static bool g_db_client_start_common(GDbClient *client, char *desc)
quick_error:
- close(client->fd);
- client->fd = -1;
-
return false;
}
@@ -572,7 +671,7 @@ static bool g_db_client_start_common(GDbClient *client, char *desc)
* *
******************************************************************************/
-static void *g_db_client_update(GDbClient *client)
+static void *g_hub_client_update(GHubClient *client)
{
packed_buffer out_pbuf; /* Tampon d'émission */
bool status; /* Bilan d'une opération */
@@ -617,7 +716,7 @@ static void *g_db_client_update(GDbClient *client)
init_packed_buffer(&in_pbuf);
- while (1)
+ while (client->fd != -1)
{
ret = poll(&fds, 1, -1);
if (ret != 1) continue;
@@ -626,6 +725,14 @@ static void *g_db_client_update(GDbClient *client)
if (fds.revents & POLLNVAL)
break;
+ /**
+ * Même chose, cf. "TCP: When is EPOLLHUP generated?"
+ * https://stackoverflow.com/questions/52976152/tcp-when-is-epollhup-generated/52976327#52976327
+ */
+
+ if (fds.revents & (POLLHUP | POLLRDHUP))
+ break;
+
if (fds.revents & (POLLIN | POLLPRI))
{
reset_packed_buffer(&in_pbuf);
@@ -701,7 +808,7 @@ static void *g_db_client_update(GDbClient *client)
exit:
- g_db_client_stop(client);
+ g_hub_client_stop(client);
exit_packed_buffer(&in_pbuf);
@@ -722,13 +829,14 @@ static void *g_db_client_update(GDbClient *client)
* *
******************************************************************************/
-void g_db_client_stop(GDbClient *client)
+void g_hub_client_stop(GHubClient *client)
{
+ int fd; /* Canal à clôturer */
int ret; /* Bilan d'un appel */
/* Canal de communication */
- if (client->fd != -1)
+ if (client->fd == -1)
{
/**
* Si la fermture est forcée, le thread de traitement va terminer en erreur.
@@ -741,15 +849,20 @@ void g_db_client_stop(GDbClient *client)
return;
}
- ret = close(client->fd);
- if (ret == -1) perror("close");
+ fd = client->fd;
client->fd = -1;
+ ret = close(fd);
+ if (ret == -1) LOG_ERROR_N("close");
+
g_thread_join(client->update);
/* Environnement TLS */
+ SSL_free(client->tls_fd);
+ client->tls_fd = NULL;
+
SSL_CTX_free(client->tls_ctx);
client->tls_ctx = NULL;
@@ -768,7 +881,7 @@ void g_db_client_stop(GDbClient *client)
* *
******************************************************************************/
-int g_db_client_get_fd(GDbClient *client)
+int g_hub_client_get_fd(GHubClient *client)
{
g_mutex_lock(&client->sending_lock);
@@ -789,7 +902,7 @@ int g_db_client_get_fd(GDbClient *client)
* *
******************************************************************************/
-void g_db_client_put_fd(GDbClient *client)
+void g_hub_client_put_fd(GHubClient *client)
{
g_mutex_unlock(&client->sending_lock);
@@ -808,18 +921,18 @@ void g_db_client_put_fd(GDbClient *client)
* *
******************************************************************************/
-bool g_db_client_save(GDbClient *client)
+bool g_hub_client_save(GHubClient *client)
{
bool result; /* Bilan partiel à remonter */
int sent; /* Quantité de données traitées*/
- g_db_client_get_fd(client);
+ g_hub_client_get_fd(client);
sent = SSL_write(client->tls_fd, (uint32_t []) { htobe32(DBC_SAVE) }, sizeof(uint32_t));
result = (sent == sizeof(uint32_t));
- g_db_client_put_fd(client);
+ g_hub_client_put_fd(client);
return result;
@@ -839,21 +952,21 @@ bool g_db_client_save(GDbClient *client)
* *
******************************************************************************/
-bool g_db_client_set_last_active(GDbClient *client, timestamp_t timestamp)
+bool g_hub_client_set_last_active(GHubClient *client, timestamp_t timestamp)
{
bool result; /* Bilan partiel à remonter */
packed_buffer out_pbuf; /* Tampon d'émission */
init_packed_buffer(&out_pbuf);
- g_db_client_get_fd(client);
+ g_hub_client_get_fd(client);
result = extend_packed_buffer(&out_pbuf, (uint32_t []) { DBC_SET_LAST_ACTIVE }, sizeof(uint32_t), true);
if (result)
result = pack_timestamp(&timestamp, &out_pbuf);
- g_db_client_put_fd(client);
+ g_hub_client_put_fd(client);
if (result)
result = ssl_send_packed_buffer(&out_pbuf, client->tls_fd);