summaryrefslogtreecommitdiffstats
path: root/common/ini/ini_metadata.c
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/ini/ini_metadata.c
parent693c44378b5a7b457b31f343730880dee8f271f3 (diff)
downloadsssd-bf7247298136660f512bd1a96f68be1487f425b6.tar.gz
sssd-bf7247298136660f512bd1a96f68be1487f425b6.tar.xz
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/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;
+
+}