summaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
authorDmitri Pal <dpal@redhat.com>2010-04-02 20:08:14 -0400
committerStephen Gallagher <sgallagh@redhat.com>2010-04-14 12:15:54 -0400
commitbf7247298136660f512bd1a96f68be1487f425b6 (patch)
treea5d6acc3bf8ce45d77fbddedfbaf7048335b02b9 /common
parent693c44378b5a7b457b31f343730880dee8f271f3 (diff)
downloadsssd-bf7247298136660f512bd1a96f68be1487f425b6.tar.gz
sssd-bf7247298136660f512bd1a96f68be1487f425b6.tar.bz2
sssd-bf7247298136660f512bd1a96f68be1487f425b6.zip
Acess control and config change checks
1) Fixed the issue that metadata was saved as numbers. Was supposed to be saved as strings. 2) Added two functions. One is to check permissions on the config file. Another to check if the file has changed and thus the cinfiguration needs to be reread. 3) Added unit test will sample code and comments how to use the functions. 4) Added doxygen description in the comments. 5) Fixed couple typos and ommisions here and there. [INI] Fixing crash detected on 64-bit system This patch corrects original code to be more on the safe side and check parameters before using. Instead of dereferencing metadata it is now passed as reference to the next level. It is not used there yet so no other new changes needed so far. [INI] Addressing review comments [INI] Addressing comments.
Diffstat (limited to 'common')
-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 66d2c03a..1c8e4aef 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 c0f82d0f..a5fd4a93 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 dde1c52c..44d633fc 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 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;
+
+}