Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adapt registry synchronization mechanism #8143

Merged
merged 5 commits into from Apr 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Makefile
Expand Up @@ -1715,7 +1715,7 @@ syscheck_o := $(syschecklib_o:.c=.o) $(syscheck_c:.c=.o) $(syscheck_sql:.sql=.o)
syscheck_eventchannel_o := $(syscheck_c:.c=-event.o) $(syscheck_sql:.sql=.o)

syscheckd/db/schema_fim_db.o: syscheckd/db/schema_fim_db.sql
${QUIET_CC}echo 'const char *schema_fim_sql = "'"`cat $< | tr -d \"\n\"`"'";' | ${MING_BASE}${CC} ${OSSEC_CFLAGS} -xc -c -o $@ -
${QUIET_CC}echo 'const char *schema_fim_sql = "'"`cat $< | sed s/\\\\\\\/\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\/g | tr -d \\\n`"'";' | ${MING_BASE}${CC} ${OSSEC_CFLAGS} -xc -c -o $@ -

syscheckd/%.o: syscheckd/%.c
${OSSEC_CC} ${OSSEC_CFLAGS} -DARGV0=\"wazuh-syscheckd\" -c $^ -o $@
Expand Down
1 change: 1 addition & 0 deletions src/shared/integrity_op.c
Expand Up @@ -40,6 +40,7 @@ char * dbsync_check_msg(const char * component, dbsync_msg msg, long id, const c
cJSON * data = cJSON_CreateObject();
cJSON_AddItemToObject(root, "data", data);
cJSON_AddNumberToObject(data, "id", id);
cJSON_AddNumberToObject(data, "version", 2.0);

if (msg != INTEGRITY_CLEAR) {
assert(start != NULL);
Expand Down
2 changes: 2 additions & 0 deletions src/syscheckd/create_db.c
Expand Up @@ -1259,6 +1259,8 @@ cJSON *fim_json_event(const char *file_name,
cJSON_AddItemToObject(json_event, "data", data);

cJSON_AddStringToObject(data, "path", file_name);
cJSON_AddNumberToObject(data, "version", 2.0);

cJSON_AddStringToObject(data, "mode", FIM_EVENT_MODE[mode]);
cJSON_AddStringToObject(data, "type", FIM_EVENT_TYPE[type]);
cJSON_AddNumberToObject(data, "timestamp", new_data->last_event);
Expand Down
69 changes: 56 additions & 13 deletions src/syscheckd/db/fim_db.c
Expand Up @@ -86,6 +86,17 @@ const char *SQL_STMT[] = {
[FIMDB_STMT_COUNT_DB_ENTRIES] = "SELECT (SELECT count(*) FROM file_entry) + (SELECT count(*) FROM registry_key) + (SELECT count(*) FROM registry_data);",
};

#ifdef WIN32
/**
* @brief Function that looks for the separator `:` between keys and values in synchronization messages.
*
* @param input string with the path of the synchronization message.
* @return char* Pointer to the separator. If the separator wasn't found, returns NULL.
*/
static char *find_key_value_limiter(char *input);

#endif

fdb_t *fim_db_init(int storage) {
fdb_t *fim;
char *path = (storage == FIM_DB_MEMORY) ? FIM_DB_MEMORY_PATH : FIM_DB_DISK_PATH;
Expand Down Expand Up @@ -298,10 +309,44 @@ fim_entry *fim_db_get_entry_from_sync_msg(fdb_t *fim_sql,
}
// LCOV_EXCL_STOP
#else

static char *find_key_value_limiter(char *input){
size_t limiter_pos = 0;
if (input == NULL || *input == '\0') {
return NULL;
}

size_t input_len = strlen(input);
size_t increment = 0;

while (limiter_pos = strcspn(input, "\\:"), input[limiter_pos] != '\0') {
switch (input[limiter_pos]) {
case ':':
return input + limiter_pos;

default: // '\':
// Check that the string won't be exceeded.
increment += limiter_pos + 2;
if (input_len <= increment) {
return NULL;
}

input += limiter_pos + 2;
break;
}
}

return NULL;
}


fim_entry *fim_db_get_entry_from_sync_msg(fdb_t *fim_sql, fim_type type, const char *path) {
char *full_path, *key_path, *value_name;
char *full_path = NULL;
char *key_path = NULL;
char *value_name = NULL;
char *finder = NULL;
int arch;
fim_entry *entry;
fim_entry *entry = NULL;

if (type == FIM_TYPE_FILE) {
return fim_db_get_path(fim_sql, path);
Expand All @@ -312,18 +357,18 @@ fim_entry *fim_db_get_entry_from_sync_msg(fdb_t *fim_sql, fim_type type, const c
os_strdup(&path[6], full_path);
value_name = full_path;

// Find where the key ends and the value starts
while ((value_name = strchr(value_name, ':'))) {
if (value_name[1] != ':') {
*value_name = '\0';
value_name++;
break;
}
value_name += 2;
finder = find_key_value_limiter(value_name);

if (finder == NULL) {
mdebug1("Separator ':' was not found in %s", full_path);
free(full_path);
return NULL;
}

key_path = wstr_replace(full_path, "::", ":");
*finder = '\0';

value_name = filter_special_chars(finder + 1);
key_path = filter_special_chars(full_path);
os_calloc(1, sizeof(fim_entry), entry);
entry->type = FIM_TYPE_REGISTRY;
entry->registry_entry.key = fim_db_get_registry_key(fim_sql, key_path, arch);
Expand All @@ -342,8 +387,6 @@ fim_entry *fim_db_get_entry_from_sync_msg(fdb_t *fim_sql, fim_type type, const c
}

free(key_path);

value_name = wstr_replace(value_name, "::", ":");
free(full_path);

entry->registry_entry.value = fim_db_get_registry_data(fim_sql, entry->registry_entry.key->id, value_name);
Expand Down
4 changes: 2 additions & 2 deletions src/syscheckd/db/schema_fim_db.sql
Expand Up @@ -76,6 +76,6 @@ CREATE TABLE IF NOT EXISTS registry_data (
CREATE INDEX IF NOT EXISTS key_name_index ON registry_data (key_id, name);

CREATE VIEW IF NOT EXISTS registry_view (path, checksum) AS
SELECT arch || ' ' || replace(path, ':', '::') || ':', checksum FROM registry_key
SELECT arch || ' ' || replace(replace(path, '\', '\\'), ':', '\:') || ':', checksum FROM registry_key
UNION ALL
SELECT arch || ' ' || replace(path, ':', '::') || ':' || replace(name, ':', '::'), registry_data.checksum FROM registry_key INNER JOIN registry_data ON registry_key.id=registry_data.key_id;
SELECT arch || ' ' || replace(replace(path, '\', '\\'), ':', '\:') || ':' || replace(replace(name, '\', '\\'), ':', '\:'), registry_data.checksum FROM registry_key INNER JOIN registry_data ON registry_key.id=registry_data.key_id;
2 changes: 1 addition & 1 deletion src/syscheckd/fim_sync.c
Expand Up @@ -148,7 +148,7 @@ cJSON *fim_entry_json(const char *key, fim_entry *entry) {
attributes = fim_registry_value_attributes_json(entry->registry_entry.value, configuration);
}
#endif

cJSON_AddNumberToObject(root, "version", 2.0);
cJSON_AddItemToObject(root, "attributes", attributes);

return root;
Expand Down
2 changes: 2 additions & 0 deletions src/syscheckd/registry/events.c
Expand Up @@ -138,6 +138,7 @@ cJSON *fim_registry_value_json_event(const fim_entry *new_data,
cJSON_AddItemToObject(json_event, "data", data);

cJSON_AddStringToObject(data, "path", new_data->registry_entry.key->path);
cJSON_AddNumberToObject(data, "version", 2.0);
cJSON_AddStringToObject(data, "mode", FIM_EVENT_MODE[mode]);
cJSON_AddStringToObject(data, "type", FIM_EVENT_TYPE[type]);
cJSON_AddStringToObject(data, "arch", new_data->registry_entry.key->arch == ARCH_32BIT ? "[x32]" : "[x64]");
Expand Down Expand Up @@ -289,6 +290,7 @@ cJSON *fim_registry_key_json_event(const fim_registry_key *new_data,
cJSON_AddItemToObject(json_event, "data", data);

cJSON_AddStringToObject(data, "path", new_data->path);
cJSON_AddNumberToObject(data, "version", 2.0);
cJSON_AddStringToObject(data, "mode", FIM_EVENT_MODE[mode]);
cJSON_AddStringToObject(data, "type", FIM_EVENT_TYPE[type]);
cJSON_AddStringToObject(data, "arch", new_data->arch == ARCH_32BIT ? "[x32]" : "[x64]");
Expand Down
8 changes: 4 additions & 4 deletions src/unit_tests/shared/test_integrity_op.c
Expand Up @@ -29,7 +29,7 @@ void test_dbsync_check_msg_left(void **state)
{
(void) state; /* unused */
char *ret;
char json[256] = "{\"component\":\"wazuh-testing\",\"type\":\"integrity_check_left\",\"data\":{\"id\":1569926892,\"begin\":\"start\",\"end\":\"top\",\"tail\":\"tail\",\"checksum\":\"51ABB9636078DEFBF888D8457A7C76F85C8F114C\"}}";
char json[256] = "{\"component\":\"wazuh-testing\",\"type\":\"integrity_check_left\",\"data\":{\"id\":1569926892,\"version\":2,\"begin\":\"start\",\"end\":\"top\",\"tail\":\"tail\",\"checksum\":\"51ABB9636078DEFBF888D8457A7C76F85C8F114C\"}}";

ret = dbsync_check_msg("wazuh-testing", INTEGRITY_CHECK_LEFT, 1569926892, "start", "top", "tail", "51ABB9636078DEFBF888D8457A7C76F85C8F114C");
*state = ret;
Expand All @@ -40,7 +40,7 @@ void test_dbsync_check_msg_right(void **state)
{
(void) state; /* unused */
char *ret;
char json[256] = "{\"component\":\"wazuh-testing\",\"type\":\"integrity_check_right\",\"data\":{\"id\":1569926892,\"begin\":\"start\",\"end\":\"top\",\"checksum\":\"51ABB9636078DEFBF888D8457A7C76F85C8F114C\"}}";
char json[256] = "{\"component\":\"wazuh-testing\",\"type\":\"integrity_check_right\",\"data\":{\"id\":1569926892,\"version\":2,\"begin\":\"start\",\"end\":\"top\",\"checksum\":\"51ABB9636078DEFBF888D8457A7C76F85C8F114C\"}}";

ret = dbsync_check_msg("wazuh-testing", INTEGRITY_CHECK_RIGHT, 1569926892, "start", "top", "tail", "51ABB9636078DEFBF888D8457A7C76F85C8F114C");
*state = ret;
Expand All @@ -51,7 +51,7 @@ void test_dbsync_check_msg_global(void **state)
{
(void) state; /* unused */
char *ret;
char json[256] = "{\"component\":\"wazuh-testing\",\"type\":\"integrity_check_global\",\"data\":{\"id\":1569926892,\"begin\":\"start\",\"end\":\"top\",\"checksum\":\"51ABB9636078DEFBF888D8457A7C76F85C8F114C\"}}";
char json[256] = "{\"component\":\"wazuh-testing\",\"type\":\"integrity_check_global\",\"data\":{\"id\":1569926892,\"version\":2,\"begin\":\"start\",\"end\":\"top\",\"checksum\":\"51ABB9636078DEFBF888D8457A7C76F85C8F114C\"}}";

ret = dbsync_check_msg("wazuh-testing", INTEGRITY_CHECK_GLOBAL, 1569926892, "start", "top", "tail", "51ABB9636078DEFBF888D8457A7C76F85C8F114C");
*state = ret;
Expand All @@ -62,7 +62,7 @@ void test_dbsync_check_msg_clear(void **state)
{
(void) state; /* unused */
char *ret;
char json[128] = "{\"component\":\"wazuh-testing\",\"type\":\"integrity_clear\",\"data\":{\"id\":1569926892}}";
char json[128] = "{\"component\":\"wazuh-testing\",\"type\":\"integrity_clear\",\"data\":{\"id\":1569926892,\"version\":2}}";

ret = dbsync_check_msg("wazuh-testing", INTEGRITY_CLEAR, 1569926892, "start", "top", "tail", "51ABB9636078DEFBF888D8457A7C76F85C8F114C");
*state = ret;
Expand Down
65 changes: 61 additions & 4 deletions src/unit_tests/syscheckd/db/test_fim_db.c
Expand Up @@ -2170,7 +2170,7 @@ void test_fim_db_get_entry_from_sync_msg_get_registry_key(void **state) {
expect_fim_db_get_registry_key(&data);

entry =
fim_db_get_entry_from_sync_msg(&fim_sql, FIM_TYPE_REGISTRY, "[x64] HKEY_LOCAL_MACHINE\\software\\some::\\key");
fim_db_get_entry_from_sync_msg(&fim_sql, FIM_TYPE_REGISTRY, "[x64] HKEY_LOCAL_MACHINE\\\\software\\\\some\\:\\\\key:");

*state = entry;

Expand All @@ -2190,7 +2190,7 @@ void test_fim_db_get_entry_from_sync_msg_get_registry_key_fail_to_get_key(void *
expect_fim_db_get_registry_key_fail(&data);

entry =
fim_db_get_entry_from_sync_msg(&fim_sql, FIM_TYPE_REGISTRY, "[x64] HKEY_LOCAL_MACHINE\\software\\some::\\key:value");
fim_db_get_entry_from_sync_msg(&fim_sql, FIM_TYPE_REGISTRY, "[x64] HKEY_LOCAL_MACHINE\\\\software\\\\some\\:\\\\key:value");

*state = entry;

Expand All @@ -2206,7 +2206,7 @@ void test_fim_db_get_entry_from_sync_msg_get_registry_value_fail_to_get_data(voi
expect_fim_db_get_registry_data_fail("some:value", key_data.id);

entry = fim_db_get_entry_from_sync_msg(&fim_sql, FIM_TYPE_REGISTRY,
"[x64] HKEY_LOCAL_MACHINE\\software\\some::\\key:some::value");
"[x64] HKEY_LOCAL_MACHINE\\\\software\\\\some\\:\\\\key:some\\:value");

*state = entry;

Expand All @@ -2223,7 +2223,7 @@ void test_fim_db_get_entry_from_sync_msg_get_registry_value_success(void **state
expect_fim_db_get_registry_data("some:value", key_data.id, &value_data);

entry = fim_db_get_entry_from_sync_msg(&fim_sql, FIM_TYPE_REGISTRY,
"[x64] HKEY_LOCAL_MACHINE\\software\\some::\\key:some::value");
"[x64] HKEY_LOCAL_MACHINE\\\\software\\\\some\\:\\\\key:some\\:value");

*state = entry;

Expand All @@ -2237,6 +2237,59 @@ void test_fim_db_get_entry_from_sync_msg_get_registry_value_success(void **state
assert_int_equal(entry->registry_entry.value->id, entry->registry_entry.key->id);
}

void test_fim_db_get_entry_from_sync_msg_two_dots_subkey(void **state) {
fdb_t fim_sql;
fim_registry_key key_data = DEFAULT_REGISTRY_KEY;
fim_registry_value_data value_data = DEFAULT_REGISTRY_VALUE;
fim_entry *entry;
key_data.path = "HKEY_LOCAL_MACHINE\\software\\some:\\:\\key";
expect_fim_db_get_registry_key(&key_data);
expect_fim_db_get_registry_data("some:value", key_data.id, &value_data);

entry = fim_db_get_entry_from_sync_msg(&fim_sql, FIM_TYPE_REGISTRY,
"[x64] HKEY_LOCAL_MACHINE\\\\software\\\\some\\:\\\\\\:\\\\key:some\\:value");

*state = entry;

assert_non_null(entry);
assert_int_equal(entry->type, FIM_TYPE_REGISTRY);
assert_non_null(entry->registry_entry.key);
assert_string_equal(entry->registry_entry.key->path, "HKEY_LOCAL_MACHINE\\software\\some:\\:\\key");
assert_int_equal(entry->registry_entry.key->arch, ARCH_64BIT);
assert_non_null(entry->registry_entry.value);
assert_string_equal(entry->registry_entry.value->name, "some:value");
assert_int_equal(entry->registry_entry.value->id, entry->registry_entry.key->id);
}

void test_fim_db_get_entry_from_sync_msg_no_separator(void **state) {
char *str = "[x64] a\\string\\without\\the\\separator\\:";
char debug_msg[OS_SIZE_128] = {0};
fdb_t fim_sql;
fim_entry *entry = NULL;

snprintf(debug_msg, OS_SIZE_128, "Separator ':' was not found in %s", "a\\string\\without\\the\\separator\\:");
expect_string(__wrap__mdebug1, formatted_msg, debug_msg);

entry = fim_db_get_entry_from_sync_msg(&fim_sql, FIM_TYPE_REGISTRY, str);

assert_null(entry);
}

void test_fim_db_get_entry_from_sync_msg_wrong_str(void **state) {
char *str = "[x64] \\\\\\\0:random_content";
char debug_msg[OS_SIZE_128] = {0};
fdb_t fim_sql;
fim_entry *entry = NULL;

snprintf(debug_msg, OS_SIZE_128, "Separator ':' was not found in %s", "\\\\\\");
expect_string(__wrap__mdebug1, formatted_msg, debug_msg);

entry = fim_db_get_entry_from_sync_msg(&fim_sql, FIM_TYPE_REGISTRY, str);

assert_null(entry);
}


#endif

/**********************************************************************************************************************\
Expand Down Expand Up @@ -2380,6 +2433,10 @@ int main(void) {
cmocka_unit_test_teardown(test_fim_db_get_entry_from_sync_msg_get_registry_key_fail_to_get_key, teardown_fim_entry),
cmocka_unit_test_teardown(test_fim_db_get_entry_from_sync_msg_get_registry_value_fail_to_get_data, teardown_fim_entry),
cmocka_unit_test_teardown(test_fim_db_get_entry_from_sync_msg_get_registry_value_success, teardown_fim_entry),
cmocka_unit_test_teardown(test_fim_db_get_entry_from_sync_msg_two_dots_subkey, teardown_fim_entry),
cmocka_unit_test(test_fim_db_get_entry_from_sync_msg_no_separator),
cmocka_unit_test(test_fim_db_get_entry_from_sync_msg_wrong_str),

#endif
};
return cmocka_run_group_tests(tests, setup_fim_db_group, teardown_fim_db_group);
Expand Down