summaryrefslogtreecommitdiffstats
path: root/common/ini/ini_metadata.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/ini/ini_metadata.c')
-rw-r--r--common/ini/ini_metadata.c307
1 files changed, 293 insertions, 14 deletions
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;
+
+}