From fbde6e0ebfc5b0203eda1c5fe3c6ba72d1427896 Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Tue, 22 Feb 2022 13:57:05 +0100 Subject: Introduce a generic way to subclass Python analysis clients. --- plugins/pychrysalide/analysis/db/analyst.c | 48 +++++++++------ plugins/pychrysalide/helpers.c | 58 +++++++++++++++++ plugins/pychrysalide/helpers.h | 16 +++++ src/analysis/db/analyst-int.h | 76 +++++++++++++++++++++++ src/analysis/db/analyst.c | 99 ++++++++++++++---------------- src/analysis/db/analyst.h | 3 +- 6 files changed, 225 insertions(+), 75 deletions(-) create mode 100644 src/analysis/db/analyst-int.h diff --git a/plugins/pychrysalide/analysis/db/analyst.c b/plugins/pychrysalide/analysis/db/analyst.c index c55f34a..3cb77d1 100644 --- a/plugins/pychrysalide/analysis/db/analyst.c +++ b/plugins/pychrysalide/analysis/db/analyst.c @@ -30,7 +30,7 @@ #include -#include +#include #include @@ -45,8 +45,8 @@ -/* Crée un nouvel objet Python de type 'AnalystClient'. */ -static PyObject *py_analyst_client_new(PyTypeObject *, PyObject *, PyObject *); +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_analyst_client_init(PyObject *, PyObject *, PyObject *); /* Envoie un contenu binaire pour conservation côté serveur. */ static PyObject *py_analyst_client_send_content(PyObject *, PyObject *); @@ -80,23 +80,26 @@ static PyObject *py_analyst_client_get_current_snapshot(PyObject *, void *); +CREATE_DYN_CONSTRUCTOR(analyst_client, G_TYPE_ANALYST_CLIENT); + + /****************************************************************************** * * -* Paramètres : type = type de l'objet à instancier. * +* Paramètres : self = objet à initialiser (théoriquement). * * args = arguments fournis à l'appel. * * kwds = arguments de type key=val fournis. * * * -* Description : Crée un nouvel objet Python de type 'AnalystClient'. * +* Description : Initialise une instance sur la base du dérivé de GObject. * * * -* Retour : Instance Python mise en place. * +* Retour : 0. * * * * Remarques : - * * * ******************************************************************************/ -static PyObject *py_analyst_client_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +static int py_analyst_client_init(PyObject *self, PyObject *args, PyObject *kwds) { - PyObject *result; /* Instance à retourner */ + int result; /* Bilan à retourner */ GLoadedContent *loaded; /* Contenu local déjà chargé */ const char *hash; /* Empreinte du binaire visé */ const char *class; /* Nature du contenu analysé */ @@ -107,7 +110,8 @@ static PyObject *py_analyst_client_new(PyTypeObject *type, PyObject *args, PyObj Py_ssize_t i; /* Boucle de parcours */ PyObject *item; /* Elément de la liste Python */ GDbCollection *collec; /* Version équivalente native */ - GAnalystClient *client; /* Serveur mis en place */ + GAnalystClient *client; /* Client mis en place */ + bool status; /* Bilan d'initialisation */ #define ANALYST_CLIENT_DOC \ "AnalystClient provides and receives binary updates to and from a connected" \ @@ -142,12 +146,17 @@ static PyObject *py_analyst_client_new(PyTypeObject *type, PyObject *args, PyObj loaded = NULL; ret = PyArg_ParseTuple(args, "ssO|O&", &hash, &class, &list, convert_to_loaded_content, &loaded); - if (!ret) return NULL; + if (!ret) return -1; + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; if (!PySequence_Check(list)) { PyErr_SetString(PyExc_TypeError, _("The second argument must be a collection list")); - return NULL; + return -1; } length = PySequence_Length(list); @@ -165,7 +174,7 @@ static PyObject *py_analyst_client_new(PyTypeObject *type, PyObject *args, PyObj if (ret != 1) { delete_collections_list(&collections); - result = NULL; + result = -1; goto exit; } @@ -174,14 +183,11 @@ static PyObject *py_analyst_client_new(PyTypeObject *type, PyObject *args, PyObj } - client = g_analyst_client_new(hash, class, collections, loaded); + client = G_ANALYST_CLIENT(pygobject_get(self)); - if (client != NULL) - { - result = pygobject_new(G_OBJECT(client)); - g_object_unref(client); - } - else result = NULL; + status = g_analyst_client_setup(client, hash, class, collections, loaded); + + result = status ? 0 : -1; exit: @@ -861,7 +867,9 @@ PyTypeObject *get_python_analyst_client_type(void) .tp_methods = py_analyst_client_methods, .tp_getset = py_analyst_client_getseters, - .tp_new = py_analyst_client_new, + + .tp_init = py_analyst_client_init, + .tp_new = py_analyst_client_new }; diff --git a/plugins/pychrysalide/helpers.c b/plugins/pychrysalide/helpers.c index 320e40a..b04c801 100644 --- a/plugins/pychrysalide/helpers.c +++ b/plugins/pychrysalide/helpers.c @@ -37,6 +37,7 @@ #include #include +#include #include "access.h" @@ -509,6 +510,63 @@ bool register_python_module_object(PyObject *module, PyTypeObject *type) * args = éventuelle liste d'arguments. * * kwds = éventuel dictionnaire de valeurs mises à disposition. * * * +* Description : Accompagne la création d'une instance dérivée en Python. * +* * +* Retour : Nouvel objet Python mis en place ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyObject *python_constructor_with_dynamic_gtype(PyTypeObject *type, PyObject *args, PyObject *kwds, PyTypeObject *base, GType base_gtype) +{ + PyObject *result; /* Objet à retourner */ + bool first_time; /* Evite les multiples passages*/ + GType gtype; /* Nouveau type de processeur */ + bool status; /* Bilan d'un enregistrement */ + + /* Validations diverses */ + + if (type == base) + goto simple_way; + + /* Mise en place d'un type dédié */ + + first_time = (g_type_from_name(type->tp_name) == 0); + + gtype = build_dynamic_type(base_gtype, type->tp_name, NULL, NULL, NULL); + + if (first_time) + { + status = register_class_for_dynamic_pygobject(gtype, type, base); + + if (!status) + { + result = NULL; + goto exit; + } + + } + + /* On crée, et on laisse ensuite la main à PyGObject_Type.tp_init() */ + + simple_way: + + result = PyType_GenericNew(type, args, kwds); + + exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : type = type du nouvel objet à mettre en place. * +* args = éventuelle liste d'arguments. * +* kwds = éventuel dictionnaire de valeurs mises à disposition. * +* * * Description : Marque l'interdiction d'une instanciation depuis Python. * * * * Retour : NULL pour la levée d'exception. * diff --git a/plugins/pychrysalide/helpers.h b/plugins/pychrysalide/helpers.h index 0ef8adc..32851c0 100644 --- a/plugins/pychrysalide/helpers.h +++ b/plugins/pychrysalide/helpers.h @@ -158,6 +158,22 @@ bool register_python_module_object(PyObject *, PyTypeObject *); #define APPLY_ABSTRACT_FLAG(tp) tp->tp_new = PyBaseObject_Type.tp_new +/* Accompagne la création d'une instance dérivée en Python. */ +PyObject *python_constructor_with_dynamic_gtype(PyTypeObject *, PyObject *, PyObject *, PyTypeObject *, GType); + + +#define CREATE_DYN_CONSTRUCTOR(pyname, gbase) \ +static PyObject *py_ ## pyname ## _new(PyTypeObject *, PyObject *, PyObject *); \ +static PyObject *py_ ## pyname ## _new(PyTypeObject *type, PyObject *args, PyObject *kwds) \ +{ \ + PyObject *result; /* Objet à retourner */ \ + PyTypeObject *base; /* Type de base à dériver */ \ + base = get_python_ ## pyname ## _type(); \ + result = python_constructor_with_dynamic_gtype(type, args, kwds, base, gbase); \ + return result; \ +} + + /* Marque l'interdiction d'une instanciation depuis Python. */ PyObject *no_python_constructor_allowed(PyTypeObject *, PyObject *, PyObject *); diff --git a/src/analysis/db/analyst-int.h b/src/analysis/db/analyst-int.h new file mode 100644 index 0000000..4f76eff --- /dev/null +++ b/src/analysis/db/analyst-int.h @@ -0,0 +1,76 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * analyst-int.h - prototypes pour la définition interne des connexions en analyste à un serveur Chrysalide + * + * Copyright (C) 2022 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_ANALYST_INT_H +#define _ANALYSIS_DB_ANALYST_INT_H + + +#include "analyst.h" +#include "client-int.h" + + + +/* Description de client à l'écoute (instance) */ +struct _GAnalystClient +{ + GHubClient parent; /* A laisser en premier */ + + char *cnt_hash; /* Empreinte du binaire lié */ + char *cnt_class; /* Interprétation du contenu */ + + GLoadedContent *loaded; /* Contenu chargé */ + GList *collections; /* Collections d'un binaire */ + + bool can_get_updates; /* Réception de maj possibles ?*/ + + snapshot_info_t *snapshots; /* Liste des instantanés */ + size_t snap_count; /* Taille de cette liste */ + GMutex snap_lock; /* Concurrence des accès */ + + snapshot_id_t current; /* Instantané courant */ + bool has_current; /* Validité de l'identifiant */ + GMutex cur_lock; /* Concurrence des accès */ + +}; + +/* Description de client à l'écoute (classe) */ +struct _GAnalystClientClass +{ + GHubClientClass parent; /* A laisser en premier */ + + /* Signaux */ + + void (* ready) (GAnalystClient *); + void (* server_status_changed) (GAnalystClient *, LoadingStatusHint); + void (* snapshots_updated) (GAnalystClient *); + void (* snapshot_changed) (GAnalystClient *); + +}; + + +/* Prépare un client pour une connexion à une BD. */ +bool g_analyst_client_setup(GAnalystClient *, const char *, const char *, GList *, GLoadedContent *); + + + +#endif /* _ANALYSIS_DB_ANALYST_INT_H */ diff --git a/src/analysis/db/analyst.c b/src/analysis/db/analyst.c index 2e1cc23..43fb840 100644 --- a/src/analysis/db/analyst.c +++ b/src/analysis/db/analyst.c @@ -29,59 +29,13 @@ #include -#include "client-int.h" +#include "analyst-int.h" #include "../storage/storage.h" #include "../../core/logs.h" - - - - -/* ------------------------- PRISES EN COMPTE DES COMMANDES ------------------------- */ - - - - - - -/* Description de client à l'écoute (instance) */ -struct _GAnalystClient -{ - GHubClient parent; /* A laisser en premier */ - - char *cnt_hash; /* Empreinte du binaire lié */ - char *cnt_class; /* Interprétation du contenu */ - - GLoadedContent *loaded; /* Contenu chargé */ - GList *collections; /* Collections d'un binaire */ - - bool can_get_updates; /* Réception de maj possibles ?*/ - - snapshot_info_t *snapshots; /* Liste des instantanés */ - size_t snap_count; /* Taille de cette liste */ - GMutex snap_lock; /* Concurrence des accès */ - - snapshot_id_t current; /* Instantané courant */ - bool has_current; /* Validité de l'identifiant */ - GMutex cur_lock; /* Concurrence des accès */ - -}; - -/* Description de client à l'écoute (classe) */ -struct _GAnalystClientClass -{ - GHubClientClass parent; /* A laisser en premier */ - - /* Signaux */ - - void (* ready) (GAnalystClient *); - void (* server_status_changed) (GAnalystClient *, LoadingStatusHint); - void (* snapshots_updated) (GAnalystClient *); - void (* snapshot_changed) (GAnalystClient *); - -}; +/* ----------------------- DEFINITION D'ANALYSTE COMME CLIENT ----------------------- */ /* Initialise la classe des descriptions de fichier binaire. */ @@ -118,7 +72,6 @@ static bool g_analyst_client_handle_loading_hints(GAnalystClient *, packed_buffe - /* ---------------------------------------------------------------------------------- */ /* GLUES POUR LA GLIB */ /* ---------------------------------------------------------------------------------- */ @@ -158,6 +111,9 @@ GType g_loading_status_hint_type(void) +/* ---------------------------------------------------------------------------------- */ +/* DEFINITION D'ANALYSTE COMME CLIENT */ +/* ---------------------------------------------------------------------------------- */ /* Indique le type défini pour une description de client à l'écoute. */ @@ -330,7 +286,7 @@ static void g_analyst_client_finalize(GAnalystClient *client) * collections = ensemble de collections existantes. * * loaded = éventuel élément local préchargé. * * * -* Description : Prépare un client pour une connexion à une BD. * +* Description : Met en place un client pour une connexion à une BD. * * * * Retour : Structure mise en place ou NULL en cas d'échec. * * * @@ -341,16 +297,51 @@ static void g_analyst_client_finalize(GAnalystClient *client) GAnalystClient *g_analyst_client_new(const char *hash, const char *class, GList *collections, GLoadedContent *loaded) { GAnalystClient *result; /* Adresse à retourner */ + bool status; /* Bilan de l'initialisation */ result = g_object_new(G_TYPE_ANALYST_CLIENT, NULL); - result->cnt_hash = strdup(hash); - result->cnt_class = strdup(class); + status = g_analyst_client_setup(result, hash, class, collections, loaded); + + assert(status); + + if (!status) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : client = client pour les accès distants à initialiser. * +* hash = empreinte d'un binaire en cours d'analyse. * +* class = nature de l'interprétation de ce contenu. * +* collections = ensemble de collections existantes. * +* loaded = éventuel élément local préchargé. * +* * +* Description : Prépare un client pour une connexion à une BD. * +* * +* Retour : Structure mise en place ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_analyst_client_setup(GAnalystClient *client, const char *hash, const char *class, GList *collections, GLoadedContent *loaded) +{ + bool result; /* Bilan à retourner */ + + result = true; + + client->cnt_hash = strdup(hash); + client->cnt_class = strdup(class); - result->loaded = loaded; + client->loaded = loaded; if (loaded != NULL) g_object_ref(G_OBJECT(loaded)); - result->collections = collections; + client->collections = collections; return result; diff --git a/src/analysis/db/analyst.h b/src/analysis/db/analyst.h index 459034e..ff189ba 100644 --- a/src/analysis/db/analyst.h +++ b/src/analysis/db/analyst.h @@ -50,6 +50,7 @@ GType g_loading_status_hint_type(void); +/* ----------------------- DEFINITION D'ANALYSTE COMME CLIENT ----------------------- */ #define G_TYPE_ANALYST_CLIENT g_analyst_client_get_type() @@ -70,7 +71,7 @@ typedef struct _GAnalystClientClass GAnalystClientClass; /* Indique le type défini pour une description de client à l'écoute. */ GType g_analyst_client_get_type(void); -/* Prépare un client pour une connexion à une BD. */ +/* Met en place un client pour une connexion à une BD. */ GAnalystClient *g_analyst_client_new(const char *, const char *, GList *, GLoadedContent *); /* Envoie un contenu binaire pour conservation côté serveur. */ -- cgit v0.11.2-87-g4458