diff --git a/mdm/login.c b/mdm/login.c index 47befa7..aa22177 100644 --- a/mdm/login.c +++ b/mdm/login.c @@ -1,20 +1,26 @@ #include "mdm.h" #include +#include +#include #include #include +#include +#include MwWidget root; -MwWidget window, sesscombo, usercombo, passentry; +MwWidget window, sesscombo, usercombo, passentry, error; typedef struct session { - char* key; - char* value; + char* key; + session_environment_t* value; } session_t; -session_t* sessions = NULL; -char* name_line; -char* exec_line; +session_t* sessions = NULL; +char* name_line = NULL; +char* try_exec_line = NULL; +char* exec_line = NULL; +char* desktop_names_line = NULL; static void add_user(const char* name, void* user) { MwComboBoxAdd(user, -1, name); @@ -25,42 +31,61 @@ static int dumper(void* user, const char* section, const char* name, const char* if(strcmp(name, "Name") == 0) { name_line = MDEStringDuplicate(value); + } else if(strcmp(name, "TryExec") == 0) { + try_exec_line = MDEStringDuplicate(value); } else if(strcmp(name, "Exec") == 0) { exec_line = MDEStringDuplicate(value); + } else if(strcmp(name, "DesktopNames") == 0) { + desktop_names_line = MDEStringDuplicate(value); } return 1; } -static void add_session(const char* path, int dir, int symlink, void* user) { - int m = 1; +static void add_session(session_type_t session_type, const char* path, int dir, int symlink, void* user) { + int m = 1; + session_environment_t* value = malloc(sizeof(session_environment_t)); + + name_line = NULL; + exec_line = NULL; + try_exec_line = NULL; + desktop_names_line = NULL; - name_line = NULL; - exec_line = NULL; - if(dir || symlink) return; ini_parse(path, dumper, user); - if(name_line != NULL && exec_line != NULL) { + if(name_line != NULL && (exec_line != NULL || try_exec_line != NULL)) { int i; - for(i = 0; i < shlen(sessions); i++){ + for(i = 0; i < shlen(sessions); i++) { if(strcmp(sessions[i].key, name_line) == 0) break; } - - if(i == shlen(sessions)){ + + if(i == shlen(sessions)) { MwComboBoxAdd(user, -1, name_line); - shput(sessions, name_line, exec_line); + value->run = exec_line; + value->try_run = try_exec_line; + value->session_type = session_type; + value->desktop_names = desktop_names_line; + shput(sessions, name_line, value); m = 0; } } if(name_line != NULL) free(name_line); + if(desktop_names_line != NULL) free(desktop_names_line); + if(m && try_exec_line != NULL) free(try_exec_line); if(m && exec_line != NULL) free(exec_line); } +static void add_session_x(const char* path, int dir, int symlink, void* user) { + add_session(MDM_SESSION_TYPE_X, path, dir, symlink, user); +} +static void add_session_wayland(const char* path, int dir, int symlink, void* user) { + add_session(MDM_SESSION_TYPE_WAYLAND, path, dir, symlink, user); +} static int conversation(int num_msg, const struct pam_message** msg, struct pam_response** resp, void* appdata) { int i; @@ -82,53 +107,85 @@ static int conversation(int num_msg, const struct pam_message** msg, struct pam_ } static void try_login(MwWidget handle, void* user, void* client) { - const char* username = MwComboBoxGet(usercombo, MwGetInteger(usercombo, MwNvalue)); - struct pam_conv conv = {conversation, NULL}; + const char* username; + const char* place; + struct pam_conv conv; pam_handle_t* pam; + int err; + int err2; int ret; - jmp_buf cleanup; - int err = 1; + char err_str[255]; + int print_error = 0; + int i, n; + + username = MwComboBoxGet(usercombo, MwGetInteger(usercombo, MwNvalue)); + conv.conv = conversation; + conv.appdata_ptr = NULL; + err = 1; (void)handle; (void)user; (void)client; - if(setjmp(cleanup)) { - pam_end(pam, 0); - - if(err) { - MwSetText(passentry, MwNtext, ""); - } else { - struct passwd* pwd = getpwnam(username); - const char* session = MwComboBoxGet(sesscombo, MwGetInteger(sesscombo, MwNvalue)); - - uid = pwd->pw_uid; - gid = pwd->pw_gid; - run = shget(sessions, session); - - MwDestroyWidget(root); - } - - return; - } - ret = pam_start("mdm", username, &conv, &pam); if(ret != PAM_SUCCESS) { - longjmp(cleanup, 1); + place = "Error calling pam_start"; + goto cleanup; } ret = pam_authenticate(pam, 0); if(ret != PAM_SUCCESS) { - longjmp(cleanup, 1); + place = "Error calling pam_authenticate"; + goto cleanup; } ret = pam_acct_mgmt(pam, 0); if(ret != PAM_SUCCESS) { - longjmp(cleanup, 1); + place = "Error calling pam_acct_mgmt"; + goto cleanup; } - err = 0; - longjmp(cleanup, 1); + ret = pam_open_session(pam, 0); + if(ret != PAM_SUCCESS) { + place = "Error calling pam_open_session"; + goto cleanup; + } +cleanup: + pam_close_session(pam, 0); + + // if pam_end fails but we have another error, we care more about the error at hand + // then whether pam successfully ended. + err2 = pam_end(pam, 0); + + if(err && ret != PAM_SUCCESS) { + MwSetText(passentry, MwNtext, ""); + snprintf(err_str, 255, "%s: %s", place, pam_strerror(pam, err)); + print_error = 1; + } else if(err2) { + MwSetText(passentry, MwNtext, ""); + snprintf(err_str, 255, "Error calling pam_end: %s", pam_strerror(pam, err2)); + print_error = 1; + } + if(print_error) { + n = 0; + for(i = 0; err_str[i] != '\0' && i <= 255; i++ && n++) { + if(err_str[i] == ' ' && n >= 40) { + err_str[i] = '\n'; + n = 0; + } + } + MwSetText(error, MwNtext, err_str); + } else { + printf("Logging in as %s\n", username); + struct passwd* pwd = getpwnam(username); + const char* session = MwComboBoxGet(sesscombo, MwGetInteger(sesscombo, MwNvalue)); + + uid = pwd->pw_uid; + gid = pwd->pw_gid; + env = shget(sessions, session); + + MwDestroyWidget(root); + } } void login_window(void) { @@ -143,7 +200,7 @@ void login_window(void) { root = MwCreateWidget(NULL, "root", NULL, 0, 0, 0, 0); - window = MwVaCreateWidget(MwWindowClass, "login", root, (x_width() - 366) / 2, (x_height() - 183) / 2, 366, 183, + window = MwVaCreateWidget(MwWindowClass, "login", root, (x_width() - 366) / 2, (x_height() - 200) / 2, 366, 250, MwNtitle, "login", NULL); p = config_picture == NULL ? NULL : MwLoadImage(window, config_picture); @@ -179,7 +236,7 @@ void login_window(void) { ok = MwVaCreateWidget(MwButtonClass, "ok", window, 366 - 10 - 60, 10 + 137 + 10, 60, 18, MwNtext, "OK", NULL); - + error = MwVaCreateWidget(MwLabelClass, "error", window, 10, 10 + 137 + 10 + 20, 366, 48, NULL); if(p != NULL) MwVaApply(pic, MwNpixmap, p, NULL); MwAddUserHandler(ok, MwNactivateHandler, try_login, NULL); @@ -193,8 +250,10 @@ void login_window(void) { shfree(sessions); sh_new_strdup(sessions); shdefault(sessions, NULL); - MDEDirectoryScan(DATADIR "/xsessions", add_session, sesscombo); - MDEDirectoryScan("/usr/share/xsessions", add_session, sesscombo); + MDEDirectoryScan(DATADIR "/xsessions", add_session_x, sesscombo); + MDEDirectoryScan("/usr/share/xsessions", add_session_x, sesscombo); + MDEDirectoryScan(DATADIR "/wayland-sessions", add_session_wayland, sesscombo); + MDEDirectoryScan("/usr/share/wayland-sessions", add_session_wayland, sesscombo); pthread_mutex_unlock(&xmutex); diff --git a/mdm/main.c b/mdm/main.c index 0f5c5f8..455ef3f 100644 --- a/mdm/main.c +++ b/mdm/main.c @@ -1,14 +1,21 @@ #include "mdm.h" +#include +#include +#include +#include int is_launch_x = 1; -int is_daemon = 1; +int is_daemon = 1; -gid_t gid; -uid_t uid; -char* run; +gid_t gid; +uid_t uid; +session_environment_t* env; + +static void set_env_standard(struct passwd* pwd); +static void set_env_xdg(struct passwd* pwd); int main(int argc, char** argv) { - int i, st; + int i, st, exit; char* backup = NULL; pid_t pid; @@ -16,7 +23,7 @@ int main(int argc, char** argv) { if(argv[i][0] == '-') { if(strcmp(argv[i], "-X") == 0 || strcmp(argv[i], "--no-launch-x") == 0) { is_launch_x = 0; - }else if(strcmp(argv[i], "-d") == 0 || strcmp(argv[i], "--no-daemon") == 0) { + } else if(strcmp(argv[i], "-d") == 0 || strcmp(argv[i], "--no-daemon") == 0) { is_daemon = 0; } else { fprintf(stderr, "%s: bad option: %s\n", argv[0], argv[i]); @@ -30,7 +37,7 @@ int main(int argc, char** argv) { return 1; } - if(is_daemon && (pid = fork()) != 0){ + if(is_daemon && (pid = fork()) != 0) { FILE* f = fopen("/var/run/mdm.pid", "w"); fprintf(f, "%d\n", pid); fclose(f); @@ -52,7 +59,7 @@ int main(int argc, char** argv) { login_window(); - if(run == NULL) continue; + if(env->run == NULL && env->try_run == NULL) continue; if((pid = fork()) == 0) { struct passwd* pwd = getpwuid(uid); @@ -60,18 +67,62 @@ int main(int argc, char** argv) { setgid(gid); setuid(uid); chdir(pwd->pw_dir); - setenv("USER", pwd->pw_name, 1); - setenv("SHELL", pwd->pw_shell, 1); - setenv("HOME", pwd->pw_dir, 1); - _exit(system(run)); + + set_env_standard(pwd); + set_env_xdg(pwd); + + if((exit = system(env->try_run)) != 0) { + exit = system(env->run); + } else { + _exit(exit); + } } else { waitpid(pid, NULL, 0); } if(is_launch_x) { + unsetenv("DISPLAY"); kill_x(); } } while(is_launch_x); if(backup != NULL) free(backup); } + +void set_env_standard(struct passwd* pwd) { + setenv("HOME", pwd->pw_dir, 1); + setenv("PWD", pwd->pw_dir, 1); + setenv("USER", pwd->pw_name, 1); + setenv("SHELL", pwd->pw_shell, 1); + setenv("LOGNAME", pwd->pw_shell, 1); +} +void set_env_xdg(struct passwd* pwd) { + // this directory isn't avaliable on bsd, but we can't check for all of them. + // so just assume it's only on linux, idek if that's true but who care +#if defined(__linux__) + char runtime_dir[255]; + snprintf(runtime_dir, 255, "/run/user/%d", pwd->pw_uid); + setenv("XDG_RUNTIME_DIR", runtime_dir, 1); +#endif + + switch(env->session_type) { + case MDM_SESSION_TYPE_X: + setenv("XDG_SESSION_TYPE", "x11", 1); + break; + case MDM_SESSION_TYPE_WAYLAND: + setenv("XDG_SESSION_TYPE", "wayland", 1); + break; + } + + if(env->desktop_names) { + if(strlen(env->desktop_names) > 1) { + setenv("XDG_SESSION_DESKTOP", strtok(env->desktop_names, ";"), 1); + } + setenv("XDG_CURRENT_DESKTOP", env->desktop_names, 1); + } + + setenv("XDG_SESSION_CLASS", "user", 1); + setenv("XDG_SESSION_ID", "1", 1); + setenv("XDG_SEAT", "seat0", 1); + // setenv("XDG_VTNR", "/dev/pts/7", 1); +} diff --git a/mdm/mdm.h b/mdm/mdm.h index fa93b51..25375f7 100644 --- a/mdm/mdm.h +++ b/mdm/mdm.h @@ -22,10 +22,25 @@ #include #include +/* login.c */ +extern MwWidget root; +typedef enum session_type { + MDM_SESSION_TYPE_X, + MDM_SESSION_TYPE_WAYLAND, +} session_type_t; +typedef struct session_environment { + char* run; + char* try_run; + session_type_t session_type; + char* desktop_names; +} session_environment_t; + +void login_window(void); + /* main.c */ -extern gid_t gid; -extern uid_t uid; -extern char* run; +extern gid_t gid; +extern uid_t uid; +extern session_environment_t* env; /* xserver.c */ extern pthread_t xthread; @@ -39,11 +54,6 @@ int init_x(void); void loop_x(void); void kill_x(void); -/* login.c */ -extern MwWidget root; - -void login_window(void); - /* config.c */ extern char* config_picture; diff --git a/mdm/xserver.c b/mdm/xserver.c index e1a42c1..e1bb954 100644 --- a/mdm/xserver.c +++ b/mdm/xserver.c @@ -1,3 +1,4 @@ +#include #define _MILSKO #define USE_X11 #include "mdm.h" @@ -22,8 +23,6 @@ int launch_x(void) { signal(SIGUSR1, catch_usr1); - /* TODO: Remove hardcoded DISPLAY */ - if((xserver = fork()) == 0) { signal(SIGUSR1, SIG_IGN); execlp("X", "X", ":0", NULL);