From 7d292a10a8dcdf2501b6d5ce374502e4b45a77c3 Mon Sep 17 00:00:00 2001 From: Matt Mundell Date: Wed, 28 Jan 2026 17:11:55 +0200 Subject: [PATCH 1/3] Change: move iterators to dedicated permission files --- src/manage.h | 36 ---- src/manage_permissions.h | 37 ++++ src/manage_sql.c | 369 ----------------------------------- src/manage_sql_permissions.c | 222 +++++++++++++++++++++ src/manage_sql_permissions.h | 147 ++++++++++++++ 5 files changed, 406 insertions(+), 405 deletions(-) diff --git a/src/manage.h b/src/manage.h index 477f7f943..72ba5e809 100644 --- a/src/manage.h +++ b/src/manage.h @@ -2909,42 +2909,6 @@ trash_permission_writable (permission_t); int permission_count (const get_data_t *); -int -init_permission_iterator (iterator_t*, get_data_t *); - -const char* -permission_iterator_resource_type (iterator_t*); - -const char* -permission_iterator_resource_uuid (iterator_t*); - -const char* -permission_iterator_resource_name (iterator_t*); - -int -permission_iterator_resource_in_trash (iterator_t*); - -int -permission_iterator_resource_orphan (iterator_t*); - -int -permission_iterator_resource_readable (iterator_t*); - -const char* -permission_iterator_subject_type (iterator_t*); - -const char* -permission_iterator_subject_uuid (iterator_t*); - -const char* -permission_iterator_subject_name (iterator_t*); - -int -permission_iterator_subject_in_trash (iterator_t*); - -int -permission_iterator_subject_readable (iterator_t*); - int delete_permission (const char*, int); diff --git a/src/manage_permissions.h b/src/manage_permissions.h index e0d0ac34c..b73fbe868 100644 --- a/src/manage_permissions.h +++ b/src/manage_permissions.h @@ -7,6 +7,7 @@ #define _GVMD_MANAGE_PERMISSIONS_H #include "manage_resources.h" +#include "gmp_get.h" int permission_is_admin (const char *); @@ -14,4 +15,40 @@ permission_is_admin (const char *); char * permission_uuid (permission_t); +int +init_permission_iterator (iterator_t*, get_data_t *); + +const char* +permission_iterator_resource_type (iterator_t*); + +const char* +permission_iterator_resource_uuid (iterator_t*); + +const char* +permission_iterator_resource_name (iterator_t*); + +int +permission_iterator_resource_in_trash (iterator_t*); + +int +permission_iterator_resource_orphan (iterator_t*); + +int +permission_iterator_resource_readable (iterator_t*); + +const char* +permission_iterator_subject_type (iterator_t*); + +const char* +permission_iterator_subject_uuid (iterator_t*); + +const char* +permission_iterator_subject_name (iterator_t*); + +int +permission_iterator_subject_in_trash (iterator_t*); + +int +permission_iterator_subject_readable (iterator_t*); + #endif /* not _GVMD_MANAGE_PERMISSIONS_H */ diff --git a/src/manage_sql.c b/src/manage_sql.c index 1f3de9b30..70eb18467 100644 --- a/src/manage_sql.c +++ b/src/manage_sql.c @@ -33743,375 +33743,6 @@ trash_permission_writable (permission_t permission) return 1; } -/** - * @brief Filter columns for permission iterator. - */ -#define PERMISSION_ITERATOR_FILTER_COLUMNS \ - { GET_ITERATOR_FILTER_COLUMNS, "type", "resource_uuid", "subject_type", \ - "_subject", "_resource", "subject_uuid", "orphan", NULL } - -/** - * @brief Permission iterator columns. - */ -#define PERMISSION_ITERATOR_COLUMNS \ - { \ - GET_ITERATOR_COLUMNS (permissions), \ - { "resource_type", "type", KEYWORD_TYPE_STRING }, \ - { "resource_uuid", NULL, KEYWORD_TYPE_STRING }, \ - { \ - "(CASE" \ - " WHEN resource_type = '' OR resource_type IS NULL" \ - " THEN ''" \ - " ELSE resource_name (resource_type, resource_uuid, resource_location)" \ - " END)", \ - "_resource", \ - KEYWORD_TYPE_STRING \ - }, \ - { "CAST ((resource_location = " G_STRINGIFY (LOCATION_TRASH) ")" \ - " AS INTEGER)", \ - NULL, \ - KEYWORD_TYPE_INTEGER }, \ - { \ - "(CASE" \ - " WHEN resource = -1" \ - " THEN 1" \ - " ELSE 0" \ - " END)", \ - "orphan", \ - KEYWORD_TYPE_INTEGER \ - }, \ - { "subject_type", NULL, KEYWORD_TYPE_STRING }, \ - { \ - "(CASE" \ - " WHEN subject_type = 'user'" \ - " THEN (SELECT uuid FROM users WHERE users.id = subject)" \ - " WHEN subject_type = 'group'" \ - " AND subject_location = " G_STRINGIFY (LOCATION_TRASH) \ - " THEN (SELECT uuid FROM groups_trash" \ - " WHERE groups_trash.id = subject)" \ - " WHEN subject_type = 'group'" \ - " THEN (SELECT uuid FROM groups WHERE groups.id = subject)" \ - " WHEN subject_location = " G_STRINGIFY (LOCATION_TRASH) \ - " THEN (SELECT uuid FROM roles_trash" \ - " WHERE roles_trash.id = subject)" \ - " ELSE (SELECT uuid FROM roles WHERE roles.id = subject)" \ - " END)", \ - "subject_uuid", \ - KEYWORD_TYPE_STRING \ - }, \ - { \ - "(CASE" \ - " WHEN subject_type = 'user'" \ - " THEN (SELECT name FROM users WHERE users.id = subject)" \ - " WHEN subject_type = 'group'" \ - " AND subject_location = " G_STRINGIFY (LOCATION_TRASH) \ - " THEN (SELECT name FROM groups_trash" \ - " WHERE groups_trash.id = subject)" \ - " WHEN subject_type = 'group'" \ - " THEN (SELECT name FROM groups WHERE groups.id = subject)" \ - " WHEN subject_location = " G_STRINGIFY (LOCATION_TRASH) \ - " THEN (SELECT name FROM roles_trash" \ - " WHERE roles_trash.id = subject)" \ - " ELSE (SELECT name FROM roles WHERE roles.id = subject)" \ - " END)", \ - "_subject", \ - KEYWORD_TYPE_STRING \ - }, \ - { "CAST ((subject_location = " G_STRINGIFY (LOCATION_TRASH) ")" \ - " AS INTEGER)", \ - NULL, \ - KEYWORD_TYPE_INTEGER }, \ - { NULL, NULL, KEYWORD_TYPE_UNKNOWN } \ - } - -/** - * @brief Permission iterator columns for trash case. - */ -#define PERMISSION_ITERATOR_TRASH_COLUMNS \ - { \ - GET_ITERATOR_COLUMNS (permissions_trash), \ - { "resource_type", "type", KEYWORD_TYPE_STRING }, \ - { "resource_uuid", NULL, KEYWORD_TYPE_STRING }, \ - { \ - "(CASE" \ - " WHEN resource_type = '' OR resource_type IS NULL" \ - " THEN ''" \ - " ELSE resource_name (resource_type, resource_uuid, resource_location)" \ - " END)", \ - "_resource", \ - KEYWORD_TYPE_STRING \ - }, \ - { "CAST ((resource_location = " G_STRINGIFY (LOCATION_TRASH) ")" \ - " AS INTEGER)", \ - NULL, \ - KEYWORD_TYPE_INTEGER }, \ - { "resource = -1", NULL, KEYWORD_TYPE_INTEGER }, \ - { "subject_type", NULL, KEYWORD_TYPE_STRING }, \ - { \ - "(CASE" \ - " WHEN subject_type = 'user'" \ - " THEN (SELECT uuid FROM users WHERE users.id = subject)" \ - " WHEN subject_type = 'group'" \ - " AND subject_location = " G_STRINGIFY (LOCATION_TRASH) \ - " THEN (SELECT uuid FROM groups_trash" \ - " WHERE groups_trash.id = subject)" \ - " WHEN subject_type = 'group'" \ - " THEN (SELECT uuid FROM groups WHERE groups.id = subject)" \ - " WHEN subject_location = " G_STRINGIFY (LOCATION_TRASH) \ - " THEN (SELECT uuid FROM roles_trash" \ - " WHERE roles_trash.id = subject)" \ - " ELSE (SELECT uuid FROM roles WHERE roles.id = subject)" \ - " END)", \ - "subject_uuid", \ - KEYWORD_TYPE_STRING \ - }, \ - { \ - "(CASE" \ - " WHEN subject_type = 'user'" \ - " THEN (SELECT name FROM users WHERE users.id = subject)" \ - " WHEN subject_type = 'group'" \ - " AND subject_location = " G_STRINGIFY (LOCATION_TRASH) \ - " THEN (SELECT name FROM groups_trash" \ - " WHERE groups_trash.id = subject)" \ - " WHEN subject_type = 'group'" \ - " THEN (SELECT name FROM groups WHERE groups.id = subject)" \ - " WHEN subject_location = " G_STRINGIFY (LOCATION_TRASH) \ - " THEN (SELECT name FROM roles_trash" \ - " WHERE roles_trash.id = subject)" \ - " ELSE (SELECT name FROM roles WHERE roles.id = subject)" \ - " END)", \ - "_subject", \ - KEYWORD_TYPE_STRING \ - }, \ - { "CAST ((subject_location = " G_STRINGIFY (LOCATION_TRASH) ")" \ - " AS INTEGER)", \ - NULL, \ - KEYWORD_TYPE_INTEGER }, \ - { NULL, NULL, KEYWORD_TYPE_UNKNOWN } \ - } - -/** - * @brief Count number of permissions. - * - * @param[in] get GET params. - * - * @return Total number of permissions in filtered set. - */ -int -permission_count (const get_data_t *get) -{ - static const char *filter_columns[] = PERMISSION_ITERATOR_FILTER_COLUMNS; - static column_t columns[] = PERMISSION_ITERATOR_COLUMNS; - static column_t trash_columns[] = PERMISSION_ITERATOR_TRASH_COLUMNS; - - return count ("permission", get, columns, trash_columns, filter_columns, - 0, 0, 0, TRUE); -} - -/** - * @brief Initialise a permission iterator. - * - * @param[in] iterator Iterator. - * @param[in] get GET data. - * - * @return 0 success, 1 failed to find target, 2 failed to find filter, - * -1 error. - */ -int -init_permission_iterator (iterator_t* iterator, get_data_t *get) -{ - static const char *filter_columns[] = PERMISSION_ITERATOR_FILTER_COLUMNS; - static column_t columns[] = PERMISSION_ITERATOR_COLUMNS; - static column_t trash_columns[] = PERMISSION_ITERATOR_TRASH_COLUMNS; - - return init_get_iterator (iterator, - "permission", - get, - columns, - trash_columns, - filter_columns, - 0, - NULL, - NULL, - TRUE); -} - -/** - * @brief Get the type of resource from a permission iterator. - * - * @param[in] iterator Iterator. - * - * @return Type, or NULL if iteration is complete. - */ -DEF_ACCESS (permission_iterator_resource_type, GET_ITERATOR_COLUMN_COUNT); - -/** - * @brief Get the UUID of the resource from a permission iterator. - * - * @param[in] iterator Iterator. - * - * @return UUID, or NULL if iteration is complete. - */ -DEF_ACCESS (permission_iterator_resource_uuid, GET_ITERATOR_COLUMN_COUNT + 1); - -/** - * @brief Get the name of the resource from a permission iterator. - * - * @param[in] iterator Iterator. - * - * @return Name, or NULL if iteration is complete. - */ -DEF_ACCESS (permission_iterator_resource_name, GET_ITERATOR_COLUMN_COUNT + 2); - -/** - * @brief Return the permission resource location. - * - * @param[in] iterator Iterator. - * - * @return Whether the resource is in the trashcan - */ -int -permission_iterator_resource_in_trash (iterator_t* iterator) -{ - if (iterator->done) return 0; - return iterator_int64 (iterator, GET_ITERATOR_COLUMN_COUNT + 3); -} - -/** - * @brief Check if the permission resource has been deleted. - * - * @param[in] iterator Iterator. - * - * @return Whether the resource has been deleted. - */ -int -permission_iterator_resource_orphan (iterator_t* iterator) -{ - if (iterator->done) return 0; - return iterator_int64 (iterator, GET_ITERATOR_COLUMN_COUNT + 4); -} - -/** - * @brief Get the readable status of a resource from a permission iterator. - * - * @param[in] iterator Iterator. - * - * @return 1 if readable, otherwise 0. - */ -int -permission_iterator_resource_readable (iterator_t* iterator) -{ - resource_t found; - const char *type, *uuid; - gchar *permission; - - if (iterator->done) return 0; - - type = permission_iterator_resource_type (iterator); - uuid = permission_iterator_resource_uuid (iterator); - - if (type == NULL || uuid == NULL) - return 0; - - if (type_is_info_subtype (type)) - permission = g_strdup ("get_info"); - else if (type_is_asset_subtype (type)) - permission = g_strdup ("get_assets"); - else - permission = g_strdup_printf ("get_%ss", type); - - found = 0; - find_resource_with_permission (type, - uuid, - &found, - permission, - permission_iterator_resource_in_trash - (iterator)); - g_free (permission); - return found > 0; -} - -/** - * @brief Get the type of subject from a permission iterator. - * - * @param[in] iterator Iterator. - * - * @return Type, or NULL if iteration is complete. - */ -DEF_ACCESS (permission_iterator_subject_type, GET_ITERATOR_COLUMN_COUNT + 5); - -/** - * @brief Get the subject UUID from a permission iterator. - * - * @param[in] iterator Iterator. - * - * @return UUID, or NULL if iteration is complete. - */ -DEF_ACCESS (permission_iterator_subject_uuid, GET_ITERATOR_COLUMN_COUNT + 6); - -/** - * @brief Get the subject name from a permission iterator. - * - * @param[in] iterator Iterator. - * - * @return Name, or NULL if iteration is complete. - */ -DEF_ACCESS (permission_iterator_subject_name, GET_ITERATOR_COLUMN_COUNT + 7); - -/** - * @brief Return the permission subject location. - * - * @param[in] iterator Iterator. - * - * @return Whether the subject is in the trashcan - */ -int -permission_iterator_subject_in_trash (iterator_t* iterator) -{ - if (iterator->done) return 0; - return iterator_int64 (iterator, GET_ITERATOR_COLUMN_COUNT + 8); -} - -/** - * @brief Get the readable status of a subject from a permission iterator. - * - * @param[in] iterator Iterator. - * - * @return 1 if readable, otherwise 0. - */ -int -permission_iterator_subject_readable (iterator_t* iterator) -{ - resource_t found; - const char *type, *uuid; - gchar *permission; - - if (iterator->done) return 0; - - type = permission_iterator_subject_type (iterator); - uuid = permission_iterator_subject_uuid (iterator); - - if (type == NULL || uuid == NULL) - return 0; - - if ((strcmp (type, "user") == 0) - || (strcmp (type, "role") == 0) - || (strcmp (type, "group") == 0)) - permission = g_strdup_printf ("get_%ss", type); - else - return 0; - - found = 0; - find_resource_with_permission (type, - uuid, - &found, - permission, - permission_iterator_subject_in_trash - (iterator)); - g_free (permission); - return found > 0; -} - /** * @brief Find a permission with a given permission, given a UUID. * diff --git a/src/manage_sql_permissions.c b/src/manage_sql_permissions.c index adc4c0913..40be40c4e 100644 --- a/src/manage_sql_permissions.c +++ b/src/manage_sql_permissions.c @@ -511,3 +511,225 @@ clean_feed_role_permissions (const char *type, return; } + +/** + * @brief Count number of permissions. + * + * @param[in] get GET params. + * + * @return Total number of permissions in filtered set. + */ +int +permission_count (const get_data_t *get) +{ + static const char *filter_columns[] = PERMISSION_ITERATOR_FILTER_COLUMNS; + static column_t columns[] = PERMISSION_ITERATOR_COLUMNS; + static column_t trash_columns[] = PERMISSION_ITERATOR_TRASH_COLUMNS; + + return count ("permission", get, columns, trash_columns, filter_columns, + 0, 0, 0, TRUE); +} + +/** + * @brief Initialise a permission iterator. + * + * @param[in] iterator Iterator. + * @param[in] get GET data. + * + * @return 0 success, 1 failed to find target, 2 failed to find filter, + * -1 error. + */ +int +init_permission_iterator (iterator_t* iterator, get_data_t *get) +{ + static const char *filter_columns[] = PERMISSION_ITERATOR_FILTER_COLUMNS; + static column_t columns[] = PERMISSION_ITERATOR_COLUMNS; + static column_t trash_columns[] = PERMISSION_ITERATOR_TRASH_COLUMNS; + + return init_get_iterator (iterator, + "permission", + get, + columns, + trash_columns, + filter_columns, + 0, + NULL, + NULL, + TRUE); +} + +/** + * @brief Get the type of resource from a permission iterator. + * + * @param[in] iterator Iterator. + * + * @return Type, or NULL if iteration is complete. + */ +DEF_ACCESS (permission_iterator_resource_type, GET_ITERATOR_COLUMN_COUNT); + +/** + * @brief Get the UUID of the resource from a permission iterator. + * + * @param[in] iterator Iterator. + * + * @return UUID, or NULL if iteration is complete. + */ +DEF_ACCESS (permission_iterator_resource_uuid, GET_ITERATOR_COLUMN_COUNT + 1); + +/** + * @brief Get the name of the resource from a permission iterator. + * + * @param[in] iterator Iterator. + * + * @return Name, or NULL if iteration is complete. + */ +DEF_ACCESS (permission_iterator_resource_name, GET_ITERATOR_COLUMN_COUNT + 2); + +/** + * @brief Return the permission resource location. + * + * @param[in] iterator Iterator. + * + * @return Whether the resource is in the trashcan + */ +int +permission_iterator_resource_in_trash (iterator_t* iterator) +{ + if (iterator->done) return 0; + return iterator_int64 (iterator, GET_ITERATOR_COLUMN_COUNT + 3); +} + +/** + * @brief Check if the permission resource has been deleted. + * + * @param[in] iterator Iterator. + * + * @return Whether the resource has been deleted. + */ +int +permission_iterator_resource_orphan (iterator_t* iterator) +{ + if (iterator->done) return 0; + return iterator_int64 (iterator, GET_ITERATOR_COLUMN_COUNT + 4); +} + +/** + * @brief Get the readable status of a resource from a permission iterator. + * + * @param[in] iterator Iterator. + * + * @return 1 if readable, otherwise 0. + */ +int +permission_iterator_resource_readable (iterator_t* iterator) +{ + resource_t found; + const char *type, *uuid; + gchar *permission; + + if (iterator->done) return 0; + + type = permission_iterator_resource_type (iterator); + uuid = permission_iterator_resource_uuid (iterator); + + if (type == NULL || uuid == NULL) + return 0; + + if (type_is_info_subtype (type)) + permission = g_strdup ("get_info"); + else if (type_is_asset_subtype (type)) + permission = g_strdup ("get_assets"); + else + permission = g_strdup_printf ("get_%ss", type); + + found = 0; + find_resource_with_permission (type, + uuid, + &found, + permission, + permission_iterator_resource_in_trash + (iterator)); + g_free (permission); + return found > 0; +} + +/** + * @brief Get the type of subject from a permission iterator. + * + * @param[in] iterator Iterator. + * + * @return Type, or NULL if iteration is complete. + */ +DEF_ACCESS (permission_iterator_subject_type, GET_ITERATOR_COLUMN_COUNT + 5); + +/** + * @brief Get the subject UUID from a permission iterator. + * + * @param[in] iterator Iterator. + * + * @return UUID, or NULL if iteration is complete. + */ +DEF_ACCESS (permission_iterator_subject_uuid, GET_ITERATOR_COLUMN_COUNT + 6); + +/** + * @brief Get the subject name from a permission iterator. + * + * @param[in] iterator Iterator. + * + * @return Name, or NULL if iteration is complete. + */ +DEF_ACCESS (permission_iterator_subject_name, GET_ITERATOR_COLUMN_COUNT + 7); + +/** + * @brief Return the permission subject location. + * + * @param[in] iterator Iterator. + * + * @return Whether the subject is in the trashcan + */ +int +permission_iterator_subject_in_trash (iterator_t* iterator) +{ + if (iterator->done) return 0; + return iterator_int64 (iterator, GET_ITERATOR_COLUMN_COUNT + 8); +} + +/** + * @brief Get the readable status of a subject from a permission iterator. + * + * @param[in] iterator Iterator. + * + * @return 1 if readable, otherwise 0. + */ +int +permission_iterator_subject_readable (iterator_t* iterator) +{ + resource_t found; + const char *type, *uuid; + gchar *permission; + + if (iterator->done) return 0; + + type = permission_iterator_subject_type (iterator); + uuid = permission_iterator_subject_uuid (iterator); + + if (type == NULL || uuid == NULL) + return 0; + + if ((strcmp (type, "user") == 0) + || (strcmp (type, "role") == 0) + || (strcmp (type, "group") == 0)) + permission = g_strdup_printf ("get_%ss", type); + else + return 0; + + found = 0; + find_resource_with_permission (type, + uuid, + &found, + permission, + permission_iterator_subject_in_trash + (iterator)); + g_free (permission); + return found > 0; +} diff --git a/src/manage_sql_permissions.h b/src/manage_sql_permissions.h index af242a400..d3eaf7443 100644 --- a/src/manage_sql_permissions.h +++ b/src/manage_sql_permissions.h @@ -19,6 +19,153 @@ */ #define PERMISSION_UUID_SUPER_ADMIN_EVERYTHING "a9801074-6fe2-11e4-9d81-406186ea4fc5" +/** + * @brief Filter columns for permission iterator. + */ +#define PERMISSION_ITERATOR_FILTER_COLUMNS \ + { GET_ITERATOR_FILTER_COLUMNS, "type", "resource_uuid", "subject_type", \ + "_subject", "_resource", "subject_uuid", "orphan", NULL } + +/** + * @brief Permission iterator columns. + */ +#define PERMISSION_ITERATOR_COLUMNS \ + { \ + GET_ITERATOR_COLUMNS (permissions), \ + { "resource_type", "type", KEYWORD_TYPE_STRING }, \ + { "resource_uuid", NULL, KEYWORD_TYPE_STRING }, \ + { \ + "(CASE" \ + " WHEN resource_type = '' OR resource_type IS NULL" \ + " THEN ''" \ + " ELSE resource_name (resource_type, resource_uuid, resource_location)" \ + " END)", \ + "_resource", \ + KEYWORD_TYPE_STRING \ + }, \ + { "CAST ((resource_location = " G_STRINGIFY (LOCATION_TRASH) ")" \ + " AS INTEGER)", \ + NULL, \ + KEYWORD_TYPE_INTEGER }, \ + { \ + "(CASE" \ + " WHEN resource = -1" \ + " THEN 1" \ + " ELSE 0" \ + " END)", \ + "orphan", \ + KEYWORD_TYPE_INTEGER \ + }, \ + { "subject_type", NULL, KEYWORD_TYPE_STRING }, \ + { \ + "(CASE" \ + " WHEN subject_type = 'user'" \ + " THEN (SELECT uuid FROM users WHERE users.id = subject)" \ + " WHEN subject_type = 'group'" \ + " AND subject_location = " G_STRINGIFY (LOCATION_TRASH) \ + " THEN (SELECT uuid FROM groups_trash" \ + " WHERE groups_trash.id = subject)" \ + " WHEN subject_type = 'group'" \ + " THEN (SELECT uuid FROM groups WHERE groups.id = subject)" \ + " WHEN subject_location = " G_STRINGIFY (LOCATION_TRASH) \ + " THEN (SELECT uuid FROM roles_trash" \ + " WHERE roles_trash.id = subject)" \ + " ELSE (SELECT uuid FROM roles WHERE roles.id = subject)" \ + " END)", \ + "subject_uuid", \ + KEYWORD_TYPE_STRING \ + }, \ + { \ + "(CASE" \ + " WHEN subject_type = 'user'" \ + " THEN (SELECT name FROM users WHERE users.id = subject)" \ + " WHEN subject_type = 'group'" \ + " AND subject_location = " G_STRINGIFY (LOCATION_TRASH) \ + " THEN (SELECT name FROM groups_trash" \ + " WHERE groups_trash.id = subject)" \ + " WHEN subject_type = 'group'" \ + " THEN (SELECT name FROM groups WHERE groups.id = subject)" \ + " WHEN subject_location = " G_STRINGIFY (LOCATION_TRASH) \ + " THEN (SELECT name FROM roles_trash" \ + " WHERE roles_trash.id = subject)" \ + " ELSE (SELECT name FROM roles WHERE roles.id = subject)" \ + " END)", \ + "_subject", \ + KEYWORD_TYPE_STRING \ + }, \ + { "CAST ((subject_location = " G_STRINGIFY (LOCATION_TRASH) ")" \ + " AS INTEGER)", \ + NULL, \ + KEYWORD_TYPE_INTEGER }, \ + { NULL, NULL, KEYWORD_TYPE_UNKNOWN } \ + } + +/** + * @brief Permission iterator columns for trash case. + */ +#define PERMISSION_ITERATOR_TRASH_COLUMNS \ + { \ + GET_ITERATOR_COLUMNS (permissions_trash), \ + { "resource_type", "type", KEYWORD_TYPE_STRING }, \ + { "resource_uuid", NULL, KEYWORD_TYPE_STRING }, \ + { \ + "(CASE" \ + " WHEN resource_type = '' OR resource_type IS NULL" \ + " THEN ''" \ + " ELSE resource_name (resource_type, resource_uuid, resource_location)" \ + " END)", \ + "_resource", \ + KEYWORD_TYPE_STRING \ + }, \ + { "CAST ((resource_location = " G_STRINGIFY (LOCATION_TRASH) ")" \ + " AS INTEGER)", \ + NULL, \ + KEYWORD_TYPE_INTEGER }, \ + { "resource = -1", NULL, KEYWORD_TYPE_INTEGER }, \ + { "subject_type", NULL, KEYWORD_TYPE_STRING }, \ + { \ + "(CASE" \ + " WHEN subject_type = 'user'" \ + " THEN (SELECT uuid FROM users WHERE users.id = subject)" \ + " WHEN subject_type = 'group'" \ + " AND subject_location = " G_STRINGIFY (LOCATION_TRASH) \ + " THEN (SELECT uuid FROM groups_trash" \ + " WHERE groups_trash.id = subject)" \ + " WHEN subject_type = 'group'" \ + " THEN (SELECT uuid FROM groups WHERE groups.id = subject)" \ + " WHEN subject_location = " G_STRINGIFY (LOCATION_TRASH) \ + " THEN (SELECT uuid FROM roles_trash" \ + " WHERE roles_trash.id = subject)" \ + " ELSE (SELECT uuid FROM roles WHERE roles.id = subject)" \ + " END)", \ + "subject_uuid", \ + KEYWORD_TYPE_STRING \ + }, \ + { \ + "(CASE" \ + " WHEN subject_type = 'user'" \ + " THEN (SELECT name FROM users WHERE users.id = subject)" \ + " WHEN subject_type = 'group'" \ + " AND subject_location = " G_STRINGIFY (LOCATION_TRASH) \ + " THEN (SELECT name FROM groups_trash" \ + " WHERE groups_trash.id = subject)" \ + " WHEN subject_type = 'group'" \ + " THEN (SELECT name FROM groups WHERE groups.id = subject)" \ + " WHEN subject_location = " G_STRINGIFY (LOCATION_TRASH) \ + " THEN (SELECT name FROM roles_trash" \ + " WHERE roles_trash.id = subject)" \ + " ELSE (SELECT name FROM roles WHERE roles.id = subject)" \ + " END)", \ + "_subject", \ + KEYWORD_TYPE_STRING \ + }, \ + { "CAST ((subject_location = " G_STRINGIFY (LOCATION_TRASH) ")" \ + " AS INTEGER)", \ + NULL, \ + KEYWORD_TYPE_INTEGER }, \ + { NULL, NULL, KEYWORD_TYPE_UNKNOWN } \ + } + resource_t permission_resource (permission_t); From 0f702acb3f9931602e0d02800b05e5ba8e6ae283 Mon Sep 17 00:00:00 2001 From: Matt Mundell Date: Wed, 28 Jan 2026 17:20:58 +0200 Subject: [PATCH 2/3] Change: move subject_where_clause to dedicated permission files Used in manage_restore so needs to be exported. --- src/manage_sql.c | 43 ------------------------------------ src/manage_sql_permissions.c | 43 ++++++++++++++++++++++++++++++++++++ src/manage_sql_permissions.h | 3 +++ 3 files changed, 46 insertions(+), 43 deletions(-) diff --git a/src/manage_sql.c b/src/manage_sql.c index 70eb18467..26b61f93d 100644 --- a/src/manage_sql.c +++ b/src/manage_sql.c @@ -33372,49 +33372,6 @@ check_permission_args (gboolean check_access, const char *name_arg, return 0; } -/** - * @brief Create a SQL clause to select the subject users. - * - * @param[in] subject_type Subject type. - * @param[in] subject The subject. - * - * @return Newly allocated string containing the SQL clause. - */ -static gchar* -subject_where_clause (const char* subject_type, resource_t subject) -{ - gchar *subject_where = NULL; - if (subject && subject_type) - { - if (strcmp (subject_type, "user") == 0) - { - subject_where - = g_strdup_printf ("id = %llu", subject); - } - else if (strcmp (subject_type, "group") == 0) - { - subject_where - = g_strdup_printf ("id IN (SELECT \"user\" FROM group_users" - " WHERE \"group\" = %llu)", - subject); - } - else if (strcmp (subject_type, "role") == 0) - { - subject_where - = g_strdup_printf ("id IN (SELECT \"user\" FROM role_users" - " WHERE \"role\" = %llu)", - subject); - } - else - { - subject_where = strdup ("t()"); - g_warning ("%s: unknown subject_type %s", - __func__, subject_type); - } - } - return subject_where; -} - /** * @brief Create a permission. * diff --git a/src/manage_sql_permissions.c b/src/manage_sql_permissions.c index 40be40c4e..8449a8ae2 100644 --- a/src/manage_sql_permissions.c +++ b/src/manage_sql_permissions.c @@ -733,3 +733,46 @@ permission_iterator_subject_readable (iterator_t* iterator) g_free (permission); return found > 0; } + +/** + * @brief Create a SQL clause to select the subject users. + * + * @param[in] subject_type Subject type. + * @param[in] subject The subject. + * + * @return Newly allocated string containing the SQL clause. + */ +gchar * +subject_where_clause (const char* subject_type, resource_t subject) +{ + gchar *subject_where = NULL; + if (subject && subject_type) + { + if (strcmp (subject_type, "user") == 0) + { + subject_where + = g_strdup_printf ("id = %llu", subject); + } + else if (strcmp (subject_type, "group") == 0) + { + subject_where + = g_strdup_printf ("id IN (SELECT \"user\" FROM group_users" + " WHERE \"group\" = %llu)", + subject); + } + else if (strcmp (subject_type, "role") == 0) + { + subject_where + = g_strdup_printf ("id IN (SELECT \"user\" FROM role_users" + " WHERE \"role\" = %llu)", + subject); + } + else + { + subject_where = strdup ("t()"); + g_warning ("%s: unknown subject_type %s", + __func__, subject_type); + } + } + return subject_where; +} diff --git a/src/manage_sql_permissions.h b/src/manage_sql_permissions.h index d3eaf7443..ac92893d7 100644 --- a/src/manage_sql_permissions.h +++ b/src/manage_sql_permissions.h @@ -199,4 +199,7 @@ add_feed_role_permissions (const char *, const char *, int *, int *); void clean_feed_role_permissions (const char *, const char *, int *, int *); +gchar * +subject_where_clause (const char *, resource_t); + #endif //_GVMD_MANAGE_SQL_PERMISSIONS_H From 21b036ea29cc8d7cdb3aa05343208b36d807db60 Mon Sep 17 00:00:00 2001 From: Matt Mundell Date: Wed, 28 Jan 2026 17:48:36 +0200 Subject: [PATCH 3/3] Change: move create and copy to dedicated permission files --- src/manage_sql.c | 593 +---------------------------------- src/manage_sql.h | 18 ++ src/manage_sql_permissions.c | 567 +++++++++++++++++++++++++++++++++ 3 files changed, 597 insertions(+), 581 deletions(-) diff --git a/src/manage_sql.c b/src/manage_sql.c index 26b61f93d..d8d0ba33f 100644 --- a/src/manage_sql.c +++ b/src/manage_sql.c @@ -234,12 +234,6 @@ find_trash_report_with_permission (const char *, report_t *, const char *); static int cleanup_schedule_times (); -static void -cache_permissions_for_resource (const char *, resource_t, GArray*); - -static void -report_cache_counts (report_t, int, int, const char*); - static gchar * reports_extra_where (int, const gchar *, const char *); @@ -271,9 +265,6 @@ static void set_credential_snmp_secret (credential_t, const char *, const char *, const char *); -static int -setting_auto_cache_rebuild_int (); - static char * setting_timezone (); @@ -9278,7 +9269,7 @@ reports_add_for_override (GHashTable *reports_table, * * @return A GHashtable containing the affected report rowids. */ -static GHashTable * +GHashTable * reports_for_override (override_t override) { GHashTable *reports_table; @@ -9322,7 +9313,7 @@ reports_add_all (GHashTable *reports_table) * * @return A GHashtable containing the report rowids. */ -static GHashTable * +GHashTable * reports_hashtable () { GHashTable *reports_table; @@ -9541,7 +9532,7 @@ report_counts_build_iterator_user (iterator_t *iterator) * overridden severity. * @param[in] users_where Optional SQL clause to limit users. */ -static void +void report_cache_counts (report_t report, int clear_original, int clear_overridden, const char* users_where) { @@ -9601,7 +9592,7 @@ report_cache_counts (report_t report, int clear_original, int clear_overridden, * overridden severity. * @param[in] users_where Optional SQL clause to limit users. */ -static void +void report_clear_count_cache (report_t report, int clear_original, int clear_overridden, const char* users_where) @@ -33080,572 +33071,6 @@ modify_schedule (const char *schedule_id, const char *name, const char *comment, /* Permissions. */ -/** - * @brief Find a permission given a UUID. - * - * @param[in] uuid UUID of permission. - * @param[out] permission Permission return, 0 if successfully failed to find - * permission. - * - * @return FALSE on success (including if failed to find permission), TRUE on - * error. - */ -static gboolean -find_permission (const char* uuid, permission_t* permission) -{ - return find_resource ("permission", uuid, permission); -} - -/** - * @brief Check args for create_permission or modify_permission. - * - * @param[in] check_access Whether to check if user may get resource and - * subject. - * @param[in] name_arg Name of permission. - * @param[in] resource_type_arg Type of resource, for special permissions. - * @param[in] resource_id_arg UUID of resource. - * @param[in] subject_type Type of subject. - * @param[in] subject_id UUID of subject. - * @param[out] name Name return. - * @param[out] resource Resource return. - * @param[out] resource_type Resource type return. - * @param[out] resource_id Resource ID return. - * @param[out] subject Subject return. - * - * @return 0 success, 2 failed to find subject, 3 failed to find resource, - * 5 error in resource, 6 error in subject, 7 error in name, - * 8 permission on permission, 9 permission does not accept resource, - * 99 permission denied, -1 error. - */ -static int -check_permission_args (gboolean check_access, const char *name_arg, - const char *resource_type_arg, - const char *resource_id_arg, const char *subject_type, - const char *subject_id, gchar **name, - resource_t *resource, char **resource_type, - const char **resource_id, resource_t *subject) -{ - if ((name_arg == NULL) - || ((valid_gmp_command (name_arg) == 0) - && strcasecmp (name_arg, "super")) - || (strcasecmp (name_arg, "get_version") == 0)) - return 7; - - if (resource_id_arg - && strcmp (resource_id_arg, "") - && strcmp (resource_id_arg, "0") - && (((gmp_command_takes_resource (name_arg) == 0) - && strcasecmp (name_arg, "super")))) - return 9; - - if (resource_type_arg - && strcasecmp (name_arg, "super") == 0 - && strcmp (resource_type_arg, "group") - && strcmp (resource_type_arg, "role") - && strcmp (resource_type_arg, "user")) - return 5; - - if (resource_type_arg - && strcasecmp (name_arg, "super") - && (valid_db_resource_type (resource_type_arg) == 0 - || gmp_command_takes_resource (name_arg) == 0)) - return 5; - - if (subject_type - && strcmp (subject_type, "group") - && strcmp (subject_type, "role") - && strcmp (subject_type, "user")) - return 6; - - if (subject_id == NULL) - /* For now a permission must have a subject. */ - return 6; - - if (subject_id && (subject_type == NULL)) - return 6; - - assert (subject_type); - - *name = strcasecmp (name_arg, "super") - ? g_ascii_strdown (name_arg, -1) - : g_strdup ("Super"); - *resource = 0; - if (resource_id_arg - && strcmp (resource_id_arg, "") - && strcmp (resource_id_arg, "0")) - { - *resource_type = strcasecmp (*name, "super") - ? gmp_command_type (*name) - : g_strdup (resource_type_arg); - - if (*resource_type == NULL) - { - g_free (*name); - return 3; - } - - if (strcasecmp (*resource_type, "asset") == 0) - { - g_free (*resource_type); - *resource_type = g_strdup ("host"); - if (check_access == FALSE) - { - if (find_resource_no_acl (*resource_type, resource_id_arg, resource)) - { - g_free (*name); - g_free (*resource_type); - return -1; - } - } - else - { - if (find_resource (*resource_type, resource_id_arg, resource)) - { - g_free (*name); - g_free (*resource_type); - return -1; - } - } - - if (*resource == 0) - { - g_free (*resource_type); - *resource_type = g_strdup ("os"); - if (check_access == FALSE) - { - if (find_resource_no_acl (*resource_type, resource_id_arg, resource)) - { - g_free (*name); - g_free (*resource_type); - return -1; - } - } - else - { - if (find_resource (*resource_type, resource_id_arg, resource)) - { - g_free (*name); - g_free (*resource_type); - return -1; - } - } - } - } - else if (check_access == FALSE) - { - if (find_resource_no_acl (*resource_type, resource_id_arg, resource)) - { - g_free (*name); - g_free (*resource_type); - return -1; - } - } - else - { - gchar *get_permission; - get_permission = g_strdup_printf ("get_%ss", *resource_type); - if (find_resource_with_permission (*resource_type, resource_id_arg, - resource, get_permission, 0)) - { - g_free (*name); - g_free (*resource_type); - g_free (get_permission); - return -1; - } - g_free (get_permission); - } - - if (*resource == 0) - { - g_free (*name); - g_free (*resource_type); - return 3; - } - - *resource_id = resource_id_arg; - } - else - { - *resource_id = NULL; - *resource_type = NULL; - } - - if (strcasecmp (*name, "super") == 0) - { - if (*resource == 0) - { - g_free (*name); - g_free (*resource_type); - return 3; - } - - if ((acl_user_is_owner (*resource_type, *resource_id) == 0) - && (acl_user_can_super_everyone (current_credentials.uuid) == 0)) - { - g_free (*name); - g_free (*resource_type); - return 99; - } - } - - /* For simplicity refuse to make permissions on permissions. */ - if (*resource && strcasestr (*name, "permission")) - { - g_free (*name); - g_free (*resource_type); - return 8; - } - - /* Ensure the user may grant this permission. */ - - if (((*resource == 0) || strcasecmp (*name, "super") == 0) - && (acl_user_can_everything (current_credentials.uuid) == 0)) - { - g_free (*name); - g_free (*resource_type); - return 99; - } - - *subject = 0; - assert (subject_id); - if (*resource) - { - /* Permission on a particular resource. Only need read access to the - * subject. */ - if (check_access) - { - if (find_resource_with_permission (subject_type, - subject_id, - subject, - NULL, /* GET permission. */ - 0)) /* Trash. */ - { - g_free (*name); - g_free (*resource_type); - return -1; - } - } - else - { - if (find_resource_no_acl (subject_type, subject_id, subject)) - { - g_free (*name); - g_free (*resource_type); - return -1; - } - } - } - else - { - gchar *permission; - - /* Command level permission. Must have write access to the subject. */ - - /* However, modification of the predefined roles is forbidden. */ - if (subject_id - && strcmp (subject_type, "role") == 0 - && role_is_predefined_id (subject_id)) - return 99; - - permission = g_strdup_printf ("modify_%s", subject_type); - if (find_resource_with_permission (subject_type, - subject_id, - subject, - permission, - 0)) /* Trash. */ - { - g_free (*name); - g_free (*resource_type); - g_free (permission); - return -1; - } - g_free (permission); - } - - if (*subject == 0) - { - g_free (*name); - g_free (*resource_type); - return 2; - } - - return 0; -} - -/** - * @brief Create a permission. - * - * Caller must organise the transaction. - * - * @param[in] check_access Whether to check if user may CREATE_PERMISSION. - * @param[in] name_arg Name of permission. - * @param[in] comment Comment on permission. - * @param[in] resource_type_arg Type of resource, for special permissions. - * @param[in] resource_id_arg UUID of resource. - * @param[in] subject_type Type of subject. - * @param[in] subject_id UUID of subject. - * @param[out] permission Permission. - * - * @return 0 success, 2 failed to find subject, 3 failed to find resource, - * 5 error in resource, 6 error in subject, 7 error in name, - * 8 permission on permission, 9 permission does not accept resource, - * 99 permission denied, -1 internal error. - */ -int -create_permission_internal (int check_access, const char *name_arg, - const char *comment, const char *resource_type_arg, - const char *resource_id_arg, - const char *subject_type, const char *subject_id, - permission_t *permission) -{ - int ret; - gchar *name, *quoted_name, *quoted_comment, *resource_type; - resource_t resource, subject; - const char *resource_id; - GHashTable *reports = NULL; - int clear_original = 0; - gchar *subject_where; - - assert (current_credentials.uuid); - - if (check_access && (acl_user_may ("create_permission") == 0)) - return 99; - - ret = check_permission_args (check_access, name_arg, resource_type_arg, - resource_id_arg, subject_type, subject_id, &name, - &resource, &resource_type, &resource_id, - &subject); - - if (ret) - return ret; - - assert (subject); - assert ((resource_id == resource_id_arg) || (resource_id == NULL)); - - quoted_name = sql_quote (name); - g_free (name); - quoted_comment = sql_quote (comment ? comment : ""); - - sql ("INSERT INTO permissions" - " (uuid, owner, name, comment, resource_type, resource_uuid, resource," - " resource_location, subject_type, subject, subject_location," - " creation_time, modification_time)" - " VALUES" - " (make_uuid ()," - " (SELECT id FROM users WHERE users.uuid = '%s')," - " '%s', '%s', '%s', '%s', %llu, " G_STRINGIFY (LOCATION_TABLE) "," - " %s%s%s, %llu, " G_STRINGIFY (LOCATION_TABLE) ", m_now (), m_now ());", - current_credentials.uuid, - quoted_name, - quoted_comment, - resource_id ? resource_type : "", - resource_id ? resource_id : "", - resource, - subject_id ? "'" : "", - subject_id ? subject_type : "NULL", - subject_id ? "'" : "", - subject); - - subject_where = subject_where_clause (subject_type, subject); - - if (permission) - *permission = sql_last_insert_id (); - - /* Update Permissions cache */ - if (strcasecmp (quoted_name, "super") == 0) - cache_all_permissions_for_users (NULL); - else if (resource_type && resource) - cache_permissions_for_resource (resource_type, resource, NULL); - - /* Update Reports cache */ - if (resource_type && resource_id && strcmp (resource_type, "override") == 0) - { - reports = reports_for_override (resource); - } - else if (strcasecmp (quoted_name, "super") == 0) - { - reports = reports_hashtable (); - clear_original = 1; - } - - if (reports && g_hash_table_size (reports)) - { - GHashTableIter reports_iter; - report_t *reports_ptr; - int auto_cache_rebuild; - - reports_ptr = NULL; - g_hash_table_iter_init (&reports_iter, reports); - auto_cache_rebuild = setting_auto_cache_rebuild_int (); - while (g_hash_table_iter_next (&reports_iter, - ((gpointer*)&reports_ptr), NULL)) - { - if (auto_cache_rebuild) - report_cache_counts (*reports_ptr, clear_original, 1, - subject_where); - else - report_clear_count_cache (*reports_ptr, clear_original, 1, - subject_where); - } - } - - if (reports) - g_hash_table_destroy (reports); - - g_free (quoted_comment); - g_free (quoted_name); - g_free (resource_type); - g_free (subject_where); - - return 0; -} - -/** - * @brief Create a permission. - * - * @param[in] name_arg Name of permission. - * @param[in] comment Comment on permission. - * @param[in] resource_type_arg Type of resource, for special permissions. - * @param[in] resource_id_arg UUID of resource. - * @param[in] subject_type Type of subject. - * @param[in] subject_id UUID of subject. - * @param[out] permission Permission. - * - * @return 0 success, 2 failed to find subject, 3 failed to find resource, - * 5 error in resource, 6 error in subject, 7 error in name, - * 8 permission on permission, 9 permission does not accept resource, - * 99 permission denied, -1 internal error. - */ -int -create_permission (const char *name_arg, const char *comment, - const char *resource_type_arg, const char *resource_id_arg, - const char *subject_type, const char *subject_id, - permission_t *permission) -{ - int ret; - - sql_begin_immediate (); - - ret = create_permission_internal (1, name_arg, comment, resource_type_arg, - resource_id_arg, subject_type, subject_id, - permission); - if (ret) - sql_rollback (); - else - sql_commit (); - - return ret; -} - -/** - * @brief Create a permission. - * - * Does not require current user to have CREATE_PERMISSION access. - * - * @param[in] name_arg Name of permission. - * @param[in] comment Comment on permission. - * @param[in] resource_type_arg Type of resource, for special permissions. - * @param[in] resource_id_arg UUID of resource. - * @param[in] subject_type Type of subject. - * @param[in] subject_id UUID of subject. - * @param[out] permission Permission. - * - * @return 0 success, 2 failed to find subject, 3 failed to find resource, - * 5 error in resource, 6 error in subject, 7 error in name, - * 8 permission on permission, 9 permission does not accept resource, - * 99 permission denied, -1 internal error. - */ -int -create_permission_no_acl (const char *name_arg, const char *comment, - const char *resource_type_arg, - const char *resource_id_arg, - const char *subject_type, const char *subject_id, - permission_t *permission) -{ - return create_permission_internal (0, name_arg, comment, resource_type_arg, - resource_id_arg, subject_type, subject_id, - permission); -} - -/** - * @brief Create a permission from an existing permission. - * - * @param[in] comment Comment on new permission. NULL to copy from existing. - * @param[in] permission_id UUID of existing permission. - * @param[out] new_permission New permission. - * - * @return 0 success, 1 permission exists already, 2 failed to find existing - * permission, 99 permission denied, -1 error. - */ -int -copy_permission (const char* comment, const char *permission_id, - permission_t* new_permission) -{ - int ret; - permission_t permission, new, old; - char *subject_type, *name; - resource_t subject; - - sql_begin_immediate (); - - permission = 0; - /* There are no permissions on permissions, so no need for the - * "_with_permission" version. */ - if (find_permission (permission_id, &permission)) - { - sql_rollback (); - return -1; - } - - if (permission == 0) - { - sql_rollback (); - return 2; - } - - /* Prevent copying of command level permissions for predefined roles. */ - subject_type = permission_subject_type (permission); - subject = permission_subject (permission); - if (permission_resource (permission) == 0 - && subject_type - && strcmp (subject_type, "role") == 0 - && subject - && role_is_predefined (subject)) - { - free (subject_type); - sql_rollback (); - return 99; - } - free (subject_type); - - /* Refuse to copy Super On Everyone. */ - name = permission_name (permission); - if ((strcmp (name, "Super") == 0) - && (permission_resource (permission) == 0)) - { - free (name); - sql_rollback (); - return 99; - } - free (name); - - ret = copy_resource_lock ("permission", NULL, comment, permission_id, - "resource_type, resource, resource_uuid," - " resource_location, subject_type, subject," - " subject_location", - 0, &new, &old); - if (ret) - { - sql_rollback (); - return ret; - } - - sql_commit (); - if (new_permission) *new_permission = new; - return 0; - -} - /** * @brief Return whether a permission is in use. * @@ -33901,6 +33326,12 @@ char * permission_resource_id (permission_t); char * permission_subject_id (permission_t); +gboolean +find_permission (const char *, permission_t *); +int +check_permission_args (gboolean, const char *, const char *, const char *, + const char *, const char *, gchar **, resource_t *, + char **, const char **, resource_t *); /** * @brief Modify a permission. * @@ -35663,7 +35094,7 @@ setting_timezone () * * @return 1 if cache is rebuilt automatically, 0 if not. */ -static int +int setting_auto_cache_rebuild_int () { return sql_int ("SELECT coalesce" @@ -39934,7 +39365,7 @@ all_users_array () * @param[in] resource The resource to update the cache for. * @param[in] cache_users GArray of users to create cache for or NULL for all. */ -static void +void cache_permissions_for_resource (const char *type, resource_t resource, GArray *cache_users) { diff --git a/src/manage_sql.h b/src/manage_sql.h index dfd5836f1..f7e2c240a 100644 --- a/src/manage_sql.h +++ b/src/manage_sql.h @@ -487,6 +487,9 @@ int create_permission_no_acl (const char *, const char *, const char *, const char *, const char *, const char *, permission_t *); +void +cache_permissions_for_resource (const char *, resource_t, GArray *); + int copy_resource_lock (const char *, const char *, const char *, const char *, const char *, int, resource_t *, resource_t *); @@ -500,6 +503,9 @@ setting_value_sql (const char *, char **); int setting_value_int_sql (const char *, int *); +int +setting_auto_cache_rebuild_int (); + int setting_dynamic_severity_int (); @@ -525,6 +531,18 @@ new_severity_clause (int, int); void reports_clear_count_cache_dynamic (); +GHashTable * +reports_for_override (override_t); + +GHashTable * +reports_hashtable (); + +void +report_cache_counts (report_t, int, int, const char *); + +void +report_clear_count_cache (report_t, int, int, const char *); + int cleanup_config_sequences (); diff --git a/src/manage_sql_permissions.c b/src/manage_sql_permissions.c index 8449a8ae2..668cd9a6f 100644 --- a/src/manage_sql_permissions.c +++ b/src/manage_sql_permissions.c @@ -5,6 +5,7 @@ #include "manage_sql_permissions.h" #include "manage_acl.h" +#include "manage_sql_roles.h" #include "manage_sql_users.h" #include "sql.h" @@ -776,3 +777,569 @@ subject_where_clause (const char* subject_type, resource_t subject) } return subject_where; } + +/** + * @brief Find a permission given a UUID. + * + * @param[in] uuid UUID of permission. + * @param[out] permission Permission return, 0 if successfully failed to find + * permission. + * + * @return FALSE on success (including if failed to find permission), TRUE on + * error. + */ +gboolean +find_permission (const char* uuid, permission_t* permission) +{ + return find_resource ("permission", uuid, permission); +} + +/** + * @brief Check args for create_permission or modify_permission. + * + * @param[in] check_access Whether to check if user may get resource and + * subject. + * @param[in] name_arg Name of permission. + * @param[in] resource_type_arg Type of resource, for special permissions. + * @param[in] resource_id_arg UUID of resource. + * @param[in] subject_type Type of subject. + * @param[in] subject_id UUID of subject. + * @param[out] name Name return. + * @param[out] resource Resource return. + * @param[out] resource_type Resource type return. + * @param[out] resource_id Resource ID return. + * @param[out] subject Subject return. + * + * @return 0 success, 2 failed to find subject, 3 failed to find resource, + * 5 error in resource, 6 error in subject, 7 error in name, + * 8 permission on permission, 9 permission does not accept resource, + * 99 permission denied, -1 error. + */ +int +check_permission_args (gboolean check_access, const char *name_arg, + const char *resource_type_arg, + const char *resource_id_arg, const char *subject_type, + const char *subject_id, gchar **name, + resource_t *resource, char **resource_type, + const char **resource_id, resource_t *subject) +{ + if ((name_arg == NULL) + || ((valid_gmp_command (name_arg) == 0) + && strcasecmp (name_arg, "super")) + || (strcasecmp (name_arg, "get_version") == 0)) + return 7; + + if (resource_id_arg + && strcmp (resource_id_arg, "") + && strcmp (resource_id_arg, "0") + && (((gmp_command_takes_resource (name_arg) == 0) + && strcasecmp (name_arg, "super")))) + return 9; + + if (resource_type_arg + && strcasecmp (name_arg, "super") == 0 + && strcmp (resource_type_arg, "group") + && strcmp (resource_type_arg, "role") + && strcmp (resource_type_arg, "user")) + return 5; + + if (resource_type_arg + && strcasecmp (name_arg, "super") + && (valid_db_resource_type (resource_type_arg) == 0 + || gmp_command_takes_resource (name_arg) == 0)) + return 5; + + if (subject_type + && strcmp (subject_type, "group") + && strcmp (subject_type, "role") + && strcmp (subject_type, "user")) + return 6; + + if (subject_id == NULL) + /* For now a permission must have a subject. */ + return 6; + + if (subject_id && (subject_type == NULL)) + return 6; + + assert (subject_type); + + *name = strcasecmp (name_arg, "super") + ? g_ascii_strdown (name_arg, -1) + : g_strdup ("Super"); + *resource = 0; + if (resource_id_arg + && strcmp (resource_id_arg, "") + && strcmp (resource_id_arg, "0")) + { + *resource_type = strcasecmp (*name, "super") + ? gmp_command_type (*name) + : g_strdup (resource_type_arg); + + if (*resource_type == NULL) + { + g_free (*name); + return 3; + } + + if (strcasecmp (*resource_type, "asset") == 0) + { + g_free (*resource_type); + *resource_type = g_strdup ("host"); + if (check_access == FALSE) + { + if (find_resource_no_acl (*resource_type, resource_id_arg, resource)) + { + g_free (*name); + g_free (*resource_type); + return -1; + } + } + else + { + if (find_resource (*resource_type, resource_id_arg, resource)) + { + g_free (*name); + g_free (*resource_type); + return -1; + } + } + + if (*resource == 0) + { + g_free (*resource_type); + *resource_type = g_strdup ("os"); + if (check_access == FALSE) + { + if (find_resource_no_acl (*resource_type, resource_id_arg, resource)) + { + g_free (*name); + g_free (*resource_type); + return -1; + } + } + else + { + if (find_resource (*resource_type, resource_id_arg, resource)) + { + g_free (*name); + g_free (*resource_type); + return -1; + } + } + } + } + else if (check_access == FALSE) + { + if (find_resource_no_acl (*resource_type, resource_id_arg, resource)) + { + g_free (*name); + g_free (*resource_type); + return -1; + } + } + else + { + gchar *get_permission; + get_permission = g_strdup_printf ("get_%ss", *resource_type); + if (find_resource_with_permission (*resource_type, resource_id_arg, + resource, get_permission, 0)) + { + g_free (*name); + g_free (*resource_type); + g_free (get_permission); + return -1; + } + g_free (get_permission); + } + + if (*resource == 0) + { + g_free (*name); + g_free (*resource_type); + return 3; + } + + *resource_id = resource_id_arg; + } + else + { + *resource_id = NULL; + *resource_type = NULL; + } + + if (strcasecmp (*name, "super") == 0) + { + if (*resource == 0) + { + g_free (*name); + g_free (*resource_type); + return 3; + } + + if ((acl_user_is_owner (*resource_type, *resource_id) == 0) + && (acl_user_can_super_everyone (current_credentials.uuid) == 0)) + { + g_free (*name); + g_free (*resource_type); + return 99; + } + } + + /* For simplicity refuse to make permissions on permissions. */ + if (*resource && strcasestr (*name, "permission")) + { + g_free (*name); + g_free (*resource_type); + return 8; + } + + /* Ensure the user may grant this permission. */ + + if (((*resource == 0) || strcasecmp (*name, "super") == 0) + && (acl_user_can_everything (current_credentials.uuid) == 0)) + { + g_free (*name); + g_free (*resource_type); + return 99; + } + + *subject = 0; + assert (subject_id); + if (*resource) + { + /* Permission on a particular resource. Only need read access to the + * subject. */ + if (check_access) + { + if (find_resource_with_permission (subject_type, + subject_id, + subject, + NULL, /* GET permission. */ + 0)) /* Trash. */ + { + g_free (*name); + g_free (*resource_type); + return -1; + } + } + else + { + if (find_resource_no_acl (subject_type, subject_id, subject)) + { + g_free (*name); + g_free (*resource_type); + return -1; + } + } + } + else + { + gchar *permission; + + /* Command level permission. Must have write access to the subject. */ + + /* However, modification of the predefined roles is forbidden. */ + if (subject_id + && strcmp (subject_type, "role") == 0 + && role_is_predefined_id (subject_id)) + return 99; + + permission = g_strdup_printf ("modify_%s", subject_type); + if (find_resource_with_permission (subject_type, + subject_id, + subject, + permission, + 0)) /* Trash. */ + { + g_free (*name); + g_free (*resource_type); + g_free (permission); + return -1; + } + g_free (permission); + } + + if (*subject == 0) + { + g_free (*name); + g_free (*resource_type); + return 2; + } + + return 0; +} + +/** + * @brief Create a permission. + * + * Caller must organise the transaction. + * + * @param[in] check_access Whether to check if user may CREATE_PERMISSION. + * @param[in] name_arg Name of permission. + * @param[in] comment Comment on permission. + * @param[in] resource_type_arg Type of resource, for special permissions. + * @param[in] resource_id_arg UUID of resource. + * @param[in] subject_type Type of subject. + * @param[in] subject_id UUID of subject. + * @param[out] permission Permission. + * + * @return 0 success, 2 failed to find subject, 3 failed to find resource, + * 5 error in resource, 6 error in subject, 7 error in name, + * 8 permission on permission, 9 permission does not accept resource, + * 99 permission denied, -1 internal error. + */ +int +create_permission_internal (int check_access, const char *name_arg, + const char *comment, const char *resource_type_arg, + const char *resource_id_arg, + const char *subject_type, const char *subject_id, + permission_t *permission) +{ + int ret; + gchar *name, *quoted_name, *quoted_comment, *resource_type; + resource_t resource, subject; + const char *resource_id; + GHashTable *reports = NULL; + int clear_original = 0; + gchar *subject_where; + + assert (current_credentials.uuid); + + if (check_access && (acl_user_may ("create_permission") == 0)) + return 99; + + ret = check_permission_args (check_access, name_arg, resource_type_arg, + resource_id_arg, subject_type, subject_id, &name, + &resource, &resource_type, &resource_id, + &subject); + + if (ret) + return ret; + + assert (subject); + assert ((resource_id == resource_id_arg) || (resource_id == NULL)); + + quoted_name = sql_quote (name); + g_free (name); + quoted_comment = sql_quote (comment ? comment : ""); + + sql ("INSERT INTO permissions" + " (uuid, owner, name, comment, resource_type, resource_uuid, resource," + " resource_location, subject_type, subject, subject_location," + " creation_time, modification_time)" + " VALUES" + " (make_uuid ()," + " (SELECT id FROM users WHERE users.uuid = '%s')," + " '%s', '%s', '%s', '%s', %llu, " G_STRINGIFY (LOCATION_TABLE) "," + " %s%s%s, %llu, " G_STRINGIFY (LOCATION_TABLE) ", m_now (), m_now ());", + current_credentials.uuid, + quoted_name, + quoted_comment, + resource_id ? resource_type : "", + resource_id ? resource_id : "", + resource, + subject_id ? "'" : "", + subject_id ? subject_type : "NULL", + subject_id ? "'" : "", + subject); + + subject_where = subject_where_clause (subject_type, subject); + + if (permission) + *permission = sql_last_insert_id (); + + /* Update Permissions cache */ + if (strcasecmp (quoted_name, "super") == 0) + cache_all_permissions_for_users (NULL); + else if (resource_type && resource) + cache_permissions_for_resource (resource_type, resource, NULL); + + /* Update Reports cache */ + if (resource_type && resource_id && strcmp (resource_type, "override") == 0) + { + reports = reports_for_override (resource); + } + else if (strcasecmp (quoted_name, "super") == 0) + { + reports = reports_hashtable (); + clear_original = 1; + } + + if (reports && g_hash_table_size (reports)) + { + GHashTableIter reports_iter; + report_t *reports_ptr; + int auto_cache_rebuild; + + reports_ptr = NULL; + g_hash_table_iter_init (&reports_iter, reports); + auto_cache_rebuild = setting_auto_cache_rebuild_int (); + while (g_hash_table_iter_next (&reports_iter, + ((gpointer*)&reports_ptr), NULL)) + { + if (auto_cache_rebuild) + report_cache_counts (*reports_ptr, clear_original, 1, + subject_where); + else + report_clear_count_cache (*reports_ptr, clear_original, 1, + subject_where); + } + } + + if (reports) + g_hash_table_destroy (reports); + + g_free (quoted_comment); + g_free (quoted_name); + g_free (resource_type); + g_free (subject_where); + + return 0; +} + +/** + * @brief Create a permission. + * + * @param[in] name_arg Name of permission. + * @param[in] comment Comment on permission. + * @param[in] resource_type_arg Type of resource, for special permissions. + * @param[in] resource_id_arg UUID of resource. + * @param[in] subject_type Type of subject. + * @param[in] subject_id UUID of subject. + * @param[out] permission Permission. + * + * @return 0 success, 2 failed to find subject, 3 failed to find resource, + * 5 error in resource, 6 error in subject, 7 error in name, + * 8 permission on permission, 9 permission does not accept resource, + * 99 permission denied, -1 internal error. + */ +int +create_permission (const char *name_arg, const char *comment, + const char *resource_type_arg, const char *resource_id_arg, + const char *subject_type, const char *subject_id, + permission_t *permission) +{ + int ret; + + sql_begin_immediate (); + + ret = create_permission_internal (1, name_arg, comment, resource_type_arg, + resource_id_arg, subject_type, subject_id, + permission); + if (ret) + sql_rollback (); + else + sql_commit (); + + return ret; +} + +/** + * @brief Create a permission. + * + * Does not require current user to have CREATE_PERMISSION access. + * + * @param[in] name_arg Name of permission. + * @param[in] comment Comment on permission. + * @param[in] resource_type_arg Type of resource, for special permissions. + * @param[in] resource_id_arg UUID of resource. + * @param[in] subject_type Type of subject. + * @param[in] subject_id UUID of subject. + * @param[out] permission Permission. + * + * @return 0 success, 2 failed to find subject, 3 failed to find resource, + * 5 error in resource, 6 error in subject, 7 error in name, + * 8 permission on permission, 9 permission does not accept resource, + * 99 permission denied, -1 internal error. + */ +int +create_permission_no_acl (const char *name_arg, const char *comment, + const char *resource_type_arg, + const char *resource_id_arg, + const char *subject_type, const char *subject_id, + permission_t *permission) +{ + return create_permission_internal (0, name_arg, comment, resource_type_arg, + resource_id_arg, subject_type, subject_id, + permission); +} + +/** + * @brief Create a permission from an existing permission. + * + * @param[in] comment Comment on new permission. NULL to copy from existing. + * @param[in] permission_id UUID of existing permission. + * @param[out] new_permission New permission. + * + * @return 0 success, 1 permission exists already, 2 failed to find existing + * permission, 99 permission denied, -1 error. + */ +int +copy_permission (const char* comment, const char *permission_id, + permission_t* new_permission) +{ + int ret; + permission_t permission, new, old; + char *subject_type, *name; + resource_t subject; + + sql_begin_immediate (); + + permission = 0; + /* There are no permissions on permissions, so no need for the + * "_with_permission" version. */ + if (find_permission (permission_id, &permission)) + { + sql_rollback (); + return -1; + } + + if (permission == 0) + { + sql_rollback (); + return 2; + } + + /* Prevent copying of command level permissions for predefined roles. */ + subject_type = permission_subject_type (permission); + subject = permission_subject (permission); + if (permission_resource (permission) == 0 + && subject_type + && strcmp (subject_type, "role") == 0 + && subject + && role_is_predefined (subject)) + { + free (subject_type); + sql_rollback (); + return 99; + } + free (subject_type); + + /* Refuse to copy Super On Everyone. */ + name = permission_name (permission); + if ((strcmp (name, "Super") == 0) + && (permission_resource (permission) == 0)) + { + free (name); + sql_rollback (); + return 99; + } + free (name); + + ret = copy_resource_lock ("permission", NULL, comment, permission_id, + "resource_type, resource, resource_uuid," + " resource_location, subject_type, subject," + " subject_location", + 0, &new, &old); + if (ret) + { + sql_rollback (); + return ret; + } + + sql_commit (); + if (new_permission) *new_permission = new; + return 0; + +}