diff options
Diffstat (limited to 'common/ini/ini_metadata.c')
-rw-r--r-- | common/ini/ini_metadata.c | 307 |
1 files changed, 293 insertions, 14 deletions
diff --git a/common/ini/ini_metadata.c b/common/ini/ini_metadata.c index a5d5109f..3ee9fbaa 100644 --- a/common/ini/ini_metadata.c +++ b/common/ini/ini_metadata.c @@ -33,6 +33,12 @@ #define INI_METADATA "meta" +/* Beffer length used for int to string conversions */ +#define CONVERSION_BUFFER 80 + +/* Invalid file mode */ +#define WRONG_FMODE 0x80000000 + /* Prepare metadata */ int prepare_metadata(uint32_t metaflags, struct collection_item **metadata, @@ -73,6 +79,7 @@ int prepare_metadata(uint32_t metaflags, TRACE_ERROR_NUMBER("Failed to create error section", error); col_destroy_collection(metasec); col_destroy_collection(*metadata); + *metadata = NULL; return error; } /* If we are here we would have to save file open error */ @@ -96,6 +103,7 @@ int collect_metadata(uint32_t metaflags, struct collection_item *metasec = NULL; int filedes; struct stat file_stats; + char buff[CONVERSION_BUFFER]; TRACE_FLOW_STRING("collect_metadata", "Entry"); /* Check and create section for file error if needed */ @@ -123,10 +131,13 @@ int collect_metadata(uint32_t metaflags, /* Record statistics */ /* UID */ - error = col_add_int_property(metasec, + snprintf(buff, CONVERSION_BUFFER, "%lu", + (unsigned long)file_stats.st_uid); + error = col_add_str_property(metasec, NULL, INI_META_KEY_UID, - file_stats.st_uid); + buff, + 0); if (error) { TRACE_ERROR_NUMBER("Failed to save uid", error); col_destroy_collection(metasec); @@ -134,10 +145,13 @@ int collect_metadata(uint32_t metaflags, } /* GID */ - error = col_add_int_property(metasec, + snprintf(buff, CONVERSION_BUFFER, "%lu", + (unsigned long)file_stats.st_gid); + error = col_add_str_property(metasec, NULL, INI_META_KEY_GID, - file_stats.st_gid); + buff, + 0); if (error) { TRACE_ERROR_NUMBER("Failed to save gid", error); col_destroy_collection(metasec); @@ -145,10 +159,13 @@ int collect_metadata(uint32_t metaflags, } /* PERMISSIONS */ - error = col_add_unsigned_property(metasec, - NULL, - INI_META_KEY_PERM, - file_stats.st_mode); + snprintf(buff, CONVERSION_BUFFER, "%lu", + (unsigned long)file_stats.st_mode); + error = col_add_str_property(metasec, + NULL, + INI_META_KEY_PERM, + buff, + 0); if (error) { TRACE_ERROR_NUMBER("Failed to save permissions", error); col_destroy_collection(metasec); @@ -156,10 +173,13 @@ int collect_metadata(uint32_t metaflags, } /* Modification time stamp */ - error = col_add_int_property(metasec, + snprintf(buff, CONVERSION_BUFFER, "%ld", + (long int)file_stats.st_mtime); + error = col_add_str_property(metasec, NULL, INI_META_KEY_MODIFIED, - file_stats.st_mtime); + buff, + 0); if (error) { TRACE_ERROR_NUMBER("Failed to save modification time", error); col_destroy_collection(metasec); @@ -178,11 +198,26 @@ int collect_metadata(uint32_t metaflags, return error; } + /* The device ID can actualy be bigger than + * 32-bits according to the type sizes. + * However it is probaly not going to happen + * on a real system. + * Add a check for this case. + */ + if (file_stats.st_dev > ULONG_MAX) { + TRACE_ERROR_NUMBER("Device is out of range", ERANGE); + col_destroy_collection(metasec); + return ERANGE; + } + /* Device ID */ - error = col_add_int_property(metasec, + snprintf(buff, CONVERSION_BUFFER, "%lu", + (unsigned long)file_stats.st_dev); + error = col_add_str_property(metasec, NULL, INI_META_KEY_DEV, - file_stats.st_dev); + buff, + 0); if (error) { TRACE_ERROR_NUMBER("Failed to save inode", error); col_destroy_collection(metasec); @@ -190,10 +225,13 @@ int collect_metadata(uint32_t metaflags, } /* i-node */ - error = col_add_int_property(metasec, + snprintf(buff, CONVERSION_BUFFER, "%lu", + (unsigned long)file_stats.st_ino); + error = col_add_str_property(metasec, NULL, INI_META_KEY_INODE, - file_stats.st_ino); + buff, + 0); if (error) { TRACE_ERROR_NUMBER("Failed to save inode", error); col_destroy_collection(metasec); @@ -227,3 +265,244 @@ void free_ini_config_metadata(struct collection_item *metadata) col_destroy_collection(metadata); TRACE_FLOW_STRING("free_ini_config_metadata", "Exit"); } + +/* Function to check uid or gid */ +static int check_id(struct collection_item *metadata, + unsigned long id, + const char *key) +{ + int error = EOK; + struct collection_item *item = NULL; + unsigned long fid; + + TRACE_FLOW_STRING("check_id", "Entry"); + TRACE_INFO_STRING("Key", key); + + error = get_config_item(INI_META_SEC_ACCESS, + key, + metadata, + &item); + if (error) { + TRACE_ERROR_NUMBER("Internal collection error.", error); + return error; + } + + /* Entry is supposed to be there so it is an error + * is the item is not found. + */ + if (item == NULL) { + TRACE_ERROR_NUMBER("Expected item is not found.", ENOENT); + return ENOENT; + } + + fid = get_ulong_config_value(item, 1, -1, &error); + if ((error) || (fid == -1)) { + TRACE_ERROR_NUMBER("Conversion failed", EINVAL); + return EINVAL; + } + + if (id != fid) { + TRACE_ERROR_NUMBER("File ID:", fid); + TRACE_ERROR_NUMBER("ID passed in.", id); + TRACE_ERROR_NUMBER("Access denied.", EACCES); + return EACCES; + } + + TRACE_FLOW_STRING("check_id", "Exit"); + return EOK; +} + +/* Function to check access */ +int config_access_check(struct collection_item *metadata, + uint32_t flags, + uid_t uid, + gid_t gid, + mode_t mode, + mode_t mask) +{ + int error = EOK; + struct collection_item *item = NULL; + mode_t f_mode; + + TRACE_FLOW_STRING("config_access_check", "Entry"); + + flags &= INI_ACCESS_CHECK_MODE | + INI_ACCESS_CHECK_GID | + INI_ACCESS_CHECK_UID; + + if ((metadata == NULL) || (flags == 0)) { + TRACE_ERROR_NUMBER("Invalid parameter.", EINVAL); + return EINVAL; + + } + + /* Check that metadata is actually metadata */ + if(!col_is_of_class(metadata, COL_CLASS_INI_META)) { + TRACE_ERROR_NUMBER("Invalid collection.", EINVAL); + return EINVAL; + } + + /* Check mode */ + if (flags & INI_ACCESS_CHECK_MODE) { + + error = get_config_item(INI_META_SEC_ACCESS, + INI_META_KEY_PERM, + metadata, + &item); + if (error) { + TRACE_ERROR_NUMBER("Internal collection error.", error); + return error; + } + + /* Entry is supposed to be there so it is an error + * is the item is not found. + */ + if (item == NULL) { + TRACE_ERROR_NUMBER("Expected item is not found.", ENOENT); + return ENOENT; + } + + f_mode = (mode_t)get_ulong_config_value(item, 1, WRONG_FMODE, &error); + if ((error) || (f_mode == WRONG_FMODE)) { + TRACE_ERROR_NUMBER("Conversion failed", error); + return ENOENT; + } + + TRACE_INFO_NUMBER("File mode as saved.", f_mode); + f_mode &= S_IRWXU | S_IRWXG | S_IRWXO; + TRACE_INFO_NUMBER("File mode adjusted.", f_mode); + + TRACE_INFO_NUMBER("Mode as provided.", mode); + mode &= S_IRWXU | S_IRWXG | S_IRWXO; + TRACE_INFO_NUMBER("Mode adjusted.", mode); + + /* Adjust mask */ + if (mask == 0) mask = S_IRWXU | S_IRWXG | S_IRWXO; + else mask &= S_IRWXU | S_IRWXG | S_IRWXO; + + if ((mode & mask) != (f_mode & mask)) { + TRACE_INFO_NUMBER("File mode:", (mode & mask)); + TRACE_INFO_NUMBER("Mode adjusted.", (f_mode & mask)); + TRACE_ERROR_NUMBER("Access denied.", EACCES); + return EACCES; + } + } + + /* Check uid */ + if (flags & INI_ACCESS_CHECK_UID) { + + error = check_id(metadata, (unsigned long)uid, INI_META_KEY_UID); + if (error) { + TRACE_ERROR_NUMBER("Check for UID failed.", error); + return error; + } + } + + /* Check gid */ + if (flags & INI_ACCESS_CHECK_GID) { + + error = check_id(metadata, (unsigned long)gid, INI_META_KEY_GID); + if (error) { + TRACE_ERROR_NUMBER("Check for UID failed.", error); + return error; + } + } + + TRACE_FLOW_STRING("config_access_check", "Exit"); + return error; + +} + +static unsigned long get_checked_value(struct collection_item *metadata, + const char *key, + int *err) +{ + + int error = EOK; + struct collection_item *item = NULL; + unsigned long value; + + TRACE_FLOW_STRING("get_checked_value", "Entry"); + TRACE_INFO_STRING("Key", key); + + error = get_config_item(INI_META_SEC_ACCESS, + key, + metadata, + &item); + if (error) { + TRACE_ERROR_NUMBER("Internal collection error.", error); + *err = error; + return 0; + } + + /* Entry is supposed to be there so it is an error + * is the item is not found. + */ + if (item == NULL) { + TRACE_ERROR_NUMBER("Expected item is not found.", ENOENT); + *err = ENOENT; + return 0; + } + + value = get_ulong_config_value(item, 1, -1, &error); + if ((error) || (value == -1)) { + TRACE_ERROR_NUMBER("Conversion failed", EINVAL); + *err = EINVAL; + return 0; + } + + *err = 0; + + TRACE_FLOW_NUMBER("get_checked_value Returning", value); + return value; + +} + + +/* Function to check whether the configuration is different */ +int config_changed(struct collection_item *metadata, + struct collection_item *saved_metadata, + int *changed) +{ + int error = EOK; + struct collection_item *md[2]; + unsigned long value[3][2]; + const char *key[] = { INI_META_KEY_MODIFIED, + INI_META_KEY_DEV, + INI_META_KEY_INODE }; + int i, j; + + + TRACE_FLOW_STRING("config_changed", "Entry"); + + if ((!metadata) || + (!saved_metadata) || + (!changed) || + (!col_is_of_class(metadata, COL_CLASS_INI_META)) || + (!col_is_of_class(saved_metadata, COL_CLASS_INI_META))) { + TRACE_ERROR_NUMBER("Invalid argument.", EINVAL); + return EINVAL; + } + + md[0] = metadata; + md[1] = saved_metadata; + + /* Get three values from each collection and compare them */ + for (i = 0; i < 3; i++) { + for (j = 0; j < 2; j++) { + value[i][j] = get_checked_value(md[j], key[i] , &error); + if (error) { + TRACE_ERROR_NUMBER("Failed to get section.", error); + return error; + } + } + if (value[i][0] != value[i][1]) { + *changed = 1; + break; + } + } + + TRACE_FLOW_STRING("config_changed", "Exit"); + return error; + +} |