mirror of
https://github.com/javalsai/lidm.git
synced 2025-09-05 04:28:00 +02:00
feat: xorg sessions work
leaves a few TODOs: * error handling * properly passing VT around * `wait_for_x_ready` * allow compile-time overriding `DEFAULT_XORG_DISPLAY` and `XORG_COMMAND`
This commit is contained in:
@@ -1,6 +1,9 @@
|
|||||||
#ifndef DESKTOP_EXEC_H_
|
#ifndef DESKTOP_EXEC_H_
|
||||||
#define 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);
|
int parse_exec_string(const char* exec_s, int* arg_count, char*** args);
|
||||||
void free_parsed_args(int arg_count, char** args);
|
void free_parsed_args(int arg_count, char** args);
|
||||||
|
|
||||||
|
@@ -4,6 +4,7 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "desktop_exec.h"
|
||||||
#include "macros.h"
|
#include "macros.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
@@ -56,7 +57,7 @@ static inline int session_exec_exec(struct session_exec* NNULLABLE exec,
|
|||||||
case EXEC_SHELL:
|
case EXEC_SHELL:
|
||||||
return execle(exec->shell, exec->shell, NULL, envlist);
|
return execle(exec->shell, exec->shell, NULL, envlist);
|
||||||
case EXEC_DESKTOP:
|
case EXEC_DESKTOP:
|
||||||
return execve(exec->desktop.args[0], exec->desktop.args, envlist);
|
return execvpe_desktop(exec->desktop.args, envlist);
|
||||||
default:
|
default:
|
||||||
__builtin_unreachable();
|
__builtin_unreachable();
|
||||||
}
|
}
|
||||||
|
132
src/auth.c
132
src/auth.c
@@ -1,23 +1,32 @@
|
|||||||
|
// TODO: handle `fork() == -1`s
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <grp.h>
|
#include <grp.h>
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#include <security/pam_misc.h>
|
#include <security/pam_misc.h>
|
||||||
|
#include <signal.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "auth.h"
|
#include "auth.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "macros.h"
|
||||||
#include "pam.h"
|
#include "pam.h"
|
||||||
#include "sessions.h"
|
#include "sessions.h"
|
||||||
#include "ui.h"
|
#include "ui.h"
|
||||||
#include "util.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,
|
static void try_source_file(struct Vector* NNULLABLE vec_envlist,
|
||||||
char* NNULLABLE filepath) {
|
char* NNULLABLE filepath) {
|
||||||
log_printf("sourcing %s\n", filepath);
|
log_printf("sourcing %s\n", filepath);
|
||||||
@@ -89,6 +98,93 @@ struct child_msg {
|
|||||||
bool err;
|
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) \
|
#define SEND_MSG(MSG) \
|
||||||
{ \
|
{ \
|
||||||
write(pipefd[1], &(MSG), sizeof(struct child_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,
|
inline static void forked(int pipefd[2], struct passwd* pw,
|
||||||
char* NNULLABLE user,
|
char* NNULLABLE user,
|
||||||
struct session_exec* NNULLABLE exec,
|
struct session* NNULLABLE session,
|
||||||
char** NNULLABLE envlist) {
|
char** NNULLABLE envlist) {
|
||||||
if (chdir(pw->pw_dir) == -1) SEND_ERR("chdir");
|
if (chdir(pw->pw_dir) == -1) SEND_ERR("chdir");
|
||||||
if (setgid(pw->pw_gid) == -1) SEND_ERR("setgid");
|
if (setgid(pw->pw_gid) == -1) SEND_ERR("setgid");
|
||||||
if (initgroups(user, pw->pw_gid) == -1) SEND_ERR("initgroups");
|
if (initgroups(user, pw->pw_gid) == -1) SEND_ERR("initgroups");
|
||||||
if (setuid(pw->pw_uid) == -1) SEND_ERR("setuid");
|
if (setuid(pw->pw_uid) == -1) SEND_ERR("setuid");
|
||||||
|
|
||||||
// or maybe Xorg fork should happen here
|
|
||||||
|
|
||||||
SEND_MSG((struct child_msg){.err = false});
|
SEND_MSG((struct child_msg){.err = false});
|
||||||
DUMMY_READ();
|
DUMMY_READ();
|
||||||
close(pipefd[0]);
|
close(pipefd[0]);
|
||||||
|
|
||||||
int exit = session_exec_exec(exec, envlist);
|
if (session->type == XORG) {
|
||||||
perror("exec error");
|
launch_with_xorg_server(&session->exec, pw, envlist);
|
||||||
(void)fputs("failure calling session\n", stderr);
|
} else {
|
||||||
_exit(exit);
|
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_MSG
|
||||||
#undef SEND_ERR
|
#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);
|
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,
|
source_paths(&envlist_vec, &config->behavior.source, pw->pw_dir,
|
||||||
&config->behavior.user_source);
|
&config->behavior.user_source);
|
||||||
char** envlist = (char**)vec_as_raw(envlist_vec);
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: start X server here if needed
|
|
||||||
// e.g. spawn (also after downgrading privs):
|
|
||||||
//
|
|
||||||
// `X :0 tty<X> -auth <user-home>/.Xauthority -nolisten tcp -background none`
|
|
||||||
//
|
|
||||||
// Then `DISPLAY=:0 <xsession>`
|
|
||||||
|
|
||||||
int pipefd[2];
|
int pipefd[2];
|
||||||
pipe(pipefd);
|
pipe(pipefd);
|
||||||
|
|
||||||
uint pid = fork();
|
uint pid = fork();
|
||||||
if (pid == 0)
|
if (pid == 0)
|
||||||
forked(pipefd, pw, user, &session.exec, envlist);
|
forked(pipefd, pw, user, &session, envlist);
|
||||||
else {
|
else {
|
||||||
struct child_msg msg;
|
struct child_msg msg;
|
||||||
read(pipefd[0], &msg, sizeof(struct child_msg));
|
read(pipefd[0], &msg, sizeof(struct child_msg));
|
||||||
|
@@ -24,8 +24,10 @@ int chvt_str(char* str) {
|
|||||||
return chvt((int)i);
|
return chvt((int)i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int vt = -1;
|
||||||
int chvt(int n) {
|
int chvt(int n) {
|
||||||
(void)fprintf(stderr, "activating vt %d\n", n);
|
(void)fprintf(stderr, "activating vt %d\n", n);
|
||||||
|
vt = n;
|
||||||
// NOLINTNEXTLINE(readability-identifier-length)
|
// NOLINTNEXTLINE(readability-identifier-length)
|
||||||
char c = 0;
|
char c = 0;
|
||||||
for (size_t i = 0; i < LEN(vterms); i++) {
|
for (size_t i = 0; i < LEN(vterms); i++) {
|
||||||
|
@@ -1,14 +1,59 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "desktop_exec.h"
|
#include "desktop_exec.h"
|
||||||
|
#include "macros.h"
|
||||||
|
|
||||||
// constants for exec string parsing
|
// constants for exec string parsing
|
||||||
#define MAX_ARGS 100
|
#define MAX_ARGS 100
|
||||||
// ARG_LENGTH is the initial length of a parsed argument
|
// ARG_LENGTH is the initial length of a parsed argument
|
||||||
#define ARG_LENGTH 64
|
#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
|
// parse Exec=/bin/prog arg1 arg2\ with\ spaces
|
||||||
void free_parsed_args(int arg_count, char** args) {
|
void free_parsed_args(int arg_count, char** args) {
|
||||||
if (!args) return;
|
if (!args) return;
|
||||||
|
Reference in New Issue
Block a user