diff --git a/include/desktop_exec.h b/include/desktop_exec.h index 2bc03e6..3374445 100644 --- a/include/desktop_exec.h +++ b/include/desktop_exec.h @@ -1,6 +1,9 @@ #ifndef DESKTOP_EXEC_H_ #define DESKTOP_EXEC_H_ +#include "macros.h" + +int execvpe_desktop(char** args, char* NNULLABLE* NNULLABLE envlist); int parse_exec_string(const char* exec_s, int* arg_count, char*** args); void free_parsed_args(int arg_count, char** args); diff --git a/include/sessions.h b/include/sessions.h index 06118d7..cd4153b 100644 --- a/include/sessions.h +++ b/include/sessions.h @@ -4,6 +4,7 @@ #include #include +#include "desktop_exec.h" #include "macros.h" #include "util.h" @@ -56,7 +57,7 @@ static inline int session_exec_exec(struct session_exec* NNULLABLE exec, case EXEC_SHELL: return execle(exec->shell, exec->shell, NULL, envlist); case EXEC_DESKTOP: - return execve(exec->desktop.args[0], exec->desktop.args, envlist); + return execvpe_desktop(exec->desktop.args, envlist); default: __builtin_unreachable(); } diff --git a/src/auth.c b/src/auth.c index 00ab01a..88506db 100644 --- a/src/auth.c +++ b/src/auth.c @@ -1,23 +1,32 @@ +// TODO: handle `fork() == -1`s + #include #include #include #include +#include #include #include #include #include #include +#include #include #include #include "auth.h" #include "config.h" #include "log.h" +#include "macros.h" #include "pam.h" #include "sessions.h" #include "ui.h" #include "util.h" +#define DEFAULT_XORG_DISPLAY 0 +// no PATH search for now +#define XORG_COMMAND "/usr/bin/X" + static void try_source_file(struct Vector* NNULLABLE vec_envlist, char* NNULLABLE filepath) { log_printf("sourcing %s\n", filepath); @@ -89,6 +98,93 @@ struct child_msg { bool err; }; +// TODO: OR check if xorg_pid fail exited +static int wait_for_x_ready(const int xorg_pipefd[1], __pid_t xorg_pid) { + // TODO + UNUSED(xorg_pipefd); + UNUSED(xorg_pid); + sleep(2); + return 0; +} + +// TODO: properly pass this down +extern int vt; +// TODO: add error msgs +static void launch_with_xorg_server(struct session_exec* NNULLABLE exec, + struct passwd* pw, + char** NNULLABLE envlist) { + int xorg_pipefd[2]; + pipe(xorg_pipefd); + (void)fflush(NULL); + __pid_t xorg_pid = fork(); + if (xorg_pid == 0) { + if (!pw->pw_dir) _exit(EXIT_FAILURE); + // !!!!!!!!!! ATTENTION: this fails silently, of course add failure msgs but + // for now I can't so be careful + if (vt == -1) _exit(EXIT_FAILURE); + + char* display_thing; + asprintf(&display_thing, ":%d", DEFAULT_XORG_DISPLAY); + if (!display_thing) _exit(EXIT_FAILURE); + + char* vt_path; + asprintf(&vt_path, "vt%d", vt); + if (!vt_path) { + free(display_thing); + _exit(EXIT_FAILURE); + } + + // dup2(xorg_pipefd[1], STDERR_FILENO); + // dup2(xorg_pipefd[1], STDOUT_FILENO); + // close(xorg_pipefd[0]); + // close(xorg_pipefd[1]); + + int exit = execle(XORG_COMMAND, XORG_COMMAND, display_thing, vt_path, NULL, + envlist); + perror("exec"); + // execle("X", "X", display_thing, vt_path, "-auth", xauth_path, + // "-nolisten", "tcp", "-background", "none", NULL, envlist); + + printf("wtf3\n"); + (void)fflush(stdout); + + free(vt_path); + free(display_thing); + _exit(exit); + } + + wait_for_x_ready(xorg_pipefd, xorg_pid); + + __pid_t xorg_session_pid = fork(); + if (xorg_session_pid == 0) { + int exit = session_exec_exec(exec, envlist); + perror("exec error"); + (void)fputs("failure calling session\n", stderr); + _exit(exit); + } + + // looks weird, waiting on -1 should wait on any child and then just check if + // its xorg server or the session and kill the other waiting on it + __pid_t pid; + int status; // not even read for now + while ((pid = waitpid(-1, &status, 0)) > 0) { + if (pid == xorg_pid || pid == xorg_session_pid) { + __pid_t pid_to_kill = pid ^ xorg_pid ^ xorg_session_pid; + if (pid == xorg_pid) printf("Xorg server died\n"); + if (pid == xorg_session_pid) printf("Xorg session died\n"); + + kill(pid_to_kill, SIGTERM); + waitpid(pid_to_kill, &status, 0); + printf("wtf %d, x%d s%d - k%d\n", status, xorg_pid, xorg_session_pid, + pid_to_kill); + (void)fflush(stdout); + sleep(10); + + break; + } + } +} + #define SEND_MSG(MSG) \ { \ write(pipefd[1], &(MSG), sizeof(struct child_msg)); \ @@ -109,23 +205,25 @@ struct child_msg { } inline static void forked(int pipefd[2], struct passwd* pw, char* NNULLABLE user, - struct session_exec* NNULLABLE exec, + struct session* NNULLABLE session, char** NNULLABLE envlist) { if (chdir(pw->pw_dir) == -1) SEND_ERR("chdir"); if (setgid(pw->pw_gid) == -1) SEND_ERR("setgid"); if (initgroups(user, pw->pw_gid) == -1) SEND_ERR("initgroups"); if (setuid(pw->pw_uid) == -1) SEND_ERR("setuid"); - // or maybe Xorg fork should happen here - SEND_MSG((struct child_msg){.err = false}); DUMMY_READ(); close(pipefd[0]); - int exit = session_exec_exec(exec, envlist); - perror("exec error"); - (void)fputs("failure calling session\n", stderr); - _exit(exit); + if (session->type == XORG) { + launch_with_xorg_server(&session->exec, pw, envlist); + } else { + int exit = session_exec_exec(&session->exec, envlist); + perror("exec error"); + (void)fputs("failure calling session\n", stderr); + _exit(exit); + } } #undef SEND_MSG #undef SEND_ERR @@ -160,6 +258,17 @@ bool launch(char* user, char* passwd, struct session session, void (*cb)(void), } struct Vector envlist_vec = vec_from_raw((void**)env_ret.envlist); + + if (session.type == XORG) { + char* display_env; + asprintf(&display_env, "DISPLAY=:%d", DEFAULT_XORG_DISPLAY); + if (!display_env) { + print_err("alloc error"); + return false; + } + vec_push(&envlist_vec, display_env); + } + source_paths(&envlist_vec, &config->behavior.source, pw->pw_dir, &config->behavior.user_source); char** envlist = (char**)vec_as_raw(envlist_vec); @@ -168,19 +277,12 @@ bool launch(char* user, char* passwd, struct session session, void (*cb)(void), return false; } - // TODO: start X server here if needed - // e.g. spawn (also after downgrading privs): - // - // `X :0 tty -auth /.Xauthority -nolisten tcp -background none` - // - // Then `DISPLAY=:0 ` - int pipefd[2]; pipe(pipefd); uint pid = fork(); if (pid == 0) - forked(pipefd, pw, user, &session.exec, envlist); + forked(pipefd, pw, user, &session, envlist); else { struct child_msg msg; read(pipefd[0], &msg, sizeof(struct child_msg)); diff --git a/src/chvt.c b/src/chvt.c index bdb1b8f..d5c71d8 100644 --- a/src/chvt.c +++ b/src/chvt.c @@ -24,8 +24,10 @@ int chvt_str(char* str) { return chvt((int)i); } +int vt = -1; int chvt(int n) { (void)fprintf(stderr, "activating vt %d\n", n); + vt = n; // NOLINTNEXTLINE(readability-identifier-length) char c = 0; for (size_t i = 0; i < LEN(vterms); i++) { diff --git a/src/desktop_exec.c b/src/desktop_exec.c index 2774add..a2a7dac 100644 --- a/src/desktop_exec.c +++ b/src/desktop_exec.c @@ -1,14 +1,59 @@ #include +#include #include #include +#include +#include #include "desktop_exec.h" +#include "macros.h" // constants for exec string parsing #define MAX_ARGS 100 // ARG_LENGTH is the initial length of a parsed argument #define ARG_LENGTH 64 +// returns NULL on any error +// otherwise it returns the absolute path of the program that MUST BE FREED +static char* NULLABLE search_path(const char* NNULLABLE for_binary) { + char* path = strdup(getenv("PATH")); + if (!path) return NULL; + + char* tok = strtok(path, ":"); + while (tok) { + char* bin_path; + asprintf(&bin_path, "%s/%s", tok, for_binary); + if (!bin_path) { + free(path); + return NULL; + } + + struct stat stat_buf; + if (stat(bin_path, &stat_buf) == 0) { + // TODO: check exec bit ig + // if(stat_buf.) {} + free(path); + return bin_path; + } + + free(bin_path); + tok = strtok(NULL, ":"); + } + + return NULL; +} + +// returns -1 on exec failure and -2 on search failure +int execvpe_desktop(char** args, char* NNULLABLE* NNULLABLE envlist) { + char* new_arg = search_path(args[0]); + if (!new_arg) return -2; + + free(args[0]); + args[0] = new_arg; + + return execve(args[0], args, envlist); +} + // parse Exec=/bin/prog arg1 arg2\ with\ spaces void free_parsed_args(int arg_count, char** args) { if (!args) return;