diff --git a/src/auth.zig b/src/auth.zig index ab3cf01..ed25c33 100644 --- a/src/auth.zig +++ b/src/auth.zig @@ -23,17 +23,10 @@ pub fn sessionSignalHandler(i: c_int) callconv(.C) void { if (child_pid > 0) _ = std.c.kill(child_pid, i); } -pub fn authenticate(config: Config, current_environment: Session.Environment, login: [:0]const u8, password: [:0]const u8) !void { - var tty_buffer: [3]u8 = undefined; - const tty_str = try std.fmt.bufPrintZ(&tty_buffer, "{d}", .{config.tty}); - +pub fn authenticate(config: Config, login: [:0]const u8, password: [:0]const u8) !*interop.pam.pam_handle { var pam_tty_buffer: [6]u8 = undefined; const pam_tty_str = try std.fmt.bufPrintZ(&pam_tty_buffer, "tty{d}", .{config.tty}); - // Set the XDG environment variables - setXdgSessionEnv(current_environment.display_server); - try setXdgEnv(tty_str, current_environment.xdg_session_desktop orelse "", current_environment.xdg_desktop_names orelse ""); - // Open the PAM session var credentials = [_:null]?[*:0]const u8{ login, password }; @@ -43,15 +36,15 @@ pub fn authenticate(config: Config, current_environment: Session.Environment, lo }; var handle: ?*interop.pam.pam_handle = undefined; + // Do the PAM routine var status = interop.pam.pam_start(config.service_name, null, &conv, &handle); if (status != interop.pam.PAM_SUCCESS) return pamDiagnose(status); - defer _ = interop.pam.pam_end(handle, status); + errdefer interop.pam.pam_end(handle, status); // Set PAM_TTY as the current TTY. This is required in case it isn't being set by another PAM module status = interop.pam.pam_set_item(handle, interop.pam.PAM_TTY, pam_tty_str.ptr); if (status != interop.pam.PAM_SUCCESS) return pamDiagnose(status); - // Do the PAM routine status = interop.pam.pam_authenticate(handle, 0); if (status != interop.pam.PAM_SUCCESS) return pamDiagnose(status); @@ -59,12 +52,27 @@ pub fn authenticate(config: Config, current_environment: Session.Environment, lo if (status != interop.pam.PAM_SUCCESS) return pamDiagnose(status); status = interop.pam.pam_setcred(handle, interop.pam.PAM_ESTABLISH_CRED); + defer { + if (status != interop.pam.PAM_SUCCESS) _ = interop.pam.pam_end(handle, status); + } + if (status != interop.pam.PAM_SUCCESS) return pamDiagnose(status); + return handle.?; +} + +pub fn finaliseAuth(config: Config, current_environment: Session.Environment, handle: ?*interop.pam.pam_handle, login: [:0]const u8) !void { + var tty_buffer: [2]u8 = undefined; + const tty_str = try std.fmt.bufPrintZ(&tty_buffer, "{d}", .{config.tty}); + + // Close the PAM session + var status = interop.pam.pam_open_session(handle, 0); + defer status = interop.pam.pam_close_session(handle, status); if (status != interop.pam.PAM_SUCCESS) return pamDiagnose(status); defer status = interop.pam.pam_setcred(handle, interop.pam.PAM_DELETE_CRED); + defer status = interop.pam.pam_end(handle, status); - status = interop.pam.pam_open_session(handle, 0); - if (status != interop.pam.PAM_SUCCESS) return pamDiagnose(status); - defer status = interop.pam.pam_close_session(handle, 0); + // Set the XDG environment variables + setXdgSessionEnv(current_environment.display_server); + try setXdgEnv(tty_str, current_environment.xdg_session_desktop orelse "", current_environment.xdg_desktop_names orelse ""); var pwd: *interop.pwd.passwd = undefined; { @@ -120,102 +128,6 @@ pub fn authenticate(config: Config, current_environment: Session.Environment, lo if (shared_err.readError()) |err| return err; } -pub fn fingerprintAuth(config: Config, login: [:0]const u8) !*interop.pam.pam_handle { - // Open the PAM session - var credentials = [_:null]?[*:0]const u8{ login, "" }; - - const conv = interop.pam.pam_conv{ - .conv = loginConv, - .appdata_ptr = @ptrCast(&credentials), - }; - var handle: ?*interop.pam.pam_handle = undefined; - - var status = interop.pam.pam_start(config.service_name.ptr, null, &conv, &handle); - if (status != interop.pam.PAM_SUCCESS) return pamDiagnose(status); - - // Do the PAM routine - status = interop.pam.pam_authenticate(handle, 0); - if (status != interop.pam.PAM_SUCCESS) return pamDiagnose(status); - - status = interop.pam.pam_acct_mgmt(handle, 0); - if (status != interop.pam.PAM_SUCCESS) return pamDiagnose(status); - - status = interop.pam.pam_setcred(handle, interop.pam.PAM_ESTABLISH_CRED); - if (status != interop.pam.PAM_SUCCESS) return pamDiagnose(status); - - status = interop.pam.pam_open_session(handle, 0); - if (status != interop.pam.PAM_SUCCESS) return pamDiagnose(status); - - return handle.?; -} - -pub fn postFingerprintAuth(config: Config, desktop: Desktop, handle: *interop.pam.pam_handle, login: [:0]const u8) !void { - var tty_buffer: [2]u8 = undefined; - const tty_str = try std.fmt.bufPrintZ(&tty_buffer, "{d}", .{config.tty}); - const current_environment = desktop.environments.items[desktop.current]; - - // Set the XDG environment variables - setXdgSessionEnv(current_environment.display_server); - try setXdgEnv(tty_str, current_environment.xdg_session_desktop, current_environment.xdg_desktop_names orelse ""); - - var pwd: *interop.passwd = undefined; - { - defer interop.endpwent(); - - // Get password structure from username - pwd = interop.getpwnam(login.ptr) orelse return error.GetPasswordNameFailed; - } - - // Set user shell if it hasn't already been set - if (pwd.pw_shell[0] == 0) { - interop.setusershell(); - pwd.pw_shell = interop.getusershell(); - interop.endusershell(); - } - - var shared_err = try SharedError.init(); - defer shared_err.deinit(); - - child_pid = try std.posix.fork(); - if (child_pid == 0) { - startSession(config, pwd, handle, current_environment) catch |e| { - shared_err.writeError(e); - std.process.exit(1); - }; - std.process.exit(0); - } - - var entry: Utmp = std.mem.zeroes(Utmp); - addUtmpEntry(&entry, pwd.pw_name, child_pid) catch {}; - - // If we receive SIGTERM, forward it to child_pid - const act = std.posix.Sigaction{ - .handler = .{ .handler = &sessionSignalHandler }, - .mask = std.posix.empty_sigset, - .flags = 0, - }; - try std.posix.sigaction(std.posix.SIG.TERM, &act, null); - - // Wait for the session to stop - _ = std.posix.waitpid(child_pid, 0); - - removeUtmpEntry(&entry); - - try resetTerminal(pwd.pw_shell, config.term_reset_cmd); - - // Close the PAM session - var status = interop.pam.pam_close_session(handle, 0); - if (status != 0) return pamDiagnose(status); - - status = interop.pam.pam_setcred(handle, interop.pam.PAM_DELETE_CRED); - if (status != 0) return pamDiagnose(status); - - status = interop.pam.pam_end(handle, status); - if (status != 0) return pamDiagnose(status); - - if (shared_err.readError()) |err| return err; -} - fn startSession( config: Config, pwd: *interop.pwd.passwd, diff --git a/src/main.zig b/src/main.zig index b15a956..d361854 100644 --- a/src/main.zig +++ b/src/main.zig @@ -45,7 +45,7 @@ var asyncPamHandle: ?*interop.pam.pam_handle = null; fn fingerprintLogin(config: Config, login: [:0]const u8) !void { // TODO: loop if there was an error - const pamHandle = try auth.fingerprintAuth(config, login); + const pamHandle = try auth.authenticate(config, login, ""); if (currentLogin != null and !std.mem.eql(u8, std.mem.span(@as([*:0]const u8, currentLogin.?)), login)) { return; } @@ -594,18 +594,49 @@ pub fn main() !void { const event_error = termbox.tb_peek_event(&event, @intCast(@min(timeoutEnd - std.time.milliTimestamp(), maxtimeout))); if (asyncPamHandle) |handle| { - if (auth.postFingerprintAuth(config, session, handle, currentLogin.?)) |_| { - try info_line.setText(lang.logout); - } else |err| { - active_input = .password; - try info_line.setText(getAuthErrorMsg(err, lang)); - try startFingerPrintLogin(allocator, config, login); + var shared_err = try SharedError.init(); + defer shared_err.deinit(); + + { + const login_text = try allocator.dupeZ(u8, login.text.items); + defer allocator.free(login_text); + + InfoLine.clearRendered(allocator, buffer) catch {}; + info_line.draw(buffer); + _ = termbox.tb_present(); + + session_pid = try std.posix.fork(); + if (session_pid == 0) { + const current_environment = session.environments.items[session.current]; + auth.finaliseAuth(config, current_environment, handle, login_text) catch |err| { + shared_err.writeError(err); + std.process.exit(1); + }; + + std.process.exit(0); + } + _ = std.posix.waitpid(session_pid, 0); + + session_pid = -1; } + const auth_err = shared_err.readError(); + if (auth_err) |err| { + try info_line.setText(getAuthErrorMsg(err, lang)); + } else { + try info_line.setText(lang.logout); + } asyncPamHandle = null; + try startFingerPrintLogin(allocator, config, login); + try std.posix.tcsetattr(std.posix.STDIN_FILENO, .FLUSH, tb_termios); _ = termbox.tb_clear(); _ = termbox.tb_present(); + + update = true; + + var restore_cursor = std.process.Child.init(&[_][]const u8{ "/bin/sh", "-c", config.term_restore_cursor_cmd }, allocator); + _ = restore_cursor.spawnAndWait() catch .{}; } skipEvent = event_error < 0; if ((event_error < 0 and event_error != -6) or event.type == termbox.TB_EVENT_KEY) break; @@ -721,16 +752,21 @@ pub fn main() !void { _ = termbox.tb_shutdown(); session_pid = try std.posix.fork(); - if (session_pid == 0) { - const current_environment = session.label.list.items[session.label.current]; - auth.authenticate(config, current_environment, login_text, password_text) catch |err| { - shared_err.writeError(err); - std.process.exit(1); - }; - std.process.exit(0); + const current_environment = session.environments.items[session.current]; + if (auth.authenticate(config, login_text, password_text)) |handle| { + if (session_pid == 0) { + auth.finaliseAuth(config, current_environment, handle, login_text) catch |err| { + shared_err.writeError(err); + std.process.exit(1); + }; + + std.process.exit(0); + } + _ = std.posix.waitpid(session_pid, 0); + } else |err| { + shared_err.writeError(err); } - _ = std.posix.waitpid(session_pid, 0); session_pid = -1; }