Skip to content

Commit

Permalink
Change how to Windows agent process permissions of a file, from char …
Browse files Browse the repository at this point in the history
…to cJSON
  • Loading branch information
jotacarma90 committed Jul 1, 2021
1 parent a3d2d1a commit 4744cc0
Show file tree
Hide file tree
Showing 6 changed files with 267 additions and 28 deletions.
6 changes: 6 additions & 0 deletions src/config/syscheck-config.h
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,13 @@ typedef struct registry_ignore_regex {
typedef struct fim_file_data {
// Checksum attributes
unsigned int size;

#ifdef WIN32
cJSON * perm;
#else
char * perm;
#endif

char * attributes;
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
12 changes: 9 additions & 3 deletions src/headers/syscheck_op.h
Original file line number Diff line number Diff line change
Expand Up @@ -360,11 +360,10 @@ 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
* @param [out] acl_json cJSON in which to write the acl
* @return 0 on success, the error code on failure, -2 if ACE could not be obtained
*/
int w_get_file_permissions(const char *file_path, char *permissions, int perm_size);
int w_get_file_permissions(const char *file_path, cJSON *acl_json);

/**
* @brief Retrieves the group name from a group ID in windows
Expand Down Expand Up @@ -441,6 +440,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
203 changes: 188 additions & 15 deletions src/shared/syscheck_op.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,36 @@ extern void mock_assert(const int result, const char* const expression,
#endif
#endif

/**
* @brief Retrieves the permissions of a specific file (Windows)
*
* @param [in] ace ACE structure
* @param [out] acl_json cJSON to write the permissions
* @return 0 on success, the error code on failure, -2 if ACE could not be obtained
*/
static int process_ace_info(void *ace, cJSON *acl_json);

/**
* @brief Retrieves the permissions of a specific file (Windows)
*
* @param [out] acl_json cJSON to write the permissions
* @param [in] sid The user ID associated to the user
* @param [in] account_name The account name associated to the sid
* @param [in] ace_type int with 0 if "allowed" ace, 1 if "denied" ace
* @param [in] mask Mask with the permissions
*/
static void add_ace_to_json(cJSON *acl_json, char *sid, char *account_name, const char *ace_type, int mask);

/**
* @brief Retrieves the permissions of a specific file (Windows)
*
* @param [out] ace_json cJSON with the mask to process
* @param [in] mask Mask with the permissions
* @param [in] ace_type string "allowed" or "denied" depends on ace type
*/
static void make_mask_readable (cJSON *ace_json, int mask, char *ace_type);


char *escape_syscheck_field(char *field) {
char *esc_it;

Expand Down Expand Up @@ -765,7 +795,7 @@ char *get_user(const char *path, char **sid, HANDLE hndl, SE_OBJECT_TYPE object_
return result;
}

int w_get_file_permissions(const char *file_path, char *permissions, int perm_size) {
int w_get_file_permissions(const char *file_path, cJSON *acl_json) {
int retval = 0;
int error;
unsigned int i;
Expand All @@ -775,9 +805,6 @@ int w_get_file_permissions(const char *file_path, char *permissions, int perm_si
int has_dacl, default_dacl;
unsigned long size = 0;
ACL_SIZE_INFORMATION acl_size;
char *perm_it = permissions;

*permissions = '\0';

if (!GetFileSecurity(file_path, DACL_SECURITY_INFORMATION, 0, 0, &size)) {
// We must have this error at this point
Expand Down Expand Up @@ -813,30 +840,98 @@ int w_get_file_permissions(const char *file_path, char *permissions, int perm_si
}

for (i = 0; i < acl_size.AceCount; i++) {
int written;

if (!GetAce(f_acl, i, &f_ace)) {
mdebug1("ACE number %d could not be obtained.", i);
retval = -2;
*permissions = '\0';
goto end;
}
written = copy_ace_info(f_ace, perm_it, perm_size);
if (written > 0) {
perm_it += written;
perm_size -= written;
if (perm_size > 0) {
continue;
}
if (process_ace_info(f_ace, acl_json)) {
mdebug1("ACE number %d could not be processed.", i);
}
mdebug1("The parameters of ACE number %d from '%s' could not be extracted. %d bytes remaining.", i, file_path, perm_size);
}

end:
free(s_desc);
return retval;
}

int process_ace_info(void *ace, cJSON *acl_json) {
SID *sid;
char *sid_str = NULL;
char *account_name = NULL;
char *domain_name = NULL;
int mask;
int ace_type;
int error;

if (((ACCESS_ALLOWED_ACE *)ace)->Header.AceType == ACCESS_ALLOWED_ACE_TYPE) {
ACCESS_ALLOWED_ACE *allowed_ace = (ACCESS_ALLOWED_ACE *)ace;
sid = (SID *)&allowed_ace->SidStart;
mask = allowed_ace->Mask;
ace_type = 0;
} else if (((ACCESS_DENIED_ACE *)ace)->Header.AceType == ACCESS_DENIED_ACE_TYPE) {
ACCESS_DENIED_ACE *denied_ace = (ACCESS_DENIED_ACE *)ace;
sid = (SID *)&denied_ace->SidStart;
mask = denied_ace->Mask;
ace_type = 1;
} else {
mdebug2("Invalid ACE type.");
return 1;
}

if (!IsValidSid(sid)) {
mdebug2("Invalid SID found in ACE.");
return 1;
}

if (error = w_get_account_info(sid, &account_name, &domain_name), error) {
mdebug2("No information could be extracted from the account linked to the SID. Error: %d.", error);
}

if (!ConvertSidToStringSid(sid, &sid_str)) {
mdebug2("Could not extract the SID.");
free(account_name);
free(domain_name);
return 1;
}

add_ace_to_json(acl_json, sid_str, account_name, ace_type ? "denied" : "allowed", mask);
LocalFree(sid_str);

return 0;
}

void add_ace_to_json(cJSON *acl_json, char *sid, char *account_name, const char *ace_type, int mask) {
cJSON *ace_json = NULL;
cJSON *mask_json = NULL;
int saved_mask;

assert(acl_json != NULL);
assert(strcmp(ace_type, "allowed") == 0 || strcmp(ace_type, "denied") == 0);

ace_json = cJSON_GetObjectItem(acl_json, sid);
if (ace_json == NULL) {
ace_json = cJSON_CreateObject();
if (ace_json == NULL) {
mwarn(FIM_CJSON_ERROR_CREATE_ITEM);
return;
}
cJSON_AddStringToObject(acl_json, "name", account_name);
cJSON_AddItemToObject(acl_json, sid, ace_json);
}

mask_json = cJSON_GetObjectItem(ace_json, ace_type);
if (mask_json == NULL) {
cJSON_AddNumberToObject(ace_json, ace_type, mask);
return;
}

saved_mask = mask_json->valueint;
cJSON_SetNumberValue(mask_json, (saved_mask | mask));

return;
}

int copy_ace_info(void *ace, char *perm, int perm_size) {
SID *sid;
char *sid_str = NULL;
Expand Down Expand Up @@ -1170,6 +1265,84 @@ void decode_win_attributes(char *str, unsigned int attrs) {
}
}

void decode_win_acl_json (cJSON *acl_json) {
cJSON *json_object = NULL;
cJSON *allowed_item = NULL;
cJSON *denied_item = NULL;

assert(acl_json != NULL);

cJSON_ArrayForEach(json_object, acl_json) {
allowed_item = cJSON_GetObjectItem(json_object, "allowed");
if (allowed_item) {
make_mask_readable(json_object, allowed_item->valueint, "allowed");
}
denied_item = cJSON_GetObjectItem(json_object, "denied");
if (denied_item) {
make_mask_readable(json_object, denied_item->valueint, "denied");
}
}
}

void make_mask_readable (cJSON *ace_json, int mask, char *ace_type) {
int i;
int perm_bits[] = {
GENERIC_READ,
GENERIC_WRITE,
GENERIC_EXECUTE,
GENERIC_ALL,
DELETE,
READ_CONTROL,
WRITE_DAC,
WRITE_OWNER,
SYNCHRONIZE,
FILE_READ_DATA,
FILE_WRITE_DATA,
FILE_APPEND_DATA,
FILE_READ_EA,
FILE_WRITE_EA,
FILE_EXECUTE,
FILE_READ_ATTRIBUTES,
FILE_WRITE_ATTRIBUTES,
0
};

static const char * const perm_strings[] = {
"generic_read",
"generic_write",
"generic_execute",
"generic_all",
"delete",
"read_control",
"write_dac",
"write_owner",
"synchronize",
"read_data",
"write_data",
"append_data",
"read_ea",
"write_ea",
"execute",
"read_attributes",
"write_attributes",
NULL
};

cJSON *perm_array = cJSON_CreateArray();
if (perm_array == NULL) {
mwarn(FIM_CJSON_ERROR_CREATE_ITEM);
return;
}

for (i = 0; perm_bits[i]; i++) {
if (mask & perm_bits[i]) {
cJSON_AddItemToArray(perm_array, cJSON_CreateString(perm_strings[i]));
}
}

cJSON_ReplaceItemInObject(ace_json, ace_type, perm_array);
}

char *decode_win_permissions(char *raw_perm) {
int written = 0;
int size = 0;
Expand Down

0 comments on commit 4744cc0

Please sign in to comment.