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

Change format for permissions on Windows from string to cJSON #9162

Merged
merged 9 commits into from
Jul 9, 2021
94 changes: 94 additions & 0 deletions src/analysisd/decoders/syscheck.c
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,15 @@ static int fim_fetch_attributes_state(cJSON *attr, Eventinfo *lf, char new_state
// Replace the coded fields with the decoded ones in the checksum
static void fim_adjust_checksum(sk_sum_t *newsum, char **checksum);

/**
* @brief Decode a cJSON with Windows permissions and convert to old format string
*
* @param perm_json cJSON with the permissions
*
* @returns A string with the old format Windows permissions
*/
static char *perm_json_to_old_format(cJSON *perm_json);

// Mutexes
static pthread_mutex_t control_msg_mutex = PTHREAD_MUTEX_INITIALIZER;

Expand Down Expand Up @@ -1665,6 +1674,7 @@ int fim_fetch_attributes_state(cJSON *attr, Eventinfo *lf, char new_state) {
char buf_ptr[26];

assert(lf != NULL);
assert(lf->fields != NULL);

cJSON_ArrayForEach(attr_it, attr) {
if (!attr_it->string) {
Expand Down Expand Up @@ -1724,6 +1734,14 @@ int fim_fetch_attributes_state(cJSON *attr, Eventinfo *lf, char new_state) {
if (dst_data) {
os_strdup(attr_it->valuestring, *dst_data);
}
} else if (attr_it->type == cJSON_Object) {
if (strcmp(attr_it->string, "perm") == 0) {
if (new_state) {
lf->fields[FIM_PERM].value = perm_json_to_old_format(attr_it);
} else {
lf->fields[FIM_PERM_BEFORE].value = perm_json_to_old_format(attr_it);
}
}
} else {
mdebug1("Unknown FIM data type.");
}
Expand All @@ -1732,6 +1750,82 @@ int fim_fetch_attributes_state(cJSON *attr, Eventinfo *lf, char new_state) {
return 0;
}

char *decode_ace_json(const cJSON *const perm_array, const char *const account_name, const char *const ace_type) {
cJSON *it;
char *output = NULL;
char *perms = NULL;
int length;

if (perm_array == NULL) {
return NULL;
}

length = snprintf(NULL, 0, "%s (%s): ", account_name, ace_type);

if (length <= 0) {
return NULL; // LCOV_EXCL_LINE
}

os_malloc(length + 1, output);

snprintf(output, length + 1, "%s (%s): ", account_name, ace_type);

cJSON_ArrayForEach(it, perm_array) {
wm_strcat(&perms, cJSON_GetStringValue(it), '|');
}

if (perms) {
str_uppercase(perms);
wm_strcat(&output, perms, '\0');
free(perms);
}

wm_strcat(&output, ", ", '\0');

return output;
}

char *perm_json_to_old_format(cJSON *perm_json) {
char *account_name;
char *output = NULL;
int length;
cJSON *json_it;

assert(perm_json != NULL);

cJSON_ArrayForEach(json_it, perm_json) {
char *ace;
account_name = cJSON_GetStringValue(cJSON_GetObjectItem(json_it, "name"));
if (account_name == NULL) {
account_name = json_it->string;
}

ace = decode_ace_json(cJSON_GetObjectItem(json_it, "allowed"), account_name, "allowed");
if (ace) {
wm_strcat(&output, ace, '\0');
free(ace);
}

ace = decode_ace_json(cJSON_GetObjectItem(json_it, "denied"), account_name, "denied");
if (ace) {
wm_strcat(&output, ace, '\0');
free(ace);
}
}

if (output == NULL) {
return NULL;
}

length = strlen(output);

if (length > 2 && output[strlen(output) - 2] == ',') {
output[length - 2] = '\0';
}

return output;
}

void fim_adjust_checksum(sk_sum_t *newsum, char **checksum) {
// Adjust attributes
if (newsum->attributes) {
Expand Down
4 changes: 4 additions & 0 deletions src/config/syscheck-config.h
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,9 @@ typedef struct registry_ignore_regex {
typedef struct fim_file_data {
// Checksum attributes
unsigned int size;
#ifdef WIN32
cJSON * perm_json;
#endif
char * perm;
char * attributes;
char * uid;
Expand All @@ -302,6 +305,7 @@ typedef struct fim_file_data {
typedef struct fim_registry_key {
unsigned int id;
char * path;
cJSON * perm_json;
char * perm;
char * uid;
char * gid;
Expand Down
2 changes: 2 additions & 0 deletions src/error_messages/warning_messages.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@
#define FIM_AUDIT_DISABLED "(6946): Audit is disabled."
#define FIM_WARN_FORMAT_PATH "(6947): Error formatting path: '%s'"
#define FIM_DATABASE_NODES_COUNT_FAIL "(6948): Unable to get the number of entries in database."
#define FIM_CJSON_ERROR_CREATE_ITEM "(6949): Cannot create a cJSON item"


/* Monitord warning messages */
#define ROTATE_LOG_LONG_PATH "(7500): The path of the rotated log is too long."
Expand Down
37 changes: 18 additions & 19 deletions src/headers/syscheck_op.h
Original file line number Diff line number Diff line change
Expand Up @@ -360,11 +360,12 @@ unsigned int w_get_file_attrs(const char *file_path);
* @brief Retrieves the permissions of a specific file (Windows)
*
* @param [in] file_path The path of the file from which to check permissions
* @param [out] permissions Buffer in which to write the permissions
* @param [in] perm_size The size of the permissions buffer
* @return 0 on success, the error code on failure, -2 if ACE could not be obtained
* @param [out] output_acl A cJSON pointer to an object holding the ACL of the file.
* @retval 0 on success.
* @retval -1 if the cJSON object could not be initialized.
* @retval An error code retrieved from `GetLastError` otherwise.
*/
int w_get_file_permissions(const char *file_path, char *permissions, int perm_size);
int w_get_file_permissions(const char *file_path, cJSON **output_acl);

/**
* @brief Retrieves the group name from a group ID in windows
Expand All @@ -387,12 +388,13 @@ char *get_registry_group(char **sid, HANDLE hndl);
/**
* @brief Retrieves the permissions of a registry key.
*
* @param hndl Handle for the registry key to check the permissions of.
* @param perm_key Permissions associated to the registry key.
*
* @return Permissions in perm_key. ERROR_SUCCESS on success, different otherwise
* @param [in] hndl Handle for the registry key to check the permissions of.
* @param [out] output_acl A cJSON pointer to an object holding the ACL of the file.
* @retval 0 on success.
* @retval -1 if the cJSON object could not be initialized.
* @retval An error code retrieved from `GetLastError` otherwise.
*/
DWORD get_registry_permissions(HKEY hndl, char *perm_key);
DWORD get_registry_permissions(HKEY hndl, cJSON **output_acl);

/**
* @brief Get last modification time from registry key.
Expand All @@ -403,16 +405,6 @@ DWORD get_registry_permissions(HKEY hndl, char *perm_key);
*/
unsigned int get_registry_mtime(HKEY hndl);

/**
* @brief Copy ACE information into buffer
*
* @param [in] ace ACE structure
* @param [out] perm Buffer in which to write the ACE information
* @param [in] perm_size The size of the buffer
* @return 0 on failure, the number of bytes written into perm on success
*/
int copy_ace_info(void *ace, char *perm, int perm_size);

/**
* @brief Retrieves the account information (name and domain) from SID
*
Expand Down Expand Up @@ -441,6 +433,13 @@ void decode_win_attributes(char *str, unsigned int attrs);
*/
char *decode_win_permissions(char *raw_perm);

/**
* @brief Decodes a permission string and converts it to a human readable format
*
* @param [out] acl_json A cJSON with the permissions to decode
*/
void decode_win_acl_json(cJSON *acl_json);

/**
* @brief Transforms a bit mask of attributes into a human readable cJSON
*
Expand Down