summaryrefslogtreecommitdiff
path: root/src/analysis/db/auth.c
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2019-08-29 21:43:47 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2019-08-29 21:43:47 (GMT)
commitfa40856e942a7e1bd1cb2729645182c1fa717468 (patch)
tree954db169d2b734e661d904e502cd1c803f51c6ea /src/analysis/db/auth.c
parent7f973e015eb59b626edc584a19a1ad3ffddf4867 (diff)
Defined a new way to launch updates share servers.
Diffstat (limited to 'src/analysis/db/auth.c')
-rw-r--r--src/analysis/db/auth.c705
1 files changed, 705 insertions, 0 deletions
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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "auth.h"
+
+
+#include <fcntl.h>
+#include <glib.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+
+#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;
+
+}