From fa40856e942a7e1bd1cb2729645182c1fa717468 Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Thu, 29 Aug 2019 23:43:47 +0200 Subject: Defined a new way to launch updates share servers. --- .gitignore | 1 + plugins/pychrysalide/analysis/db/Makefile.am | 5 +- plugins/pychrysalide/analysis/db/certs.c | 20 +- plugins/pychrysalide/analysis/db/client.c | 360 +++++++++ plugins/pychrysalide/analysis/db/client.h | 45 ++ plugins/pychrysalide/analysis/db/collection.c | 45 ++ plugins/pychrysalide/analysis/db/collection.h | 5 +- plugins/pychrysalide/analysis/db/constants.c | 70 ++ plugins/pychrysalide/analysis/db/constants.h | 39 + plugins/pychrysalide/analysis/db/module.c | 4 + plugins/pychrysalide/analysis/db/server.c | 331 ++++++++ plugins/pychrysalide/analysis/db/server.h | 45 ++ src/Makefile.am | 16 +- src/analysis/binary.c | 34 +- src/analysis/binary.h | 2 +- src/analysis/contents/file.c | 2 +- src/analysis/db/Makefile.am | 1 + src/analysis/db/auth.c | 705 +++++++++++++++++ src/analysis/db/auth.h | 59 ++ src/analysis/db/cdb.c | 84 +- src/analysis/db/cdb.h | 4 +- src/analysis/db/certs.c | 4 +- src/analysis/db/certs.h | 4 +- src/analysis/db/client.c | 373 +++++---- src/analysis/db/client.h | 34 +- src/analysis/db/keymgn.c | 6 +- src/analysis/db/keymgn.h | 2 + src/analysis/db/protocol.h | 2 +- src/analysis/db/server.c | 810 ++++++++++++------- src/analysis/db/server.h | 38 +- src/common/io.c | 78 +- src/common/io.h | 6 +- src/core/logs.h | 14 + src/gui/panels/history.c | 8 +- src/hub.c | 1036 +++++++++++++++++++++++++ src/main.c | 45 +- 36 files changed, 3736 insertions(+), 601 deletions(-) create mode 100644 plugins/pychrysalide/analysis/db/client.c create mode 100644 plugins/pychrysalide/analysis/db/client.h create mode 100644 plugins/pychrysalide/analysis/db/constants.c create mode 100644 plugins/pychrysalide/analysis/db/constants.h create mode 100644 plugins/pychrysalide/analysis/db/server.c create mode 100644 plugins/pychrysalide/analysis/db/server.h create mode 100644 src/analysis/db/auth.c create mode 100644 src/analysis/db/auth.h create mode 100644 src/hub.c diff --git a/.gitignore b/.gitignore index d67d2d2..9f7a214 100644 --- a/.gitignore +++ b/.gitignore @@ -68,6 +68,7 @@ resources.[ch] # Binaries src/chrysalide +src/chrysalide-hub src/csrvmng tools/d2c/d2c diff --git a/plugins/pychrysalide/analysis/db/Makefile.am b/plugins/pychrysalide/analysis/db/Makefile.am index 709f153..4bd8353 100644 --- a/plugins/pychrysalide/analysis/db/Makefile.am +++ b/plugins/pychrysalide/analysis/db/Makefile.am @@ -3,9 +3,12 @@ noinst_LTLIBRARIES = libpychrysaanalysisdb.la libpychrysaanalysisdb_la_SOURCES = \ certs.h certs.c \ + client.h client.c \ collection.h collection.c \ + constants.h constants.c \ item.h item.c \ - module.h module.c + module.h module.c \ + server.h server.c libpychrysaanalysisdb_la_LIBADD = \ items/libpychrysaanalysisdbitems.la diff --git a/plugins/pychrysalide/analysis/db/certs.c b/plugins/pychrysalide/analysis/db/certs.c index 3da3849..3d9fcc6 100644 --- a/plugins/pychrysalide/analysis/db/certs.c +++ b/plugins/pychrysalide/analysis/db/certs.c @@ -42,10 +42,10 @@ static bool py_certs_fill_x509_entries(PyObject *, x509_entries *); /* Crée un certificat de signature racine. */ -static PyObject *py_certs_make_ca(PyObject *, PyObject *); +static PyObject *py_certs_build_keys_and_ca(PyObject *, PyObject *); /* Crée un certificat pour application. */ -static PyObject *py_certs_make_request(PyObject *, PyObject *); +static PyObject *py_certs_build_keys_and_request(PyObject *, PyObject *); /* Signe un certificat pour application. */ static PyObject *py_certs_sign_cert(PyObject *, PyObject *); @@ -127,7 +127,7 @@ static bool py_certs_fill_x509_entries(PyObject *dict, x509_entries *out) * * ******************************************************************************/ -static PyObject *py_certs_make_ca(PyObject *self, PyObject *args) +static PyObject *py_certs_build_keys_and_ca(PyObject *self, PyObject *args) { PyObject *result; /* Désignation à retourner */ const char *dir; /* Répertoire de sortie */ @@ -144,7 +144,7 @@ static PyObject *py_certs_make_ca(PyObject *self, PyObject *args) status = py_certs_fill_x509_entries(dict, &entries); if (!status) return NULL; - status = make_ca(dir, label, valid, &entries); + status = build_keys_and_ca(dir, label, valid, &entries); free_x509_entries(&entries); @@ -170,7 +170,7 @@ static PyObject *py_certs_make_ca(PyObject *self, PyObject *args) * * ******************************************************************************/ -static PyObject *py_certs_make_request(PyObject *self, PyObject *args) +static PyObject *py_certs_build_keys_and_request(PyObject *self, PyObject *args) { PyObject *result; /* Désignation à retourner */ const char *dir; /* Répertoire de sortie */ @@ -186,7 +186,7 @@ static PyObject *py_certs_make_request(PyObject *self, PyObject *args) status = py_certs_fill_x509_entries(dict, &entries); if (!status) return NULL; - status = make_request(dir, label, &entries); + status = build_keys_and_request(dir, label, &entries); free_x509_entries(&entries); @@ -253,13 +253,13 @@ PyTypeObject *get_python_certs_type(void) { static PyMethodDef py_certs_methods[] = { - { "make_ca", py_certs_make_ca, + { "build_keys_and_ca", py_certs_build_keys_and_ca, METH_VARARGS | METH_STATIC, - "make_ca(dir, label, valid, entries, /)\n--\n\nCreate a certificate authority." + "build_keys_and_ca(dir, label, valid, entries, /)\n--\n\nCreate a certificate authority." }, - { "make_request", py_certs_make_request, + { "build_keys_and_request", py_certs_build_keys_and_request, METH_VARARGS | METH_STATIC, - "make_request(dir, label, entries, /)\n--\n\nCreate a certificate sign request." + "build_keys_and_request(dir, label, entries, /)\n--\n\nCreate a certificate sign request." }, { "sign_cert", py_certs_sign_cert, METH_VARARGS | METH_STATIC, diff --git a/plugins/pychrysalide/analysis/db/client.c b/plugins/pychrysalide/analysis/db/client.c new file mode 100644 index 0000000..a9ad930 --- /dev/null +++ b/plugins/pychrysalide/analysis/db/client.c @@ -0,0 +1,360 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * client.c - équivalent Python du fichier "analysis/db/client.c" + * + * Copyright (C) 2019 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "client.h" + + +#include + + +#include +#include +#include + + +#include "collection.h" +#include "../../access.h" +#include "../../helpers.h" + + + +/* Crée un nouvel objet Python de type 'HubClient'. */ +static PyObject *py_hub_client_new(PyTypeObject *, PyObject *, PyObject *); + +/* Démarre la connexion à la base de données. */ +static PyObject *py_hub_client_start(PyObject *, PyObject *); + +/* Arrête la connexion à la base de données. */ +static PyObject *py_hub_client_stop(PyObject *, PyObject *); + + + +/****************************************************************************** +* * +* Paramètres : type = type de l'objet à instancier. * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Crée un nouvel objet Python de type 'HubClient'. * +* * +* Retour : Instance Python mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_hub_client_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *result; /* Instance à retourner */ + const char *hash; /* Empreinte du binaire visé */ + PyObject *list; /* Liste Python de collections */ + int ret; /* Bilan de lecture des args. */ + Py_ssize_t length; /* Nombre d'éléments collectés */ + GList *collections; /* Liste native de collections */ + Py_ssize_t i; /* Boucle de parcours */ + PyObject *item; /* Elément de la liste Python */ + GDbCollection *collec; /* Version équivalente native */ + GHubClient *client; /* Serveur mis en place */ + +#define HUB_CLIENT_DOC \ + "HubClient provides binary updates to a given server.\n" \ + "\n" \ + "Such clients must be authenticated and communications are encrypted using TLS.\n" \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " HubClient(hash, list)" \ + "\n" \ + "Where hash is a SHA256 fingerprint of the studied binary and list is a list of" \ + " pychrysalide.analysis.db.DbCollection instances.\n" \ + "\n" \ + "This kind of list can be retrived with the" \ + " pychrysalide.analysis.LoadedBinary.collections attribute." + + ret = PyArg_ParseTuple(args, "sO", &hash, &list); + if (!ret) return NULL; + + if (!PySequence_Check(list)) + { + PyErr_SetString(PyExc_TypeError, _("The second argument must be a collection list")); + return NULL; + } + + length = PySequence_Length(list); + + collections = NULL; + + for (i = 0; i < length; i++) + { + item = PySequence_GetItem(list, i); + + ret = convert_to_db_collection(item, &collec); + + Py_DECREF(item); + + if (ret != 1) + { + delete_collections_list(&collections); + result = NULL; + goto exit; + } + + g_object_ref(G_OBJECT(collec)); + collections = g_list_append(collections, collec); + + } + + client = g_hub_client_new(hash, collections); + + if (client != NULL) + { + result = pygobject_new(G_OBJECT(client)); + g_object_unref(client); + } + else result = NULL; + + exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = serveur à manipuler. * +* args = paramètres à transmettre à l'appel natif. * +* * +* Description : Démarre la connexion à la base de données. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_hub_client_start(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à retourner */ + const char *host; /* Désignation de serveur */ + const char *port; /* Port d'écoute associé */ + bool ipv6; /* Préférence pour IPv6 ? */ + int ret; /* Bilan de lecture des args. */ + GHubClient *client; /* Version native du serveur */ + bool status; /* Bilan de l'opération */ + +#define HUB_CLIENT_START_METHOD PYTHON_METHOD_DEF \ +( \ + start, "$self, /, host=None, port='1337', ipv6=True", \ + METH_VARARGS, py_hub_client, \ + "Connect to a server for binary updates.\n" \ + "\n" \ + "host and port define the properties of the server, and ipv6" \ + " tries to establish IPv6 connections first." \ +) + + host = NULL; + port = "1337"; + ipv6 = true; + + ret = PyArg_ParseTuple(args, "|ssp", &host, &port, &ipv6); + if (!ret) return NULL; + + client = G_HUB_CLIENT(pygobject_get(self)); + + if (host == NULL) + status = g_hub_client_start_internal(client); + else + status = g_hub_client_start_remote(client, host, port, ipv6); + + result = status ? Py_True : Py_False; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = serveur à manipuler. * +* args = arguments d'appel non utilisés ici. * +* * +* Description : Arrête la connexion à la base de données. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_hub_client_stop(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à retourner */ + GHubClient *client; /* Version native du serveur */ + +#define HUB_CLIENT_STOP_METHOD PYTHON_METHOD_DEF \ +( \ + stop, "$self, /", \ + METH_NOARGS, py_hub_client, \ + "Stop the client." \ +) + + client = G_HUB_CLIENT(pygobject_get(self)); + + g_hub_client_stop(client); + + result = Py_None; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_hub_client_type(void) +{ + static PyMethodDef py_hub_client_methods[] = { + HUB_CLIENT_START_METHOD, + HUB_CLIENT_STOP_METHOD, + { NULL } + }; + + static PyGetSetDef py_hub_client_getseters[] = { + { NULL } + }; + + static PyTypeObject py_hub_client_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.db.HubClient", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = HUB_CLIENT_DOC, + + .tp_methods = py_hub_client_methods, + .tp_getset = py_hub_client_getseters, + .tp_new = py_hub_client_new, + + }; + + return &py_hub_client_type; + +} + + +/****************************************************************************** +* * +* Paramètres : module = module dont la définition est à compléter. * +* * +* Description : Prend en charge l'objet 'pychrysalide....db.HubClient'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_hub_client_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'HubClient' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_hub_client_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.analysis.db"); + + dict = PyModule_GetDict(module); + + if (!register_class_for_pygobject(dict, G_TYPE_HUB_CLIENT, type, &PyGObject_Type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en client de base de données. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_hub_client(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_hub_client_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to hub client"); + break; + + case 1: + *((GHubClient **)dst) = G_HUB_CLIENT(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/analysis/db/client.h b/plugins/pychrysalide/analysis/db/client.h new file mode 100644 index 0000000..dbeb91f --- /dev/null +++ b/plugins/pychrysalide/analysis/db/client.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * client.h - prototypes pour l'équivalent Python du fichier "analysis/db/client.h" + * + * Copyright (C) 2019 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_DB_CLIENT_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_DB_CLIENT_H + + +#include +#include + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_hub_client_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.db.HubClient'. */ +bool ensure_python_hub_client_is_registered(void); + +/* Tente de convertir en client de base de données. */ +int convert_to_hub_client(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_DB_CLIENT_H */ diff --git a/plugins/pychrysalide/analysis/db/collection.c b/plugins/pychrysalide/analysis/db/collection.c index 699c272..b7e3e0b 100644 --- a/plugins/pychrysalide/analysis/db/collection.c +++ b/plugins/pychrysalide/analysis/db/collection.c @@ -116,3 +116,48 @@ bool ensure_python_db_collection_is_registered(void) return true; } + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en collection de traitements sur binaire. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_db_collection(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_db_collection_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to DB collection"); + break; + + case 1: + *((GDbCollection **)dst) = G_DB_COLLECTION(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/analysis/db/collection.h b/plugins/pychrysalide/analysis/db/collection.h index 9fa3c8a..13ca273 100644 --- a/plugins/pychrysalide/analysis/db/collection.h +++ b/plugins/pychrysalide/analysis/db/collection.h @@ -37,6 +37,9 @@ PyTypeObject *get_python_db_collection_type(void); /* Prend en charge l'objet 'pychrysalide.analysis.db.DbCollection'. */ bool ensure_python_db_collection_is_registered(void); +/* Tente de convertir en collection de traitements sur binaire. */ +int convert_to_db_collection(PyObject *, void *); -#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_DB_COLLECTIONS_H */ + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_DB_COLLECTION_H */ diff --git a/plugins/pychrysalide/analysis/db/constants.c b/plugins/pychrysalide/analysis/db/constants.c new file mode 100644 index 0000000..9685ba6 --- /dev/null +++ b/plugins/pychrysalide/analysis/db/constants.c @@ -0,0 +1,70 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * constants.c - équivalent Python partiel du fichier "plugins/dex/dex_def.h" + * + * Copyright (C) 2018 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "constants.h" + + +#include + + +#include "../../helpers.h" + + + +/****************************************************************************** +* * +* Paramètres : type = type dont le dictionnaire est à compléter. * +* * +* Description : Définit les constantes pour les serveurs de données. * +* * +* Retour : true en cas de succès de l'opération, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool define_hub_server_constants(PyTypeObject *type) +{ + bool result; /* Bilan à retourner */ + PyObject *values; /* Groupe de valeurs à établir */ + + values = PyDict_New(); + + result = add_const_to_group(values, "FAILURE", SSS_FAILURE); + if (result) result = add_const_to_group(values, "SUCCESS", SSS_SUCCESS); + if (result) result = add_const_to_group(values, "ALREADY_RUNNING", SSS_ALREADY_RUNNING); + + if (!result) + { + Py_DECREF(values); + goto exit; + } + + result = attach_constants_group(type, false, "ServerStartStatus", values, "Status of a server start."); + + exit: + + return result; + +} diff --git a/plugins/pychrysalide/analysis/db/constants.h b/plugins/pychrysalide/analysis/db/constants.h new file mode 100644 index 0000000..a2fc49e --- /dev/null +++ b/plugins/pychrysalide/analysis/db/constants.h @@ -0,0 +1,39 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * constants.h - prototypes pour l'ajout des constantes liées aux bases de données + * + * Copyright (C) 2019 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_DB_CONSTANTS_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_DB_CONSTANTS_H + + +#include +#include + + + +/* Définit les constantes pour les serveurs de données. */ +bool define_hub_server_constants(PyTypeObject *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_DB_CONSTANTS_H */ diff --git a/plugins/pychrysalide/analysis/db/module.c b/plugins/pychrysalide/analysis/db/module.c index 33af35f..efe780f 100644 --- a/plugins/pychrysalide/analysis/db/module.c +++ b/plugins/pychrysalide/analysis/db/module.c @@ -29,8 +29,10 @@ #include "certs.h" +#include "client.h" #include "collection.h" #include "item.h" +#include "server.h" #include "items/module.h" #include "../../helpers.h" @@ -97,8 +99,10 @@ bool populate_analysis_db_module(void) result = true; if (result) result = ensure_python_certs_is_registered(); + if (result) result = ensure_python_hub_client_is_registered(); if (result) result = ensure_python_db_collection_is_registered(); if (result) result = ensure_python_db_item_is_registered(); + if (result) result = ensure_python_hub_server_is_registered(); if (result) result = populate_analysis_db_items_module(); diff --git a/plugins/pychrysalide/analysis/db/server.c b/plugins/pychrysalide/analysis/db/server.c new file mode 100644 index 0000000..cee6bf6 --- /dev/null +++ b/plugins/pychrysalide/analysis/db/server.c @@ -0,0 +1,331 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * server.c - équivalent Python du fichier "analysis/db/server.c" + * + * Copyright (C) 2019 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "server.h" + + +#include + + +#include +#include + + +#include "constants.h" +#include "../../access.h" +#include "../../helpers.h" + + + +/* Crée un nouvel objet Python de type 'HubServer'. */ +static PyObject *py_hub_server_new(PyTypeObject *, PyObject *, PyObject *); + +/* Démarre le serveur de base de données. */ +static PyObject *py_hub_server_start(PyObject *, PyObject *); + +/* Arrête le serveur de base de données. */ +static PyObject *py_hub_server_stop(PyObject *, PyObject *); + + + +/****************************************************************************** +* * +* Paramètres : type = type de l'objet à instancier. * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Crée un nouvel objet Python de type 'HubServer'. * +* * +* Retour : Instance Python mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_hub_server_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *result; /* Instance à retourner */ + const char *host; /* Désignation de serveur */ + const char *port; /* Port d'écoute associé */ + bool ipv6; /* Préférence pour IPv6 ? */ + int ret; /* Bilan de lecture des args. */ + GHubServer *server; /* Serveur mis en place */ + +#define HUB_SERVER_DOC \ + "HubServer creates a server listening for binary updates from clients.\n" \ + "\n" \ + "Such clients are authenticated and communications are encrypted using TLS.\n" \ + "\n" \ + "There are two kinds of servers:\n" \ + "* one \"local\", which aims to server one given local user account;\n" \ + "* one \"remote\", which may target several different users at the same time.\n" \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " HubServer(host=None, port='1337', ipv6=True)" \ + "\n" \ + "Where host and port define the listening properties of the server, and ipv6" \ + " tries to establish IPv6 connections first." \ + "\n" \ + "Without any parameters, a local server is created." + + host = NULL; + port = "1337"; + ipv6 = true; + + ret = PyArg_ParseTuple(args, "|ssp", &host, &port, &ipv6); + if (!ret) return NULL; + + if (host == NULL) + server = g_hub_server_new_internal(); + else + server = g_hub_server_new_remote(host, port, ipv6); + + if (server != NULL) + { + result = pygobject_new(G_OBJECT(server)); + g_object_unref(server); + } + else result = NULL; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = serveur à manipuler. * +* args = arguments d'appel non utilisés ici. * +* * +* Description : Démarre le serveur de base de données. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_hub_server_start(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à retourner */ + int backlog; /* Nombre de connexions */ + int ret; /* Bilan de lecture des args. */ + GHubServer *server; /* Version native du serveur */ + bool status; /* Bilan de l'opération */ + +#define HUB_SERVER_START_METHOD PYTHON_METHOD_DEF \ +( \ + start, "$self, /, backlog=10", \ + METH_VARARGS, py_hub_server, \ + "Run a listening server waiting for client connections." \ + "\n" \ + "The backlog argument defines the maximum length to which" \ + " the queue of pending connections may grow." \ + "\n" \ + "The returned value is a status of type" \ + " pychrysalide.analysis.db.HubServer.ServerStartStatus." \ +) + + backlog = 10; + + ret = PyArg_ParseTuple(args, "|i", &backlog); + if (!ret) return NULL; + + server = G_HUB_SERVER(pygobject_get(self)); + + status = g_hub_server_start(server, backlog, true); + + result = cast_with_constants_group(get_python_hub_server_type(), "ServerStartStatus", status); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = serveur à manipuler. * +* args = arguments d'appel non utilisés ici. * +* * +* Description : Arrête le serveur de base de données. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_hub_server_stop(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à retourner */ + GHubServer *server; /* Version native du serveur */ + +#define HUB_SERVER_STOP_METHOD PYTHON_METHOD_DEF \ +( \ + stop, "$self, /", \ + METH_NOARGS, py_hub_server, \ + "Stop the listening server." \ +) + + server = G_HUB_SERVER(pygobject_get(self)); + + g_hub_server_stop(server); + + result = Py_None; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_hub_server_type(void) +{ + static PyMethodDef py_hub_server_methods[] = { + HUB_SERVER_START_METHOD, + HUB_SERVER_STOP_METHOD, + { NULL } + }; + + static PyGetSetDef py_hub_server_getseters[] = { + { NULL } + }; + + static PyTypeObject py_hub_server_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.db.HubServer", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = HUB_SERVER_DOC, + + .tp_methods = py_hub_server_methods, + .tp_getset = py_hub_server_getseters, + .tp_new = py_hub_server_new, + + }; + + return &py_hub_server_type; + +} + + +/****************************************************************************** +* * +* Paramètres : module = module dont la définition est à compléter. * +* * +* Description : Prend en charge l'objet 'pychrysalide....db.HubServer'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_hub_server_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'HubServer' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_hub_server_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.analysis.db"); + + dict = PyModule_GetDict(module); + + if (!register_class_for_pygobject(dict, G_TYPE_HUB_SERVER, type, &PyGObject_Type)) + return false; + + if (!define_hub_server_constants(type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en serveur de base de données. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_hub_server(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_hub_server_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to hub server"); + break; + + case 1: + *((GHubServer **)dst) = G_HUB_SERVER(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/analysis/db/server.h b/plugins/pychrysalide/analysis/db/server.h new file mode 100644 index 0000000..a5dbcde --- /dev/null +++ b/plugins/pychrysalide/analysis/db/server.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * server.h - prototypes pour l'équivalent Python du fichier "analysis/db/server.h" + * + * Copyright (C) 2019 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_DB_SERVER_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_DB_SERVER_H + + +#include +#include + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_hub_server_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.db.HubServer'. */ +bool ensure_python_hub_server_is_registered(void); + +/* Tente de convertir en serveur de base de données. */ +int convert_to_hub_server(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_DB_SERVER_H */ diff --git a/src/Makefile.am b/src/Makefile.am index a547084..f1fc25c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,7 +1,7 @@ lib_LTLIBRARIES = libchrysacore.la -bin_PROGRAMS = chrysalide csrvmng +bin_PROGRAMS = chrysalide chrysalide-hub csrvmng @@ -64,6 +64,20 @@ chrysalide_LDADD = $(LIBINTL) # Gestionnaire de serveurs distants ############################################################ +EXTRA_chrysalide_hub_DEPENDENCIES = $(lib_LTLIBRARIES) + +chrysalide_hub_SOURCES = \ + hub.c + + +chrysalide_hub_LDFLAGS = $(LIBGTK_LIBS) -L.libs -lchrysacore + + + +############################################################ +# Gestionnaire de serveurs distants +############################################################ + EXTRA_csrvmng_DEPENDENCIES = $(lib_LTLIBRARIES) csrvmng_SOURCES = \ diff --git a/src/analysis/binary.c b/src/analysis/binary.c index 80d12d3..5ac8e04 100644 --- a/src/analysis/binary.c +++ b/src/analysis/binary.c @@ -72,8 +72,8 @@ struct _GLoadedBinary char *remote_host; /* Nom du serveur distant */ unsigned short remote_port; /* Port du serveur distant */ - GDbClient *local; /* Enregistrements locaux */ - GDbClient *remote; /* Enregistrements distants */ + GHubClient *local; /* Enregistrements locaux */ + GHubClient *remote; /* Enregistrements distants */ DBStorage storages[DBF_COUNT]; /* Lieux d'enregistrement */ GList *collections; /* Ensemble de modifications */ @@ -862,12 +862,12 @@ static bool g_loaded_binary_connect_internal(GLoadedBinary *binary) /* Tentative de connexion */ - binary->local = g_db_client_new(author, priv, + binary->local = g_hub_client_new(/*author, priv, g_loaded_binary_get_name(binary, false), - checksum, + */checksum, binary->collections); - result = g_db_client_start_internal(binary->local); + result = g_hub_client_start_internal(binary->local); glbcl_exit: @@ -920,12 +920,12 @@ static bool g_loaded_binary_connect_remote(GLoadedBinary *binary) /* Tentative de connexion */ - binary->remote = g_db_client_new(author, priv, + binary->remote = g_hub_client_new(/*author, priv, g_loaded_binary_get_name(binary, false), - checksum, + */checksum, binary->collections); - result = g_db_client_start_remote(binary->local, binary->remote_host, binary->remote_port); + result = g_hub_client_start_remote(binary->local, binary->remote_host, "1337", true);//binary->remote_port); if (!result) { @@ -1008,9 +1008,9 @@ bool g_loaded_binary_save_cache(const GLoadedBinary *binary) * * ******************************************************************************/ -GDbClient *g_loaded_binary_get_db_client(const GLoadedBinary *binary) +GHubClient *g_loaded_binary_get_db_client(const GLoadedBinary *binary) { - GDbClient *result; /* Instance à retourner */ + GHubClient *result; /* Instance à retourner */ result = binary->local; @@ -1106,7 +1106,7 @@ bool _g_loaded_binary_add_to_collection(GLoadedBinary *binary, GDbItem *item, bo DBFeatures feature; /* Domaine de fonctionnalité */ GDbCollection *collec; /* Collection visée au final */ DBStorage storage; /* Forme d'enregistrement */ - GDbClient *client; /* Liaison à utiliser */ + GHubClient *client; /* Liaison à utiliser */ packed_buffer out_pbuf; /* Tampon d'émission */ int fd; /* Identifiant du canal de com.*/ @@ -1134,11 +1134,11 @@ bool _g_loaded_binary_add_to_collection(GLoadedBinary *binary, GDbItem *item, bo init_packed_buffer(&out_pbuf); - fd = g_db_client_get_fd(client); + fd = g_hub_client_get_fd(client); result = g_db_collection_pack(collec, &out_pbuf, DBA_ADD_ITEM, item); - g_db_client_put_fd(client); + g_hub_client_put_fd(client); if (result) result = send_packed_buffer(&out_pbuf, fd); @@ -1175,7 +1175,7 @@ bool _g_loaded_binary_remove_from_collection(GLoadedBinary *binary, DBFeatures f bool result; /* Bilan à faire remonter */ GDbCollection *collec; /* Collection visée au final */ DBStorage storage; /* Forme d'enregistrement */ - GDbClient *client; /* Liaison à utiliser */ + GHubClient *client; /* Liaison à utiliser */ packed_buffer out_pbuf; /* Tampon d'émission */ int fd; /* Identifiant du canal de com.*/ @@ -1201,11 +1201,11 @@ bool _g_loaded_binary_remove_from_collection(GLoadedBinary *binary, DBFeatures f init_packed_buffer(&out_pbuf); - fd = g_db_client_get_fd(client); + fd = g_hub_client_get_fd(client); result = g_db_collection_pack(collec, &out_pbuf, DBA_REM_ITEM, item); - g_db_client_put_fd(client); + g_hub_client_put_fd(client); if (result) result = send_packed_buffer(&out_pbuf, fd); @@ -1629,7 +1629,7 @@ static bool g_loaded_binary_save(GLoadedBinary *binary, xmlDoc *xdoc, xmlXPathCo /* Sauvegarde côté serveur */ if (result) - g_db_client_save(binary->local); + g_hub_client_save(binary->local); return result; diff --git a/src/analysis/binary.h b/src/analysis/binary.h index ad4f568..2c57283 100644 --- a/src/analysis/binary.h +++ b/src/analysis/binary.h @@ -117,7 +117,7 @@ bool g_loaded_binary_save_cache(const GLoadedBinary *); /* Fournit le client assurant la liaison avec un serveur. */ -GDbClient *g_loaded_binary_get_db_client(const GLoadedBinary *); +GHubClient *g_loaded_binary_get_db_client(const GLoadedBinary *); /* Fournit l'ensemble des collections utilisées par un binaire. */ GDbCollection **g_loaded_binary_get_all_collections(const GLoadedBinary *, size_t *); diff --git a/src/analysis/contents/file.c b/src/analysis/contents/file.c index 951828f..5509455 100644 --- a/src/analysis/contents/file.c +++ b/src/analysis/contents/file.c @@ -294,7 +294,7 @@ static void g_file_content_finalize(GFileContent *content) GBinContent *g_file_content_new(const char *filename) { - GFileContent *result; /* Structure à retourner */ + GFileContent *result; /* Structure à retourner */ int fd; /* Descripteur du fichier */ struct stat info; /* Informations sur le fichier */ int ret; /* Bilan d'un appel */ diff --git a/src/analysis/db/Makefile.am b/src/analysis/db/Makefile.am index 53d7c36..2f7cddd 100644 --- a/src/analysis/db/Makefile.am +++ b/src/analysis/db/Makefile.am @@ -3,6 +3,7 @@ noinst_LTLIBRARIES = libanalysisdb.la libanalysiskeys.la libanalysisdb_la_SOURCES = \ + auth.h auth.c \ cdb.h cdb.c \ certs.h certs.c \ client.h client.c \ diff --git a/src/analysis/db/auth.c b/src/analysis/db/auth.c new file mode 100644 index 0000000..af51af6 --- /dev/null +++ b/src/analysis/db/auth.c @@ -0,0 +1,705 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * auth.c - mise en place et gestion des autorisations pour les partages + * + * Copyright (C) 2019 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 . + */ + + +#include "auth.h" + + +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "../../common/extstr.h" +#include "../../common/io.h" +#include "../../common/pathname.h" +#include "../../common/xdg.h" +#include "../../core/logs.h" + + + +/* Fournit le répertoire d'enregistrement des certificats. */ +static char *get_cert_storage_directory(const char *, const char *, const char *); + +/* Calcule l'empreinte d'un fichier de demande de signature. */ +static char *compute_csr_fingerprint(const char *); + + + +/****************************************************************************** +* * +* Paramètres : addr = adresse UNIX constituée. [OUT] * +* * +* Description : Met en place un canal UNIX pour un serveur interne. * +* * +* Retour : Bilan de la définition. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool build_internal_server_socket(struct sockaddr_un *addr) +{ + bool result; /* Bilan à retourner */ + char *suffix; /* Fin de la destination */ + char *path; /* Chemin d'accès au canal */ + int ret; /* Bilan intermédiaire */ + size_t length; /* Taille du chemin complet */ + + suffix = strdup("chrysalide"); + suffix = stradd(suffix, G_DIR_SEPARATOR_S); + suffix = stradd(suffix, "internal-server"); + + path = get_xdg_config_dir(suffix); + + free(suffix); + + ret = ensure_path_exists(path); + if (ret != 0) goto mts_exit; + + length = strlen(path) + 1; + +#ifndef UNIX_PATH_MAX +# define UNIX_PATH_MAX 108 +#endif + + if (length > UNIX_PATH_MAX) + { + log_variadic_message(LMT_ERROR, + _("Impossible to use '%s' as UNIX socket path: string is too long ! (%zu vs %u)\n"), + path, length, UNIX_PATH_MAX); + goto mts_exit; + } + + memset(addr, 0, sizeof(struct sockaddr_un)); + + addr->sun_family = AF_UNIX; + strncpy(addr->sun_path, path, UNIX_PATH_MAX - 1); + + result = true; + + mts_exit: + + free(path); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : type = type de certificat à gérer. * +* host = dénomination du serveur visé ou NULL. * +* port = port d'écoute ou NULL. * +* sub = éventuelle sous-partie ou NULL. * +* * +* Description : Fournit le répertoire de travail pour les données d'analyse. * +* * +* Retour : Définition d'emplacement à libérer de la mémoire après usage.* +* * +* Remarques : - * +* * +******************************************************************************/ + +char *get_db_working_directory(const char *type, const char *host, const char *port, const char *sub) +{ + char *result; /* Chemin à retourner */ + char *suffix; /* Fin de la destination */ + + suffix = strdup("chrysalide"); + suffix = stradd(suffix, G_DIR_SEPARATOR_S); + suffix = stradd(suffix, type); + suffix = stradd(suffix, G_DIR_SEPARATOR_S); + + if (host != NULL) + { + suffix = stradd(suffix, host); + + if (port == NULL) + suffix = stradd(suffix, G_DIR_SEPARATOR_S); + + } + + if (port != NULL) + { + suffix = stradd(suffix, "-"); + suffix = stradd(suffix, port); + suffix = stradd(suffix, G_DIR_SEPARATOR_S); + } + + if (sub != NULL) + { + suffix = stradd(suffix, sub); + suffix = stradd(suffix, G_DIR_SEPARATOR_S); + } + + result = get_xdg_config_dir(suffix); + + free(suffix); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : outdir = répertoire de sortie pour les nouveaux fichiers. * +* host = dénomination du serveur visé. * +* port = port d'écoute ou NULL. * +* * +* Description : Fournit le répertoire d'enregistrement des certificats. * +* * +* Retour : Définition d'emplacement à libérer de la mémoire après usage.* +* * +* Remarques : - * +* * +******************************************************************************/ + +static char *get_cert_storage_directory(const char *outdir, const char *host, const char *port) +{ + char *result; /* Chemin à retourner */ + + result = strdup(outdir); + + if (!endswith(result, G_DIR_SEPARATOR_S)) + result = stradd(result, G_DIR_SEPARATOR_S); + + result = stradd(result, host); + + if (port == NULL) + result = stradd(result, G_DIR_SEPARATOR_S); + + else + { + result = stradd(result, "-"); + result = stradd(result, port); + result = stradd(result, G_DIR_SEPARATOR_S); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : valid = durée de validité des certificats. * +* entries = éléments d'identité à utiliser pour l'opération. * +* * +* Description : Etablit une base pour l'identité de l'utilisateur. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool setup_client_identity(unsigned long valid, x509_entries *entries) +{ + bool result; /* Bilan de l'opération */ + char *working; /* Répertoire pour le client */ + uid_t uid; /* Identifiant d'utilisateur */ + struct passwd *pw; /* Indications sur l'usager */ + + working = get_db_working_directory("clients", NULL, NULL, NULL); + + result = mkpath(working); + + if (result) + { + if (entries->common_name == NULL) + { + uid = geteuid(); + pw = getpwuid(uid); + + if (pw != NULL) + { + log_variadic_message(LMT_WARNING, + _("Replaced the empty identity common name with '%s'"), + pw->pw_name); + + entries->common_name = strdup(pw->pw_name); + + } + + } + + result = build_keys_and_request(working, "client", entries); + + } + + free(working); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : host = désignation du serveur à contacter. * +* port = port d'écoute correspondant. * +* valid = durée de validité des certificats. * +* entries = éléments d'identité à utiliser pour l'opération. * +* * +* Description : Etablit une base pour l'identité d'un serveur. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool setup_server_identity(const char *host, const char *port, unsigned long valid, x509_entries *entries) +{ + bool result; /* Bilan de l'opération */ + char *working; /* Répertoire pour le serveur */ + char *csr; /* Requête de signature */ + char *old; /* Conservation de l'origine */ + char *new; /* Nouvelle désignation */ + char *cacert; /* Certificat d'autorité */ + char *cakey; /* Clef de cette autorité */ + char *cert; /* Certificat signé en sortie */ + + if (host == NULL) + { + host = "standalone"; + port = NULL; + } + + else if (strcmp(host, "standalone") != 0 && port == NULL) + port = "1337"; + + working = get_db_working_directory("servers", host, port, NULL); + + result = mkpath(working); + + if (result) + { + if (entries->common_name == NULL) + { + log_variadic_message(LMT_WARNING, + _("Replaced the empty identity common name with '%s'"), + host); + + entries->common_name = strdup(host); + + } + + old = entries->common_name; + + new = strdup(old); + new = stradd(new, " CA"); + + entries->common_name = new; + + result = build_keys_and_ca(working, "ca", valid, entries); + + entries->common_name = old; + + free(new); + + if (result) + result = build_keys_and_request(working, "server", entries); + + if (result) + { + csr = build_absolute_filename(working, "server-csr.pem"); + cacert = build_absolute_filename(working, "ca-cert.pem"); + cakey = build_absolute_filename(working, "ca-key.pem"); + cert = build_absolute_filename(working, "server-cert.pem"); + + result = sign_cert(csr, cacert, cakey, cert, valid); + + free(csr); + free(cacert); + free(cakey); + free(cert); + + } + + } + + free(working); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : csr = fichier contenant le certificat à signer. * +* * +* Description : Calcule l'empreinte d'un fichier de demande de signature. * +* * +* Retour : Empreinte calculée ou NULL en cas d'erreur. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static char *compute_csr_fingerprint(const char *csr) +{ + char *result; /* Empreinte à retourner */ + int fd; /* Descripteur du fichier */ + struct stat info; /* Informations sur le fichier */ + int ret; /* Bilan d'un appel */ + void *data; /* Quantité de données traitées*/ + bool status; /* Bilan de la lecture */ + + result = NULL; + + fd = open(csr, O_RDONLY); + if (fd == -1) + { + LOG_ERROR_N("open"); + goto exit; + } + + ret = fstat(fd, &info); + if (ret == -1) + { + LOG_ERROR_N("fstat"); + goto done; + } + + data = malloc(info.st_size); + + status = safe_read(fd, data, info.st_size); + + if (status) + result = g_compute_checksum_for_data(G_CHECKSUM_SHA256, data, info.st_size); + + free(data); + + done: + + close(fd); + + exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : host = désignation du serveur à contacter. * +* port = port d'écoute correspondant. * +* valid = durée de validité des certificats. * +* csr = fichier contenant le certificat à signer. * +* outdir = répertoire de sortie pour les nouveaux fichiers. * +* * +* Description : Ajoute un certificat dans les utilisateurs d'un serveur. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool add_client_to_server(const char *host, const char *port, unsigned long valid, const char *csr, const char *outdir) +{ + bool result; /* Bilan de l'opération */ + char *hash; /* Empreinte de la requête */ + char *working; /* Répertoire pour le serveur */ + char *cacert; /* Certificat d'autorité */ + char *cakey; /* Clef de cette autorité */ + char *storage; /* Répertoire de stockage */ + char *dest; /* Destination d'une copie */ + + result = false; + + if (host == NULL) + { + host = "standalone"; + port = NULL; + } + + else if (strcmp(host, "standalone") != 0 && port == NULL) + port = "1337"; + + hash = compute_csr_fingerprint(csr); + if (hash == NULL) goto exit; + + working = get_db_working_directory("servers", host, port, "authorized"); + + result = mkpath(working); + + if (result) + { + hash = strprep(hash, working); + hash = stradd(hash, "-cert.pem"); + + free(working); + + working = get_db_working_directory("servers", host, port, NULL); + + cacert = build_absolute_filename(working, "ca-cert.pem"); + cakey = build_absolute_filename(working, "ca-key.pem"); + + result = sign_cert(csr, cacert, cakey, hash, valid); + + if (result) + { + storage = get_cert_storage_directory(outdir, host, port); + + result = mkpath(storage); + + if (result) + { + dest = build_absolute_filename(storage, "ca-cert.pem"); + + result = copy_file(dest, cacert); + + free(dest); + + } + + if (result) + { + dest = build_absolute_filename(storage, "client-cert.pem"); + + result = copy_file(dest, hash); + + free(dest); + + } + + free(storage); + + } + + free(cacert); + free(cakey); + + free(hash); + + } + + free(working); + + exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Assure la présence d'unenvironnement pour serveur interne. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_internal_connections_setup(void) +{ + bool result; /* Bilan à retourner */ + unsigned long valid; /* Durée de validité */ + char *filename; /* Fichier devant être présent */ + int ret; /* Bilan d'une validation */ + x509_entries identity; /* Nouvelle identité à pousser */ + bool status; /* Bilan intermédiaire */ + char *csr; /* Fichier de requête */ + char *outdir; /* Répertoire de sortie */ + + result = false; + + valid = 3 * 365 * 24 * 60 * 60; + + /* Teste la présence d'une identitié pour le client */ + + filename = get_db_working_directory("clients", NULL, NULL, NULL); + filename = stradd(filename, "client-csr.pem"); + + ret = access(filename, R_OK); + + if (ret != 0) + { + memset(&identity, 0, sizeof(identity)); + + status = setup_client_identity(valid, &identity); + + free_x509_entries(&identity); + + if (status) + ret = access(filename, R_OK); + else + ret = -1; + + } + + free(filename); + + if (ret != 0) + goto done; + + /* Teste la présence d'une identitié pour le serveur interne */ + + filename = get_db_working_directory("servers", "standalone", NULL, NULL); + filename = stradd(filename, "server-csr.pem"); + + ret = access(filename, R_OK); + + if (ret != 0) + { + memset(&identity, 0, sizeof(identity)); + + status = setup_server_identity("standalone", NULL, valid, &identity); + + free_x509_entries(&identity); + + if (status) + ret = access(filename, R_OK); + else + ret = -1; + + } + + free(filename); + + if (ret != 0) + goto done; + + /* Teste la présence d'une autorisation pour l'accès à ce serveur */ + + filename = get_db_working_directory("clients", "standalone", NULL, NULL); + filename = stradd(filename, "client-cert.pem"); + + ret = access(filename, R_OK); + + if (ret != 0) + { + csr = get_db_working_directory("clients", NULL, NULL, NULL); + csr = stradd(csr, "client-csr.pem"); + + outdir = get_db_working_directory("clients", NULL, NULL, NULL); + + status = add_client_to_server("standalone", NULL, valid, csr, outdir); + + free(outdir); + free(csr); + + if (status) + ret = access(filename, R_OK); + else + ret = -1; + + } + + free(filename); + + if (ret != 0) + goto done; + + result = true; + + done: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Lance un serveur interne si besoin est. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool launch_internal_server(void) +{ + bool result; /* Bilan à retourner */ + pid_t child; /* Identifiant de processus */ + const char *prgm; /* Programme à exécuter */ + int wstatus; /* Etat du serveur lancé */ + pid_t ret; /* Bilan d'un appel */ + + char * const argv[] = { + "chrysalide-hub", + "run", + NULL + }; + + child = fork(); + + switch (child) + { + case -1: + result = false; + LOG_ERROR_N("fork"); + break; + + case 0: +#ifndef DISCARD_LOCAL + prgm = PACKAGE_SOURCE_DIR "/src/chrysalide-hub"; +#else + prgm = "chrysalide-hub"; +#endif + + execvp(prgm, argv); + + LOG_ERROR_N("execvp"); + exit(EXIT_FAILURE); + break; + + default: + + ret = waitpid(child, &wstatus, 0); + + if (ret == -1) + { + result = false; + LOG_ERROR_N("waitpid"); + } + + else + result = (WEXITSTATUS(wstatus) == EXIT_SUCCESS); + + break; + + } + + return result; + +} diff --git a/src/analysis/db/auth.h b/src/analysis/db/auth.h new file mode 100644 index 0000000..4db7af7 --- /dev/null +++ b/src/analysis/db/auth.h @@ -0,0 +1,59 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * auth.h - prototypes pour la mise en place et gestion des autorisations pour les partages + * + * Copyright (C) 2019 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 . + */ + + +#ifndef _ANALYSIS_DB_AUTH_H +#define _ANALYSIS_DB_AUTH_H + + +#include +#include + + +#include "certs.h" + + + +/* Met en place un canal UNIX pour un serveur interne. */ +bool build_internal_server_socket(struct sockaddr_un *); + +/* Fournit le répertoire de travail pour les données d'analyse. */ +char *get_db_working_directory(const char *, const char *, const char *, const char *); + +/* Etablit une base pour l'identité de l'utilisateur. */ +bool setup_client_identity(unsigned long, x509_entries *); + +/* Etablit une base pour l'identité d'un serveur. */ +bool setup_server_identity(const char *, const char *, unsigned long, x509_entries *); + +/* Ajoute un certificat dans les utilisateurs d'un serveur. */ +bool add_client_to_server(const char *, const char *, unsigned long, const char *, const char *); + +/* Assure la présence d'unenvironnement pour serveur interne. */ +bool ensure_internal_connections_setup(void); + +/* Lance un serveur interne si besoin est. */ +bool launch_internal_server(void); + + + +#endif /* _ANALYSIS_DB_AUTH_H */ diff --git a/src/analysis/db/cdb.c b/src/analysis/db/cdb.c index c2855f7..74e8501 100644 --- a/src/analysis/db/cdb.c +++ b/src/analysis/db/cdb.c @@ -51,7 +51,6 @@ #include "../../common/xml.h" #include "../../core/collections.h" #include "../../core/logs.h" -#include "../../core/params.h" @@ -59,7 +58,7 @@ typedef struct _cdb_client { SSL *ssl_fd; /* Canal de communication */ - rle_string user; /* Utilisateur à l'autre bout */ + char *user; /* Utilisateur à l'autre bout */ uint64_t last_time; /* Date de dernier envoi */ @@ -125,7 +124,7 @@ static bool g_cdb_archive_read(GCdbArchive *); /* Crée la description XML correspondant à l'archive. */ -static bool g_cdb_archive_create_xml_desc(GCdbArchive *, const rle_string *); +static bool g_cdb_archive_create_xml_desc(GCdbArchive *); /* Vérifie la conformité d'une description XML avec le serveur. */ static bool g_cdb_archive_check_xml_version(const GCdbArchive *); @@ -263,7 +262,7 @@ static void g_cdb_archive_finalize(GCdbArchive *archive) if (archive->xml_desc != NULL) { ret = unlink(archive->xml_desc); - if (ret != 0) perror("unlink"); + if (ret != 0) LOG_ERROR_N("unlink"); free(archive->xml_desc); @@ -272,7 +271,7 @@ static void g_cdb_archive_finalize(GCdbArchive *archive) if (archive->sql_db != NULL) { ret = unlink(archive->sql_db); - if (ret != 0) perror("unlink"); + if (ret != 0) LOG_ERROR_N("unlink"); free(archive->sql_db); @@ -290,8 +289,8 @@ static void g_cdb_archive_finalize(GCdbArchive *archive) /****************************************************************************** * * * Paramètres : basedir = répertoire de stockage des enregistrements. * +* tmpdir = répertoire de travail temporaire. * * hash = empreinte du binaire à représenter. * -* user = désignation d'un éventuel nouveau créateur. * * error = indication éventuelle en cas d'échec. [OUT] * * * * Description : Définit ou ouvre une archive d'éléments utilisateur. * @@ -303,11 +302,9 @@ static void g_cdb_archive_finalize(GCdbArchive *archive) * * ******************************************************************************/ -GCdbArchive *g_cdb_archive_new(const char *basedir, const rle_string *hash, const rle_string *user, DBError *error) +GCdbArchive *g_cdb_archive_new(const char *basedir, const char *tmpdir, const rle_string *hash, DBError *error) { GCdbArchive *result; /* Adresse à retourner */ - const char *tmpdir; /* Répertoire d'accueil */ - bool status; /* Bilan d'un consultation */ int ret; /* Retour d'un appel */ struct stat finfo; /* Information sur l'archive */ @@ -318,7 +315,6 @@ GCdbArchive *g_cdb_archive_new(const char *basedir, const rle_string *hash, cons /* Chemin de l'archive */ result->filename = strdup(basedir); - result->filename = stradd(result->filename, G_DIR_SEPARATOR_S); result->filename = stradd(result->filename, hash->data); result->filename = stradd(result->filename, ".cdb.tar.xz"); @@ -327,8 +323,8 @@ GCdbArchive *g_cdb_archive_new(const char *basedir, const rle_string *hash, cons /* Chemin des enregistrements temporaires */ - status = g_generic_config_get_value(get_main_configuration(), MPK_TMPDIR, &tmpdir); - if (!status) goto gcan_no_tmp; + if (!mkpath(tmpdir)) + goto gcan_error; ret = asprintf(&result->xml_desc, "%s" G_DIR_SEPARATOR_S "%s_desc.xml", tmpdir, result->hash.data); if (ret == -1) goto gcan_no_tmp; @@ -348,7 +344,7 @@ GCdbArchive *g_cdb_archive_new(const char *basedir, const rle_string *hash, cons /* Le soucis ne vient pas de l'absence du fichier... */ if (errno != ENOENT) goto gcan_error; - g_cdb_archive_create_xml_desc(result, user); + g_cdb_archive_create_xml_desc(result); g_cdb_archive_create_db(result); *error = g_cdb_archive_write(result); @@ -573,7 +569,6 @@ int g_cdb_archive_compare_hash(const GCdbArchive *archive, const rle_string *has /****************************************************************************** * * * Paramètres : archive = archive à constituer. * -* user = désignation d'un éventuel nouveau créateur. * * * * Description : Crée la description XML correspondant à l'archive. * * * @@ -583,34 +578,38 @@ int g_cdb_archive_compare_hash(const GCdbArchive *archive, const rle_string *has * * ******************************************************************************/ -static bool g_cdb_archive_create_xml_desc(GCdbArchive *archive, const rle_string *user) +static bool g_cdb_archive_create_xml_desc(GCdbArchive *archive) { bool result; /* Bilan à retourner */ timestamp_t timestamp; /* Date de création */ char tmp[sizeof(XSTR(UINT64_MAX))]; /* Stockage temporaire */ result = create_new_xml_file(&archive->xdoc, &archive->context); - if (!result) return false; - result &= add_content_to_node(archive->xdoc, archive->context, - "/ChrysalideBinary/Version", PACKAGE_VERSION); + if (result) + result = add_content_to_node(archive->xdoc, archive->context, + "/ChrysalideBinary/Version", PACKAGE_VERSION); - result &= add_content_to_node(archive->xdoc, archive->context, - "/ChrysalideBinary/Protocol", XSTR(CDB_PROTOCOL_VERSION)); + if (result) + result = add_content_to_node(archive->xdoc, archive->context, + "/ChrysalideBinary/Protocol", XSTR(CDB_PROTOCOL_VERSION)); - result &= add_content_to_node(archive->xdoc, archive->context, - "/ChrysalideBinary/Hash", archive->hash.data); + if (result) + result = add_content_to_node(archive->xdoc, archive->context, + "/ChrysalideBinary/Hash", archive->hash.data); - result &= add_content_to_node(archive->xdoc, archive->context, - "/ChrysalideBinary/Creation/Author", user->data); + if (result) + { + init_timestamp(×tamp); + snprintf(tmp, sizeof(tmp), "%" PRIu64, timestamp); - init_timestamp(×tamp); - snprintf(tmp, sizeof(tmp), "%" PRIu64, timestamp); + result = add_content_to_node(archive->xdoc, archive->context, + "/ChrysalideBinary/CreationDate", tmp); - result &= add_content_to_node(archive->xdoc, archive->context, - "/ChrysalideBinary/Creation/Date", tmp); + } - save_xml_file(archive->xdoc, archive->xml_desc); + if (result) + result = save_xml_file(archive->xdoc, archive->xml_desc); return result; @@ -863,7 +862,7 @@ static void *g_cdb_archive_process(GCdbArchive *archive) { if (errno == EINTR) continue; - perror("poll"); + LOG_ERROR_N("poll"); break; } @@ -874,7 +873,15 @@ static void *g_cdb_archive_process(GCdbArchive *archive) { /* Le canal est fermé, une sortie doit être demandée... */ if (fds[i].revents & POLLNVAL) - goto gcap_closed_exchange; + 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[i].revents & (POLLHUP | POLLRDHUP)) + goto closed_exchange; /* Données présentes en entrée */ if (fds[i].revents & (POLLIN | POLLPRI)) @@ -979,7 +986,7 @@ static void *g_cdb_archive_process(GCdbArchive *archive) exit_packed_buffer(&in_pbuf); - gcap_closed_exchange: + closed_exchange: g_cdb_archive_remove_client(archive, i); @@ -1012,7 +1019,6 @@ static void *g_cdb_archive_process(GCdbArchive *archive) * * * Paramètres : archive = archive à connecter avec un utilisateur. * * fd = canal de communication réseau ouvert. * -* user = désignation de l'utilisateur associé. * * * * Description : Associe un nouvel utilisateur à l'archive. * * * @@ -1022,8 +1028,9 @@ static void *g_cdb_archive_process(GCdbArchive *archive) * * ******************************************************************************/ -void g_cdb_archive_add_client(GCdbArchive *archive, SSL *fd, const rle_string *user) +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 */ /** @@ -1051,7 +1058,12 @@ void g_cdb_archive_add_client(GCdbArchive *archive, SSL *fd, const rle_string *u archive->clients = realloc(archive->clients, ++archive->count * sizeof(cdb_client)); archive->clients[archive->count - 1].ssl_fd = fd; - dup_into_rle_string(&archive->clients[archive->count - 1].user, get_rle_string(user)); + + 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 */ @@ -1099,7 +1111,7 @@ static void g_cdb_archive_remove_client(GCdbArchive *archive, size_t index) g_mutex_lock(&archive->clients_access); SSL_free(client->ssl_fd); - exit_rle_string(&client->user); + free(client->user); if ((index + 1) < archive->count) memmove(&archive->clients[index], &archive->clients[index + 1], diff --git a/src/analysis/db/cdb.h b/src/analysis/db/cdb.h index 601b10f..8d4a86b 100644 --- a/src/analysis/db/cdb.h +++ b/src/analysis/db/cdb.h @@ -54,7 +54,7 @@ typedef struct _GCdbArchiveClass GCdbArchiveClass; GType g_cdb_archive_get_type(void); /* Prépare un client pour une connexion à une BD. */ -GCdbArchive *g_cdb_archive_new(const char *, const rle_string *, const rle_string *, DBError *); +GCdbArchive *g_cdb_archive_new(const char *, const char *, const rle_string *, DBError *); /* Enregistre une archive avec tous les éléments à conserver. */ DBError g_cdb_archive_write(const GCdbArchive *); @@ -67,7 +67,7 @@ int g_cdb_archive_compare_hash(const GCdbArchive *, const rle_string *); /* Associe un nouvel utilisateur à l'archive. */ -void g_cdb_archive_add_client(GCdbArchive *, SSL *, const rle_string *); +void g_cdb_archive_add_client(GCdbArchive *, SSL *); diff --git a/src/analysis/db/certs.c b/src/analysis/db/certs.c index 41a40b7..a333d9a 100644 --- a/src/analysis/db/certs.c +++ b/src/analysis/db/certs.c @@ -252,7 +252,7 @@ static RSA *generate_rsa_key(unsigned int bits, unsigned long e) * * ******************************************************************************/ -bool make_ca(const char *dir, const char *label, unsigned long valid, const x509_entries *entries) +bool build_keys_and_ca(const char *dir, const char *label, unsigned long valid, const x509_entries *entries) { RSA *rsa; /* Clef RSA pour le certificat */ EVP_PKEY *pk; /* Enveloppe pour clef publique*/ @@ -455,7 +455,7 @@ static bool add_extension_to_req(STACK_OF(X509_EXTENSION) *sk, int nid, /*const * * ******************************************************************************/ -bool make_request(const char *dir, const char *label, const x509_entries *entries) +bool build_keys_and_request(const char *dir, const char *label, const x509_entries *entries) { RSA *rsa; /* Clef RSA pour le certificat */ EVP_PKEY *pk; /* Enveloppe pour clef publique*/ diff --git a/src/analysis/db/certs.h b/src/analysis/db/certs.h index 31da82f..132cd7f 100644 --- a/src/analysis/db/certs.h +++ b/src/analysis/db/certs.h @@ -49,10 +49,10 @@ bool are_x509_entries_empty(const x509_entries *); void free_x509_entries(x509_entries *); /* Crée un certificat de signature racine. */ -bool make_ca(const char *, const char *, unsigned long, const x509_entries *); +bool build_keys_and_ca(const char *, const char *, unsigned long, const x509_entries *); /* Crée un certificat pour application. */ -bool make_request(const char *, const char *, const x509_entries *); +bool build_keys_and_request(const char *, const char *, const x509_entries *); /* Signe un certificat pour application. */ bool sign_cert(const char *, const char *, const char *, const char *, unsigned long); 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 -#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(×tamp, &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); diff --git a/src/analysis/db/client.h b/src/analysis/db/client.h index 23b85f8..66ca6ab 100644 --- a/src/analysis/db/client.h +++ b/src/analysis/db/client.h @@ -33,47 +33,47 @@ -#define G_TYPE_DB_CLIENT g_db_client_get_type() -#define G_DB_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_DB_CLIENT, GDbClient)) -#define G_IS_DB_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_DB_CLIENT)) -#define G_DB_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_DB_CLIENT, GDbClientClass)) -#define G_IS_DB_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_DB_CLIENT)) -#define G_DB_CLIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_DB_CLIENT, GDbClientClass)) +#define G_TYPE_HUB_CLIENT g_hub_client_get_type() +#define G_HUB_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_HUB_CLIENT, GHubClient)) +#define G_IS_HUB_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_HUB_CLIENT)) +#define G_HUB_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_HUB_CLIENT, GHubClientClass)) +#define G_IS_HUB_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_HUB_CLIENT)) +#define G_HUB_CLIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_HUB_CLIENT, GHubClientClass)) /* Description de client à l'écoute (instance) */ -typedef struct _GDbClient GDbClient; +typedef struct _GHubClient GHubClient; /* Description de client à l'écoute (classe) */ -typedef struct _GDbClientClass GDbClientClass; +typedef struct _GHubClientClass GHubClientClass; /* Indique le type défini pour une description de client à l'écoute. */ -GType g_db_client_get_type(void); +GType g_hub_client_get_type(void); /* Prépare un client pour une connexion à une BD. */ -GDbClient *g_db_client_new(char *, char *, const char *, const char *, GList *); +GHubClient *g_hub_client_new(const char *, GList *); /* Démarre la connexion à la base de données interne. */ -bool g_db_client_start_internal(GDbClient *); +bool g_hub_client_start_internal(GHubClient *); /* Démarre la connexion à la base de données distante. */ -bool g_db_client_start_remote(GDbClient *, const char *, unsigned short); +bool g_hub_client_start_remote(GHubClient *, const char *, const char *, bool); /* Arrête la connexion à la base de données. */ -void g_db_client_stop(GDbClient *); +void g_hub_client_stop(GHubClient *); /* Identifie le canal de communication pour envois au serveur. */ -int g_db_client_get_fd(GDbClient *); +int g_hub_client_get_fd(GHubClient *); /* Marque le canal de communication comme disponible. */ -void g_db_client_put_fd(GDbClient *); +void g_hub_client_put_fd(GHubClient *); /* Effectue une demande de sauvegarde de l'état courant. */ -bool g_db_client_save(GDbClient *); +bool g_hub_client_save(GHubClient *); /* Active les éléments en amont d'un horodatage donné. */ -bool g_db_client_set_last_active(GDbClient *, timestamp_t); +bool g_hub_client_set_last_active(GHubClient *, timestamp_t); diff --git a/src/analysis/db/keymgn.c b/src/analysis/db/keymgn.c index 4334896..d2abd7c 100644 --- a/src/analysis/db/keymgn.c +++ b/src/analysis/db/keymgn.c @@ -329,10 +329,10 @@ bool register_server_cert(const char *name, const x509_entries *entries) if (!result) goto rsc_quick_exit; - result = make_ca(working, "ca", valid, entries); + result = build_keys_and_ca(working, "ca", valid, entries); if (!result) goto rsc_quick_exit; - result = make_request(working, "server", entries); + result = build_keys_and_request(working, "server", entries); if (!result) goto rsc_quick_exit; csr = build_absolute_filename(working, "server-csr.pem"); @@ -384,7 +384,7 @@ bool make_client_sign_request(const char *name, const x509_entries *entries) result = mkpath(working); if (result) - result = make_request(working, "client", entries); + result = build_keys_and_request(working, "client", entries); if (result) store_identity(entries, true); diff --git a/src/analysis/db/keymgn.h b/src/analysis/db/keymgn.h index df4f1f5..24ada61 100644 --- a/src/analysis/db/keymgn.h +++ b/src/analysis/db/keymgn.h @@ -31,6 +31,8 @@ #include "certs.h" +#include "auth.h" + /* Charge en mémoire la définition de l'identité courante. */ void load_identity(bool, x509_entries *); diff --git a/src/analysis/db/protocol.h b/src/analysis/db/protocol.h index 311a691..1c03d62 100644 --- a/src/analysis/db/protocol.h +++ b/src/analysis/db/protocol.h @@ -29,7 +29,7 @@ /** * Version de la définition courante du protocole. */ -#define CDB_PROTOCOL_VERSION 0xc0de0003 +#define CDB_PROTOCOL_VERSION 0xc0de0004 diff --git a/src/analysis/db/server.c b/src/analysis/db/server.c index deb54e9..bd221d7 100644 --- a/src/analysis/db/server.c +++ b/src/analysis/db/server.c @@ -25,6 +25,8 @@ #include +#include +#include #include #include #include @@ -33,55 +35,50 @@ #include #include #include +#include #include +#include "auth.h" #include "cdb.h" -#include "keymgn.h" #include "protocol.h" #include "misc/rlestr.h" +#include "../../common/extstr.h" #include "../../common/io.h" #include "../../common/pathname.h" #include "../../common/xdg.h" #include "../../core/logs.h" -#include "../../core/params.h" -/* Utilisateur enregistré */ -typedef struct _registered_user -{ - rle_string author; /* Désignation d'utilisateur */ - char *key_file; /* Chemin vers sa clef publique*/ - -} registered_user; - /* Format générique des adresses de connexion */ typedef union _gen_sockaddr_t { - struct sockaddr_in inet_addr; /* Adresse d'écoute IPv4 */ struct sockaddr_un unix_addr; /* Adresse d'écoute Unix */ + 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; /* Assure que le point de connexion est vierge. */ -typedef bool (* clean_server_socket_cb) (GDbServer *); +typedef bool (* lock_server_socket_cb) (GHubServer *); + +/* Assure que le point de connexion est rendu disponible. */ +typedef void (* unlock_server_socket_cb) (GHubServer *); /* Description de serveur à l'écoute (instance) */ -struct _GDbServer +struct _GHubServer { GObject parent; /* A laisser en premier */ - registered_user *users; /* Liste d'utilisateurs */ - size_t users_count; /* Nombre d'enregistrés */ + 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 */ int domain; /* Domaine du canal */ @@ -89,56 +86,60 @@ struct _GDbServer socklen_t sock_len; /* Taille de cette adresse */ char *desc; /* Désignation du serveur */ - clean_server_socket_cb clean_socket; /* Procédure de nettoyage ? */ - - char *basedir; /* Répertoire de stockage */ + lock_server_socket_cb lock_socket; /* Procédure de nettoyage ? */ + unlock_server_socket_cb unlock_socket; /* Procédure de nettoyage ? */ + int lock_fd; /* Eventuel verrou d'accès */ GThread *listener; /* Procédure de traitement */ GList *archives; /* Liste des binaires ouverts */ GMutex mutex; /* Verrou pour l'accès */ + GMutex wait_mutex; /* Accès à la condition */ + GCond wait_cond; /* Attente de signal */ + }; /* Description de serveur à l'écoute (classe) */ -struct _GDbServerClass +struct _GHubServerClass { GObjectClass parent; /* A laisser en premier */ }; +/* Indice pour le passage d'arguments */ +static int _ssl_data_index = -1; + + /* Initialise la classe des descriptions de fichier binaire. */ -static void g_db_server_class_init(GDbServerClass *); +static void g_hub_server_class_init(GHubServerClass *); /* Initialise une description de fichier binaire. */ -static void g_db_server_init(GDbServer *); +static void g_hub_server_init(GHubServer *); /* Supprime toutes les références externes. */ -static void g_db_server_dispose(GDbServer *); +static void g_hub_server_dispose(GHubServer *); /* Procède à la libération totale de la mémoire. */ -static void g_db_server_finalize(GDbServer *); +static void g_hub_server_finalize(GHubServer *); /* Assure que le point de connexion est vierge. */ -static bool g_db_server_clean_internal_socket(GDbServer *); +static bool g_hub_server_lock_internal_socket(GHubServer *); -/* Supprime toute trace d'utilisateur inscrit. */ -static void g_db_server_unregister_all_user(GDbServer *); +/* Assure que le point de connexion est rendu disponible. */ +static void g_hub_server_unlock_internal_socket(GHubServer *); -/* Inscrit un nouvel utilisateur comme étant enregistré. */ -static bool g_db_server_register_user(GDbServer *, const char *, char *); - -/* Inscrit un nouvel utilisateur comme étant enregistré. */ -static bool g_db_server_is_registered_user(GDbServer *, const rle_string *, unsigned char *); +/* Vérifie la légitimité d'une connexion sécurisée au serveur. */ +static int g_hub_server_verify(int, X509_STORE_CTX *); /* Assure l'accueil des nouveaux clients. */ -static void *g_db_server_listener(GDbServer *); +static void *g_hub_server_listener(GHubServer *); /* Indique le type défini pour une description de serveur à l'écoute. */ -G_DEFINE_TYPE(GDbServer, g_db_server, G_TYPE_OBJECT); +G_DEFINE_TYPE(GHubServer, g_hub_server, G_TYPE_OBJECT); /****************************************************************************** @@ -153,14 +154,14 @@ G_DEFINE_TYPE(GDbServer, g_db_server, G_TYPE_OBJECT); * * ******************************************************************************/ -static void g_db_server_class_init(GDbServerClass *klass) +static void g_hub_server_class_init(GHubServerClass *klass) { GObjectClass *object; /* Autre version de la classe */ object = G_OBJECT_CLASS(klass); - object->dispose = (GObjectFinalizeFunc/* ! */)g_db_server_dispose; - object->finalize = (GObjectFinalizeFunc)g_db_server_finalize; + object->dispose = (GObjectFinalizeFunc/* ! */)g_hub_server_dispose; + object->finalize = (GObjectFinalizeFunc)g_hub_server_finalize; } @@ -177,18 +178,23 @@ static void g_db_server_class_init(GDbServerClass *klass) * * ******************************************************************************/ -static void g_db_server_init(GDbServer *server) +static void g_hub_server_init(GHubServer *server) { + server->working = NULL; + server->tls_ctx = NULL; - server->cert_file = NULL; - server->key_file = NULL; server->fd = -1; - server->basedir = NULL; + server->lock_socket = NULL; + server->unlock_socket = NULL; + server->lock_fd = -1; g_mutex_init(&server->mutex); + g_mutex_init(&server->wait_mutex); + g_cond_init(&server->wait_cond); + } @@ -204,11 +210,11 @@ static void g_db_server_init(GDbServer *server) * * ******************************************************************************/ -static void g_db_server_dispose(GDbServer *server) +static void g_hub_server_dispose(GHubServer *server) { GList *iter; /* Boucle de parcours */ - g_db_server_stop(server); + g_hub_server_stop(server); for (iter = g_list_first(server->archives); iter != NULL; @@ -220,7 +226,10 @@ static void g_db_server_dispose(GDbServer *server) g_mutex_clear(&server->mutex); - G_OBJECT_CLASS(g_db_server_parent_class)->dispose(G_OBJECT(server)); + g_mutex_clear(&server->wait_mutex); + g_cond_clear(&server->wait_cond); + + G_OBJECT_CLASS(g_hub_server_parent_class)->dispose(G_OBJECT(server)); } @@ -237,32 +246,37 @@ static void g_db_server_dispose(GDbServer *server) * * ******************************************************************************/ -static void g_db_server_finalize(GDbServer *server) +static void g_hub_server_finalize(GHubServer *server) { - g_db_server_unregister_all_user(server); + int ret; /* Bilan d'un appel */ - free(server->desc); + if (server->working != NULL) + free(server->working); assert(server->tls_ctx == NULL); - if (server->cert_file != NULL) - free(server->cert_file); + free(server->desc); - if (server->key_file != NULL) - free(server->key_file); + if (server->lock_fd != -1) + { + ret = flock(server->lock_fd, LOCK_UN); + if (ret == -1) + LOG_ERROR_N("flock"); - if (server->basedir != NULL) - free(server->basedir); + ret = close(server->lock_fd); + if (ret == -1) + LOG_ERROR_N("close"); - G_OBJECT_CLASS(g_db_server_parent_class)->finalize(G_OBJECT(server)); + } + + G_OBJECT_CLASS(g_hub_server_parent_class)->finalize(G_OBJECT(server)); } /****************************************************************************** * * -* Paramètres : author = utilisateur à représenter via le client. * -* kfile = clef menant à sa clef publique. * +* Paramètres : - * * * * Description : Prépare un serveur de BD pour les clients internes. * * * @@ -272,49 +286,21 @@ static void g_db_server_finalize(GDbServer *server) * * ******************************************************************************/ -GDbServer *g_db_server_new_internal(const char *author, char *kfile) +GHubServer *g_hub_server_new_internal(void) { - GDbServer *result; /* Adresse à retourner */ + GHubServer *result; /* Adresse à retourner */ bool status; /* Bilan d'un chargement */ - char *working; /* Répertoire par le client */ - int ret[2]; /* Bilan d'une vérification */ - - result = g_object_new(G_TYPE_DB_SERVER, NULL); - - /* Chargement du profil */ - - status = g_db_server_register_user(result, author, kfile); - if (!status) goto gdsni_error; - - /* Paramètres de chiffrement */ - - working = get_cert_working_directory("servers", "standalone"); - - result->cert_file = build_absolute_filename(working, "server-cert.pem"); - result->key_file = build_absolute_filename(working, "server-key.pem"); - ret[0] = access(result->cert_file, R_OK); - ret[1] = access(result->key_file, R_OK); + result = g_object_new(G_TYPE_HUB_SERVER, NULL); - if (ret[0] != 0 || ret[1] != 0) - { - log_variadic_message(LMT_ERROR, _("The serveur certificate is missing in the '%s' directory!"), working); - log_simple_message(LMT_ERROR, _("Generate it using the menu (Tool > Identity) and restart the program.")); - - free(working); - - goto gdsni_missing_pem; - - } - - free(working); + result->working = get_db_working_directory("servers", "standalone", NULL, NULL); /* Détermination du point d'écoute */ result->domain = AF_UNIX; - status = build_tmp_socket("internal-server", &result->addr.unix_addr); - if (!status) goto gdsni_error; + status = build_internal_server_socket(&result->addr.unix_addr); + if (!status) goto sock_error; result->sock_len = sizeof(struct sockaddr_un); @@ -324,17 +310,12 @@ GDbServer *g_db_server_new_internal(const char *author, char *kfile) /* Aide pour une sortie propre ? */ - result->clean_socket = g_db_server_clean_internal_socket; - - /* Répertoire de stockage */ - - result->basedir = get_xdg_config_dir("chrysalide" G_DIR_SEPARATOR_S "cdbs"); + result->lock_socket = g_hub_server_lock_internal_socket; + result->unlock_socket = g_hub_server_unlock_internal_socket; return result; - gdsni_missing_pem: - - gdsni_error: + sock_error: g_object_unref(G_OBJECT(result)); @@ -355,16 +336,42 @@ GDbServer *g_db_server_new_internal(const char *author, char *kfile) * * ******************************************************************************/ -static bool g_db_server_clean_internal_socket(GDbServer *server) +static bool g_hub_server_lock_internal_socket(GHubServer *server) { bool result; /* Bilan à faire remonter */ char *sock_path; /* Chemin vers le canal UNIX */ + char *lock_path; /* Chemin vers le verrou */ int ret; /* Bilan d'un appel */ - result = true; + result = false; sock_path = server->addr.unix_addr.sun_path; + /* Partie d'exclusivité */ + + lock_path = strdup(sock_path); + lock_path = stradd(lock_path, ".lock"); + + assert(server->lock_fd == -1); + + server->lock_fd = open(lock_path, O_RDONLY | O_CREAT, 0600); + if (server->lock_fd == -1) + { + LOG_ERROR_N("open"); + goto exit; + } + + free(lock_path); + + ret = flock(server->lock_fd, LOCK_EX | LOCK_NB); + + result = (ret == 0); + + if (!result) + goto exit; + + /* Partie de nettoye */ + ret = access(sock_path, F_OK); if (ret == 0) @@ -373,12 +380,24 @@ static bool g_db_server_clean_internal_socket(GDbServer *server) if (ret != 0) { - perror("unlink"); + LOG_ERROR_N("unlink"); + + ret = flock(server->lock_fd, LOCK_UN); + if (ret == -1) + LOG_ERROR_N("flock"); + + ret = close(server->lock_fd); + if (ret == -1) + LOG_ERROR_N("close"); + result = false; + } } + exit: + return result; } @@ -386,90 +405,164 @@ static bool g_db_server_clean_internal_socket(GDbServer *server) /****************************************************************************** * * -* Paramètres : conf = fichier de configuration à interpréter. * +* Paramètres : server = instance à consulter et nettoyer. * * * -* Description : Prépare un serveur de BD pour les clients distants. * +* Description : Assure que le point de connexion est rendu disponible. * * * -* Retour : Structure mise en place ou NULL en cas d'échec. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -GDbServer *g_db_server_new_remote(const char *conf) +static void g_hub_server_unlock_internal_socket(GHubServer *server) { - GDbServer *result; /* Adresse à retourner */ + int ret; /* Bilan d'un appel */ + + assert(server->lock_fd != -1); + + ret = flock(server->lock_fd, LOCK_UN); + if (ret == -1) + LOG_ERROR_N("flock"); - char *host; - short port; + ret = close(server->lock_fd); + if (ret == -1) + LOG_ERROR_N("close"); + + server->lock_fd = -1; + +} - struct hostent *hp; /* Informations sur l'hôte */ +/****************************************************************************** +* * +* Paramètres : host = désignation du serveur à lancer. * +* port = port d'écoute à ouvrir. * +* ipv6 = adopte une préférence pour les adresses IPv6. * +* * +* Description : Prépare un serveur de BD pour les clients distants. * +* * +* Retour : Structure mise en place ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GHubServer *g_hub_server_new_remote(const char *host, const char *port, bool ipv6) +{ + GHubServer *result; /* Adresse à retourner */ + struct addrinfo hints; /* Cadre de connexion souhaité */ + struct addrinfo *available; /* Cadres de connexion dispos */ + int ret; /* Bilan d'une consultation */ + struct addrinfo *iter; /* Boucle de parcours */ size_t desclen; /* Taille de désignation */ + struct sockaddr_in *addr4; /* Adresse IPv4 brute */ + struct sockaddr_in6 *addr6; /* Adresse IPv6 brute */ const char *ip; /* Adresse IPv4 ou IPv6 */ - const char *tmpdir; /* Répertoire de travail */ - bool status; /* Bilan d'un consultation */ - result = g_object_new(G_TYPE_DB_SERVER, NULL); + result = g_object_new(G_TYPE_HUB_SERVER, NULL); - /* Chargement des profils */ + assert(host != NULL); + if (port == NULL) + port = "1337"; - /* - ret = g_db_server_register_user(result, author, kfile); - if (!ret) goto gdsni_error; - */ + result->working = get_db_working_directory("servers", host, port, NULL); - result->domain = AF_INET; + /* Détermination du point d'écoute */ - host = "localhost"; - port = 9999; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; - /* Détermination du point d'écoute */ + ret = getaddrinfo(host, port, &hints, &available); + if (ret != 0) + { + LOG_ERROR_GAI_N("getaddrinfo", ret); + goto error; + } + + result->domain = AF_UNSPEC; - hp = gethostbyname(host); - if (hp == NULL) + /** + * Premier tour : on essaie de se plier à la demande. + */ + + for (iter = available; iter != NULL && result->domain == AF_UNSPEC; iter = iter->ai_next) { - perror("gethostbyname"); - goto gdsn_error; + if (ipv6 && iter->ai_family != AF_INET6) + continue; + + if (!ipv6 && iter->ai_family != AF_INET) + continue; + + result->domain = iter->ai_family; + + memcpy(&result->addr.inet_4_6_addr, iter->ai_addr, iter->ai_addrlen); + result->sock_len = iter->ai_addrlen; + } - result->addr.inet_addr.sin_family = hp->h_addrtype; - memcpy(&result->addr.inet_addr.sin_addr, hp->h_addr_list[0], sizeof(struct in_addr)); + /** + * Second tour : on fait avec ce qu'on a. + */ - result->addr.inet_addr.sin_port = htons(port); + for (iter = available; iter != NULL && result->domain == AF_UNSPEC; iter = iter->ai_next) + { + if (iter->ai_family != AF_INET6 && iter->ai_family != AF_INET) + continue; - result->sock_len = sizeof(struct sockaddr_in); + result->domain = iter->ai_family; - desclen = INET6_ADDRSTRLEN + 1 + 5 + 1; - result->desc = calloc(desclen, sizeof(char)); + memcpy(&result->addr.inet_4_6_addr, iter->ai_addr, iter->ai_addrlen); + result->sock_len = iter->ai_addrlen; - ip = inet_ntop(AF_INET, &result->addr.inet_addr.sin_addr, result->desc, INET6_ADDRSTRLEN); - if (ip == NULL) + } + + if (available != NULL) + freeaddrinfo(available); + + if (result->domain == AF_UNSPEC) { - perror("inet_ntop"); - goto gdsn_error; + log_variadic_message(LMT_ERROR, _("No suitable address found for %s:%s"), host, port); + goto error; } /* Désignation humaine */ - snprintf(result->desc + strlen(ip), 1 + 5, ":%hu", port); + desclen = INET6_ADDRSTRLEN + 1 + strlen(port) + 1; + result->desc = calloc(desclen, sizeof(char)); - /* Aide pour une sortie propre ? */ + if (result->domain == AF_INET) + { + addr4 = (struct sockaddr_in *)&result->addr.inet_4_6_addr; + ip = inet_ntop(result->domain, &addr4->sin_addr, result->desc, INET6_ADDRSTRLEN); + } - result->clean_socket = NULL; + else if (result->domain == AF_INET6) + { + addr6 = (struct sockaddr_in6 *)&result->addr.inet_4_6_addr; + ip = inet_ntop(result->domain, &addr6->sin6_addr, result->desc, INET6_ADDRSTRLEN); + } - /* Répertoire de stockage */ + else + assert(false); - status = g_generic_config_get_value(get_main_configuration(), MPK_TMPDIR, &tmpdir); - if (!status) goto gdsn_error; + if (ip == NULL) + { + LOG_ERROR_N("inet_ntop"); + goto error; + } - result->basedir = strdup(tmpdir); + log_variadic_message(LMT_INFO, _("Resolved server IP: %s"), ip); + + snprintf(result->desc + strlen(ip), 1 + strlen(port) + 1, ":%s", port); return result; - gdsn_error: + error: g_object_unref(G_OBJECT(result)); @@ -480,112 +573,126 @@ GDbServer *g_db_server_new_remote(const char *conf) /****************************************************************************** * * -* Paramètres : server = serveur pour les accès distants à manipuler. * +* Paramètres : preverify_ok = état de la prévalidation. * +* ctx = contexte de la certification en cours. * * * -* Description : Supprime toute trace d'utilisateur inscrit. * +* Description : Vérifie la légitimité d'une connexion sécurisée au serveur. * * * -* Retour : - * +* Retour : 1 si la connexion est validée, 0 sinon. * * * * Remarques : - * * * ******************************************************************************/ -static void g_db_server_unregister_all_user(GDbServer *server) +static int g_hub_server_verify(int preverify_ok, X509_STORE_CTX *ctx) { - size_t i; /* Boucle de parcours */ + int result; /* Bilan à retourner */ + X509 *peer_cert; /* Certificat côté client */ + SSL *ssl; /* Structure de connexion SLL */ + SSL_CTX *ssl_ctx; /* Contexte SSL du serveur */ + GHubServer *server; /* Serveur concerné */ + char *filename; /* Chemin d'accès reconstruit */ + FILE *stream; /* Flux ouvert en lecture */ + X509 *ca_cert; /* Certificat CA du serveur */ + int status; /* Bilan d'une comparaison */ + char *authorized_dir; /* Répertoire des autorisations*/ + DIR *dir; /* Répertoire à parcourir */ + struct dirent *entry; /* Elément trouvé */ + X509 *authorized_cert; /* Certificat de client validé */ - for (i = 0; i < server->users_count; i++) - { - exit_rle_string(&server->users[i].author); - free(server->users[i].key_file); - } + result = 0; - if (server->users != NULL) - free(server->users); + peer_cert = X509_STORE_CTX_get_current_cert(ctx); - server->users = NULL; - server->users_count = 0; + /* Récupération du serveur interne */ -} + ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); + ssl_ctx = SSL_get_SSL_CTX(ssl); + server = SSL_CTX_get_ex_data(ssl_ctx, _ssl_data_index); + assert(server != NULL); -/****************************************************************************** -* * -* Paramètres : server = serveur pour les accès distants à manipuler. * -* author = utilisateur à représenter via le client. * -* kfile = clef menant à sa clef publique. * -* * -* Description : Inscrit un nouvel utilisateur comme étant enregistré. * -* * -* Retour : Bilan de l'inscription. * -* * -* Remarques : - * -* * -******************************************************************************/ + /* Test du certificat d'autorité */ -static bool g_db_server_register_user(GDbServer *server, const char *author, char *kfile) -{ - if (strlen(author) == 0) - return false; + filename = strdup(server->working); + filename = stradd(filename, "ca-cert.pem"); - server->users = realloc(server->users, ++server->users_count * sizeof(registered_user)); + stream = fopen(filename, "rb"); + if (stream == NULL) goto authorized; - dup_into_rle_string(&server->users[server->users_count - 1].author, author); - server->users[server->users_count - 1].key_file = kfile; + ca_cert = PEM_read_X509(stream, NULL, NULL, NULL); - return true; + fclose(stream); -} + status = X509_cmp(peer_cert, ca_cert); + if (status == 0) + result = 1; -/****************************************************************************** -* * -* Paramètres : server = serveur pour les accès distants à manipuler. * -* author = utilisateur à représenter via le client. * -* sig = signature d'utilisateur à valider. * -* * -* Description : Inscrit un nouvel utilisateur comme étant enregistré. * -* * -* Retour : true si l'utilisateur est bien enregistré, false sinon. * -* * -* Remarques : - * -* * -******************************************************************************/ + X509_free(ca_cert); -static bool g_db_server_is_registered_user(GDbServer *server, const rle_string *author, unsigned char *sig) -{ - bool result; /* Bilan à retourner */ - size_t i; /* Boucle de parcours */ - GChecksum *checksum; /* Empreinte MD5 à signer */ - unsigned char md5_digest[16]; /* Empreinte MD5 calculée */ - RSA *key; /* Clef pour la signature */ + free(filename); - result = false; + if (result == 1) + goto verified; + + /* Détermination du répertoire des autorisations */ + + authorized: + + authorized_dir = strdup(server->working); + authorized_dir = stradd(authorized_dir, "authorized" G_DIR_SEPARATOR_S); - /* Recherche de l'utilisateur */ + dir = opendir(authorized_dir); + if (dir == NULL) goto verified; + + /* Recherche d'une entrée de validation */ + + while (result == 0) + { + entry = readdir(dir); + + if (entry == NULL) + { + if (errno != 0) + LOG_ERROR_N("readdir"); - for (i = 0; i < server->users_count; i++) - if (cmp_rle_string(&server->users[i].author, author) == 0) break; - if (i == server->users_count) - goto gdsiru_exit; + } + + if (entry->d_type != DT_REG && entry->d_type != DT_LNK) continue; + if (entry->d_name[0] == '.') continue; + + filename = strdup(authorized_dir); + filename = stradd(filename, G_DIR_SEPARATOR_S); + filename = stradd(filename, entry->d_name); + + stream = fopen(filename, "rb"); + if (stream == NULL) goto next; - /* Validation de la signature présentée */ + authorized_cert = PEM_read_X509(stream, NULL, NULL, NULL); - checksum = g_checksum_new(G_CHECKSUM_MD5); - g_checksum_update(checksum, (guchar *)get_rle_string(author), get_rle_length(author)); - g_checksum_get_digest(checksum, (guint8 *)md5_digest, (gsize []) { sizeof(md5_digest) }); - g_checksum_free(checksum); + fclose(stream); - key = load_rsa_key(server->users[i].key_file, false); - if (key == NULL) goto gdsiru_exit; + status = X509_cmp(peer_cert, authorized_cert); - result = verify_md5_hash(key, md5_digest, sig); + if (status == 0) + result = 1; - RSA_free(key); + X509_free(authorized_cert); - gdsiru_exit: + next: + + free(filename); + + } + + /* Sortie */ + + closedir(dir); + + verified: return result; @@ -604,7 +711,7 @@ static bool g_db_server_is_registered_user(GDbServer *server, const rle_string * * * ******************************************************************************/ -static void *g_db_server_listener(GDbServer *server) +static void *g_hub_server_listener(GHubServer *server) { struct pollfd fds; /* Surveillance des flux */ int ret; /* Bilan d'un appel */ @@ -612,29 +719,37 @@ static void *g_db_server_listener(GDbServer *server) int fd; /* Canal établi vers un client */ SSL *tls_fd; /* Même canal, mais sécurisé */ rle_string hash; /* Empreinte du binaire visé */ - rle_string user; /* Nom d'utilisateur du client */ 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 */ - unsigned char sig[RSA_USED_SIZE]; /* Signature effectuée */ - GList *iter; /* Boucle de parcours */ + char *basedir; /* Répertoire de stockage */ + char *tmpdir; /* Répertoire de travail */ packed_buffer out_pbuf; /* Tampon d'émission */ fds.fd = server->fd; fds.events = POLLIN | POLLPRI; - while (1) + while (server->fd != -1) { ret = poll(&fds, 1, -1); if (ret != 1) continue; /* Le canal est fermé, une sortie doit être demandée... */ - if (fds.revents & POLLHUP) + 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)) @@ -642,7 +757,7 @@ static void *g_db_server_listener(GDbServer *server) fd = accept(server->fd, (struct sockaddr *)&peer, (socklen_t []) { sizeof(gen_sockaddr_t) }); if (fd == -1) { - perror("accept"); + LOG_ERROR_N("accept"); continue; } @@ -667,7 +782,6 @@ static void *g_db_server_listener(GDbServer *server) /* Initialisation à vide pour les sorties en erreur */ init_dynamic_rle_string(&hash, NULL); - init_dynamic_rle_string(&user, NULL); /* Construction d'une représentation */ @@ -678,14 +792,29 @@ static void *g_db_server_listener(GDbServer *server) { peer_name = calloc(INET6_ADDRSTRLEN + 1 + 5 + 1, sizeof(char)); - ip = inet_ntop(AF_INET, &peer.inet_addr.sin_addr, peer_name, INET6_ADDRSTRLEN); + ip = inet_ntop(AF_INET, &peer.inet4_addr.sin_addr, peer_name, INET6_ADDRSTRLEN); + if (ip == NULL) + { + LOG_ERROR_N("inet_ntop"); + goto id_error; + } + + snprintf(peer_name + strlen(ip), 1 + 5, ":%hu", ntohs(peer.inet4_addr.sin_port)); + + } + + else if (*((sa_family_t *)&peer) == AF_INET6) + { + peer_name = calloc(INET6_ADDRSTRLEN + 1 + 5 + 1, sizeof(char)); + + ip = inet_ntop(AF_INET6, &peer.inet6_addr.sin6_addr, peer_name, INET6_ADDRSTRLEN); if (ip == NULL) { - perror("inet_ntop"); + LOG_ERROR_N("inet_ntop"); goto id_error; } - snprintf(peer_name + strlen(ip), 1 + 5, ":%hu", ntohs(peer.inet_addr.sin_port)); + snprintf(peer_name + strlen(ip), 1 + 5, ":%hu", ntohs(peer.inet6_addr.sin6_port)); } @@ -695,13 +824,13 @@ static void *g_db_server_listener(GDbServer *server) 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. * - 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_client_start(). */ @@ -744,24 +873,6 @@ static void *g_db_server_listener(GDbServer *server) goto error_sending; } - status = unpack_rle_string(&user, &in_pbuf); - if (!status) - { - log_variadic_message(LMT_ERROR, _("Error while getting the user name from '%s'..."), - peer_name); - error = DBE_BAD_EXCHANGE; - goto error_sending; - } - - status = extract_packed_buffer(&in_pbuf, sig, RSA_USED_SIZE, false); - if (!status) - { - log_variadic_message(LMT_ERROR, _("Error while getting the signature from '%s'..."), - peer_name); - error = DBE_BAD_EXCHANGE; - goto error_sending; - } - if (cmd != DBC_HELO) { log_variadic_message(LMT_ERROR, _("The client from '%s' did not introduce itself!"), @@ -786,21 +897,6 @@ static void *g_db_server_listener(GDbServer *server) goto error_sending; } - if (is_rle_string_empty(&user)) - { - log_variadic_message(LMT_ERROR, _("No user is associated with the client from '%s'..."), - peer_name); - error = DBE_BAD_EXCHANGE; - goto error_sending; - } - - if (!g_db_server_is_registered_user(server, &user, sig)) - { - log_variadic_message(LMT_ERROR, _("This user is not registered.")); - 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. @@ -818,7 +914,19 @@ static void *g_db_server_listener(GDbServer *server) } if (iter == NULL) - archive = g_cdb_archive_new(server->basedir, &hash, &user, &error); + { + basedir = strdup(server->working); + basedir = stradd(basedir, "cdbs" G_DIR_SEPARATOR_S); + + tmpdir = strdup(server->working); + tmpdir = stradd(tmpdir, "tmp" G_DIR_SEPARATOR_S); + + archive = g_cdb_archive_new(basedir, tmpdir, &hash, &error); + + free(tmpdir); + free(basedir); + + } /** * Le serveur doit répondre pour un message type : @@ -856,14 +964,13 @@ static void *g_db_server_listener(GDbServer *server) if (iter == NULL) server->archives = g_list_append(server->archives, archive); - g_cdb_archive_add_client(archive, tls_fd, &user); + g_cdb_archive_add_client(archive, tls_fd); exit_packed_buffer(&out_pbuf); free(peer_name); exit_rle_string(&hash); - exit_rle_string(&user); continue; @@ -884,7 +991,6 @@ static void *g_db_server_listener(GDbServer *server) free(peer_name); exit_rle_string(&hash); - exit_rle_string(&user); invalid_conn: @@ -898,6 +1004,8 @@ static void *g_db_server_listener(GDbServer *server) } + g_hub_server_stop(server); + return NULL; } @@ -905,7 +1013,9 @@ static void *g_db_server_listener(GDbServer *server) /****************************************************************************** * * -* Paramètres : server = serveur pour les accès distants à manipuler. * +* Paramètres : server = serveur pour les accès distants à manipuler. * +* backlog = nombre de connexions maximal. * +* keep = conservation du serveur en avant plan. * * * * Description : Démarre le serveur de base de données. * * * @@ -915,12 +1025,16 @@ static void *g_db_server_listener(GDbServer *server) * * ******************************************************************************/ -bool g_db_server_start(GDbServer *server) +ServerStartStatus g_hub_server_start(GHubServer *server, int backlog, bool keep) { + ServerStartStatus result; /* Bilan à retourner */ const SSL_METHOD *method; /* Mode du canal sécurisé */ + char *filename; /* Fichier PEM à manipuler */ int ret; /* Bilan d'un appel */ + STACK_OF(X509_NAME) *ca_cert; /* Certificat de l'autorité */ bool status; /* Bilan d'un nettoyage */ - int backlog; /* Nombre de connexions maximal*/ + + result = SSS_FAILURE; /* Définition d'un environnement TLS */ @@ -934,7 +1048,12 @@ bool g_db_server_start(GDbServer *server) goto quick_error; } - ret = SSL_CTX_use_certificate_file(server->tls_ctx, server->cert_file, SSL_FILETYPE_PEM); + filename = strdup(server->working); + filename = stradd(filename, "server-cert.pem"); + + ret = SSL_CTX_use_certificate_file(server->tls_ctx, filename, SSL_FILETYPE_PEM); + + free(filename); if (ret != 1) { @@ -942,7 +1061,12 @@ bool g_db_server_start(GDbServer *server) goto tls_error; } - ret = SSL_CTX_use_PrivateKey_file(server->tls_ctx, server->key_file, SSL_FILETYPE_PEM); + filename = strdup(server->working); + filename = stradd(filename, "server-key.pem"); + + ret = SSL_CTX_use_PrivateKey_file(server->tls_ctx, filename, SSL_FILETYPE_PEM); + + free(filename); if (ret != 1) { @@ -958,52 +1082,99 @@ bool g_db_server_start(GDbServer *server) goto tls_error; } + /* Validation des certificats */ + + if (_ssl_data_index == -1) + { + _ssl_data_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL); + assert(_ssl_data_index != -1); + } + + ret = SSL_CTX_set_ex_data(server->tls_ctx, _ssl_data_index, server); + if (ret != 1) + { + LOG_ERROR_OPENSSL; + goto tls_error; + } + + SSL_CTX_set_verify(server->tls_ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, g_hub_server_verify); + + filename = strdup(server->working); + filename = stradd(filename, "ca-cert.pem"); + + ca_cert = SSL_load_client_CA_file(filename); + + free(filename); + + if (ca_cert == NULL) + { + LOG_ERROR_OPENSSL; + goto tls_error; + } + + SSL_CTX_set_client_CA_list(server->tls_ctx, ca_cert); + /* Mise en place d'un canal de communication */ server->fd = socket(server->domain, SOCK_STREAM, 0); if (server->fd == -1) { - perror("socket"); + LOG_ERROR_N("socket"); return false; } ret = setsockopt(server->fd, SOL_SOCKET, SO_REUSEADDR, (int []) { 1 }, sizeof(int)); if (ret == -1) { - perror("setsockopt"); - goto gdss_error; + LOG_ERROR_N("setsockopt"); + goto network_error; } - if (server->clean_socket != NULL) + if (server->lock_socket != NULL) { - status = server->clean_socket(server); - if (!status) goto gdss_error; + status = server->lock_socket(server); + if (!status) + { + result = SSS_ALREADY_RUNNING; + goto network_error; + } + } ret = bind(server->fd, (struct sockaddr *)&server->addr, server->sock_len); if (ret == -1) { - perror("bind"); - goto gdss_error; + LOG_ERROR_N("bind"); + goto network_error; } - if (!g_generic_config_get_value(get_main_configuration(), MPK_SERVER_BACKLOG, &backlog)) - goto gdss_error; - ret = listen(server->fd, backlog); if (ret == -1) { - perror("listen"); - goto gdss_error; + LOG_ERROR_N("listen"); + goto network_error; } - server->listener = g_thread_new("cdb_listener", (GThreadFunc)g_db_server_listener, server); + if (!keep) + { + ret = daemon(1, 1); + if (ret != 0) + { + LOG_ERROR_N("daemon"); + goto network_error; + } + + } + + server->listener = g_thread_new("cdb_listener", (GThreadFunc)g_hub_server_listener, server); log_variadic_message(LMT_PROCESS, _("Server started and listening at %s"), server->desc); - return true; + result = SSS_SUCCESS; - gdss_error: + return result; + + network_error: close(server->fd); server->fd = -1; @@ -1015,7 +1186,30 @@ bool g_db_server_start(GDbServer *server) quick_error: - return false; + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : server = serveur pour les accès distants à consulter. * +* * +* Description : Attend l'arrête du serveur de base de données. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_hub_server_wait_for_stop(GHubServer *server) +{ + g_mutex_lock(&server->wait_mutex); + + g_cond_wait(&server->wait_cond, &server->wait_mutex); + + g_mutex_unlock(&server->wait_mutex); } @@ -1032,34 +1226,52 @@ bool g_db_server_start(GDbServer *server) * * ******************************************************************************/ -void g_db_server_stop(GDbServer *server) +void g_hub_server_stop(GHubServer *server) { + int fd; /* Canal à clôturer */ int ret; /* Bilan d'un appel */ /* Canal de communication */ if (server->fd == -1) { - assert(server->tls_ctx == NULL); + /** + * Si la fermture est forcée, le thread de traitement va terminer en erreur. + * Donc cette fonction sera appelée deux fois. Seule la première va affecter + * le contexte, donc on le peut pas s'assurer de la condition suivante dans + * tous les cas. + */ + + /*assert(client->tls_ctx == NULL);*/ return; } - ret = shutdown(server->fd, SHUT_RDWR); - if (ret == -1) perror("shutdown"); + fd = server->fd; - g_thread_join(server->listener); + server->fd = -1; - ret = close(server->fd); - if (ret == -1) perror("close"); + ret = shutdown(fd, SHUT_RDWR); + if (ret == -1) LOG_ERROR_N("shutdown"); - server->fd = -1; + ret = close(fd); + if (ret == -1) LOG_ERROR_N("close"); + + g_thread_join(server->listener); + + /* Verrou d'accès */ - if (server->clean_socket != NULL) - server->clean_socket(server); + if (server->unlock_socket != NULL) + server->unlock_socket(server); /* Environnement TLS */ SSL_CTX_free(server->tls_ctx); server->tls_ctx = NULL; + /* Fin de service */ + + g_mutex_lock(&server->wait_mutex); + g_cond_signal(&server->wait_cond); + g_mutex_unlock(&server->wait_mutex); + } diff --git a/src/analysis/db/server.h b/src/analysis/db/server.h index 5be7886..44aef54 100644 --- a/src/analysis/db/server.h +++ b/src/analysis/db/server.h @@ -30,35 +30,47 @@ -#define G_TYPE_DB_SERVER g_db_server_get_type() -#define G_DB_SERVER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_DB_SERVER, GDbServer)) -#define G_IS_DB_SERVER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_DB_SERVER)) -#define G_DB_SERVER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_DB_SERVER, GDbServerClass)) -#define G_IS_DB_SERVER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_DB_SERVER)) -#define G_DB_SERVER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_DB_SERVER, GDbServerClass)) +#define G_TYPE_HUB_SERVER g_hub_server_get_type() +#define G_HUB_SERVER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_HUB_SERVER, GHubServer)) +#define G_IS_HUB_SERVER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_HUB_SERVER)) +#define G_HUB_SERVER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_HUB_SERVER, GHubServerClass)) +#define G_IS_HUB_SERVER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_HUB_SERVER)) +#define G_HUB_SERVER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_HUB_SERVER, GHubServerClass)) /* Description de serveur à l'écoute (instance) */ -typedef struct _GDbServer GDbServer; +typedef struct _GHubServer GHubServer; /* Description de serveur à l'écoute (classe) */ -typedef struct _GDbServerClass GDbServerClass; +typedef struct _GHubServerClass GHubServerClass; /* Indique le type défini pour une description de serveur à l'écoute. */ -GType g_db_server_get_type(void); +GType g_hub_server_get_type(void); /* Prépare un serveur de BD pour les clients internes. */ -GDbServer *g_db_server_new_internal(const char *, char *); +GHubServer *g_hub_server_new_internal(void); /* Prépare un serveur de BD pour les clients distants. */ -GDbServer *g_db_server_new_remote(const char *); +GHubServer *g_hub_server_new_remote(const char *, const char *, bool); + +/* Bilan du lancement d'un serveur */ +typedef enum _ServerStartStatus +{ + SSS_FAILURE, /* Echec du démarrage */ + SSS_SUCCESS, /* Serveur démarré */ + SSS_ALREADY_RUNNING, /* Instance déjà en place */ + +} ServerStartStatus; /* Démarre le serveur de base de données. */ -bool g_db_server_start(GDbServer *); +ServerStartStatus g_hub_server_start(GHubServer *, int, bool); + +/* Attend l'arrête du serveur de base de données. */ +void g_hub_server_wait_for_stop(GHubServer *); /* Arrête le serveur de base de données. */ -void g_db_server_stop(GDbServer *); +void g_hub_server_stop(GHubServer *); diff --git a/src/common/io.c b/src/common/io.c index 2a68649..754b8a9 100644 --- a/src/common/io.c +++ b/src/common/io.c @@ -25,6 +25,7 @@ #include +#include #include #include #include @@ -387,60 +388,75 @@ int make_tmp_file(const char *prefix, const char *suffix, char **filename) /****************************************************************************** * * -* Paramètres : base = préfixe du nom du fichier temporaire à créer. * -* addr = adresse UNIX constituée. [OUT] * +* Paramètres : dest = fichier de destination de la copie. * +* src = fichier source à copier. * * * -* Description : Met en place un canal UNIX temporaire. * +* Description : Copie un fichier. * * * -* Retour : Bilan de la définition. * +* Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ -bool build_tmp_socket(const char *base, struct sockaddr_un *addr) +bool copy_file(const char *dest, const char *src) { bool result; /* Bilan à retourner */ - const char *tmpdir; /* Répertoire d'accueil */ - bool status; /* Bilan d'un consultation */ - char *path; /* Chemin d'accès au canal */ - int ret; /* Bilan intermédiaire */ - size_t length; /* Taille du chemin complet */ - - status = g_generic_config_get_value(get_main_configuration(), MPK_TMPDIR, &tmpdir); - if (!status) return false; + int fd; /* Descripteur du fichier */ + struct stat info; /* Informations sur le fichier */ + int ret; /* Bilan d'un appel */ + void *data; /* Quantité de données traitées*/ + bool status; /* Bilan de la lecture */ result = false; - asprintf(&path, "%s" G_DIR_SEPARATOR_S "%s-%d", tmpdir, base, getpid()); + /* Côté source */ - ret = ensure_path_exists(path); - if (ret != 0) goto mts_exit; + fd = open(src, O_RDONLY); + if (fd == -1) + { + LOG_ERROR_N("open"); + goto exit; + } - length = strlen(path) + 1; + ret = fstat(fd, &info); + if (ret == -1) + { + LOG_ERROR_N("fstat"); + goto done; + } -#ifndef UNIX_PATH_MAX -# define UNIX_PATH_MAX 108 -#endif + data = malloc(info.st_size); - if (length > UNIX_PATH_MAX) + status = safe_read(fd, data, info.st_size); + if (!status) goto clean; + + close(fd); + + /* Côté destination */ + + fd = open(dest, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); + if (fd == -1) { - log_variadic_message(LMT_ERROR, - _("Impossible to use '%s' as UNIX socket path: string is too long ! (%zu vs %u)\n"), - path, length, UNIX_PATH_MAX); - goto mts_exit; + LOG_ERROR_N("open"); + free(data); + goto exit; } - memset(addr, 0, sizeof(struct sockaddr_un)); - - addr->sun_family = AF_UNIX; - strncpy(addr->sun_path, path, UNIX_PATH_MAX - 1); + status = safe_write(fd, data, info.st_size); + if (!status) goto clean; result = true; - mts_exit: + clean: + + free(data); + + done: + + close(fd); - free(path); + exit: return result; diff --git a/src/common/io.h b/src/common/io.h index 3639d98..b67359b 100644 --- a/src/common/io.h +++ b/src/common/io.h @@ -27,8 +27,6 @@ #include #include -#include -#include @@ -53,8 +51,8 @@ int ensure_path_exists(const char *); /* Met en place un fichier temporaire. */ int make_tmp_file(const char *, const char *, char **); -/* Met en place un canal UNIX temporaire. */ -bool build_tmp_socket(const char *, struct sockaddr_un *); +/* Copie un fichier. */ +bool copy_file(const char *, const char *); diff --git a/src/core/logs.h b/src/core/logs.h index afdcfa2..4ddb6ab 100644 --- a/src/core/logs.h +++ b/src/core/logs.h @@ -26,6 +26,7 @@ #include +#include #include #include #include @@ -87,6 +88,19 @@ void log_variadic_message(LogMessageType, const char *, ...); } \ while (0) +#define LOG_ERROR_GAI_N(func, errcode) \ + do \ + { \ + char __msg[1024]; \ + const char *__msg_ptr; \ + if (errcode == EAI_SYSTEM) \ + __msg_ptr = strerror_r(errno, __msg, sizeof(__msg)); \ + else \ + __msg_ptr = gai_strerror(errcode); \ + log_variadic_message(LMT_EXT_ERROR, "[%s:%u] %s: %s", __FUNCTION__, __LINE__, func, __msg_ptr); \ + } \ + while (0) + #define LOG_ERROR_OPENSSL \ do \ { \ diff --git a/src/gui/panels/history.c b/src/gui/panels/history.c index 4b694c7..4383ed6 100644 --- a/src/gui/panels/history.c +++ b/src/gui/panels/history.c @@ -599,7 +599,7 @@ static void do_history_undo(GtkButton *button, GHistoryPanel *panel) GtkTreeModel *model; /* Modèle de gestion de données*/ GtkTreeIter iter; /* Pointeur vers la ligne visée*/ GDbItem *item; /* Elément de collection */ - GDbClient *client; /* Connexion vers la base */ + GHubClient *client; /* Connexion vers la base */ builder = G_PANEL_ITEM(panel)->builder; @@ -615,7 +615,7 @@ static void do_history_undo(GtkButton *button, GHistoryPanel *panel) gtk_tree_model_get(model, &iter, HTC_ITEM, &item, -1); client = g_loaded_binary_get_db_client(panel->binary); - g_db_client_set_last_active(client, g_db_item_get_timestamp(item)); + g_hub_client_set_last_active(client, g_db_item_get_timestamp(item)); g_object_unref(G_OBJECT(client)); g_object_unref(G_OBJECT(item)); @@ -646,7 +646,7 @@ static void do_history_redo(GtkButton *button, GHistoryPanel *panel) GtkTreeModel *model; /* Modèle de gestion de données*/ GtkTreeIter iter; /* Pointeur vers la ligne visée*/ GDbItem *item; /* Elément de collection */ - GDbClient *client; /* Connexion vers la base */ + GHubClient *client; /* Connexion vers la base */ builder = G_PANEL_ITEM(panel)->builder; @@ -659,7 +659,7 @@ static void do_history_redo(GtkButton *button, GHistoryPanel *panel) gtk_tree_model_get(model, &iter, HTC_ITEM, &item, -1); client = g_loaded_binary_get_db_client(panel->binary); - g_db_client_set_last_active(client, g_db_item_get_timestamp(item)); + g_hub_client_set_last_active(client, g_db_item_get_timestamp(item)); g_object_unref(G_OBJECT(client)); g_object_unref(G_OBJECT(item)); diff --git a/src/hub.c b/src/hub.c new file mode 100644 index 0000000..916aea5 --- /dev/null +++ b/src/hub.c @@ -0,0 +1,1036 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * hub.c - fichier d'entrée du centre de collecte + * + * Copyright (C) 2019 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include +#include + + +#include "gleak.h" +#include "analysis/db/auth.h" +#include "analysis/db/server.h" +#include "core/global.h" +#include "core/logs.h" + + + +/* Liste des commandes principales */ +typedef enum _HubMainCommand +{ + HMC_NONE, /* Absence de commande */ + HMC_CLIENT_ID, /* Création d'une identité */ + HMC_SERVER_ID, /* Création d'une identité */ + HMC_ADD_CLIENT, /* Enregistrement d'utilisateur*/ + HMC_RUN /* Lancement d'un serveur */ + +} HubMainCommand; + + +/* Affiche des indications quant à l'utilisation du programme. */ +static void show_hub_help(const char *); + +/* Affiche des indications sur la version courante du programme. */ +static void show_hub_version(void); + +/* Construit une identité selon les indications fournies. */ +static int parse_identity_properties(const char *, x509_entries *); + +/* Traite la commande "client-id" et ses arguments. */ +static int exec_cmd_client_identity(int, char **); + +/* Traite la commande "server-id" et ses arguments. */ +static int exec_cmd_server_identity(int, char **); + +/* Traite la commande "add-client" et ses arguments. */ +static int exec_cmd_add_client(int, char **); + +/* Traite la commande "run" et ses arguments. */ +static int exec_cmd_run_server(int, char **); + + +/* Serveur pour les enregistrements en base */ +static GHubServer *_server = NULL; + + + +/****************************************************************************** +* * +* Paramètres : name = nom du programme en question. * +* * +* Description : Affiche des indications quant à l'utilisation du programme. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void show_hub_help(const char *name) +{ + char *tmp; /* Conservation modifiable */ + char *base; /* Version courte du nom */ + + tmp = strdup(name); + + base = basename(tmp); + + printf("\n"); + + printf("Usage: %s [--help] [--version] [--verbosity] [options]\n", base); + + printf("\n"); + + printf("\t-h --help\t\tShow this help message.\n"); + printf("\t-v --version\t\tDisplay the program version.\n"); + + printf("\n"); + + printf("\t-V --verbosity=level\tSet the log level (0 for all messages, %u for none).\n", LMT_COUNT); + + printf("\n"); + + printf("Command client-id:\n"); + printf("------------------\n"); + + printf("\n"); + + printf("Usage: %s client-id [--help] [--version] [--verbosity] [--long ] \n", + base); + + printf("\n"); + + printf("\t-l --long=integer\tProvide the validity time of the certicate, in seconds (default: 3 years)\n"); + printf("\tfields\t\t\tCertificate's subject fields, as comma-separated key=value pairs.\n"); + + printf("\n"); + + printf("Command server-id:\n"); + printf("------------------\n"); + + printf("\n"); + + printf("Usage: %s server-id [--help] [--version] [--verbosity] [--name ] [--port ] [--long ] \n", + base); + + printf("\n"); + + printf("\t-n --name=string\tDefine the name of the server to reach (default: standalone)\n"); + printf("\t-p --port=integer\tSpecify the listening port of this server (default: 1337)\n"); + printf("\t-l --long=integer\tProvide the validity time of the certicate, in seconds (default: 3 years)\n"); + printf("\tfields\t\t\tCertificate's subject fields, as comma-separated key=value pairs.\n"); + + printf("\n"); + + printf("Command add-client:\n"); + printf("-------------------\n"); + + printf("\n"); + + printf("Usage: %s add-client [--help] [--version] [--verbosity] [--name ] [--port ] [--long ] \n", + base); + + printf("\n"); + + printf("\t-n --name=string\tDefine the name of the server to reach (default: standalone)\n"); + printf("\t-p --port=integer\tSpecify the listening port of this server (default: 1337)\n"); + printf("\t-l --long=integer\tProvide the validity time of the certicate, in seconds (default: 3 years)\n"); + printf("\tcsr\t\t\tCertificate Signing Request file to use in order to give an authorized access to server.\n"); + printf("\toutdir\t\t\tOutput directory for the signed certificate and the copied server CA, for the client side.\n"); + + printf("\n"); + + printf("Command run:\n"); + printf("------------\n"); + + printf("\n"); + + printf("Usage: %s add-client [--help] [--version] [--verbosity] [--name ] [--port ] [--backlog ]\n", + base); + + printf("\n"); + + printf("\t-n --name=string\tDefine the name of the server to reach (default: standalone)\n"); + printf("\t-p --port=integer\tSpecify the listening port of this server (default: 1337)\n"); + printf("\t-4 --ipv4=integer\tPrefer using an IPv4 address if possible (IPv6 by default)\n"); + printf("\t-b --backlog=integer\tSet the maximum number of incoming connections (default: 10)\n"); + + printf("\n"); + + free(tmp); + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Affiche des indications sur la version courante du programme.* +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void show_hub_version(void) +{ + printf("\n"); + + printf("-o- Chrysalide Hub r%u -o-\n", REVISION); + printf(_("Last compiled on %s at %s\n"), __DATE__, __TIME__); + + printf("\n"); + + printf(_("Pictures directory: %s\n"), PIXMAPS_DIR); + printf(_("Themes directory: %s\n"), THEMES_DIR); + printf(_("Plugins library directory: %s\n"), PLUGINS_LIB_DIR); + printf(_("Plugins data directory: %s\n"), PLUGINS_DATA_DIR); + printf(_("Locale directory: %s\n"), LOCALE_DIR); + + printf("\n"); + +} + + +/****************************************************************************** +* * +* Paramètres : argc = nombre d'arguments dans la ligne de commande. * +* argv = arguments de la ligne de commande. * +* * +* Description : Point d'entrée du programme. * +* * +* Retour : EXIT_SUCCESS si le prgm s'est déroulé sans encombres. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int main(int argc, char **argv) +{ + int result; /* Bilan de l'exécution */ + HubMainCommand command; /* Commande à satisfaire */ + bool show_help; /* Affichage de l'aide ? */ + bool show_version; /* Affichage de la version ? */ + LogMessageType verbosity; /* Niveau de filtre de message */ + int index; /* Indice d'argument */ + int ret; /* Bilan d'un appel */ + + static struct option long_options[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'v' }, + { "verbosity", required_argument, NULL, 'V' }, + { NULL, 0, NULL, 0 } + }; + + result = EXIT_FAILURE; + + /* Décodage de la commande principale */ + + command = HMC_NONE; + + if (argc >= 2) + { + if (strcmp(argv[1], "client-id") == 0) + command = HMC_CLIENT_ID; + + else if (strcmp(argv[1], "server-id") == 0) + command = HMC_SERVER_ID; + + else if (strcmp(argv[1], "add-client") == 0) + command = HMC_ADD_CLIENT; + + else if (strcmp(argv[1], "run") == 0) + command = HMC_RUN; + + } + + /* Décodage des options */ + + show_help = false; + show_version = false; + + verbosity = LMT_INFO; + + if (command == HMC_NONE) + while (true) + { + ret = getopt_long(argc, argv, "hvV:", long_options, &index); + if (ret == -1) break; + + switch (ret) + { + case 'h': + show_help = true; + break; + + case 'v': + show_version = true; + break; + + case 'V': + verbosity = strtoul(optarg, NULL, 10); + break; + + } + + } + + /* Actions de base */ + + if (show_help) + { + show_hub_help(argv[0]); + result = EXIT_SUCCESS; + goto done; + } + + if (show_version) + { + show_hub_version(); + result = EXIT_SUCCESS; + goto done; + } + + /* Lancement des choses sérieuses */ + + setlocale(LC_ALL, ""); + bindtextdomain(PACKAGE, LOCALE_DIR); + textdomain(PACKAGE); + + /* Initialisation de GTK */ + g_set_prgname("Chrysalide Hub"); + setlocale (LC_ALL, ""); + gtk_init(&argc, &argv); + + /* Initialisation du programme */ + + set_batch_mode(); + + set_log_verbosity(verbosity); + + /* Traitement des commandes */ + + switch (command) + { + case HMC_CLIENT_ID: + result = exec_cmd_client_identity(argc, argv); + break; + + case HMC_SERVER_ID: + result = exec_cmd_server_identity(argc, argv); + break; + + case HMC_ADD_CLIENT: + result = exec_cmd_add_client(argc, argv); + break; + + case HMC_RUN: + result = exec_cmd_run_server(argc, argv); + break; + + default: + show_hub_help(argv[0]); + goto done; + break; + + } + +#ifdef TRACK_GOBJECT_LEAKS + remember_gtypes_for_leaks(); +#endif + +#ifdef TRACK_GOBJECT_LEAKS + dump_remaining_gtypes(); +#endif + + done: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : properties = propriétés brutes à convertir. * +* identity = éléments de l'identité à définir. [OUT] * +* * +* Description : Construit une identité selon les indications fournies. * +* * +* Retour : Bilan de l'opération : EXIT_SUCCES ou un indicatif d'erreur. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int parse_identity_properties(const char *properties, x509_entries *identity) +{ + int result; /* Bilan de l'exécution */ + char *tmp; /* Copie modifiable */ + char *saveptr; /* Sauvegarde pour traitement */ + char *pair; /* Ensemble clef=valeur */ + char *eq; /* Signe égal présent */ + + result = EXIT_SUCCESS; + + memset(identity, 0, sizeof(*identity)); + + tmp = strdup(properties); + + for (pair = strtok_r(tmp, ",", &saveptr); + pair != NULL; + pair = strtok_r(NULL, ",", &saveptr)) + { + eq = strchr(pair, '='); + + if (eq == NULL) + { + log_variadic_message(LMT_ERROR, _("Malformed identity properties: '%s'"), properties); + + result = 3; + goto id_error; + + } + + *eq = '\0'; + + if (strcasecmp(pair, "C") == 0) + identity->country = strdup(eq + 1); + + else if (strcasecmp(pair, "ST") == 0) + identity->state = strdup(eq + 1); + + else if (strcasecmp(pair, "L") == 0) + identity->locality = strdup(eq + 1); + + else if (strcasecmp(pair, "O") == 0) + identity->organisation = strdup(eq + 1); + + else if (strcasecmp(pair, "OU") == 0) + identity->organisational_unit = strdup(eq + 1); + + else if (strcasecmp(pair, "CN") == 0) + identity->common_name = strdup(eq + 1); + + else + { + log_variadic_message(LMT_ERROR, _("Unknown identity property: '%s=%s'"), pair, eq + 1); + + result = 4; + goto id_error; + + } + + } + + id_error: + + free(tmp); + + if (result != EXIT_SUCCESS) + free_x509_entries(identity); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : argc = nombre d'arguments dans la ligne de commande. * +* argv = arguments de la ligne de commande. * +* * +* Description : Traite la commande "client-id" et ses arguments. * +* * +* Retour : EXIT_SUCCESS si le programme s'est déroulé sans encombres. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int exec_cmd_client_identity(int argc, char **argv) +{ + int result; /* Bilan de l'exécution */ + bool show_help; /* Affichage de l'aide ? */ + bool show_version; /* Affichage de la version ? */ + LogMessageType verbosity; /* Niveau de filtre de message */ + unsigned long valid; /* Durée de validité */ + int index; /* Indice d'argument */ + int ret; /* Bilan d'un appel */ + x509_entries identity; /* Nouvelle identité à pousser */ + bool status; /* Bilan d'opérations */ + + static struct option long_options[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'v' }, + { "verbosity", required_argument, NULL, 'V' }, + { "long", required_argument, NULL, 'l' }, + { NULL, 0, NULL, 0 } + }; + + result = EXIT_FAILURE; + + /* Décodage des options */ + + show_help = false; + show_version = false; + + verbosity = LMT_INFO; + valid = 3 * 365 * 24 * 60 * 60; + + while (true) + { + ret = getopt_long(argc - 1, argv + 1, "hvV:", long_options, &index); + if (ret == -1) break; + + switch (ret) + { + case 'h': + show_help = true; + break; + + case 'v': + show_version = true; + break; + + case 'V': + verbosity = strtoul(optarg, NULL, 10); + break; + + case 'l': + valid = strtoul(optarg, NULL, 10); + break; + + } + + } + + /* Actions de base */ + + if (show_help) + { + show_hub_help(argv[0]); + result = EXIT_SUCCESS; + goto done; + } + + if (show_version) + { + show_hub_version(); + result = EXIT_SUCCESS; + goto done; + } + + /* Initialisation du programme */ + + set_log_verbosity(verbosity); + + /* Elaboration de l'identité */ + + if ((optind + 1) == argc) + { + log_simple_message(LMT_ERROR, + _("Identity properties are missing; please provide at least an empty string")); + result = 2; + goto done; + } + + ret = parse_identity_properties(argv[optind + 1], &identity); + if (ret != EXIT_SUCCESS) + { + result = ret; + goto done; + } + + /* Traitement de la commande */ + + status = setup_client_identity(valid, &identity); + + if (status) + result = EXIT_SUCCESS; + + free_x509_entries(&identity); + + done: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : argc = nombre d'arguments dans la ligne de commande. * +* argv = arguments de la ligne de commande. * +* * +* Description : Traite la commande "server-id" et ses arguments. * +* * +* Retour : EXIT_SUCCESS si le programme s'est déroulé sans encombres. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int exec_cmd_server_identity(int argc, char **argv) +{ + int result; /* Bilan de l'exécution */ + bool show_help; /* Affichage de l'aide ? */ + bool show_version; /* Affichage de la version ? */ + LogMessageType verbosity; /* Niveau de filtre de message */ + char *name; /* Désignation du serveur */ + char *port; /* Définition du port associé */ + unsigned long valid; /* Durée de validité */ + int index; /* Indice d'argument */ + int ret; /* Bilan d'un appel */ + x509_entries identity; /* Nouvelle identité à pousser */ + bool status; /* Bilan d'opérations */ + + static struct option long_options[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'v' }, + { "verbosity", required_argument, NULL, 'V' }, + { "name", required_argument, NULL, 'n' }, + { "port", required_argument, NULL, 'p' }, + { "long", required_argument, NULL, 'l' }, + { NULL, 0, NULL, 0 } + }; + + result = EXIT_FAILURE; + + /* Décodage des options */ + + show_help = false; + show_version = false; + + verbosity = LMT_INFO; + name = NULL; + port = NULL; + valid = 3 * 365 * 24 * 60 * 60; + + while (true) + { + ret = getopt_long(argc - 1, argv + 1, "hvV:n:p:l:", long_options, &index); + if (ret == -1) break; + + switch (ret) + { + case 'h': + show_help = true; + break; + + case 'v': + show_version = true; + break; + + case 'V': + verbosity = strtoul(optarg, NULL, 10); + break; + + case 'n': + name = optarg; + break; + + case 'p': + port = optarg; + break; + + case 'l': + valid = strtoul(optarg, NULL, 10); + break; + + } + + } + + /* Actions de base */ + + if (show_help) + { + show_hub_help(argv[0]); + result = EXIT_SUCCESS; + goto done; + } + + if (show_version) + { + show_hub_version(); + result = EXIT_SUCCESS; + goto done; + } + + /* Initialisation du programme */ + + set_log_verbosity(verbosity); + + /* Elaboration de l'identité */ + + if ((optind + 1) == argc) + { + log_simple_message(LMT_ERROR, + _("Identity properties are missing; please provide at least an empty string")); + result = 2; + goto done; + } + + ret = parse_identity_properties(argv[optind + 1], &identity); + if (ret != EXIT_SUCCESS) + { + result = ret; + goto done; + } + + /* Traitement de la commande */ + + status = setup_server_identity(name, port, valid, &identity); + + if (status) + result = EXIT_SUCCESS; + + free_x509_entries(&identity); + + done: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : argc = nombre d'arguments dans la ligne de commande. * +* argv = arguments de la ligne de commande. * +* * +* Description : Traite la commande "add-client" et ses arguments. * +* * +* Retour : EXIT_SUCCESS si le programme s'est déroulé sans encombres. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int exec_cmd_add_client(int argc, char **argv) +{ + int result; /* Bilan de l'exécution */ + bool show_help; /* Affichage de l'aide ? */ + bool show_version; /* Affichage de la version ? */ + LogMessageType verbosity; /* Niveau de filtre de message */ + char *name; /* Désignation du serveur */ + char *port; /* Définition du port associé */ + unsigned long valid; /* Durée de validité */ + int index; /* Indice d'argument */ + int ret; /* Bilan d'un appel */ + bool status; /* Bilan d'opérations */ + + static struct option long_options[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'v' }, + { "verbosity", required_argument, NULL, 'V' }, + { "name", required_argument, NULL, 'n' }, + { "port", required_argument, NULL, 'p' }, + { "long", required_argument, NULL, 'l' }, + { NULL, 0, NULL, 0 } + }; + + result = EXIT_FAILURE; + + /* Décodage des options */ + + show_help = false; + show_version = false; + + verbosity = LMT_INFO; + name = NULL; + port = NULL; + valid = 3 * 365 * 24 * 60 * 60; + + while (true) + { + ret = getopt_long(argc - 1, argv + 1, "hvV:n:p:l:", long_options, &index); + if (ret == -1) break; + + switch (ret) + { + case 'h': + show_help = true; + break; + + case 'v': + show_version = true; + break; + + case 'V': + verbosity = strtoul(optarg, NULL, 10); + break; + + case 'n': + name = optarg; + break; + + case 'p': + port = optarg; + break; + + case 'l': + valid = strtoul(optarg, NULL, 10); + break; + + } + + } + + /* Actions de base */ + + if (show_help) + { + show_hub_help(argv[0]); + result = EXIT_SUCCESS; + goto done; + } + + if (show_version) + { + show_hub_version(); + result = EXIT_SUCCESS; + goto done; + } + + if ((optind + 2) >= argc) + { + show_hub_help(argv[0]); + goto done; + } + + /* Initialisation du programme */ + + set_log_verbosity(verbosity); + + /* Traitement de la commande */ + + status = add_client_to_server(name, port, valid, argv[optind + 1], argv[optind + 2]); + + if (status) + result = EXIT_SUCCESS; + + done: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : sig = numéro du signal reçu. * +* * +* Description : Réagit à la réception d'un signal SIGTERM. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void on_term_signal(int sig) +{ + log_simple_message(LMT_INFO, _("Stopping the server...")); + + g_hub_server_stop(_server); + +} + + +/****************************************************************************** +* * +* Paramètres : argc = nombre d'arguments dans la ligne de commande. * +* argv = arguments de la ligne de commande. * +* * +* Description : Traite la commande "run" et ses arguments. * +* * +* Retour : EXIT_SUCCESS si le programme s'est déroulé sans encombres. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int exec_cmd_run_server(int argc, char **argv) +{ + int result; /* Bilan de l'exécution */ + bool show_help; /* Affichage de l'aide ? */ + bool show_version; /* Affichage de la version ? */ + LogMessageType verbosity; /* Niveau de filtre de message */ + char *name; /* Désignation du serveur */ + char *port; /* Définition du port associé */ + bool ipv6; /* Préférence pour IPv6 ? */ + int backlog; /* Nombre de connexions max. */ + bool keep; /* Maintien en avant plan ? */ + int index; /* Indice d'argument */ + int ret; /* Bilan d'un appel */ + ServerStartStatus status; /* Bilan d'un lancement */ + sighandler_t prev; /* Gestionnaire précédent */ + + static struct option long_options[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'v' }, + { "verbosity", required_argument, NULL, 'V' }, + { "name", required_argument, NULL, 'n' }, + { "port", required_argument, NULL, 'p' }, + { "ipv4", no_argument, NULL, '4' }, + { "backlog", required_argument, NULL, 'b' }, + { "keep", no_argument, NULL, 'k' }, + { NULL, 0, NULL, 0 } + }; + + result = EXIT_FAILURE; + + /* Décodage des options */ + + show_help = false; + show_version = false; + + verbosity = LMT_INFO; + name = NULL; + port = NULL; + ipv6 = true; + backlog = 10; + keep = false; + + while (true) + { + ret = getopt_long(argc - 1, argv + 1, "hvV:n:p:4b:k", long_options, &index); + if (ret == -1) break; + + switch (ret) + { + case 'h': + show_help = true; + break; + + case 'v': + show_version = true; + break; + + case 'V': + verbosity = strtoul(optarg, NULL, 10); + break; + + case 'n': + name = optarg; + break; + + case 'p': + port = optarg; + break; + + case '4': + ipv6 = false; + break; + + case 'b': + backlog = atoi(optarg); + break; + + case 'k': + keep = true; + break; + + } + + } + + /* Actions de base */ + + if (show_help) + { + show_hub_help(argv[0]); + result = EXIT_SUCCESS; + goto done; + } + + if (show_version) + { + show_hub_version(); + result = EXIT_SUCCESS; + goto done; + } + + /* Initialisation du programme */ + + set_log_verbosity(verbosity); + + /* Traitement de la commande */ + + if (name == NULL) + _server = g_hub_server_new_internal(); + else + _server = g_hub_server_new_remote(name, port, ipv6); + + status = g_hub_server_start(_server, backlog, keep); + + switch (status) + { + case SSS_FAILURE: + goto stopped; + break; + + case SSS_SUCCESS: + + prev = signal(SIGTERM, on_term_signal); + if (prev == SIG_ERR) + { + LOG_ERROR_N("signal"); + g_hub_server_stop(_server); + goto stopped; + } + + g_hub_server_wait_for_stop(_server); + + result = EXIT_SUCCESS; + break; + + case SSS_ALREADY_RUNNING: + result = EXIT_SUCCESS; + break; + + } + + stopped: + + g_object_unref(G_OBJECT(_server)); + + done: + + return result; + +} diff --git a/src/main.c b/src/main.c index 5dc9e3c..84b0eaa 100644 --- a/src/main.c +++ b/src/main.c @@ -23,12 +23,17 @@ #include +#include #include #include +#include +#include #include +#include #include #include + #include #include @@ -37,8 +42,7 @@ #include "analysis/binary.h" #include "analysis/loading.h" #include "analysis/contents/file.h" -#include "analysis/db/server.h" -#include "common/xdg.h" +#include "analysis/db/auth.h" #include "core/core.h" #include "core/global.h" #include "core/logs.h" @@ -83,15 +87,20 @@ static int save_binary_caches(void); static void show_chrysalide_help(const char *name) { + char *tmp; /* Conservation modifiable */ char *base; /* Version courte du nom */ - base = basename(name); + tmp = strdup(name); + + base = basename(tmp); printf("\n"); printf("Usage: %s [--help] [--version]\n", base); printf(" %s [args] \n", base); + free(tmp); + printf("\n"); printf("\t-h --help\t\tShow this help message.\n"); @@ -167,13 +176,7 @@ int main(int argc, char **argv) int ret; /* Bilan d'un appel */ bool status; /* Bilan d'opérations */ GtkWidget *editor; /* Fenêtre graphique */ - GDbServer *server; /* Enregistrements locaux */ GGenConfig *config; /* Configuration globale */ - - - char *author; /* Identification à diffuser */ - char *pub; /* Chemin de la clef publique */ - bool welcome; /* Affichage de la bienvenue ? */ char resolved[PATH_MAX]; /* Résolution de nom de fichier*/ GStudyProject *project; /* Nouveau projet courant */ @@ -313,19 +316,17 @@ int main(int argc, char **argv) if (!status) goto exit_complete_gui; } - /* Utilisateur représenté */ + /* Lancement du serveur local */ - if (!g_generic_config_get_value(config, MPK_AUTHOR_NAME, &author)) - /*goto glbcl_exit*/; + status = ensure_internal_connections_setup(); - /* Chemin vers la clef privée */ + if (!status) + goto no_internal_server; - pub = get_xdg_config_dir("chrysalide" G_DIR_SEPARATOR_S "id_rsa.pub"); + status = launch_internal_server(); - server = g_db_server_new_internal(author, pub); - - if (server != NULL) - g_db_server_start(server); + if (!status) + goto no_internal_server; /* Charge le dernier projet ? */ @@ -404,13 +405,7 @@ int main(int argc, char **argv) bad_project: - if (server != NULL) - { - g_db_server_stop(server); - - g_object_unref(G_OBJECT(server)); - - } + no_internal_server: exit_complete_gui: -- cgit v0.11.2-87-g4458