diff --git a/CHANGELOG.md b/CHANGELOG.md
index 684baef22..9eb4b3a3d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Added
- Add a new modification_time column to reports [#1513](https://github.com/greenbone/gvmd/pull/1513), [#1519](https://github.com/greenbone/gvmd/pull/1519), [#1590](https://github.com/greenbone/gvmd/pull/1590)
- Add basic Sentry integration and logging [#1550](https://github.com/greenbone/gvmd/pull/1550)
+- Add GMP get_license and modify_license [#1642](https://github.com/greenbone/gvmd/pull/1642)
### Changed
- Use pg-gvm extension for C PostgreSQL functions [#1400](https://github.com/greenbone/gvmd/pull/1400), [#1453](https://github.com/greenbone/gvmd/pull/1453)
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 63a5b6f8e..c1a86b224 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -103,6 +103,7 @@ add_executable (manage-utils-test
gvmd.c gmpd.c
manage.c sql.c
manage_acl.c manage_configs.c manage_get.c
+ manage_license.c
manage_port_lists.c manage_preferences.c
manage_report_formats.c
manage_authentication.c
@@ -115,6 +116,7 @@ add_executable (manage-utils-test
sql_pg.c manage_pg.c
lsc_user.c lsc_crypt.c utils.c
gmp.c gmp_base.c gmp_configs.c gmp_delete.c gmp_get.c
+ gmp_license.c
gmp_port_lists.c gmp_report_formats.c gmp_tickets.c
gmp_tls_certificates.c)
@@ -128,6 +130,7 @@ add_executable (manage-test
gvmd.c gmpd.c
manage_utils.c sql.c
manage_acl.c manage_configs.c manage_get.c
+ manage_license.c
manage_port_lists.c manage_preferences.c
manage_report_formats.c
manage_authentication.c
@@ -140,6 +143,7 @@ add_executable (manage-test
sql_pg.c manage_pg.c
lsc_user.c lsc_crypt.c utils.c
gmp.c gmp_base.c gmp_configs.c gmp_delete.c gmp_get.c
+ gmp_license.c
gmp_port_lists.c gmp_report_formats.c gmp_tickets.c
gmp_tls_certificates.c)
@@ -153,6 +157,7 @@ add_executable (manage-sql-test
gvmd.c gmpd.c
manage_utils.c manage.c sql.c
manage_acl.c manage_configs.c manage_get.c
+ manage_license.c
manage_port_lists.c manage_preferences.c
manage_report_formats.c
manage_authentication.c
@@ -165,6 +170,7 @@ add_executable (manage-sql-test
sql_pg.c manage_pg.c
lsc_user.c lsc_crypt.c utils.c
gmp.c gmp_base.c gmp_configs.c gmp_delete.c gmp_get.c
+ gmp_license.c
gmp_port_lists.c gmp_report_formats.c gmp_tickets.c
gmp_tls_certificates.c)
@@ -178,6 +184,7 @@ add_executable (gmp-tickets-test
gvmd.c gmpd.c
manage_utils.c manage.c sql.c
manage_acl.c manage_configs.c manage_get.c
+ manage_license.c
manage_port_lists.c manage_preferences.c
manage_report_formats.c
manage_authentication.c
@@ -190,6 +197,7 @@ add_executable (gmp-tickets-test
sql_pg.c manage_pg.c
lsc_user.c lsc_crypt.c utils.c
gmp.c gmp_base.c gmp_configs.c gmp_delete.c gmp_get.c
+ gmp_license.c
gmp_port_lists.c gmp_report_formats.c gmp_tls_certificates.c)
add_test (gmp-tickets-test gmp-tickets-test)
@@ -202,6 +210,7 @@ add_executable (utils-test
gvmd.c gmpd.c
manage_utils.c manage.c sql.c
manage_acl.c manage_configs.c manage_get.c
+ manage_license.c
manage_port_lists.c manage_preferences.c
manage_report_formats.c
manage_authentication.c
@@ -214,6 +223,7 @@ add_executable (utils-test
sql_pg.c manage_pg.c
lsc_user.c lsc_crypt.c
gmp.c gmp_base.c gmp_configs.c gmp_delete.c gmp_get.c
+ gmp_license.c
gmp_port_lists.c gmp_report_formats.c gmp_tickets.c
gmp_tls_certificates.c)
@@ -229,6 +239,7 @@ add_executable (gvmd
gmpd.c
manage_utils.c manage.c sql.c
manage_acl.c manage_configs.c manage_get.c
+ manage_license.c
manage_port_lists.c manage_preferences.c
manage_report_formats.c
manage_authentication.c
@@ -241,6 +252,7 @@ add_executable (gvmd
sql_pg.c manage_pg.c
lsc_user.c lsc_crypt.c utils.c
gmp.c gmp_base.c gmp_configs.c gmp_delete.c gmp_get.c
+ gmp_license.c
gmp_port_lists.c gmp_report_formats.c gmp_tickets.c
gmp_tls_certificates.c)
diff --git a/src/gmp.c b/src/gmp.c
index 4202f28ca..c1da7f7d8 100644
--- a/src/gmp.c
+++ b/src/gmp.c
@@ -88,6 +88,7 @@
#include "gmp_delete.h"
#include "gmp_get.h"
#include "gmp_configs.h"
+#include "gmp_license.h"
#include "gmp_port_lists.h"
#include "gmp_report_formats.h"
#include "gmp_tickets.h"
@@ -4329,6 +4330,7 @@ typedef enum
CLIENT_GET_FILTERS,
CLIENT_GET_GROUPS,
CLIENT_GET_INFO,
+ CLIENT_GET_LICENSE,
CLIENT_GET_NOTES,
CLIENT_GET_NVTS,
CLIENT_GET_NVT_FAMILIES,
@@ -4401,6 +4403,7 @@ typedef enum
CLIENT_MODIFY_GROUP_COMMENT,
CLIENT_MODIFY_GROUP_NAME,
CLIENT_MODIFY_GROUP_USERS,
+ CLIENT_MODIFY_LICENSE,
CLIENT_MODIFY_NOTE,
CLIENT_MODIFY_NOTE_ACTIVE,
CLIENT_MODIFY_NOTE_HOSTS,
@@ -5282,6 +5285,13 @@ gmp_xml_handle_start_element (/* unused */ GMarkupParseContext* context,
attribute_values);
set_client_state (CLIENT_GET_GROUPS);
}
+ else if (strcasecmp ("GET_LICENSE", element_name) == 0)
+ {
+ get_license_start (gmp_parser,
+ attribute_names,
+ attribute_values);
+ set_client_state (CLIENT_GET_LICENSE);
+ }
else if (strcasecmp ("GET_NOTES", element_name) == 0)
{
const gchar* attribute;
@@ -5777,6 +5787,13 @@ gmp_xml_handle_start_element (/* unused */ GMarkupParseContext* context,
&modify_port_list_data->port_list_id);
set_client_state (CLIENT_MODIFY_PORT_LIST);
}
+ else if (strcasecmp ("MODIFY_LICENSE", element_name) == 0)
+ {
+ modify_license_start (gmp_parser,
+ attribute_names,
+ attribute_values);
+ set_client_state (CLIENT_MODIFY_LICENSE);
+ }
else if (strcasecmp ("MODIFY_NOTE", element_name) == 0)
{
append_attribute (attribute_names, attribute_values, "note_id",
@@ -7708,6 +7725,11 @@ gmp_xml_handle_start_element (/* unused */ GMarkupParseContext* context,
set_read_over (gmp_parser);
break;
+ case CLIENT_MODIFY_LICENSE:
+ modify_license_element_start (gmp_parser, element_name,
+ attribute_names, attribute_values);
+ break;
+
case CLIENT_MODIFY_NOTE:
if (strcasecmp ("ACTIVE", element_name) == 0)
set_client_state (CLIENT_MODIFY_NOTE_ACTIVE);
@@ -18812,6 +18834,15 @@ gmp_xml_handle_end_element (/* unused */ GMarkupParseContext* context,
handle_get_info (gmp_parser, error);
break;
+ case CLIENT_GET_LICENSE:
+ {
+ if (get_license_element_end (gmp_parser,
+ error,
+ element_name))
+ set_client_state (CLIENT_AUTHENTIC);
+ break;
+ }
+
case CLIENT_GET_NOTES:
handle_get_notes (gmp_parser, error);
break;
@@ -23196,6 +23227,15 @@ gmp_xml_handle_end_element (/* unused */ GMarkupParseContext* context,
CLOSE (CLIENT_MODIFY_GROUP, NAME);
CLOSE (CLIENT_MODIFY_GROUP, USERS);
+ case CLIENT_MODIFY_LICENSE:
+ {
+ if (modify_license_element_end (gmp_parser,
+ error,
+ element_name))
+ set_client_state (CLIENT_AUTHENTIC);
+ break;
+ }
+
case CLIENT_MODIFY_NOTE:
{
if (acl_user_may ("modify_note") == 0)
@@ -26319,6 +26359,11 @@ gmp_xml_handle_text (/* unused */ GMarkupParseContext* context,
}
+ case CLIENT_GET_LICENSE:
+ get_license_element_text (text, text_len);
+ break;
+
+
APPEND (CLIENT_MODIFY_ALERT_NAME,
&modify_alert_data->name);
@@ -26392,6 +26437,11 @@ gmp_xml_handle_text (/* unused */ GMarkupParseContext* context,
&modify_group_data->users);
+ case CLIENT_MODIFY_LICENSE:
+ modify_license_element_text (text, text_len);
+ break;
+
+
APPEND (CLIENT_MODIFY_NOTE_ACTIVE,
&modify_note_data->active);
diff --git a/src/gmp_license.c b/src/gmp_license.c
new file mode 100644
index 000000000..14c8fc199
--- /dev/null
+++ b/src/gmp_license.c
@@ -0,0 +1,487 @@
+/* Copyright (C) 2021 Greenbone Networks GmbH
+ *
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+/**
+ * @file gmp_license.c
+ * @brief GVM GMP layer: License information
+ *
+ * This includes function and variable definitions for GMP handling
+ * of license information.
+ */
+
+#include "gmp_license.h"
+#include "manage_license.h"
+#include "utils.h"
+
+#undef G_LOG_DOMAIN
+/**
+ * @brief GLib log domain.
+ */
+#define G_LOG_DOMAIN "md gmp"
+
+/* GET_LICENSE. */
+
+/**
+ * @brief The get_license command.
+ */
+typedef struct
+{
+ context_data_t *context; ///< XML parser context.
+} get_license_t;
+
+/**
+ * @brief Parser callback data.
+ *
+ * This is initially 0 because it's a global variable.
+ */
+static get_license_t get_license_data;
+
+/**
+ * @brief Reset command data.
+ */
+static void
+get_license_reset ()
+{
+ if (get_license_data.context->first)
+ {
+ free_entity (get_license_data.context->first->data);
+ g_slist_free_1 (get_license_data.context->first);
+ }
+ g_free (get_license_data.context);
+ memset (&get_license_data, 0, sizeof (get_license_t));
+}
+
+/**
+ * @brief Start a command.
+ *
+ * @param[in] gmp_parser GMP parser.
+ * @param[in] attribute_names All attribute names.
+ * @param[in] attribute_values All attribute values.
+ */
+void
+get_license_start (gmp_parser_t *gmp_parser,
+ const gchar **attribute_names,
+ const gchar **attribute_values)
+{
+ memset (&get_license_data, 0, sizeof (get_license_t));
+ get_license_data.context = g_malloc0 (sizeof (context_data_t));
+ get_license_element_start (gmp_parser, "get_license",
+ attribute_names, attribute_values);
+}
+
+/**
+ * @brief Start element.
+ *
+ * @param[in] gmp_parser GMP parser.
+ * @param[in] name Element name.
+ * @param[in] attribute_names All attribute names.
+ * @param[in] attribute_values All attribute values.
+ */
+void
+get_license_element_start (gmp_parser_t *gmp_parser,
+ const gchar *name,
+ const gchar **attribute_names,
+ const gchar **attribute_values)
+{
+ xml_handle_start_element (get_license_data.context, name,
+ attribute_names, attribute_values);
+}
+
+/**
+ * @brief Writes XML for a license access key to a GString buffer.
+ *
+ * This is meant to be used to traverse a GTree with g_tree_foreach.
+ *
+ * @param[in] key The key from the tree, i.e. the access key name.
+ * @param[in] value The value from the tree, i.e. the key content.
+ * @param[in] buffer The GString to buffer the XML element.
+ *
+ * @return Always FALSE to continue traversing the GTree.
+ */
+static gboolean
+buffer_license_key_xml (gchar *key, gchar *value, GString *buffer)
+{
+ xml_string_append (buffer,
+ "%s",
+ key, value);
+ return FALSE;
+}
+
+/**
+ * @brief Writes XML for a license signature info item to a GString buffer.
+ *
+ * This is meant to be used to traverse a GTree with g_tree_foreach.
+ *
+ * @param[in] key The key from the tree, i.e. the info item name.
+ * @param[in] value The value from the tree, i.e. the info item content.
+ * @param[in] buffer The GString to buffer the XML element.
+ *
+ * @return Always FALSE to continue traversing the GTree.
+ */
+static gboolean
+buffer_license_signature_xml (gchar *key, gchar *value, GString *buffer)
+{
+ xml_string_append (buffer,
+ "%s",
+ key, value);
+ return FALSE;
+}
+
+
+/**
+ * @brief Writes license data to a GString as XML
+ *
+ * @param[in] response The GString buffer to write the license content to.
+ * @param[in] license_data The license data struct to get the data from.
+ */
+static void
+buffer_license_content_xml (GString *response, license_data_t *license_data)
+{
+ xml_string_append (response,
+ ""
+ ""
+ "%s"
+ "%s"
+ "%s"
+ "%s"
+ "%s",
+ license_data->meta->id,
+ license_data->meta->version,
+ license_data->meta->title,
+ license_data->meta->type,
+ license_data->meta->customer_name);
+
+ xml_string_append (response,
+ "%s",
+ iso_time (&license_data->meta->created));
+ xml_string_append (response,
+ "%s",
+ iso_time (&license_data->meta->begins));
+ xml_string_append (response,
+ "%s",
+ iso_time (&license_data->meta->expires));
+
+ xml_string_append (response,
+ ""
+ ""
+ "%s"
+ "%s"
+ "%d"
+ ""
+ "",
+ license_data->appliance->model,
+ license_data->appliance->model_type,
+ license_data->appliance->sensor);
+
+ g_tree_foreach (license_data->keys,
+ (GTraverseFunc) buffer_license_key_xml,
+ response);
+
+ xml_string_append (response,
+ ""
+ "");
+
+ g_tree_foreach (license_data->signatures,
+ (GTraverseFunc) buffer_license_signature_xml,
+ response);
+
+ xml_string_append (response,
+ ""
+ "");
+}
+
+
+/**
+ * @brief Execute command.
+ *
+ * @param[in] gmp_parser GMP parser.
+ * @param[in] error Error parameter.
+ */
+static void
+get_license_run (gmp_parser_t *gmp_parser,
+ GError **error)
+{
+ int ret;
+
+ gchar *license_status;
+ license_data_t *license_data;
+
+ license_status = NULL;
+ license_data = NULL;
+
+ ret = manage_get_license (&license_status,
+ &license_data);
+
+ switch (ret)
+ {
+ case 0:
+ {
+ GString *response;
+
+ response = g_string_new ("");
+ xml_string_append (response,
+ ""
+ ""
+ "%s",
+ STATUS_OK,
+ STATUS_OK_TEXT,
+ license_status);
+
+ if (license_data)
+ {
+ buffer_license_content_xml (response, license_data);
+ }
+
+ xml_string_append (response,
+ ""
+ "");
+
+ SEND_TO_CLIENT_OR_FAIL (response->str);
+ g_string_free (response, TRUE);
+ }
+ break;
+ case 1:
+ SENDF_TO_CLIENT_OR_FAIL
+ ("",
+ STATUS_SERVICE_DOWN);
+ break;
+ case 99:
+ SEND_TO_CLIENT_OR_FAIL (XML_ERROR_ACCESS ("get_license"));
+ break;
+ default:
+ SEND_TO_CLIENT_OR_FAIL (XML_INTERNAL_ERROR ("get_license"));
+ break;
+ }
+
+ g_free (license_status);
+ license_data_free (license_data);
+
+ get_license_reset ();
+}
+
+/**
+ * @brief End element.
+ *
+ * @param[in] gmp_parser GMP parser.
+ * @param[in] error Error parameter.
+ * @param[in] name Element name.
+ *
+ * @return 0 success, 1 command finished.
+ */
+int
+get_license_element_end (gmp_parser_t *gmp_parser,
+ GError **error,
+ const gchar *name)
+{
+ xml_handle_end_element (get_license_data.context, name);
+ if (get_license_data.context->done)
+ {
+ get_license_run (gmp_parser, error);
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * @brief Add text to element.
+ *
+ * @param[in] text Text.
+ * @param[in] text_len Text length.
+ */
+void
+get_license_element_text (const gchar *text,
+ gsize text_len)
+{
+ xml_handle_text (get_license_data.context, text, text_len);
+}
+
+
+/* MODIFY_LICENSE. */
+
+/**
+ * @brief The modify_license command.
+ */
+typedef struct
+{
+ context_data_t *context; ///< XML parser context.
+} modify_license_t;
+
+/**
+ * @brief Parser callback data.
+ *
+ * This is initially 0 because it's a global variable.
+ */
+static modify_license_t modify_license_data;
+
+/**
+ * @brief Reset command data.
+ */
+static void
+modify_license_reset ()
+{
+ if (modify_license_data.context->first)
+ {
+ free_entity (modify_license_data.context->first->data);
+ g_slist_free_1 (modify_license_data.context->first);
+ }
+ g_free (modify_license_data.context);
+ memset (&modify_license_data, 0, sizeof (modify_license_t));
+}
+
+/**
+ * @brief Start a command.
+ *
+ * @param[in] gmp_parser GMP parser.
+ * @param[in] attribute_names All attribute names.
+ * @param[in] attribute_values All attribute values.
+ */
+void
+modify_license_start (gmp_parser_t *gmp_parser,
+ const gchar **attribute_names,
+ const gchar **attribute_values)
+{
+ memset (&modify_license_data, 0, sizeof (modify_license_t));
+ modify_license_data.context = g_malloc0 (sizeof (context_data_t));
+ modify_license_element_start (gmp_parser, "modify_license",
+ attribute_names, attribute_values);
+}
+
+/**
+ * @brief Start element.
+ *
+ * @param[in] gmp_parser GMP parser.
+ * @param[in] name Element name.
+ * @param[in] attribute_names All attribute names.
+ * @param[in] attribute_values All attribute values.
+ */
+void
+modify_license_element_start (gmp_parser_t *gmp_parser,
+ const gchar *name,
+ const gchar **attribute_names,
+ const gchar **attribute_values)
+{
+ xml_handle_start_element (modify_license_data.context, name,
+ attribute_names, attribute_values);
+}
+
+/**
+ * @brief Handles modifying the license
+ *
+ * @param[in] file_content The content of the new license file.
+ * @param[in] allow_empty Whether to allow an empty file.
+ *
+ * @return 0 success, 1 service unavailable, 2 empty file not allowed,
+ * 99 permission denied.
+ */
+static int
+modify_license (gchar *file_content, gboolean allow_empty)
+{
+ if (allow_empty == FALSE
+ && (file_content == NULL || strcmp (file_content, "") == 0))
+ return 2;
+
+ return 0;
+}
+
+/**
+ * @brief Execute command.
+ *
+ * @param[in] gmp_parser GMP parser.
+ * @param[in] error Error parameter.
+ */
+static void
+modify_license_run (gmp_parser_t *gmp_parser,
+ GError **error)
+{
+ entity_t entity, file_entity;
+ const char* allow_empty_str;
+ int allow_empty, ret;
+
+ entity = (entity_t) modify_license_data.context->first->data;
+
+ allow_empty_str = entity_attribute (entity, "allow_empty");
+ allow_empty = allow_empty_str ? atoi(allow_empty_str) != 0 : 0;
+
+ file_entity = entity_child (entity, "file");
+
+ ret = modify_license (file_entity ? file_entity->text : NULL, allow_empty);
+ switch (ret)
+ {
+ case 0:
+ SEND_TO_CLIENT_OR_FAIL (XML_OK ("modify_license"));
+ break;
+ case 1:
+ SENDF_TO_CLIENT_OR_FAIL
+ ("",
+ STATUS_SERVICE_DOWN);
+ break;
+ case 2:
+ SENDF_TO_CLIENT_OR_FAIL
+ (XML_ERROR_SYNTAX ("modify_license",
+ "A non-empty FILE or the allow_empty attribute"
+ " is required"));
+ break;
+ case 99:
+ SEND_TO_CLIENT_OR_FAIL (XML_ERROR_ACCESS ("modify_license"));
+ break;
+ default:
+ SEND_TO_CLIENT_OR_FAIL (XML_INTERNAL_ERROR ("modify_license"));
+ break;
+ }
+
+ modify_license_reset ();
+}
+
+/**
+ * @brief End element.
+ *
+ * @param[in] gmp_parser GMP parser.
+ * @param[in] error Error parameter.
+ * @param[in] name Element name.
+ *
+ * @return 0 success, 1 command finished.
+ */
+int
+modify_license_element_end (gmp_parser_t *gmp_parser,
+ GError **error,
+ const gchar *name)
+{
+ xml_handle_end_element (modify_license_data.context, name);
+ if (modify_license_data.context->done)
+ {
+ modify_license_run (gmp_parser, error);
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * @brief Add text to element.
+ *
+ * @param[in] text Text.
+ * @param[in] text_len Text length.
+ */
+void
+modify_license_element_text (const gchar *text,
+ gsize text_len)
+{
+ xml_handle_text (modify_license_data.context, text, text_len);
+}
diff --git a/src/gmp_license.h b/src/gmp_license.h
new file mode 100644
index 000000000..d6f8691a2
--- /dev/null
+++ b/src/gmp_license.h
@@ -0,0 +1,75 @@
+/* Copyright (C) 2021 Greenbone Networks GmbH
+ *
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+#include "gmp_base.h"
+
+#include
+#include
+
+
+/**
+ * @file gmp_tls_certificates.h
+ * @brief GVM GMP layer: License information headers
+ *
+ * Headers for GMP handling of license information.
+ */
+
+/* GET_LICENSE. */
+
+void
+get_license_start (gmp_parser_t *,
+ const gchar **,
+ const gchar **);
+
+void
+get_license_element_start (gmp_parser_t *,
+ const gchar *,
+ const gchar **,
+ const gchar **);
+
+int
+get_license_element_end (gmp_parser_t *,
+ GError **,
+ const gchar *);
+
+void
+get_license_element_text (const gchar *,
+ gsize);
+
+
+/* MODIFY_LICENSE. */
+
+void
+modify_license_start (gmp_parser_t *,
+ const gchar **,
+ const gchar **);
+
+void
+modify_license_element_start (gmp_parser_t *,
+ const gchar *,
+ const gchar **,
+ const gchar **);
+
+int
+modify_license_element_end (gmp_parser_t *,
+ GError **,
+ const gchar *);
+
+void
+modify_license_element_text (const gchar *,
+ gsize);
diff --git a/src/manage_license.c b/src/manage_license.c
new file mode 100644
index 000000000..d45fa8d8b
--- /dev/null
+++ b/src/manage_license.c
@@ -0,0 +1,201 @@
+/* Copyright (C) 2020-2021 Greenbone Networks GmbH
+ *
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+/**
+ * @file manage_license.c
+ * @brief GVM management layer: License information.
+ *
+ * Non-SQL license information code for the GVM management layer.
+ */
+
+#include "manage_acl.h"
+#include "manage_license.h"
+#include "utils.h"
+
+/* Data types */
+
+/**
+ * @brief Allocates a new license metadata struct
+ *
+ * @return Newly allocated license metadata. Free with license_meta_free.
+ */
+license_meta_t *
+license_meta_new ()
+{
+ return g_malloc0 (sizeof (license_meta_t));
+}
+
+/**
+ * @brief Frees a license metadata struct and its fields.
+ *
+ * @param[in] data The data struct to free.
+ */
+void
+license_meta_free (license_meta_t *data)
+{
+ if (data == NULL)
+ return;
+
+ free (data->id);
+ free (data->version);
+ free (data->title);
+ free (data->type);
+ free (data->customer_name);
+
+ g_free (data);
+}
+
+/**
+ * @brief Allocates a new license appliance data struct
+ *
+ * @return Newly allocated license appliance data. Free with license_meta_free.
+ */
+license_appliance_t *
+license_appliance_new ()
+{
+ return g_malloc0 (sizeof (license_appliance_t));
+}
+
+/**
+ * @brief Frees a license appliance data struct and its fields.
+ *
+ * @param[in] data The data struct to free.
+ */
+void
+license_appliance_free (license_appliance_t *data)
+{
+ if (data == NULL)
+ return;
+
+ free (data->model);
+ free (data->model_type);
+
+ g_free (data);
+}
+
+/**
+ * @brief Allocates a new license data struct
+ *
+ * @return Newly allocated license data. Free with license_meta_free.
+ */
+license_data_t *
+license_data_new ()
+{
+ license_data_t *data = g_malloc0 (sizeof (license_data_t));
+
+ data->meta = license_meta_new ();
+ data->appliance = license_appliance_new ();
+
+ data->keys = g_tree_new_full ((GCompareDataFunc) g_ascii_strcasecmp,
+ NULL, g_free, g_free);
+
+ data->signatures = g_tree_new_full ((GCompareDataFunc) g_ascii_strcasecmp,
+ NULL, g_free, g_free);
+
+ return data;
+}
+
+/**
+ * @brief Frees a license data struct and its fields.
+ *
+ * @param[in] data The data struct to free.
+ */
+void
+license_data_free (license_data_t *data)
+{
+ if (data == NULL)
+ return;
+
+ license_meta_free (data->meta);
+ license_appliance_free (data->appliance);
+ g_tree_destroy (data->keys);
+ g_tree_destroy (data->signatures);
+
+ g_free (data);
+}
+
+/* Actions */
+
+/**
+ * @brief Update the license file by replacing it with the given one.
+ *
+ * @param[in] new_license The content of the new license.
+ *
+ * @return 0 success, 99 permission denied.
+ */
+int
+manage_update_license_file (const char *new_license)
+{
+ if (! acl_user_may ("modify_license"))
+ return 99;
+
+ g_message ("%s: Uploaded new license file (%lu bytes)",
+ __func__, strlen (new_license));
+
+ return 0;
+}
+
+/**
+ * @brief Get the current license information.
+ *
+ * @param[out] status The validation status (e.g. "valid", "expired").
+ * @param[out] license_data The content of the license organized in a struct.
+ *
+ * @return 0 success, 1 service unavailable, 99 permission denied.
+ */
+int
+manage_get_license (gchar **status,
+ license_data_t **license_data)
+{
+ if (! acl_user_may ("get_license"))
+ return 99;
+
+ if (status)
+ *status = g_strdup ("active");
+
+ if (license_data)
+ {
+ *license_data = license_data_new ();
+ license_meta_t *license_meta = (*license_data)->meta;
+ license_appliance_t *license_appliance = (*license_data)->appliance;
+
+ // TODO : replace dummy data with data from license service
+ license_meta->id = g_strdup ("4711");
+ license_meta->version = g_strdup_printf("1.0.0");
+ license_meta->title = g_strdup ("Test License");
+ license_meta->type = g_strdup ("trial");
+ license_meta->customer_name = g_strdup ("Jane Doe");
+ license_meta->created = time (NULL) - 3600;
+ license_meta->begins = time (NULL);
+ license_meta->expires = time (NULL) + 3600 * 24 * 8;
+
+ license_appliance->model = g_strdup ("trial");
+ license_appliance->model_type = g_strdup ("virtual");
+ license_appliance->sensor = FALSE;
+
+ g_tree_replace ((*license_data)->keys,
+ g_strdup ("feed"),
+ g_strdup ("*base64 GSF key*"));
+
+ g_tree_replace ((*license_data)->signatures,
+ g_strdup ("license"),
+ g_strdup ("*base64 signature*"));
+ }
+
+ return 0;
+}
diff --git a/src/manage_license.h b/src/manage_license.h
new file mode 100644
index 000000000..ad3a0c9e7
--- /dev/null
+++ b/src/manage_license.h
@@ -0,0 +1,88 @@
+/* Copyright (C) 2020-2021 Greenbone Networks GmbH
+ *
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+/**
+ * @file manage_license.c
+ * @brief GVM management layer: License information headers.
+ *
+ * Headers for non-SQL license information code for the GVM management layer.
+ */
+
+#include
+
+/* Data types */
+
+/**
+ * @brief Defines the metadata of a license
+ */
+typedef struct {
+ char *id; ///< Unique Identifier of the license
+ char *version; ///< Version of the license file schema
+ char *title; ///< Short title summarizing the license
+ char *type; ///< Type of license, e.g. trial or commercial
+ char *customer_name; ///< Name of the customer
+ time_t created; ///< Time the license was created
+ time_t begins; ///< Time after which the license becomes valid
+ time_t expires; ///< Time the license expires
+} license_meta_t;
+
+license_meta_t *
+license_meta_new ();
+
+void
+license_meta_free (license_meta_t *);
+
+/**
+ * @brief Defines the hardware and appliance information of a license
+ */
+typedef struct {
+ char *model; ///< Appliance model, e.g. "one", "ceno", "450", ...
+ char *model_type; ///< Appliance model type, e.g. "virtual" or "hardware"
+ gboolean sensor; ///< Whether the license is applied to a sensor or not
+} license_appliance_t;
+
+license_appliance_t *
+license_appliance_new ();
+
+void
+license_appliance_free (license_appliance_t *);
+
+/**
+ * @brief Defines the information contained in a license
+ */
+typedef struct {
+ license_meta_t *meta; ///< License metadata
+ license_appliance_t *appliance; ///< Hardware and appliance information
+ GTree *keys; ///< Base64 encoded access keys, e.g. feed key
+ GTree *signatures; ///< Signature info of the license
+} license_data_t;
+
+license_data_t *
+license_data_new ();
+
+void
+license_data_free (license_data_t *);
+
+
+/* Actions */
+
+int
+manage_update_license_file (const char *);
+
+int
+manage_get_license (char **, license_data_t **);
diff --git a/src/schema_formats/XML/GMP.xml.in b/src/schema_formats/XML/GMP.xml.in
index 8b28ec81c..4e97c3fb4 100644
--- a/src/schema_formats/XML/GMP.xml.in
+++ b/src/schema_formats/XML/GMP.xml.in
@@ -12605,6 +12605,207 @@ along with this program. If not, see .
+
+ get_license
+ Get the current license
+
+
+ The client uses the get_license command to get the current license.
+
+
+
+
+
+
+
+ status
+ status
+ 1
+
+
+ status_text
+ text
+ 1
+
+ license
+
+
+ license
+ The license information
+
+ status
+ content
+
+
+ status
+ Status of the license
+ text
+
+
+ content
+ The main content of the license file
+
+ meta
+ appliance
+ keys
+ signatures
+
+
+ meta
+ License metadata
+
+ version
+ id
+ title
+ type
+ customer_name
+ created
+ begins
+ expires
+
+
+ version
+ Version of the license file schema
+ text
+
+
+ id
+ Unique Identifier of the license
+ text
+
+
+ title
+ Short title summarizing the license
+ text
+
+
+ type
+ License type, e.g. "trial" or "commercial"
+ text
+
+
+ customer_name
+ Name of the customer the license is issued for
+ text
+
+
+ created
+ Time the license was created
+ iso_time
+
+
+ begins
+ Time after which the license is valid
+ iso_time
+
+
+ expires
+ Time the license expires
+ iso_time
+
+
+
+ appliance
+ Hardware and appliance information
+
+ model
+ model_type
+
+
+ model
+ Appliance model, e.g. "one"
+ text
+
+
+ model_type
+ Appliance model type, e.g. "virtual" or "hardware"
+ text
+
+
+ sensor
+ Whether the license is applied to a sensor or not
+ boolean
+
+
+
+ keys
+ Base64 encoded access keys, e.g. feed keys
+
+ key
+
+
+ key
+ A Base64 encoded access key
+
+
+ name
+ Name of the key
+ text
+
+ text
+
+
+
+
+ signatures
+ Signatures of the license
+
+ signature
+
+
+ signature
+ A signature info item
+
+
+ name
+ Name of the signature
+ text
+
+ text
+
+
+
+
+
+
+
+ Get the current license
+
+
+
+
+
+
+
+ active
+
+
+ 4711
+ 1.0.0
+ Test License
+ trial
+ Jane Doe
+ 2021-08-27T06:05:21Z
+ 2021-08-27T07:05:21Z
+ 2021-09-04T07:05:21Z
+
+
+ trial
+ virtual
+ 0
+
+
+ *base64 GSF key*
+
+
+ *base64 signature*
+
+
+
+
+
+
+ get_nvtsGet one or many NVTs
@@ -23618,6 +23819,59 @@ along with this program. If not, see .
+
+ modify_license
+ Modify the existing license
+
+
+ The client uses the modify_license command to change the current
+ license.
+
+
+ The license has to be provided as a valid license TOML file.
+
+
+
+
+ allow_empty
+ Whether to allow an empty file
+ boolean
+ 0
+
+ file
+
+
+ file
+ The license TOML file in plain-text form
+ text
+
+
+
+
+ status
+ status
+ 1
+
+
+ status_text
+ text
+ 1
+
+
+
+
+ Upload an new license file
+
+
+ [...]
+
+
+
+
+
+
+
+ modify_noteModify an existing note