diff options
-rw-r--r-- | common/ini/ini_config.c | 38 | ||||
-rw-r--r-- | common/ini/ini_config.h | 114 | ||||
-rw-r--r-- | common/ini/ini_config_ut.c | 263 | ||||
-rw-r--r-- | common/ini/ini_metadata.c | 307 |
4 files changed, 684 insertions, 38 deletions
diff --git a/common/ini/ini_config.c b/common/ini/ini_config.c index 66d2c03af..1c8e4aef3 100644 --- a/common/ini/ini_config.c +++ b/common/ini/ini_config.c @@ -87,6 +87,8 @@ #define MAX_VALUE PATH_MAX #define BUFFER_SIZE MAX_KEY + MAX_VALUE + 3 +/* Beffer length used for int to string conversions */ +#define CONVERSION_BUFFER 80 /*============================================================*/ /* The following classes moved here from the public header @@ -583,7 +585,7 @@ static int config_with_metadata(const char *application, int error_level, struct collection_item **error_list, uint32_t metaflags, - struct collection_item *metadata) + struct collection_item **metadata) { int error; int created = 0; @@ -667,8 +669,8 @@ int config_from_fd_with_metadata(const char *application, int save_error = 0; int fd = -1; FILE *config_file = NULL; - int can_free = 0; char abs_name[PATH_MAX + 1]; + char buff[CONVERSION_BUFFER]; TRACE_FLOW_STRING("config_from_fd_with_metadata", "Entry"); @@ -703,10 +705,12 @@ int config_from_fd_with_metadata(const char *application, if (save_error) { /* Record the result of the open file operation in metadata */ - error = col_add_int_property(*metadata, + snprintf(buff, CONVERSION_BUFFER, "%d", file_error); + error = col_add_str_property(*metadata, INI_META_SEC_ERROR, INI_META_KEY_READ_ERROR, - file_error); + buff, + 0); if (error) { /* Something is really wrong if we failed here */ TRACE_ERROR_NUMBER("Failed to save file open error", error); @@ -731,15 +735,17 @@ int config_from_fd_with_metadata(const char *application, } - /* Collect meta data before actually parsing the file */ - error = collect_metadata(metaflags, - metadata, - config_file, - abs_name); - if(error) { - TRACE_ERROR_NUMBER("Failed to collect metadata", error); - fclose(config_file); - return error; + if (metadata) { + /* Collect meta data before actually parsing the file */ + error = collect_metadata(metaflags, + metadata, + config_file, + abs_name); + if(error) { + TRACE_ERROR_NUMBER("Failed to collect metadata", error); + fclose(config_file); + return error; + } } if (!(metaflags & INI_META_ACTION_NOPARSE)) { @@ -751,7 +757,7 @@ int config_from_fd_with_metadata(const char *application, error_level, error_list, metaflags, - *metadata); + metadata); } /* We opened the file we close it */ @@ -1529,7 +1535,7 @@ static unsigned long long get_ullong_config_value(struct collection_item *item, char *endptr; unsigned long long val = 0; - TRACE_FLOW_STRING("get_long_config_value", "Entry"); + TRACE_FLOW_STRING("get_ullong_config_value", "Entry"); /* Do we have the item ? */ if ((item == NULL) || @@ -1561,7 +1567,7 @@ static unsigned long long get_ullong_config_value(struct collection_item *item, return def; } - TRACE_FLOW_NUMBER("get_long_config_value returning", (long)val); + TRACE_FLOW_NUMBER("get_ullong_config_value returning", (long)val); return val; } diff --git a/common/ini/ini_config.h b/common/ini/ini_config.h index c0f82d0f1..a5fd4a932 100644 --- a/common/ini/ini_config.h +++ b/common/ini/ini_config.h @@ -264,6 +264,42 @@ */ /** + * @defgroup accesscheck Access control check flags + * + * @{ + */ + +/** + * @brief Validate access mode + * + * If this flag is specified the mode parameter + * will be matched against the permissions set on the file + * using the provided mask. + */ +#define INI_ACCESS_CHECK_MODE 0x00000001 + +/** + * @brief Validate uid + * + * Provided uid will be checked against uid + * of the file. + */ +#define INI_ACCESS_CHECK_UID 0x00000002 + +/** + * @brief Validate gid + * + * Provided gid will be checked against gid + * of the file. + */ +#define INI_ACCESS_CHECK_GID 0x00000004 + +/** + * @} + */ + + +/** * @} */ @@ -485,6 +521,7 @@ const char *parsing_error_str(int parsing_error); * * @return 0 - Success. * @return EINVAL - Invalid parameter. + * @return EMOMEM - No memory. * @return Any error returned by fopen(). * */ @@ -516,6 +553,7 @@ int config_from_file(const char *application, * detected during parsing. * * @return 0 - Success. + * @return EMOMEM - No memory. * @return EINVAL - Invalid parameter. * */ @@ -567,6 +605,7 @@ int config_from_fd(const char *application, * * @return 0 - Success. * @return EINVAL - Invalid parameter. + * @return EMOMEM - No memory. * @return Any error returned by fopen(). * * @@ -622,6 +661,7 @@ int config_from_file_with_metadata( * * @return 0 - Success. * @return EINVAL - Invalid parameter. + * @return EMOMEM - No memory. * */ int config_from_fd_with_metadata( @@ -660,6 +700,7 @@ int config_from_fd_with_metadata( * * @return 0 - Success. * @return EINVAL - Invalid parameter. + * @return EMOMEM - No memory. * @return Any error returned by fopen(). */ int config_for_app(const char *application, @@ -715,6 +756,7 @@ int config_for_app(const char *application, * * @return 0 - Success. * @return EINVAL - Invalid parameter. + * @return EMOMEM - No memory. * @return Any error returned by fopen(). */ int config_for_app_with_metadata( @@ -727,6 +769,76 @@ int config_for_app_with_metadata( uint32_t metaflags, struct collection_item **meta_default, struct collection_item **meta_appini); + + +/** + * + * @brief Function to check ownership and permissions + * + * The function allow caller to make decision + * if the configuration file is from a trusted source + * or not. + * + * The flags control how to perform check. + * See \ref accesscheck "Access control check flags" + * section for more information. + * + * @param[in] metadata Meta data object. + * Can't be NULL. + * @param[in] flags How and what to check. + * Must be nonzero. + * @param[in] uid UID to check. + * @param[in] gid GID to check. + * @param[in] mode Mode to check. + * Only permission bits + * are used. + * @param[in] mask Which mode bits to check. + * If 0 all permision bits + * are checked. + * + * @return 0 - Success. + * @return EINVAL - Invalid parameter. + * @return EACCESS - File properties do not match provided + * access parameters. + */ +int config_access_check(struct collection_item *metadata, + uint32_t flags, + uid_t uid, + gid_t gid, + mode_t mode, + mode_t mask); + + +/** + * @brief Function compares two meta data objects + * + * Function compares two meta data objects + * to determine whether the configuration + * has changed since last time the meta data + * was collected. + * The function checks three things about the + * file: + * - time stamp + * - device ID + * - i-node + * If any of those changes function will indicate + * that configuration changed. + * + * @param[in] metadata Recent meta data object. + * @param[in] saved_metadata Previously saved meta + * data object. + * @param[out] changed Will be set to a nonzero value + * if the configuration has changed. + * + * @return 0 - No internal error + * @return EINVAL - Invalid argument + * @return ENOENT - Expected value is missing + * @return ENOMEM - No memory + */ +int config_changed(struct collection_item *metadata, + struct collection_item *saved_metadata, + int *changed); + /** * @brief Function to free configuration object. * @@ -747,7 +859,7 @@ void free_ini_config_errors(struct collection_item *error_set); /** * @brief Function to free metadata. * - * @param[in] error_set Configuration meta data object. + * @param[in] metadata Configuration meta data object. * */ void free_ini_config_metadata(struct collection_item *metadata); diff --git a/common/ini/ini_config_ut.c b/common/ini/ini_config_ut.c index dde1c52cc..44d633fcb 100644 --- a/common/ini/ini_config_ut.c +++ b/common/ini/ini_config_ut.c @@ -136,8 +136,10 @@ int single_file(void) &metadata); if (error) { printf("Attempt to read configuration returned error: %d\n",error); - printf("\n\nMetadata\n"); - col_debug_collection(metadata, COL_TRAVERSE_DEFAULT); + if (metadata) { + printf("\n\nMeta data\n"); + col_debug_collection(metadata, COL_TRAVERSE_DEFAULT); + } free_ini_config_metadata(metadata); return error; } @@ -146,7 +148,7 @@ int single_file(void) printf("Expected no config but got some.\n"); col_debug_collection(ini_config, COL_TRAVERSE_DEFAULT); free_ini_config(ini_config); - printf("\n\nMetadata\n"); + printf("\n\nMeta data\n"); col_debug_collection(metadata, COL_TRAVERSE_DEFAULT); free_ini_config_metadata(metadata); return EINVAL; @@ -249,8 +251,10 @@ int single_fd(void) printf("\n\nErrors\n"); print_file_parsing_errors(stdout, error_set); free_ini_config_errors(error_set); - printf("\n\nMetadata\n"); - col_debug_collection(metadata, COL_TRAVERSE_DEFAULT); + if (metadata) { + printf("\n\nMeta data\n"); + col_debug_collection(metadata, COL_TRAVERSE_DEFAULT); + } free_ini_config_metadata(metadata); return error; } @@ -262,8 +266,6 @@ int single_fd(void) return EINVAL; } - /* FIXME get elements of the meta data and check them */ - COLOUT(printf("\n\nMeta data\n")); COLOUT(col_debug_collection(metadata, COL_TRAVERSE_DEFAULT)); @@ -1062,6 +1064,251 @@ int get_test(void) return EOK; } +/* This is an emulation of the case when daemon starts + * and one needs to parse the configuration file + * for the first time and load configuration + */ +int startup_test(void) +{ + int error; + struct collection_item *ini_config = NULL; + struct collection_item *error_set = NULL; + struct collection_item *metadata = NULL; + uint32_t flags; + + + /* At startup we can simplify our life by + * parsing configuration and then checking + * the permissions. It is less optimal from + * the performnce point of view but simple to implement. + * Since it is the start of the daemon we can + * hope that parsing the config file would + * usually not a be a wasted effort. + * If permission check fails that means we should + * exit. Ok so we just parse the INI file for nothing. + * Not a big deal, I would say... + */ + + COLOUT(printf("STARTUP TEST\n")); + + + flags = INI_META_SEC_ACCESS_FLAG | + INI_META_SEC_ERROR_FLAG; + + error = config_from_file_with_metadata("test", "./ini.conf", + &ini_config, INI_STOP_ON_NONE, + &error_set, + flags, + &metadata); + /* + * This is just for debugging. + * do not copy into your implementation + */ + if (metadata) { + COLOUT(printf("\n\nMeta data\n")); + COLOUT(col_debug_collection(metadata, COL_TRAVERSE_DEFAULT)); + } + + + if (error) { + printf("Attempt to read configuration returned error: %d\n",error); + + /* If you want to do any specific error checking, do it here. + * If you want to get the file error code from the + * metadata get it here. + */ + free_ini_config_metadata(metadata); + + /* Error reporting start ==> */ + if (error_set) { + printf("\n\nErrors\n"); + col_debug_collection(error_set, COL_TRAVERSE_DEFAULT); + } + /* <==== end */ + free_ini_config_errors(error_set); + return error; + } + + free_ini_config_errors(error_set); + + /* So we are here if we successfully got configuration. */ + /* You can check ownership and permissions here in one call */ + /* We will check just permissions here. */ + error = config_access_check(metadata, + INI_ACCESS_CHECK_MODE, /* add uid & gui flags + * in real case + */ + 0, /* <- will be real uid in real case */ + 0, /* <- will be real gid in real case */ + 0440, /* Checkling for r--r----- */ + 0); + /* This check is expected to fail since + * the actual permissions on the test file are: rw-rw-r-- + */ + + if (!error) { + printf("Expected error got success!\n"); + free_ini_config_metadata(metadata); + free_ini_config(ini_config); + return EACCES; + } + + error = config_access_check(metadata, + INI_ACCESS_CHECK_MODE, /* add uid & gui flags + * in real case + */ + 0, /* <- will be real uid in real case */ + 0, /* <- will be real gid in real case */ + 0664, /* Checkling for rw-rw-r-- */ + 0); + + if (error) { + printf("Access check failed %d!\n", error); + free_ini_config_metadata(metadata); + free_ini_config(ini_config); + return EACCES; + } + + + /* Use configuration */ + + COLOUT(printf("\n\nMeta data\n")); + COLOUT(col_debug_collection(metadata, COL_TRAVERSE_DEFAULT)); + free_ini_config_metadata(metadata); + + COLOUT(printf("\n\n----------------------\n")); + + COLOUT(printf("\n\nConfiguration\n")); + COLOUT(col_debug_collection(ini_config, COL_TRAVERSE_DEFAULT)); + free_ini_config(ini_config); + + return 0; +} + +int reload_test(void) +{ + + int error; + struct collection_item *ini_config = NULL; + struct collection_item *metadata = NULL; + struct collection_item *saved_metadata = NULL; + uint32_t flags; + int changed = 0; + int fd; + + COLOUT(printf("RELOAD TEST\n")); + + /* Assume we saved metadata at the beginning + * when we opened the file and read configuration + * for the first time. + * Here we have to emulate it. + */ + + flags = INI_META_SEC_ACCESS_FLAG | + INI_META_ACTION_NOPARSE; + + error = config_from_file_with_metadata("test", "./ini.conf", + &ini_config, + 0, + NULL, + flags, + &saved_metadata); + if (error) { + printf("Attempt to read configuration returned error: %d\n",error); + free_ini_config_metadata(saved_metadata); + return error; + } + + /*****************************************/ + + /* We are reloading so we probably doing it becuase + * we got a signal ot some kind of time out expired + * and it might be time for us to check if we need + * to reload. So assume it is time to check... + */ + + /* It is safer to open file first */ + fd = open("./ini.conf", O_RDONLY); + if (fd < 0) { + error = errno; + printf("Attempt to read configuration returned error: %d\n", error); + free_ini_config_metadata(saved_metadata); + return error; + } + + /* You migth be checking pretty frequently, once in 5 min for example + * but the config usually does not change for months + * so you do not want to do any extra processing every time you check. + */ + + /* Do permission check here right away on the file, or... */ + + + flags = INI_META_SEC_ACCESS_FLAG | + INI_META_ACTION_NOPARSE; + + error = config_from_fd_with_metadata("test", fd, + "./ini.conf", + &ini_config, + 0, + NULL, + flags, + &metadata); + if (error) { + printf("Attempt to read configuration returned error: %d\n",error); + if (metadata) { + printf("\n\nMeta data\n"); + col_debug_collection(metadata, COL_TRAVERSE_DEFAULT); + } + free_ini_config_metadata(metadata); + free_ini_config_metadata(saved_metadata); + close(fd); + return error; + } + + /* ...or you can do permission check here using the metadata + * as it is done in the startup test. + * For now we skip this part and move on. + */ + + error = config_changed(metadata, saved_metadata, &changed); + + if (error) { + printf("Internal error: %d\n",error); + printf("\n\nSaved Meta data\n"); + col_debug_collection(saved_metadata, COL_TRAVERSE_DEFAULT); + printf("\n\nMeta data\n"); + col_debug_collection(metadata, COL_TRAVERSE_DEFAULT); + free_ini_config_metadata(saved_metadata); + free_ini_config_metadata(metadata); + close(fd); + return error; + + } + + if (changed) { + + /* Read the config from the descriptor and use it. + * Discard old saved meta data and save + * the latest one for future use... + */ + + /* Here it would be an error if it is different */ + printf("Meta data is supposed to be same but different.\n"); + printf("\n\nSaved Meta data\n"); + col_debug_collection(saved_metadata, COL_TRAVERSE_DEFAULT); + printf("\n\nMeta data\n"); + col_debug_collection(metadata, COL_TRAVERSE_DEFAULT); + } + + free_ini_config_metadata(saved_metadata); + free_ini_config_metadata(metadata); + close(fd); + + return 0; +} + + int main(int argc, char *argv[]) { int error = EOK; @@ -1086,6 +1333,8 @@ int main(int argc, char *argv[]) (error = real_test(NULL)) || /* This should result in merged configuration */ (error = real_test("./ini.conf")) || + (error = startup_test()) || + (error = reload_test()) || (error = get_test())) { printf("Test failed! Error %d.\n", error); return -1; diff --git a/common/ini/ini_metadata.c b/common/ini/ini_metadata.c index a5d5109fc..3ee9fbaa4 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; + +} |