aboutsummaryrefslogtreecommitdiff
path: root/main.c
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2024-02-10 19:05:02 +0100
committerdec05eba <dec05eba@protonmail.com>2024-02-11 02:11:41 +0100
commit667a6b3b1bc20516d1bf7d8a4611cd3a4d3f3bc6 (patch)
tree2770b29323939cec51670dd0d1aebd39a8041914 /main.c
Initial commit, done
Diffstat (limited to 'main.c')
-rw-r--r--main.c154
1 files changed, 154 insertions, 0 deletions
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..1866a69
--- /dev/null
+++ b/main.c
@@ -0,0 +1,154 @@
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <limits.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/sendfile.h>
+#include <sys/capability.h>
+
+static int get_self_filepath(char *buffer, size_t size) {
+ ssize_t bytes_written = readlink("/proc/self/exe", buffer, size - 1);
+ if(bytes_written == -1)
+ return 0;
+
+ buffer[bytes_written] = '\0';
+ return 1;
+}
+
+static int file_has_sys_admin_capability(const char *filepath) {
+ cap_t cap = cap_get_file(filepath);
+ if(!cap)
+ return 0;
+
+ cap_flag_value_t res = CAP_CLEAR;
+ cap_get_flag(cap, CAP_SYS_ADMIN, CAP_PERMITTED, &res);
+ int cap_set = res == CAP_SET;
+ cap_free(cap);
+ return cap_set;
+}
+
+static int file_set_sys_admin_capability(const char *filepath, int setfcap) {
+ cap_t cap = cap_get_file(filepath);
+ if(!cap && errno != ENODATA)
+ return 0;
+
+ if(!cap) {
+ cap = cap_init();
+ if(!cap)
+ return 0;
+ }
+
+ const cap_value_t cap_to_set[] = { CAP_SYS_ADMIN, CAP_SETFCAP };
+ int num_caps = 1;
+ if(setfcap)
+ num_caps = 2;
+
+ int res = 0;
+ res |= cap_set_flag(cap, CAP_EFFECTIVE, num_caps, cap_to_set, CAP_SET);
+ res |= cap_set_flag(cap, CAP_PERMITTED, num_caps, cap_to_set, CAP_SET);
+ /*cap_set_flag(cap, CAP_INHERITABLE, num_caps, cap_to_set, CAP_SET);*/
+ res |= cap_set_file(filepath, cap);
+ cap_free(cap);
+ return res == 0;
+}
+
+static int create_local_kms_server_proxy_directory(const char *home) {
+ char path[PATH_MAX];
+ int err;
+
+ snprintf(path, sizeof(path), "%s/.local", home);
+ err = mkdir(path, S_IRWXU);
+ if(err == -1 && errno != EEXIST)
+ return 0;
+
+ snprintf(path, sizeof(path), "%s/.local/bin", home);
+ err = mkdir(path, S_IRWXU);
+ if(err == -1 && errno != EEXIST)
+ return 0;
+
+ return 1;
+}
+
+static int create_local_kms_server_proxy_file(const char *source_path, const char *dest_path) {
+ int in_fd = -1;
+ int out_fd = -1;
+ int res = 0;
+
+ in_fd = open(source_path, O_RDONLY);
+ if(in_fd == -1)
+ goto done;
+
+ struct stat st;
+ if(fstat(in_fd, &st) == -1)
+ goto done;
+
+ out_fd = open(dest_path, O_RDWR | O_CREAT | O_TRUNC, 0755);
+ if(out_fd == -1)
+ goto done;
+
+ if(sendfile(out_fd, in_fd, NULL, st.st_size) != st.st_size)
+ goto done;
+
+ res = 1;
+
+ done:
+ if(in_fd)
+ close(in_fd);
+ if(out_fd)
+ close(out_fd);
+
+ if(res)
+ res = file_set_sys_admin_capability(dest_path, 1);
+
+ return res;
+}
+
+int main(int argc, char **argv) {
+ if(argc != 4)
+ return 1;
+
+ const char *gsr_kms_server_filepath = "/usr/bin/gsr-kms-server";
+ const char *initial_socket_path = argv[1];
+ const char *card_path = argv[2];
+ const char *user_homepath = argv[3];
+
+ char self_path[PATH_MAX];
+ if(!get_self_filepath(self_path, sizeof(self_path)))
+ return 1;
+
+ char kms_server_proxy_local_filepath[PATH_MAX];
+ snprintf(kms_server_proxy_local_filepath, sizeof(kms_server_proxy_local_filepath), "%s/.local/bin/kms-server-proxy", user_homepath);
+
+ if(file_has_sys_admin_capability(gsr_kms_server_filepath)) {
+ const char *args[] = { gsr_kms_server_filepath, initial_socket_path, card_path, NULL };
+ return execv(args[0], (char *const*)args);
+ } else if(file_has_sys_admin_capability(kms_server_proxy_local_filepath)) {
+ if(strcmp(self_path, kms_server_proxy_local_filepath) != 0) {
+ const char *args[] = { kms_server_proxy_local_filepath, initial_socket_path, card_path, user_homepath, NULL };
+ return execv(args[0], (char *const*)args);
+ }
+
+ /* TODO: Remove the need for this. Instead inherit capabilities */
+ if(file_set_sys_admin_capability(gsr_kms_server_filepath, 0)) {
+ const char *args[] = { gsr_kms_server_filepath, initial_socket_path, card_path, NULL };
+ return execv(args[0], (char *const*)args);
+ }
+
+ const char *args[] = { "pkexec", 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 */
+ file_set_sys_admin_capability(gsr_kms_server_filepath, 0);
+
+ if(create_local_kms_server_proxy_directory(user_homepath))
+ create_local_kms_server_proxy_file(self_path, kms_server_proxy_local_filepath);
+
+ const char *args[] = { gsr_kms_server_filepath, initial_socket_path, card_path, NULL };
+ return execv(args[0], (char *const*)args);
+ } else {
+ const char *args[] = { "pkexec", self_path, initial_socket_path, card_path, user_homepath, NULL };
+ return execvp(args[0], (char *const*)args);
+ }
+}