diff --git a/Makefile b/Makefile index 8ffddeb..646a9e3 100644 --- a/Makefile +++ b/Makefile @@ -56,7 +56,7 @@ default: $(TARGETS) .PHONY: clean -icfs: $(BUILD_DIR)/main.o $(BUILD_DIR)/fuse_operations.o $(BUILD_DIR)/sourcefs.o $(BUILD_DIR)/ui-socket.o +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 $(CC) $(CFLAGS) $^ $(LDFLAGS) -o $(BUILD_DIR)/icfs icfs_test: $(BUILD_DIR)/main.o $(BUILD_DIR)/fuse_operations.o $(BUILD_DIR)/sourcefs.o $(BUILD_DIR)/ui-socket.o @@ -78,5 +78,8 @@ $(BUILD_DIR)/sourcefs.o: $(SOURCES_DIR)/sourcefs.c $(SOURCES_DIR)/sourcefs.h $(BUILD_DIR)/ui-socket.o: $(SOURCES_DIR)/ui-socket.c $(SOURCES_DIR)/ui-socket.h $(CC) $(CFLAGS) -c $< $(LDFLAGS) -o $@ +$(BUILD_DIR)/temp_permissions_table.o: $(SOURCES_DIR)/temp_permissions_table.c $(SOURCES_DIR)/temp_permissions_table.h + $(CC) $(CFLAGS) -c $< $(LDFLAGS) -o $@ + clean: rm $(BUILD_DIR)/*.o $(BUILD_DIR)/icfs* diff --git a/src/process_info.h b/src/process_info.h new file mode 100644 index 0000000..8e59c81 --- /dev/null +++ b/src/process_info.h @@ -0,0 +1,12 @@ + +#ifndef PROCESS_INFO_H +#define PROCESS_INFO_H + +#include +struct process_info { + pid_t PID; + const char *name; + uid_t UID; +}; + +#endif // PROCESS_INFO_H diff --git a/src/temp_permissions_table.c b/src/temp_permissions_table.c new file mode 100644 index 0000000..2701614 --- /dev/null +++ b/src/temp_permissions_table.c @@ -0,0 +1,178 @@ +/* + ICFS: Interactively Controlled File System + Copyright (C) 2024-2025 Fedir Kovalov + + This program can be distributed under the terms of the GNU GPLv2. + See the file LICENSE. +*/ + +#include "temp_permissions_table.h" +#include "cc.h" +#include "process_info.h" +#include +#include +#include + +struct temp_process_permissions { + // yes, this is a correct type for start time in jiffies (see + // proc_pid_stat(5)) + unsigned long long creation_time; + vec(char *) allowed_files; +}; + +map(pid_t, struct temp_process_permissions) temp_permissions_table; +pthread_mutex_t temp_permissions_table_lock; + +/** + * Function to get the process creation time (in jiffies) from the proc + * filesystem + * + * @param pid: The process ID of the process to get the creation time of + * @return: The process creation time in jiffies, or 0 on error + * @note: although nothing in the documentation says that the creation time is + * never really equal to 0, it exceptionally unlikely. + */ +unsigned long long get_process_creation_time(pid_t pid) { + char path[32]; + FILE *fp; + unsigned long long creation_time = 0; + + // Construct the path to the process's status file + snprintf(path, sizeof(path), "/proc/%d/stat", pid); + + // Open the status file + fp = fopen(path, "r"); + if (fp == NULL) { + perror("fopen"); + return 0; + } + + // Read the creation time (the 22nd field in the stat file) + for (int i = 1; i < 22; i++) { + if (fscanf(fp, "%*s") != 1) { + fprintf(stderr, "Error reading process stat file\n"); + fclose(fp); + return 0; + } + } + if (fscanf(fp, "%llu", &creation_time) != 1) { + fprintf(stderr, "Error reading creation time\n"); + fclose(fp); + return 0; + } + + // Close the file + fclose(fp); + + return creation_time; +} + +/** + * Initializes the temporary permissions table. + * + * @return: 0 on success, -1 on failure (e.g. ENOMEM) + */ +int init_temp_permissions_table() { + pthread_mutex_init(&temp_permissions_table_lock, PTHREAD_MUTEX_DEFAULT); + init(&temp_permissions_table); +} + +/** + * Destroys the temporary permissions table. + * + * @note: the table is guranteed to be destroyed if it is already initialized + */ +void destroy_temp_permissions_table() { + // free the memory allocated for the table + for_each(&temp_permissions_table, entry) { + for_each(&entry->allowed_files, allowed_file) { free(*allowed_file); } + cleanup(&entry->allowed_files); + } + cleanup(&temp_permissions_table); + pthread_mutex_destroy(&temp_permissions_table_lock); +} + +/** + * Checks if the process has a temporary 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_temp_access(const char *filename, struct process_info pi) { + // TODO: more efficient locking + pthread_mutex_lock(&temp_permissions_table_lock); + struct temp_process_permissions *permission_entry = + get(&temp_permissions_table, pi.PID); + if (permission_entry != NULL) { + unsigned long long process_creation_time = + get_process_creation_time(pi.PID); + if (process_creation_time == 0) { + perror("Could not retrieve process creation time"); + pthread_mutex_unlock(&temp_permissions_table_lock); + return 0; + } + + if (process_creation_time == permission_entry->creation_time) { + // the process is the same as the one that was granted temporary access + // to the file + for_each(&permission_entry->allowed_files, allowed_file) { + if (strncmp(*allowed_file, filename, strlen(filename)) == 0) { + pthread_mutex_unlock(&temp_permissions_table_lock); + return 1; + } + } + } + } + pthread_mutex_unlock(&temp_permissions_table_lock); + return 0; +} + +/** + * Gives temporary 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 (e.g. ENOMEM) + */ +int give_temp_access(const char *filename, struct process_info pi) { + pthread_mutex_lock(&temp_permissions_table_lock); + struct temp_process_permissions *permission_entry = + get(&temp_permissions_table, pi.PID); + + if (permission_entry != NULL) { + + unsigned long long process_creation_time = + get_process_creation_time(pi.PID); + if (process_creation_time == 0) { + perror("Could not retrieve process creation time"); + pthread_mutex_unlock(&temp_permissions_table_lock); + return -1; + } + + if (process_creation_time == permission_entry->creation_time) { + // the process is the same as the one that was granted temporary access + // to the file + push(&permission_entry->allowed_files, strdup(filename)); + pthread_mutex_unlock(&temp_permissions_table_lock); + return 0; + } + // we have an entry for the process, but the process is different + // delete the entry and create a new one + erase(&temp_permissions_table, pi.PID); + permission_entry = NULL; + } + + // no entry is present + // construct the entry + struct temp_process_permissions new_permission_entry; + + new_permission_entry.creation_time = get_process_creation_time(pi.PID); + init(&new_permission_entry.allowed_files); + push(&new_permission_entry.allowed_files, strdup(filename)); + + insert(&temp_permissions_table, pi.PID, new_permission_entry); + + pthread_mutex_unlock(&temp_permissions_table_lock); + return 0; +} diff --git a/src/temp_permissions_table.h b/src/temp_permissions_table.h new file mode 100644 index 0000000..32773bd --- /dev/null +++ b/src/temp_permissions_table.h @@ -0,0 +1,39 @@ + +#ifndef TEMP_PERMISSIONS_TABLE_H +#define TEMP_PERMISSIONS_TABLE_H + +#include "process_info.h" + +/** + * Initializes the temporary permissions table. + * + * @return: 0 on success, -1 on failure (e.g. ENOMEM) + */ +int init_temp_permissions_table(); + +/** + * Destroys the temporary permissions table. + * + * @note: the table is guranteed to be destroyed if it is already initialized + */ +void destroy_temp_permissions_table(); + +/** + * Checks if the process has a temporary access to the file. + * + * @param filename: The file that the process is trying to access + * @param pi: The process information + * @return: 0 if access is denied, 1 if access is allowed + */ +int check_temp_access(const char *filename, struct process_info pi); + +/** + * Gives temporary 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 (e.g. ENOMEM) + */ +int give_temp_access(const char *filename, struct process_info pi); + +#endif // !TEMP_PERMISSIONS_TABLE_H diff --git a/src/temp_premissions_table.h b/src/temp_premissions_table.h new file mode 100644 index 0000000..e69de29 diff --git a/src/ui-socket.c b/src/ui-socket.c index 7f676a0..4109e85 100644 --- a/src/ui-socket.c +++ b/src/ui-socket.c @@ -11,6 +11,7 @@ #include #define _GNU_SOURCE #include "cc.h" +#include "temp_permissions_table.h" #include "ui-socket.h" #include #include @@ -21,72 +22,18 @@ #include #include -/** - * Function to get the process creation time (in jiffies) from the proc - * filesystem - * - * @param pid: The process ID of the process to get the creation time of - * @return: The process creation time in jiffies, or 0 on error - * @note: although nothing in the documentation says that the creation time is - * never really equal to 0, it exceptionally unlikely. - */ -unsigned long long get_process_creation_time(pid_t pid) { - char path[32]; - FILE *fp; - unsigned long long creation_time = 0; - - // Construct the path to the process's status file - snprintf(path, sizeof(path), "/proc/%d/stat", pid); - - // Open the status file - fp = fopen(path, "r"); - if (fp == NULL) { - perror("fopen"); - return 0; - } - - // Read the creation time (the 22nd field in the stat file) - for (int i = 1; i < 22; i++) { - if (fscanf(fp, "%*s") != 1) { - fprintf(stderr, "Error reading process stat file\n"); - fclose(fp); - return 0; - } - } - if (fscanf(fp, "%llu", &creation_time) != 1) { - fprintf(stderr, "Error reading creation time\n"); - fclose(fp); - return 0; - } - - // Close the file - fclose(fp); - - return creation_time; -} - -struct temp_process_permissions { - // yes, this is a correct type for start time in jiffies (see - // proc_pid_stat(5)) - unsigned long long creation_time; - vec(char *) allowed_files; -}; - -map(pid_t, struct temp_process_permissions) temp_permissions_table; -pthread_mutex_t temp_permissions_table_lock; - int init_ui_socket() { char line[256]; FILE *fp; + init_temp_permissions_table(); + // Test if Zenity is installed (get version) fp = popen("zenity --version", "r"); if (fp == NULL) { - perror("Pipe returned a error"); + perror("Pipe returned an error"); return 1; } - pthread_mutex_init(&temp_permissions_table_lock, PTHREAD_MUTEX_DEFAULT); - init(&temp_permissions_table); while (fgets(line, sizeof(line), fp)) printf("%s", line); @@ -94,15 +41,7 @@ int init_ui_socket() { return 0; } -void destroy_ui_socket() { - // free the memory allocated for the table - for_each(&temp_permissions_table, entry) { - for_each(&entry->allowed_files, allowed_file) { free(*allowed_file); } - cleanup(&entry->allowed_files); - } - cleanup(&temp_permissions_table); - pthread_mutex_destroy(&temp_permissions_table_lock); -} +void destroy_ui_socket() { destroy_temp_permissions_table(); } /** * Asks the user if the process should be allowed to access the file using the @@ -155,42 +94,6 @@ int ask_access(const char *filename, struct process_info pi) { return 0; } -/** - * Checks if the process has a temporary 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_temp_access(const char *filename, struct process_info pi) { - // TODO: more efficient locking - pthread_mutex_lock(&temp_permissions_table_lock); - struct temp_process_permissions *permission_entry = - get(&temp_permissions_table, pi.PID); - if (permission_entry != NULL) { - unsigned long long process_creation_time = - get_process_creation_time(pi.PID); - if (process_creation_time == 0) { - perror("Could not retrieve process creation time"); - pthread_mutex_unlock(&temp_permissions_table_lock); - return 0; - } - - if (process_creation_time == permission_entry->creation_time) { - // the process is the same as the one that was granted temporary access - // to the file - for_each(&permission_entry->allowed_files, allowed_file) { - if (strncmp(*allowed_file, filename, strlen(filename)) == 0) { - pthread_mutex_unlock(&temp_permissions_table_lock); - return 1; - } - } - } - } - pthread_mutex_unlock(&temp_permissions_table_lock); - return 0; -} - /** * Checks if the process has a permanent access to the file. * @@ -202,49 +105,6 @@ int check_perm_access(const char *filename, struct process_info pi) { perror("Not implemented"); return 0; } - -int give_temp_access(const char *filename, struct process_info pi) { - pthread_mutex_lock(&temp_permissions_table_lock); - struct temp_process_permissions *permission_entry = - get(&temp_permissions_table, pi.PID); - - if (permission_entry != NULL) { - - unsigned long long process_creation_time = - get_process_creation_time(pi.PID); - if (process_creation_time == 0) { - perror("Could not retrieve process creation time"); - pthread_mutex_unlock(&temp_permissions_table_lock); - return -1; - } - - if (process_creation_time == permission_entry->creation_time) { - // the process is the same as the one that was granted temporary access - // to the file - push(&permission_entry->allowed_files, strdup(filename)); - pthread_mutex_unlock(&temp_permissions_table_lock); - return 0; - } - // we have an entry for the process, but the process is different - // delete the entry and create a new one - erase(&temp_permissions_table, pi.PID); - permission_entry = NULL; - } - - // no entry is present - // construct the entry - struct temp_process_permissions new_permission_entry; - - new_permission_entry.creation_time = get_process_creation_time(pi.PID); - init(&new_permission_entry.allowed_files); - push(&new_permission_entry.allowed_files, strdup(filename)); - - insert(&temp_permissions_table, pi.PID, new_permission_entry); - - pthread_mutex_unlock(&temp_permissions_table_lock); - return 0; -} - int give_perm_access(const char *filename, struct process_info pi) { perror("Not implemented"); return -1; diff --git a/src/ui-socket.h b/src/ui-socket.h index bc51e2a..14b8ddd 100644 --- a/src/ui-socket.h +++ b/src/ui-socket.h @@ -13,18 +13,31 @@ #ifndef UI_SOCKET_H #define UI_SOCKET_H +#include "process_info.h" #include -struct process_info { - pid_t PID; - const char *name; - uid_t UID; -}; +/** + * Initialize the GUI communication. + * + * @return: 0 on success, -1 on faliure. + */ +int init_ui_socket(void); -int init_ui_socket(); - -void destroy_ui_socket(); +/** + * Close the GUI communication. + */ +void destroy_ui_socket(void); +/** + * Check access according to: + * 1. temporary permission table + * 2. permanent permission table + * 3. user descision + * + * @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 interactive_access(const char *filename, struct process_info pi); #endif // !UI_SOCKET_H