summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--common/ini/ini_config.c38
-rw-r--r--common/ini/ini_config.h114
-rw-r--r--common/ini/ini_config_ut.c263
-rw-r--r--common/ini/ini_metadata.c307
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;
+
+}