From 7e111b16b77d62cf70c7fd2abc743b27e8999dff Mon Sep 17 00:00:00 2001 From: BritishTeapot Date: Sun, 30 Mar 2025 19:06:57 +0200 Subject: [PATCH] Added permanent permissions Finally implemented the permanent permission tables using sqlite3. For now, performance wasn't a consideration. There are a lot of optimizations that could be made, like having prepared queries. The code remains fairly untested. --- Makefile | 8 +- src/main.c | 2 +- src/perm_permissions_table.c | 192 +++++++++++++++++++++++++++++++++++ src/perm_permissions_table.h | 38 +++++++ src/ui-socket.c | 35 +++---- 5 files changed, 253 insertions(+), 22 deletions(-) create mode 100644 src/perm_permissions_table.c create mode 100644 src/perm_permissions_table.h diff --git a/Makefile b/Makefile index f85ecfd..9436664 100644 --- a/Makefile +++ b/Makefile @@ -12,7 +12,7 @@ CXX := g++ # dependencies -PACKAGE_NAMES := fuse3 +PACKAGE_NAMES := fuse3 sqlite3 ifeq ($(TEST), 1) # PACKAGE_NAMES += check # TODO: use check? @@ -56,7 +56,7 @@ default: $(TARGETS) .PHONY: clean -$(BUILD_DIR)/icfs: $(BUILD_DIR)/main.o $(BUILD_DIR)/fuse_operations.o $(BUILD_DIR)/sourcefs.o $(BUILD_DIR)/ui-socket.o $(BUILD_DIR)/temp_permissions_table.o +$(BUILD_DIR)/icfs: $(BUILD_DIR)/main.o $(BUILD_DIR)/fuse_operations.o $(BUILD_DIR)/sourcefs.o $(BUILD_DIR)/ui-socket.o $(BUILD_DIR)/temp_permissions_table.o $(BUILD_DIR)/perm_permissions_table.o $(CC) $(CFLAGS) $^ $(LDFLAGS) -o $(BUILD_DIR)/icfs icfs_test: $(BUILD_DIR)/icfs @@ -80,5 +80,9 @@ $(BUILD_DIR)/ui-socket.o: $(SOURCES_DIR)/ui-socket.c $(SOURCES_DIR)/ui-socket.h $(BUILD_DIR)/temp_permissions_table.o: $(SOURCES_DIR)/temp_permissions_table.c $(SOURCES_DIR)/temp_permissions_table.h $(CC) $(CFLAGS) -c $< $(LDFLAGS) -o $@ +$(BUILD_DIR)/perm_permissions_table.o: $(SOURCES_DIR)/perm_permissions_table.c $(SOURCES_DIR)/perm_permissions_table.h + $(CC) $(CFLAGS) -c $< $(LDFLAGS) -o $@ + + clean: rm $(BUILD_DIR)/*.o $(BUILD_DIR)/icfs* diff --git a/src/main.c b/src/main.c index 8597c98..5a5f16f 100644 --- a/src/main.c +++ b/src/main.c @@ -38,7 +38,7 @@ int main(int argc, char *argv[]) { ret = init_ui_socket(); if (ret != 0) { - perror("init_ui_socket"); + fprintf(stderr, "Could not initalize ui-socket.\n"); exit(EXIT_FAILURE); } diff --git a/src/perm_permissions_table.c b/src/perm_permissions_table.c new file mode 100644 index 0000000..9343916 --- /dev/null +++ b/src/perm_permissions_table.c @@ -0,0 +1,192 @@ +#include "perm_permissions_table.h" +#include "process_info.h" +#include +#include +#include +#include +#include + +sqlite3 *perm_database = NULL; +const char *const table_name = "permissions"; +// one row corresponds to a permission to access one file for one executable +const int column_count = 2; +const char *const schema[] = {"executable", "filename"}; +const char *const types[] = {"TEXT", "TEXT"}; + +static int check_table_col_schema(void *notused, int argc, char **argv, + char **colname) { + (void)notused; + (void)colname; + if (argc < 3) { + fprintf(stderr, "Unexpected amount of arguments given to the callback.\n"); + return 1; + } + int i = atoi(argv[0]); + if (i >= column_count) { + fprintf(stderr, "Table contains more columns than expected.\n"); + return 1; + } + if (strcmp(schema[i], argv[1]) == 0 && strcmp(types[i], argv[2]) == 0) { + return 0; + } + fprintf(stderr, "Column %d does not conform to the schema.\n", i); + return 1; +} + +static int set_flag(void *flag, int argc, char **argv, char **colname) { + (void)argc; + (void)argv; + (void)colname; + *(int *)flag = 1; + return 0; +} + +int create_database_schema() { + fprintf(stderr, "Creating table 'permissions'.\n"); + const char *create_query = "CREATE TABLE permissions(executable TEXT NOT " + "NULL, filename TEXT NOT NULL);"; + char *err = NULL; + int ret = sqlite3_exec(perm_database, create_query, NULL, NULL, &err); + + if (ret != SQLITE_OK) { + fprintf(stderr, "sqlite3 error: %s\n", err); + sqlite3_free(err); + return 1; + } + + fprintf(stderr, "Database created successfully\n"); + return 0; +} + +/** + * Ensures that the database schema is correct. + * + * @return: 0 if the schema is correct, 1 if the schema could not be corrected. + */ +int ensure_database_schema() { + // Check for the table. + int result = sqlite3_table_column_metadata( + perm_database, NULL, table_name, NULL, NULL, NULL, NULL, NULL, NULL); + if (result == SQLITE_ERROR) { + fprintf(stderr, "Table '%s' does not exist.\n", table_name); + if (create_database_schema()) { + fprintf(stderr, "Table could not be created.\n"); + return 1; + } + return 0; + } else if (result != SQLITE_OK) { + fprintf(stderr, "Database metadata could not be retrieved.\n"); + return 1; + } + + const char *pragma = "PRAGMA table_info(permissions);"; + char *err = NULL; + int ret = + sqlite3_exec(perm_database, pragma, check_table_col_schema, NULL, &err); + + if (ret != SQLITE_OK) { + fprintf(stderr, "sqlite3 error: %s\n", err); + sqlite3_free(err); + return 1; + } + + fprintf(stderr, "Schema is correct.\n"); + return 0; +} + +/** + * Initializes the permanent permissions table. + * + * @param db_filename: The filename of the permissions sqlite3 database + * @return: 0 on success, -1 on failure + */ +int init_perm_permissions_table(const char *db_filename) { + if (sqlite3_open(db_filename, &perm_database)) { + perror("Can't open permanent permissions database:"); + return -1; + } + if (ensure_database_schema()) { + fprintf(stderr, "Database schema is not correct.\n"); + return -1; + } + return 0; +} + +/** + * Destroys the permanent permissions table. + */ +void destroy_perm_permissions_table() { sqlite3_close(perm_database); } + +/** + * Checks if the process has a permanent access to the file. + * + * @param filename: The file that the process is trying to access + * @pram pi: The process information + * @return: 0 if access is denied, 1 if access is allowed + */ +int check_perm_access(const char *filename, struct process_info pi) { + size_t query_len = + 56 + strlen(table_name) + strlen(filename) + strlen(pi.name); + const char *query = malloc(query_len); + size_t should_be_written = snprintf( + query, query_len, + "SELECT * FROM %s WHERE executable = \'%s\' AND filename = \'%s\';", + table_name, pi.name, filename); + // -1 for the \0 + if (should_be_written != query_len - 1) { + fprintf(stderr, + "Unexpected query size while permanent access rule check: " + "Expected %lu, but snprintf returned %lu. The query: %s\n", + query_len, should_be_written, query); + return 0; + } + + char *sqlite_error = NULL; + int flag = 0; + int ret = sqlite3_exec(perm_database, query, set_flag, &flag, &sqlite_error); + if (ret != SQLITE_OK) { + fprintf(stderr, "SQLite returned an error: %s\n", sqlite_error); + sqlite3_free(sqlite_error); + free(query); + return 0; + } + + free(query); + return flag; +} + +/** + * Gives permanent access to the process to the file. + * + * @param filename: The file that the process is trying to access + * @param pi: The process information + * @return: 0 on success, 1 on failure + */ +int give_perm_access(const char *filename, struct process_info pi) { + size_t query_len = + 30 + strlen(table_name) + strlen(filename) + strlen(pi.name); + const char *query = malloc(query_len); + size_t should_be_written = + snprintf(query, query_len, "INSERT INTO %s VALUES (\'%s\', \'%s\');", + table_name, pi.name, filename); + // -1 for the \0 + if (should_be_written != query_len - 1) { + fprintf(stderr, + "Unexpected query size while permanent access rule insertion: " + "Expected %lu, but snprintf returned %lu\n", + query_len, should_be_written); + return 1; + } + + char *sqlite_error = NULL; + int ret = sqlite3_exec(perm_database, query, NULL, NULL, &sqlite_error); + if (ret != SQLITE_OK) { + fprintf(stderr, "SQLite returned an error: %s\n", sqlite_error); + sqlite3_free(sqlite_error); + free(query); + return 1; + } + + free(query); + return 0; +} diff --git a/src/perm_permissions_table.h b/src/perm_permissions_table.h new file mode 100644 index 0000000..358ea8b --- /dev/null +++ b/src/perm_permissions_table.h @@ -0,0 +1,38 @@ + +#ifndef PERM_PERMISSION_TABLE_H +#define PERM_PERMISSION_TABLE_H + +#include "process_info.h" + +/** + * Initializes the permanent permissions table. + * + * @param db_filename: The filename of the permissions sqlite3 database + * @return: 0 on success, -1 on failure (e.g. ENOMEM) + */ +int init_perm_permissions_table(const char *db_filename); + +/** + * Destroys the permanent permissions table. + */ +void destroy_perm_permissions_table(); + +/** + * Checks if the process has a permanent access to the file. + * + * @param filename: The file that the process is trying to access + * @pram pi: The process information + * @return: 0 if access is denied, 1 if access is allowed + */ +int check_perm_access(const char *filename, struct process_info pi); + +/** + * Gives permanent access to the process to the file. + * + * @param filename: The file that the process is trying to access + * @param pi: The process information + * @return: 0 on success, -1 on failure + */ +int give_perm_access(const char *filename, struct process_info pi); + +#endif // #ifdef PERM_PERMISSION_TABLE_H diff --git a/src/ui-socket.c b/src/ui-socket.c index 4109e85..f9f6228 100644 --- a/src/ui-socket.c +++ b/src/ui-socket.c @@ -11,6 +11,7 @@ #include #define _GNU_SOURCE #include "cc.h" +#include "perm_permissions_table.h" #include "temp_permissions_table.h" #include "ui-socket.h" #include @@ -26,7 +27,16 @@ int init_ui_socket() { char line[256]; FILE *fp; - init_temp_permissions_table(); + if (init_temp_permissions_table()) { + fprintf(stderr, "Could not initialize temporary permissions table.\n"); + return 1; + } + + if (init_perm_permissions_table( + "/home/fedir/Developement/uni/ICFS/test/.pt.db")) { + fprintf(stderr, "Could not initialize permanent permissions table.\n"); + return 1; + } // Test if Zenity is installed (get version) fp = popen("zenity --version", "r"); @@ -41,7 +51,10 @@ int init_ui_socket() { return 0; } -void destroy_ui_socket() { destroy_temp_permissions_table(); } +void destroy_ui_socket() { + destroy_temp_permissions_table(); + destroy_perm_permissions_table(); +} /** * Asks the user if the process should be allowed to access the file using the @@ -53,7 +66,6 @@ void destroy_ui_socket() { destroy_temp_permissions_table(); } * for the runtime of the process */ int ask_access(const char *filename, struct process_info pi) { - FILE *fp; size_t command_len = 139 + sizeof(pid_t) * 8 + strlen(pi.name) + strlen(filename); @@ -86,6 +98,7 @@ int ask_access(const char *filename, struct process_info pi) { } int zenity_exit_code = WEXITSTATUS(pclose(fp)); + fprintf(stderr, "zenity returned %d\n", zenity_exit_code); // zenity returns 1 on "No" >:( if (zenity_exit_code == 0) { return 1; @@ -94,22 +107,6 @@ int ask_access(const char *filename, struct process_info pi) { return 0; } -/** - * Checks if the process has a permanent access to the file. - * - * @param filename: The file that the process is trying to access - * @pram pi: The process information - * @return: 0 if access is denied, 1 if access is allowed - */ -int check_perm_access(const char *filename, struct process_info pi) { - perror("Not implemented"); - return 0; -} -int give_perm_access(const char *filename, struct process_info pi) { - perror("Not implemented"); - return -1; -} - /** * Check access according to: * 1. temp permission table