/* ** Copyright (C) 2001-2025 Zabbix SIA ** ** 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, version 3. ** ** 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 <https://www.gnu.org/licenses/>. **/ #include "dbupgrade_common.h" #include "dbupgrade.h" #include "zbxdb.h" #include "zbxalgo.h" #include "zbxnum.h" #include "zbxhash.h" #include "zbxcrypto.h" typedef struct { char hash_str[ZBX_SHA256_DIGEST_SIZE * 2 + 1]; zbx_vector_uint64_t groupids; zbx_vector_uint64_t ids; } zbx_dbu_group_set_t; int delete_problems_with_nonexistent_object(void) { zbx_db_result_t result; zbx_vector_uint64_t eventids; zbx_db_row_t row; zbx_uint64_t eventid; int sources[] = {EVENT_SOURCE_TRIGGERS, EVENT_SOURCE_INTERNAL}; int objects[] = {EVENT_OBJECT_ITEM, EVENT_OBJECT_LLDRULE}, i; zbx_vector_uint64_create(&eventids); for (i = 0; i < (int)ARRSIZE(sources); i++) { result = zbx_db_select( "select p.eventid" " from problem p" " where p.source=%d and p.object=%d and not exists (" "select null" " from triggers t" " where t.triggerid=p.objectid" ")", sources[i], EVENT_OBJECT_TRIGGER); while (NULL != (row = zbx_db_fetch(result))) { ZBX_STR2UINT64(eventid, row[0]); zbx_vector_uint64_append(&eventids, eventid); } zbx_db_free_result(result); } for (i = 0; i < (int)ARRSIZE(objects); i++) { result = zbx_db_select( "select p.eventid" " from problem p" " where p.source=%d and p.object=%d and not exists (" "select null" " from items i" " where i.itemid=p.objectid" ")", EVENT_SOURCE_INTERNAL, objects[i]); while (NULL != (row = zbx_db_fetch(result))) { ZBX_STR2UINT64(eventid, row[0]); zbx_vector_uint64_append(&eventids, eventid); } zbx_db_free_result(result); } zbx_vector_uint64_sort(&eventids, ZBX_DEFAULT_UINT64_COMPARE_FUNC); if (0 != eventids.values_num) zbx_db_execute_multiple_query("delete from problem where", "eventid", &eventids); zbx_vector_uint64_destroy(&eventids); return SUCCEED; } #ifndef HAVE_SQLITE3 int create_problem_3_index(void) { if (FAIL == zbx_db_index_exists("problem", "problem_3")) return DBcreate_index("problem", "problem_3", "r_eventid", 0); return SUCCEED; } int drop_c_problem_2_index(void) { #ifdef HAVE_MYSQL /* MySQL automatically creates index and might not remove it on some conditions */ if (SUCCEED == zbx_db_index_exists("problem", "c_problem_2")) return DBdrop_index("problem", "c_problem_2"); #endif return SUCCEED; } #endif static zbx_hash_t permission_group_set_hash(const void *data) { const zbx_dbu_group_set_t *group_set = (const zbx_dbu_group_set_t *)data; return ZBX_DEFAULT_STRING_HASH_FUNC(group_set->hash_str); } static int permission_group_set_compare(const void *d1, const void *d2) { const zbx_dbu_group_set_t *group_set1 = (const zbx_dbu_group_set_t *)d1; const zbx_dbu_group_set_t *group_set2 = (const zbx_dbu_group_set_t *)d2; return strcmp(group_set1->hash_str, group_set2->hash_str); } static int permission_groupsets_make(zbx_vector_uint64_t *ids, const char *fld_name_id, const char *fld_name_groupid, const char *tbl_name_groups, zbx_hashset_t *group_sets, int allow_empty_groups) { int ret = SUCCEED; char id_str[MAX_ID_LEN + 2]; zbx_db_result_t result; zbx_db_row_t row; zbx_vector_uint64_t groupids; zbx_dbu_group_set_t *gset_ptr; id_str[0] = '|'; zbx_vector_uint64_create(&groupids); for (int i = 0; i < ids->values_num; i++) { unsigned char hash[ZBX_SHA256_DIGEST_SIZE]; char *id_str_p = id_str + 1; sha256_ctx ctx; zbx_dbu_group_set_t gset; zbx_sha256_init(&ctx); result = zbx_db_select("select %s from %s where %s=" ZBX_FS_UI64 " order by %s", fld_name_groupid, tbl_name_groups, fld_name_id, ids->values[i], fld_name_groupid); while (NULL != (row = zbx_db_fetch(result))) { zbx_uint64_t groupid; ZBX_STR2UINT64(groupid, row[0]); if (1 == groupids.values_num) id_str_p = id_str; zbx_snprintf(id_str + 1, MAX_ID_LEN + 1, "%s", row[0]); zbx_sha256_process_bytes(id_str_p, strlen(id_str_p), &ctx); zbx_vector_uint64_append(&groupids, groupid); } zbx_db_free_result(result); if (0 == groupids.values_num) { if (0 == allow_empty_groups) { zabbix_log(LOG_LEVEL_WARNING, "host or template [hostid=" ZBX_FS_UI64 "] is not" " assigned to any group, permissions not granted", ids->values[i]); } continue; } zbx_sha256_finish(&ctx, hash); (void)zbx_bin2hex(hash, ZBX_SHA256_DIGEST_SIZE, gset.hash_str, ZBX_SHA256_DIGEST_SIZE * 2 + 1); if (NULL == (gset_ptr = zbx_hashset_search(group_sets, &gset))) { zbx_vector_uint64_create(&gset.ids); zbx_vector_uint64_create(&gset.groupids); zbx_vector_uint64_append_array(&gset.groupids, groupids.values, groupids.values_num); if (NULL == (gset_ptr = zbx_hashset_insert(group_sets, &gset, sizeof(zbx_dbu_group_set_t)))) { ret = FAIL; break; } } zbx_vector_uint64_append(&gset_ptr->ids, ids->values[i]); zbx_vector_uint64_clear(&groupids); } zbx_vector_uint64_destroy(&groupids); return ret; } static int permission_groupsets_insert(const char *tbl_name, zbx_hashset_t *group_sets, zbx_db_insert_t *db_gset, zbx_db_insert_t *db_gset_groups, zbx_db_insert_t *db_gset_parents, zbx_vector_uint64_t *hgsetids) { zbx_uint64_t gsetid; zbx_hashset_iter_t iter; zbx_dbu_group_set_t *gset_ptr; if (0 == group_sets->num_data) return SUCCEED; gsetid = zbx_db_get_maxid_num(tbl_name, group_sets->num_data); zbx_hashset_iter_reset(group_sets, &iter); while (NULL != (gset_ptr = (zbx_dbu_group_set_t *)zbx_hashset_iter_next(&iter))) { int i; if (NULL != hgsetids) { char *sql; zbx_db_result_t result; zbx_db_row_t row; sql = zbx_dsprintf(NULL, "select hgsetid from hgset where hash='%s'", gset_ptr->hash_str); result = zbx_db_select_n(sql, 1); zbx_free(sql); if (NULL != (row = zbx_db_fetch(result))) { zbx_uint64_t hgsetid; ZBX_STR2UINT64(hgsetid, row[0]); zbx_db_free_result(result); for (i = 0; i < gset_ptr->ids.values_num; i++) zbx_db_insert_add_values(db_gset_parents, gset_ptr->ids.values[i], hgsetid); continue; } zbx_db_free_result(result); zbx_vector_uint64_append(hgsetids, gsetid); } zbx_db_insert_add_values(db_gset, gsetid, gset_ptr->hash_str); for (i = 0; i < gset_ptr->groupids.values_num; i++) zbx_db_insert_add_values(db_gset_groups, gsetid, gset_ptr->groupids.values[i]); for (i = 0; i < gset_ptr->ids.values_num; i++) zbx_db_insert_add_values(db_gset_parents, gset_ptr->ids.values[i], gsetid); gsetid++; } if (FAIL == zbx_db_insert_execute(db_gset) || FAIL == zbx_db_insert_execute(db_gset_groups) || FAIL == zbx_db_insert_execute(db_gset_parents)) { return FAIL; } return SUCCEED; } static void permission_groupsets_destroy(zbx_hashset_t *group_sets) { zbx_hashset_iter_t iter; zbx_dbu_group_set_t *gset_ptr; zbx_hashset_iter_reset(group_sets, &iter); while (NULL != (gset_ptr = (zbx_dbu_group_set_t *)zbx_hashset_iter_next(&iter))) { zbx_vector_uint64_destroy(&gset_ptr->groupids); zbx_vector_uint64_destroy(&gset_ptr->ids); } zbx_hashset_destroy(group_sets); } /****************************************************************************** * * * Purpose: calculates hashes and adds new group sets for specified hosts * * * * Parameters: ids - [IN] host IDs * * hgsetids - [IN/OUT] added host group sets IDs, optional * * * * Return value: SUCCEED - new host group sets added successfully, * * or not needed * * FAIL - otherwise * * * * Comments: If hgsetids parameter was specified, then: * * - function checks if hgset already exists then does not create * * new hgset and skips creating link between groupid and hgsetid * * - adds only new host group set IDs to hgsetids * * (e.g. for 'permission' table update) * * * ******************************************************************************/ int permission_hgsets_add(zbx_vector_uint64_t *ids, zbx_vector_uint64_t *hgsetids) { int ret; zbx_hashset_t hgsets; zbx_db_insert_t db_insert, db_insert_groups, db_insert_hosts; zbx_hashset_create(&hgsets, 1, permission_group_set_hash, permission_group_set_compare); zbx_db_insert_prepare(&db_insert, "hgset", "hgsetid", "hash", (char*)NULL); zbx_db_insert_prepare(&db_insert_groups, "hgset_group", "hgsetid", "groupid", (char*)NULL); zbx_db_insert_prepare(&db_insert_hosts, "host_hgset", "hostid", "hgsetid", (char*)NULL); if (SUCCEED == (ret = permission_groupsets_make(ids, "hostid", "groupid", "hosts_groups", &hgsets, 0))) { ret = permission_groupsets_insert("hgset", &hgsets, &db_insert, &db_insert_groups, &db_insert_hosts, hgsetids); } zbx_db_insert_clean(&db_insert); zbx_db_insert_clean(&db_insert_groups); zbx_db_insert_clean(&db_insert_hosts); permission_groupsets_destroy(&hgsets); return ret; } /****************************************************************************** * * * Purpose: calculates hashes and adds new group sets for users * * * * Parameters: ids - [IN] user IDs * * * * Return value: SUCCEED - new user group sets added successfully, * * or not needed * * FAIL - otherwise * * * ******************************************************************************/ int permission_ugsets_add(zbx_vector_uint64_t *ids) { int ret; zbx_hashset_t ugsets; zbx_db_insert_t db_insert, db_insert_groups, db_insert_users; zbx_hashset_create(&ugsets, 1, permission_group_set_hash, permission_group_set_compare); zbx_db_insert_prepare(&db_insert, "ugset", "ugsetid", "hash", (char*)NULL); zbx_db_insert_prepare(&db_insert_groups, "ugset_group", "ugsetid", "usrgrpid", (char*)NULL); zbx_db_insert_prepare(&db_insert_users, "user_ugset", "userid", "ugsetid", (char*)NULL); if (SUCCEED == (ret = permission_groupsets_make(ids, "userid", "usrgrpid", "users_groups", &ugsets, 1))) { ret = permission_groupsets_insert("ugset", &ugsets, &db_insert, &db_insert_groups, &db_insert_users, NULL); } zbx_db_insert_clean(&db_insert); zbx_db_insert_clean(&db_insert_groups); zbx_db_insert_clean(&db_insert_users); permission_groupsets_destroy(&ugsets); return ret; }