aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--main.c160
1 files changed, 93 insertions, 67 deletions
diff --git a/main.c b/main.c
index bca38fc..119f681 100644
--- a/main.c
+++ b/main.c
@@ -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) {