Compare commits
14 Commits
22cb958b4f
...
main
Author | SHA1 | Date | |
---|---|---|---|
79e9f2fb9a
|
|||
91621605b1
|
|||
ea2e41693c
|
|||
4909a35a6a
|
|||
eec782057c
|
|||
29ce8f6cff
|
|||
cbe2bf81eb
|
|||
0a6faab7d7
|
|||
01e72e4aac
|
|||
5700238509
|
|||
b3e71d13aa
|
|||
012fa05e8f
|
|||
2ebc450132
|
|||
2f4f1a0a56
|
6
Makefile
6
Makefile
@@ -70,10 +70,10 @@ default: $(TARGETS)
|
|||||||
.PHONY: clean icfs_test clean-icfs clean-icfs_dialogue install uninstall
|
.PHONY: clean icfs_test clean-icfs clean-icfs_dialogue install uninstall
|
||||||
|
|
||||||
$(BUILD_DIR):
|
$(BUILD_DIR):
|
||||||
if [[ ! -d "FILE" ]]; then mkdir $(BUILD_DIR) fi
|
if [[ ! -d "$(BUILD_DIR)" ]]; then mkdir $(BUILD_DIR); fi
|
||||||
|
|
||||||
$(BUILD_DIR)/icfs_dialogue:
|
$(BUILD_DIR)/icfs_dialogue:
|
||||||
make -C $(SOURCES_DIR)/gui TEST=$(TEST) DEBUG=$(shell realpath $(DEBUG)) SOURCES_DIR=$(shell realpath $(SOURCES_DIR)/gui) BUILD_DIR=$(shell realpath $(BUILD_DIR)) TESTS_DIR=$(shell realpath $(TESTS_DIR)) $(BUILD_DIR)
|
make -C $(SOURCES_DIR)/gui TEST=$(TEST) DEBUG=$(DEBUG) SOURCES_DIR=$(shell realpath $(SOURCES_DIR)/gui) BUILD_DIR=$(shell realpath $(BUILD_DIR)) TESTS_DIR=$(shell realpath $(TESTS_DIR))
|
||||||
|
|
||||||
$(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 $(BUILD_DIR)/proc_operations.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 $(BUILD_DIR)/proc_operations.o
|
||||||
$(CC) $(CFLAGS) $^ $(LDFLAGS) -o $(BUILD_DIR)/icfs
|
$(CC) $(CFLAGS) $^ $(LDFLAGS) -o $(BUILD_DIR)/icfs
|
||||||
@@ -126,7 +126,7 @@ install: $(BUILD_DIR)/icfs $(BUILD_DIR)/icfs_dialogue
|
|||||||
@printf "\t3. Set the setuid bit of icfs executable.\n"
|
@printf "\t3. Set the setuid bit of icfs executable.\n"
|
||||||
sudo cp $(BUILD_DIR)/icfs /usr/bin/icfs && sudo cp $(BUILD_DIR)/icfs_dialogue /usr/bin/icfs_dialogue
|
sudo cp $(BUILD_DIR)/icfs /usr/bin/icfs && sudo cp $(BUILD_DIR)/icfs_dialogue /usr/bin/icfs_dialogue
|
||||||
id -u icfs &>/dev/null || sudo useradd --system --user-group icfs
|
id -u icfs &>/dev/null || sudo useradd --system --user-group icfs
|
||||||
sudo chown icfs: /usr/bin/icfs && sudo chmod 4777 /usr/bin/icfs
|
sudo chown icfs: /usr/bin/icfs && sudo chmod 4755 /usr/bin/icfs && sudo chmod 755 /usr/bin/icfs_dialogue
|
||||||
@read -p "Create /etc/icfs directory for permission databases [y/N]: " permd; if [[ $$permd == "y" ]]; then echo "sudo mkdir /etc/icfs && sudo chown :icfs /etc/icfs && sudo chmod g+rw,o= /etc/icfs;"; sudo mkdir /etc/icfs && sudo chown icfs:icfs /etc/icfs && sudo chmod g+rw,o= /etc/icfs; fi
|
@read -p "Create /etc/icfs directory for permission databases [y/N]: " permd; if [[ $$permd == "y" ]]; then echo "sudo mkdir /etc/icfs && sudo chown :icfs /etc/icfs && sudo chmod g+rw,o= /etc/icfs;"; sudo mkdir /etc/icfs && sudo chown icfs:icfs /etc/icfs && sudo chmod g+rw,o= /etc/icfs; fi
|
||||||
|
|
||||||
uninstall:
|
uninstall:
|
||||||
|
40
README.md
40
README.md
@@ -1,5 +1,9 @@
|
|||||||
|
|
||||||
# ICFS -- Interactively Controlled File System
|
# ICFS -- Interactively Controlled File System
|
||||||
|
|
||||||
|
> [!IMPORTANT]
|
||||||
|
> If you need the version that correponds to the thesis attachment, go [here](https://git.umbrasolis.de/fedir/ICFS/src/commit/2f4f1a0a569704b770f50b3e7cf39c09b9b8381a). This version contains corrections of errors that the opponent brought to my attention.
|
||||||
|
|
||||||
## Motivation
|
## Motivation
|
||||||
|
|
||||||
Traditional access control mechanisms in operating systems allow the same level of access to all processes running on behalf of the same user. This typically enables malicious processes to read and/or modify all data accessible to the user running a vulnerable application. It can be dealt using various mandatory access control mechanisms, but these are often complicated to configure and are rarely used in common user oriented scenarios. This thesis focuses on design and implementation of a file system layer which delegates the decision to allow or deny access to a file system object by a specific process to the user.
|
Traditional access control mechanisms in operating systems allow the same level of access to all processes running on behalf of the same user. This typically enables malicious processes to read and/or modify all data accessible to the user running a vulnerable application. It can be dealt using various mandatory access control mechanisms, but these are often complicated to configure and are rarely used in common user oriented scenarios. This thesis focuses on design and implementation of a file system layer which delegates the decision to allow or deny access to a file system object by a specific process to the user.
|
||||||
@@ -15,6 +19,10 @@ Traditional access control mechanisms in operating systems allow the same level
|
|||||||
- Install dependencies
|
- Install dependencies
|
||||||
- libfuse3
|
- libfuse3
|
||||||
- Debian: `sudo apt install fuse3 libfuse3-dev`
|
- Debian: `sudo apt install fuse3 libfuse3-dev`
|
||||||
|
- SQLite3
|
||||||
|
- Debian: `sudo apt install libsqlite3-dev`
|
||||||
|
- GTK4, libadwaita
|
||||||
|
- Debian: `sudo apt install libgtk-4-dev libadwaita-1-dev`
|
||||||
- Build tools
|
- Build tools
|
||||||
- Debian: `sudo apt install gcc make pkg-config`
|
- Debian: `sudo apt install gcc make pkg-config`
|
||||||
- Build using `make`:
|
- Build using `make`:
|
||||||
@@ -32,7 +40,9 @@ Traditional access control mechanisms in operating systems allow the same level
|
|||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
```
|
```
|
||||||
icfs <FUSE arguments> [target directory] [path to permanent permission database]
|
Usage: icfs <FUSE arguments> [target directory] [path to the permanent permissions database] <ICFS arguments>
|
||||||
|
--no-grant-on-create - do not give any access permissions on file creation(incompatible with --perm-on-create)
|
||||||
|
--perm-on-create - automatically give permanent access permission to files a process creates (incompatible with --no-grant-on-create)
|
||||||
```
|
```
|
||||||
|
|
||||||
The filesystem will be mounted over the target directory, and ask user permission every time a file in that directory is opened. We highly recommend adding `-o default_permissions` to increase performance and add an additional security layer. If you have installed icfs along with `/etc/icfs` folder, you can create your permanent permission databases in this folder (you might want to do this, if your home folder does not have the "execute" permission for other users).
|
The filesystem will be mounted over the target directory, and ask user permission every time a file in that directory is opened. We highly recommend adding `-o default_permissions` to increase performance and add an additional security layer. If you have installed icfs along with `/etc/icfs` folder, you can create your permanent permission databases in this folder (you might want to do this, if your home folder does not have the "execute" permission for other users).
|
||||||
@@ -47,6 +57,30 @@ env PATH="$(realpath ./build):$PATH" build/icfs <FUSE arguments> [target directo
|
|||||||
|
|
||||||
The `env PATH="$(realpath ./build):$PATH"` adds the access dialogue program to PATH, allowing ICFS to call it seamlessly.
|
The `env PATH="$(realpath ./build):$PATH"` adds the access dialogue program to PATH, allowing ICFS to call it seamlessly.
|
||||||
|
|
||||||
|
#### Running tests
|
||||||
|
|
||||||
|
ICFS includes a testing script in the `test` directory.
|
||||||
|
|
||||||
|
You can run it **from `test` directory** by running:
|
||||||
|
|
||||||
|
```
|
||||||
|
./test.bash
|
||||||
|
```
|
||||||
|
|
||||||
|
All testing artifacts will be available in the appropriate folders after run. To test setuid capabilities too (**from `test` directory!!!**):
|
||||||
|
|
||||||
|
```
|
||||||
|
./test.bash --setuid
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also test performance by adding `--performance` (**from `test` directory!!!**):
|
||||||
|
|
||||||
|
```
|
||||||
|
./test.bash --performance
|
||||||
|
```
|
||||||
|
|
||||||
|
***Important:*** **flags cannot be combined together (e.g. you can't add `--performance` and `--setuid`)**
|
||||||
|
|
||||||
## Docs
|
## Docs
|
||||||
|
|
||||||
- [Initial idea and motivation](./docs/bc-thesis-idea.md)
|
- [Initial idea and motivation](./docs/bc-thesis-idea.md)
|
||||||
@@ -55,6 +89,6 @@ The `env PATH="$(realpath ./build):$PATH"` adds the access dialogue program to P
|
|||||||
|
|
||||||
## Credit
|
## Credit
|
||||||
|
|
||||||
_Student:_ Fedir Kovalov
|
*Student:* Fedir Kovalov
|
||||||
|
|
||||||
_Supervisor:_ RNDr. Jaroslav Janáček, PhD.
|
*Supervisor:* RNDr. Jaroslav Janáček, PhD.
|
||||||
|
@@ -48,6 +48,8 @@
|
|||||||
|
|
||||||
int auto_create_perm = GRANT_TEMP;
|
int auto_create_perm = GRANT_TEMP;
|
||||||
|
|
||||||
|
#define HAVE_UTIMENSAT
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Sets the default permission granted by file creation.
|
* Sets the default permission granted by file creation.
|
||||||
*
|
*
|
||||||
@@ -110,7 +112,11 @@ static int xmp_access(const char *path, int mask) {
|
|||||||
|
|
||||||
// if mask is F_OK, then we don't need to check the permissions
|
// if mask is F_OK, then we don't need to check the permissions
|
||||||
// (is that possible?)
|
// (is that possible?)
|
||||||
|
//
|
||||||
|
// EDIT: now lie to the program by not telling it whether it can actually
|
||||||
|
// access the file.
|
||||||
|
|
||||||
|
/*
|
||||||
if (mask != F_OK) {
|
if (mask != F_OK) {
|
||||||
struct process_info proc_info;
|
struct process_info proc_info;
|
||||||
struct fuse_context *context = fuse_get_context();
|
struct fuse_context *context = fuse_get_context();
|
||||||
@@ -127,6 +133,7 @@ static int xmp_access(const char *path, int mask) {
|
|||||||
|
|
||||||
free((void *)proc_info.name);
|
free((void *)proc_info.name);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
res = source_access(path, mask);
|
res = source_access(path, mask);
|
||||||
|
|
||||||
@@ -451,12 +458,21 @@ static int xmp_truncate(const char *path, off_t size,
|
|||||||
static int xmp_utimens(const char *path, const struct timespec ts[2],
|
static int xmp_utimens(const char *path, const struct timespec ts[2],
|
||||||
struct fuse_file_info *fi) {
|
struct fuse_file_info *fi) {
|
||||||
int res;
|
int res;
|
||||||
|
struct process_info pi;
|
||||||
|
struct fuse_context *fc = fuse_get_context();
|
||||||
|
|
||||||
|
pi = get_process_info(fc->pid);
|
||||||
|
|
||||||
|
if (!interactive_access(path, pi, 0)) {
|
||||||
|
free(pi.name);
|
||||||
|
return -EACCES;
|
||||||
|
}
|
||||||
|
|
||||||
/* don't use utime/utimes since they follow symlinks */
|
/* don't use utime/utimes since they follow symlinks */
|
||||||
if (fi)
|
if (fi)
|
||||||
res = futimens(fi->fh, ts);
|
res = futimens(fi->fh, ts);
|
||||||
else
|
else
|
||||||
res = utimensat(0, path, ts, AT_SYMLINK_NOFOLLOW);
|
res = source_utimens(path, ts, AT_SYMLINK_NOFOLLOW);
|
||||||
if (res == -1)
|
if (res == -1)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
@@ -756,7 +772,7 @@ static const struct fuse_operations xmp_oper = {
|
|||||||
.chown = xmp_chown,
|
.chown = xmp_chown,
|
||||||
.truncate = xmp_truncate,
|
.truncate = xmp_truncate,
|
||||||
#ifdef HAVE_UTIMENSAT
|
#ifdef HAVE_UTIMENSAT
|
||||||
// .utimens = xmp_utimens,
|
.utimens = xmp_utimens,
|
||||||
#endif
|
#endif
|
||||||
.create = xmp_create,
|
.create = xmp_create,
|
||||||
.open = xmp_open,
|
.open = xmp_open,
|
||||||
|
@@ -119,7 +119,7 @@ static int on_command_line(GApplication *app, GApplicationCommandLine *cmdline,
|
|||||||
argv = g_application_command_line_get_arguments(cmdline, &argc);
|
argv = g_application_command_line_get_arguments(cmdline, &argc);
|
||||||
|
|
||||||
// Handle your arguments here
|
// Handle your arguments here
|
||||||
if (argc >= 4) {
|
if (argc >= 5) {
|
||||||
fprintf(stderr, "%s\n", argv[1]);
|
fprintf(stderr, "%s\n", argv[1]);
|
||||||
g_object_set_data_full(G_OBJECT(app), "accessing_pid", g_strdup(argv[1]),
|
g_object_set_data_full(G_OBJECT(app), "accessing_pid", g_strdup(argv[1]),
|
||||||
g_free);
|
g_free);
|
||||||
@@ -142,6 +142,13 @@ int main(int argc, char **argv) {
|
|||||||
|
|
||||||
if (argc == 2 && strcmp(argv[1], "--version") == 0) {
|
if (argc == 2 && strcmp(argv[1], "--version") == 0) {
|
||||||
fprintf(stdout, "icfs_dialogue 1.0.0");
|
fprintf(stdout, "icfs_dialogue 1.0.0");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc != 5) {
|
||||||
|
fprintf(stdout, "Usage: icfs_dialogue [accessing pid] [accessing name] "
|
||||||
|
"[root folder] [access dir]");
|
||||||
|
return 255;
|
||||||
}
|
}
|
||||||
|
|
||||||
// disable accessibility features to prevent attacks
|
// disable accessibility features to prevent attacks
|
||||||
|
18
src/main.c
18
src/main.c
@@ -31,27 +31,27 @@ int main(int argc, char *argv[]) {
|
|||||||
if (argc < 3) {
|
if (argc < 3) {
|
||||||
fprintf(stderr, "Usage: icfs <FUSE arguments> [target directory] [path to "
|
fprintf(stderr, "Usage: icfs <FUSE arguments> [target directory] [path to "
|
||||||
"the permanent permissions database] <ICFS "
|
"the permanent permissions database] <ICFS "
|
||||||
"arguments>\n\t--no-perm-on-create - do not give any "
|
"arguments>\n\t--no-grant-on-create - do not give any "
|
||||||
"access permissions on file creation"
|
"access permissions on file creation"
|
||||||
"(incompatible with --temp-on-create)\n\t--perm-on-create "
|
"(incompatible with --perm-on-create)\n\t--perm-on-create "
|
||||||
"- automatically give permanent access permission to files "
|
"- automatically give permanent access permission to files "
|
||||||
"a process creates "
|
"a process creates "
|
||||||
"(incompatible with --no-perm-on-create)\n");
|
"(incompatible with --no-grant-on-create)\n");
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((0 == strcmp(argv[argc - 1], "--no-perm-on-create") &&
|
if ((0 == strcmp(argv[argc - 1], "--no-grant-on-create") &&
|
||||||
0 == strcmp(argv[argc - 2], "--temp-on-create")) ||
|
0 == strcmp(argv[argc - 2], "--temp-on-create")) ||
|
||||||
(0 == strcmp(argv[argc - 2], "--no-perm-on-create") &&
|
(0 == strcmp(argv[argc - 2], "--no-grant-on-create") &&
|
||||||
0 == strcmp(argv[argc - 1], "--temp-on-create"))) {
|
0 == strcmp(argv[argc - 1], "--temp-on-create"))) {
|
||||||
fprintf(stderr, "Usage: icfs <FUSE arguments> [target directory] [path to "
|
fprintf(stderr, "Usage: icfs <FUSE arguments> [target directory] [path to "
|
||||||
"the permanent permissions database] <ICFS "
|
"the permanent permissions database] <ICFS "
|
||||||
"arguments>\n\t--no-perm-on-create - do not give any "
|
"arguments>\n\t--no-grant-on-create - do not give any "
|
||||||
"access permissions on file creation"
|
"access permissions on file creation"
|
||||||
"(incompatible with --temp-on-create)\n\t--perm-on-create "
|
"(incompatible with --perm-on-create)\n\t--perm-on-create "
|
||||||
"- automatically give permanent access permission to files "
|
"- automatically give permanent access permission to files "
|
||||||
"a process creates "
|
"a process creates "
|
||||||
"(incompatible with --no-perm-on-create)\n");
|
"(incompatible with --no-grant-on-create)\n");
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,7 +59,7 @@ int main(int argc, char *argv[]) {
|
|||||||
// permissions than it's caller reqested
|
// permissions than it's caller reqested
|
||||||
umask(0);
|
umask(0);
|
||||||
|
|
||||||
if (0 == strcmp(argv[argc - 1], "--no-perm-on-create")) {
|
if (0 == strcmp(argv[argc - 1], "--no-grant-on-create")) {
|
||||||
set_auto_create_perm(0);
|
set_auto_create_perm(0);
|
||||||
argc--;
|
argc--;
|
||||||
}
|
}
|
||||||
|
@@ -22,8 +22,8 @@
|
|||||||
* Stores the root directory information to enable relative path operations.
|
* Stores the root directory information to enable relative path operations.
|
||||||
*/
|
*/
|
||||||
static struct source_files_handle {
|
static struct source_files_handle {
|
||||||
const char *mountpoint; // Absolute path to the mounted filesystem root
|
char *mountpoint; // Absolute path to the mounted filesystem root
|
||||||
int root_fd; // File descriptor for the root directory (O_PATH)
|
int root_fd; // File descriptor for the root directory (O_PATH)
|
||||||
} handle;
|
} handle;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -128,8 +128,7 @@ int source_mkdir(const char *filename, mode_t mode) {
|
|||||||
/**
|
/**
|
||||||
* @brief Remove a file from the filesystem
|
* @brief Remove a file from the filesystem
|
||||||
*
|
*
|
||||||
* Uses unlinkat() with AT_REMOVEDIR flag to safely remove files relative
|
* Uses unlinkat() to safely remove files relative to the root directory.
|
||||||
* to the root directory.
|
|
||||||
*/
|
*/
|
||||||
int source_unlink(const char *filename) {
|
int source_unlink(const char *filename) {
|
||||||
const char *relative_filename = source_filename_translate(filename);
|
const char *relative_filename = source_filename_translate(filename);
|
||||||
@@ -277,3 +276,9 @@ int source_create(const char *filename, int flags, mode_t mode) {
|
|||||||
const char *relative_filename = source_filename_translate(filename);
|
const char *relative_filename = source_filename_translate(filename);
|
||||||
return openat(handle.root_fd, relative_filename, flags | O_CREAT, mode);
|
return openat(handle.root_fd, relative_filename, flags | O_CREAT, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int source_utimens(const char *filename, const struct timespec ts[2],
|
||||||
|
int flags) {
|
||||||
|
const char *relative_filename = source_filename_translate(filename);
|
||||||
|
return utimensat(handle.root_fd, relative_filename, ts, AT_SYMLINK_NOFOLLOW);
|
||||||
|
}
|
||||||
|
@@ -138,4 +138,7 @@ int source_open(const char *filename, int flags);
|
|||||||
*/
|
*/
|
||||||
int source_create(const char *filename, int flags, mode_t mode);
|
int source_create(const char *filename, int flags, mode_t mode);
|
||||||
|
|
||||||
|
int source_utimens(const char *filename, const struct timespec ts[2],
|
||||||
|
int flags);
|
||||||
|
|
||||||
#endif // !SOURCEFS_H
|
#endif // !SOURCEFS_H
|
||||||
|
@@ -7,6 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "access_t.h"
|
#include "access_t.h"
|
||||||
|
#include <signal.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
@@ -25,6 +26,7 @@
|
|||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <wait.h>
|
||||||
|
|
||||||
// Exit status codes for icfs_dialogue process interaction
|
// Exit status codes for icfs_dialogue process interaction
|
||||||
#define DIALOGUE_YES 1
|
#define DIALOGUE_YES 1
|
||||||
@@ -96,30 +98,64 @@ void destroy_ui_socket(void) {
|
|||||||
struct dialogue_response ask_access(const char *filename,
|
struct dialogue_response ask_access(const char *filename,
|
||||||
struct process_info proc_info) {
|
struct process_info proc_info) {
|
||||||
FILE *fp = NULL;
|
FILE *fp = NULL;
|
||||||
char *command = NULL;
|
|
||||||
int ret = asprintf(&command, "icfs_dialogue \"%d\" \"%s\" \"%s\" \"%s\"",
|
|
||||||
proc_info.PID, proc_info.name, get_mountpoint(), filename);
|
|
||||||
|
|
||||||
struct dialogue_response response;
|
struct dialogue_response response;
|
||||||
response.decision = DENY;
|
response.decision = DENY;
|
||||||
response.filename = NULL;
|
response.filename = NULL;
|
||||||
|
|
||||||
if (ret < 0) {
|
// instead of popeen --------------
|
||||||
// Memory allocation failed - create minimal fallback response
|
|
||||||
fprintf(stderr, "[ICFS] Could not create query on rule insertion");
|
char pid_str[sizeof(pid_t) *
|
||||||
perror("");
|
8]; // amount of bits should be enough for a decimal
|
||||||
|
snprintf(pid_str, sizeof(pid_str), "%d", proc_info.PID);
|
||||||
|
|
||||||
|
int pipefd[2];
|
||||||
|
if (pipe(pipefd) == -1) {
|
||||||
|
perror("[ICFS] pipe returned a error");
|
||||||
response.filename = malloc(2);
|
response.filename = malloc(2);
|
||||||
response.filename[0] = '/';
|
response.filename[0] = '/';
|
||||||
response.filename[1] = 0;
|
response.filename[1] = 0;
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute permission dialogue
|
pid_t pid = fork();
|
||||||
fp = popen(command, "r");
|
if (pid == -1) {
|
||||||
free(command);
|
perror("[ICFS] fork returned a error");
|
||||||
|
response.filename = malloc(2);
|
||||||
|
response.filename[0] = '/';
|
||||||
|
response.filename[1] = 0;
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pid == 0) {
|
||||||
|
// Child process
|
||||||
|
close(pipefd[0]); // Close read end
|
||||||
|
dup2(pipefd[1], STDOUT_FILENO); // Redirect stdout
|
||||||
|
close(pipefd[1]); // Close original write end
|
||||||
|
|
||||||
|
// Prepare command and arguments
|
||||||
|
char *args[] = {"icfs_dialogue", // Command name (looked up in PATH)
|
||||||
|
pid_str,
|
||||||
|
(char *)proc_info.name,
|
||||||
|
(char *)get_mountpoint(),
|
||||||
|
(char *)filename,
|
||||||
|
NULL};
|
||||||
|
|
||||||
|
// Execute the command using execvp (uses PATH)
|
||||||
|
execvp("icfs_dialogue", args);
|
||||||
|
|
||||||
|
// If execvp fails
|
||||||
|
perror("execvp failed");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// instead of popen ---------------
|
||||||
|
|
||||||
|
close(pipefd[1]); // Close write end
|
||||||
|
fp = fdopen(pipefd[0], "r");
|
||||||
|
|
||||||
if (fp == NULL) {
|
if (fp == NULL) {
|
||||||
perror("[ICFS] Pipe returned a error");
|
perror("[ICFS] fdopen returned a error");
|
||||||
response.filename = malloc(2);
|
response.filename = malloc(2);
|
||||||
response.filename[0] = '/';
|
response.filename[0] = '/';
|
||||||
response.filename[1] = 0;
|
response.filename[1] = 0;
|
||||||
@@ -133,22 +169,45 @@ struct dialogue_response ask_access(const char *filename,
|
|||||||
|
|
||||||
// Read entire command output
|
// Read entire command output
|
||||||
while (fgets(line, sizeof(line), fp)) {
|
while (fgets(line, sizeof(line), fp)) {
|
||||||
push_fmt(&dialogue_output, line);
|
if (push_fmt(&dialogue_output, line) == NULL) {
|
||||||
|
cleanup(&dialogue_output);
|
||||||
|
perror("[ICFS] not enough memory for dialogue output.");
|
||||||
|
// kill the dialogue if it's still there
|
||||||
|
kill(pid, SIGQUIT);
|
||||||
|
fclose(fp);
|
||||||
|
response.filename = malloc(2);
|
||||||
|
response.filename[0] = '/';
|
||||||
|
response.filename[1] = 0;
|
||||||
|
return response;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int dialogue_exit_code = WEXITSTATUS(pclose(fp));
|
fclose(fp);
|
||||||
|
|
||||||
|
// Wait for the child to finish
|
||||||
|
int status;
|
||||||
|
if (waitpid(pid, &status, 0) == -1) {
|
||||||
|
cleanup(&dialogue_output);
|
||||||
|
perror("[ICFS] waitpid error");
|
||||||
|
// kill the dialogue if it is still there
|
||||||
|
kill(pid, SIGQUIT);
|
||||||
|
response.filename = malloc(2);
|
||||||
|
response.filename[0] = '/';
|
||||||
|
response.filename[1] = 0;
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dialogue_exit_code = WEXITSTATUS(status);
|
||||||
|
|
||||||
fprintf(stderr, "[ICFS] dialogue wrote out %s\n", first(&dialogue_output));
|
fprintf(stderr, "[ICFS] dialogue wrote out %s\n", first(&dialogue_output));
|
||||||
fprintf(stderr, "[ICFS] dialogue returned %d\n", dialogue_exit_code);
|
fprintf(stderr, "[ICFS] dialogue returned %d\n", dialogue_exit_code);
|
||||||
|
|
||||||
// Handle empty output case
|
// Handle empty output case
|
||||||
if (size(&dialogue_output) == 0) {
|
if (size(&dialogue_output) == 0) {
|
||||||
|
perror("[ICFS] empty dialogue output.");
|
||||||
push(&dialogue_output, '/');
|
push(&dialogue_output, '/');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate string length consistency
|
|
||||||
assert(strlen(first(&dialogue_output)) == size(&dialogue_output));
|
|
||||||
|
|
||||||
// Allocate and copy final filename
|
// Allocate and copy final filename
|
||||||
response.filename = malloc(size(&dialogue_output) + 1);
|
response.filename = malloc(size(&dialogue_output) + 1);
|
||||||
strcpy(response.filename, first(&dialogue_output));
|
strcpy(response.filename, first(&dialogue_output));
|
||||||
|
@@ -54,24 +54,32 @@ int main(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Construct the full path
|
// Construct the full path
|
||||||
char fullpath[PATH_MAX];
|
char *fullpath = NULL;
|
||||||
snprintf(fullpath, PATH_MAX, "%s/%s", path, entry->d_name);
|
if (asprintf(&fullpath, "%s/%s", path, entry->d_name) == -1 ||
|
||||||
|
fullpath == NULL) {
|
||||||
|
perror("asprintf");
|
||||||
|
success = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// Stat the entry to check if it's a regular file
|
// Stat the entry to check if it's a regular file
|
||||||
struct stat entry_stat;
|
struct stat entry_stat;
|
||||||
if (lstat(fullpath, &entry_stat) == -1) {
|
if (lstat(fullpath, &entry_stat) == -1) {
|
||||||
perror("lstat");
|
perror("lstat");
|
||||||
success = 0;
|
success = 0;
|
||||||
|
free(fullpath);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only process regular files
|
// Only process regular files
|
||||||
if (!S_ISREG(entry_stat.st_mode)) {
|
if (!S_ISREG(entry_stat.st_mode)) {
|
||||||
|
free(fullpath);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to open and immediately close the file
|
// Try to open and immediately close the file
|
||||||
int fd = open(fullpath, O_RDONLY);
|
int fd = open(fullpath, O_RDONLY);
|
||||||
|
free(fullpath);
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
perror("open");
|
perror("open");
|
||||||
success = 0;
|
success = 0;
|
||||||
|
Reference in New Issue
Block a user