diff options
-rw-r--r-- | main.c | 160 |
1 files changed, 93 insertions, 67 deletions
@@ -5,6 +5,7 @@ #include <limits.h> #include <errno.h> #include <fcntl.h> +#include <stdbool.h> #include <sys/stat.h> #include <sys/sendfile.h> #include <sys/capability.h> @@ -13,45 +14,45 @@ #define GSR_KMS_SERVER_FILEPATH "/var/lib/flatpak/app/com.dec05eba.gpu_screen_recorder/current/active/files/bin/gsr-kms-server" #define GSR_GLOBAL_HOTKEYS_FILEPATH "/var/lib/flatpak/app/com.dec05eba.gpu_screen_recorder/current/active/files/bin/gsr-global-hotkeys" -static int readlink_realpath(const char *filepath, char *buffer) { +static bool readlink_realpath(const char *filepath, char *buffer) { char symlinked_path[PATH_MAX]; ssize_t bytes_written = readlink(filepath, symlinked_path, sizeof(symlinked_path) - 1); if(bytes_written == -1 && errno == EINVAL) { /* Not a symlink */ strncpy(symlinked_path, filepath, sizeof(symlinked_path)); } else if(bytes_written == -1) { - return 0; + return false; } else { symlinked_path[bytes_written] = '\0'; } if(!realpath(symlinked_path, buffer)) - return 0; + return false; - return 1; + return true; } -static int file_has_sys_admin_capability(const char *filepath) { +static bool file_has_sys_admin_capability(const char *filepath) { cap_t cap = cap_get_file(filepath); if(!cap) - return 0; + return false; cap_flag_value_t res = CAP_CLEAR; cap_get_flag(cap, CAP_SYS_ADMIN, CAP_PERMITTED, &res); - int cap_set = res == CAP_SET; + bool cap_set = res == CAP_SET; cap_free(cap); return cap_set; } -static int file_set_capabilities(const char *filepath, const cap_value_t *caps_to_set, int num_caps_to_set) { +static bool file_set_capabilities(const char *filepath, const cap_value_t *caps_to_set, int num_caps_to_set) { cap_t cap = cap_get_file(filepath); if(!cap && errno != ENODATA) - return 0; + return false; if(!cap) { cap = cap_init(); if(!cap) - return 0; + return false; } int res = 0; @@ -63,7 +64,7 @@ static int file_set_capabilities(const char *filepath, const cap_value_t *caps_t return res == 0; } -static int create_local_kms_server_proxy_directory(const char *home) { +static bool create_local_kms_server_proxy_directory(const char *home) { char path[PATH_MAX]; int err; @@ -73,16 +74,16 @@ static int create_local_kms_server_proxy_directory(const char *home) { snprintf(path, sizeof(path), "%s/%s", home, path_part); err = mkdir(path, S_IRWXU); if(err == -1 && errno != EEXIST) - return 0; + return false; } - return 1; + return true; } -static int copy_file_atomic(const char *source_path, const char *dest_path) { +static bool copy_file_atomic(const char *source_path, const char *dest_path) { int in_fd = -1; int out_fd = -1; - int res = 0; + bool res = false; char tmp_filepath[PATH_MAX]; snprintf(tmp_filepath, sizeof(tmp_filepath), "%s.tmp", dest_path); @@ -101,7 +102,7 @@ static int copy_file_atomic(const char *source_path, const char *dest_path) { if(sendfile(out_fd, in_fd, NULL, st.st_size) != st.st_size) goto done; - res = 1; + res = true; done: if(in_fd) @@ -122,6 +123,46 @@ static void usage(void) { exit(1); } +static bool set_gsr_files_set_permissions_and_capabilities(const char *kms_server_proxy_local_filepath) { + /* owner: read/write/execute, group: read/execute, public: read/execute */ + if(chmod(kms_server_proxy_local_filepath, 0755) != 0) { + fprintf(stderr, "Error: failed to set %s permissions\n", kms_server_proxy_local_filepath); + return false; + } + + if(chown(kms_server_proxy_local_filepath, 0, 0) != 0) { + fprintf(stderr, "Error: failed to set %s ownership\n", kms_server_proxy_local_filepath); + return false; + } + + if(!file_set_capabilities(kms_server_proxy_local_filepath, (const cap_value_t[]){ CAP_SYS_ADMIN, CAP_SETFCAP, CAP_SETUID }, 3)) { + fprintf(stderr, "Error: failed to set kms-server-proxy capabilities\n"); + return false; + } + + return true; +} + +/* |gsr_global_hotkeys_local_filepath| can be NULL */ +static bool setup_local_gsr_files(const char *user_homepath, const char *kms_server_proxy_local_filepath, const char *kms_server_proxy_home) { + if(!create_local_kms_server_proxy_directory(user_homepath)) { + fprintf(stderr, "Error: failed to create ~/.local/share/gpu-screen-recorder directory\n"); + return false; + } + + if(!copy_file_atomic(KMS_SERVER_PROXY_FILEPATH, kms_server_proxy_local_filepath)) { + fprintf(stderr, "Error: failed to copy kms-server-proxy to %s\n", kms_server_proxy_local_filepath); + return false; + } + + if(!copy_file_atomic(KMS_SERVER_PROXY_FILEPATH, kms_server_proxy_home)) { + fprintf(stderr, "Error: failed to copy kms-server-proxy to %s\n", kms_server_proxy_home); + return false; + } + + return true; +} + static int setup_gsr_ui(const char *user_homepath) { char self_path[PATH_MAX]; if(!readlink_realpath("/proc/self/exe", self_path)) { @@ -139,39 +180,25 @@ static int setup_gsr_ui(const char *user_homepath) { /* Update kms-server-proxy-N to kms-server-proxy-N+1 on update (update that needs to run before this program launches itself) */ snprintf(kms_server_proxy_local_filepath, sizeof(kms_server_proxy_local_filepath), "%s/.local/share/gpu-screen-recorder/kms-server-proxy-2", user_homepath); - char gsr_kms_server_local_filepath[PATH_MAX]; - snprintf(gsr_kms_server_local_filepath, sizeof(gsr_kms_server_local_filepath), "%s/.local/share/gpu-screen-recorder/gsr-kms-server", user_homepath); - - char gsr_global_hotkeys_local_filepath[PATH_MAX]; - snprintf(gsr_global_hotkeys_local_filepath, sizeof(gsr_global_hotkeys_local_filepath), "%s/.local/share/gpu-screen-recorder/gsr-global-hotkeys", user_homepath); + /* Weird-ass distros like openSUSE only allow pkexec for files in $HOME!!! */ + char kms_server_proxy_home[PATH_MAX]; + snprintf(kms_server_proxy_home, sizeof(kms_server_proxy_home), "%s/kms-server-proxy", user_homepath); if(geteuid() == 0) { /* is current user root? */ - int success = 1; - success &= (file_set_capabilities(kms_server_proxy_local_filepath, (const cap_value_t[]){ CAP_SYS_ADMIN, CAP_SETFCAP, CAP_SETUID }, 3) == 1); - return success ? 0 : 1; - } else { - if(create_local_kms_server_proxy_directory(user_homepath) != 1) { - fprintf(stderr, "Error: failed to create ~/.local/share/gpu-screen-recorder directory\n"); + remove(kms_server_proxy_home); + if(!set_gsr_files_set_permissions_and_capabilities(kms_server_proxy_local_filepath)) return 1; - } - - if(copy_file_atomic(KMS_SERVER_PROXY_FILEPATH, kms_server_proxy_local_filepath) != 1) { - fprintf(stderr, "Error: failed to copy kms-server-proxy to %s\n", kms_server_proxy_local_filepath); - return 1; - } - - if(copy_file_atomic(GSR_KMS_SERVER_FILEPATH, gsr_kms_server_local_filepath) != 1) { - fprintf(stderr, "Error: failed to copy gsr-kms-server to %s\n", gsr_kms_server_local_filepath); - return 1; - } - if(copy_file_atomic(GSR_GLOBAL_HOTKEYS_FILEPATH, gsr_global_hotkeys_local_filepath) != 1) { - fprintf(stderr, "Error: failed to copy gsr-global-hotkeys to %s\n", gsr_global_hotkeys_local_filepath); + return 0; + } else { + if(!setup_local_gsr_files(user_homepath, kms_server_proxy_local_filepath, kms_server_proxy_home)) return 1; - } - const char *args[] = { "pkexec", kms_server_proxy_local_filepath, "setup-gsr-ui", user_homepath, NULL }; - return execvp(args[0], (char *const*)args); + const char *args[] = { "pkexec", kms_server_proxy_home, "setup-gsr-ui", user_homepath, NULL }; + const int result = execvp(args[0], (char *const*)args); + perror("pkexec"); + remove(kms_server_proxy_home); + return result; } } @@ -186,8 +213,9 @@ static int launch_gsr_kms_server(const char *initial_socket_path, const char *ca /* Update kms-server-proxy-N to kms-server-proxy-N+1 on update (update that needs to run before this program launches itself) */ snprintf(kms_server_proxy_local_filepath, sizeof(kms_server_proxy_local_filepath), "%s/.local/share/gpu-screen-recorder/kms-server-proxy-2", user_homepath); - char gsr_kms_server_local_filepath[PATH_MAX]; - snprintf(gsr_kms_server_local_filepath, sizeof(gsr_kms_server_local_filepath), "%s/.local/share/gpu-screen-recorder/gsr-kms-server", user_homepath); + /* Weird-ass distros like openSUSE only allow pkexec for files in $HOME!!! */ + char kms_server_proxy_home[PATH_MAX]; + snprintf(kms_server_proxy_home, sizeof(kms_server_proxy_home), "%s/kms-server-proxy", user_homepath); if(file_has_sys_admin_capability(kms_server_proxy_local_filepath)) { /* Need to resolve kms_server_proxy_local_filepath because /home can be a symlink to another location */ @@ -206,30 +234,29 @@ static int launch_gsr_kms_server(const char *initial_socket_path, const char *ca return execv(args[0], (char *const*)args); } - const char *args[] = { "pkexec", gsr_kms_server_local_filepath, initial_socket_path, card_path, NULL }; - return execvp(args[0], (char *const*)args); - } else if(geteuid() == 0) { /* is current user root? */ - file_set_capabilities(kms_server_proxy_local_filepath, (const cap_value_t[]){ CAP_SYS_ADMIN, CAP_SETFCAP, CAP_SETUID }, 3); - const char *args[] = { gsr_kms_server_local_filepath, initial_socket_path, card_path, NULL }; - return execv(args[0], (char *const*)args); - } else { - if(create_local_kms_server_proxy_directory(user_homepath) != 1) { - fprintf(stderr, "Error: failed to create ~/.local/share/gpu-screen-recorder directory\n"); + if(setuid(0) == -1) { + fprintf(stderr, "Error: failed to switch to root user to launch gsr-kms-server\n"); return 1; } - if(copy_file_atomic(KMS_SERVER_PROXY_FILEPATH, kms_server_proxy_local_filepath) != 1) { - fprintf(stderr, "Error: failed to copy kms-server-proxy to %s\n", kms_server_proxy_local_filepath); + const char *args[] = { GSR_KMS_SERVER_FILEPATH, initial_socket_path, card_path, NULL }; + return execvp(args[0], (char *const*)args); + } else if(geteuid() == 0) { /* is current user root? */ + remove(kms_server_proxy_home); + if(!set_gsr_files_set_permissions_and_capabilities(kms_server_proxy_local_filepath)) return 1; - } - if(copy_file_atomic(GSR_KMS_SERVER_FILEPATH, gsr_kms_server_local_filepath) != 1) { - fprintf(stderr, "Error: failed to copy gsr-kms-server to %s\n", gsr_kms_server_local_filepath); + const char *args[] = { GSR_KMS_SERVER_FILEPATH, initial_socket_path, card_path, NULL }; + return execv(args[0], (char *const*)args); + } else { + if(!setup_local_gsr_files(user_homepath, kms_server_proxy_local_filepath, kms_server_proxy_home)) return 1; - } - const char *args[] = { "pkexec", kms_server_proxy_local_filepath, initial_socket_path, card_path, user_homepath, NULL }; - return execvp(args[0], (char *const*)args); + const char *args[] = { "pkexec", kms_server_proxy_home, initial_socket_path, card_path, user_homepath, NULL }; + const int result = execvp(args[0], (char *const*)args); + perror("pkexec"); + remove(kms_server_proxy_home); + return result; } } @@ -246,9 +273,6 @@ static int launch_gsr_global_hotkeys(char **argv) { /* Update kms-server-proxy-N to kms-server-proxy-N+1 on update (update that needs to run before this program launches itself) */ snprintf(kms_server_proxy_local_filepath, sizeof(kms_server_proxy_local_filepath), "%s/.local/share/gpu-screen-recorder/kms-server-proxy-2", user_homepath); - char gsr_global_hotkeys_local_filepath[PATH_MAX]; - snprintf(gsr_global_hotkeys_local_filepath, sizeof(gsr_global_hotkeys_local_filepath), "%s/.local/share/gpu-screen-recorder/gsr-global-hotkeys", user_homepath); - if(!file_has_sys_admin_capability(kms_server_proxy_local_filepath)) { fprintf(stderr, "Error: kms-server-proxy is missing cap sys admin capability\n"); return 1; @@ -275,8 +299,10 @@ static int launch_gsr_global_hotkeys(char **argv) { return 1; } - argv[2] = gsr_global_hotkeys_local_filepath; - return execv(argv[2], argv + 2); + argv[2] = GSR_GLOBAL_HOTKEYS_FILEPATH; + const int result = execv(argv[2], argv + 2); + perror(argv[2]); + return result; } int main(int argc, char **argv) { |