Fix processing wrt fingerprint login

This also involves a major split of the authentication code, which allows
the fingerprint and password logins to use the same code.
This commit is contained in:
Jaap Aarts
2024-07-18 15:59:23 +02:00
parent 2db48c50c9
commit c42cf125d3
2 changed files with 72 additions and 124 deletions

View File

@@ -23,17 +23,10 @@ pub fn sessionSignalHandler(i: c_int) callconv(.C) void {
if (child_pid > 0) _ = std.c.kill(child_pid, i); 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 { pub fn authenticate(config: Config, login: [:0]const u8, password: [:0]const u8) !*interop.pam.pam_handle {
var tty_buffer: [3]u8 = undefined;
const tty_str = try std.fmt.bufPrintZ(&tty_buffer, "{d}", .{config.tty});
var pam_tty_buffer: [6]u8 = undefined; var pam_tty_buffer: [6]u8 = undefined;
const pam_tty_str = try std.fmt.bufPrintZ(&pam_tty_buffer, "tty{d}", .{config.tty}); 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 // Open the PAM session
var credentials = [_:null]?[*:0]const u8{ login, password }; 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; var handle: ?*interop.pam.pam_handle = undefined;
// Do the PAM routine
var status = interop.pam.pam_start(config.service_name, null, &conv, &handle); var status = interop.pam.pam_start(config.service_name, null, &conv, &handle);
if (status != interop.pam.PAM_SUCCESS) return pamDiagnose(status); 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 // 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); status = interop.pam.pam_set_item(handle, interop.pam.PAM_TTY, pam_tty_str.ptr);
if (status != interop.pam.PAM_SUCCESS) return pamDiagnose(status); if (status != interop.pam.PAM_SUCCESS) return pamDiagnose(status);
// Do the PAM routine
status = interop.pam.pam_authenticate(handle, 0); status = interop.pam.pam_authenticate(handle, 0);
if (status != interop.pam.PAM_SUCCESS) return pamDiagnose(status); 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); if (status != interop.pam.PAM_SUCCESS) return pamDiagnose(status);
status = interop.pam.pam_setcred(handle, interop.pam.PAM_ESTABLISH_CRED); 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); 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_setcred(handle, interop.pam.PAM_DELETE_CRED);
defer status = interop.pam.pam_end(handle, status);
status = interop.pam.pam_open_session(handle, 0); // Set the XDG environment variables
if (status != interop.pam.PAM_SUCCESS) return pamDiagnose(status); setXdgSessionEnv(current_environment.display_server);
defer status = interop.pam.pam_close_session(handle, 0); try setXdgEnv(tty_str, current_environment.xdg_session_desktop orelse "", current_environment.xdg_desktop_names orelse "");
var pwd: *interop.pwd.passwd = undefined; 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; 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( fn startSession(
config: Config, config: Config,
pwd: *interop.pwd.passwd, pwd: *interop.pwd.passwd,

View File

@@ -45,7 +45,7 @@ var asyncPamHandle: ?*interop.pam.pam_handle = null;
fn fingerprintLogin(config: Config, login: [:0]const u8) !void { fn fingerprintLogin(config: Config, login: [:0]const u8) !void {
// TODO: loop if there was an error // 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)) { if (currentLogin != null and !std.mem.eql(u8, std.mem.span(@as([*:0]const u8, currentLogin.?)), login)) {
return; return;
} }
@@ -594,18 +594,49 @@ pub fn main() !void {
const event_error = termbox.tb_peek_event(&event, @intCast(@min(timeoutEnd - std.time.milliTimestamp(), maxtimeout))); const event_error = termbox.tb_peek_event(&event, @intCast(@min(timeoutEnd - std.time.milliTimestamp(), maxtimeout)));
if (asyncPamHandle) |handle| { if (asyncPamHandle) |handle| {
if (auth.postFingerprintAuth(config, session, handle, currentLogin.?)) |_| { var shared_err = try SharedError.init();
try info_line.setText(lang.logout); defer shared_err.deinit();
} else |err| {
active_input = .password; {
try info_line.setText(getAuthErrorMsg(err, lang)); const login_text = try allocator.dupeZ(u8, login.text.items);
try startFingerPrintLogin(allocator, config, login); 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; asyncPamHandle = null;
try startFingerPrintLogin(allocator, config, login);
try std.posix.tcsetattr(std.posix.STDIN_FILENO, .FLUSH, tb_termios); try std.posix.tcsetattr(std.posix.STDIN_FILENO, .FLUSH, tb_termios);
_ = termbox.tb_clear(); _ = termbox.tb_clear();
_ = termbox.tb_present(); _ = 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; skipEvent = event_error < 0;
if ((event_error < 0 and event_error != -6) or event.type == termbox.TB_EVENT_KEY) break; 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(); _ = termbox.tb_shutdown();
session_pid = try std.posix.fork(); session_pid = try std.posix.fork();
const current_environment = session.environments.items[session.current];
if (auth.authenticate(config, login_text, password_text)) |handle| {
if (session_pid == 0) { if (session_pid == 0) {
const current_environment = session.label.list.items[session.label.current]; auth.finaliseAuth(config, current_environment, handle, login_text) catch |err| {
auth.authenticate(config, current_environment, login_text, password_text) catch |err| {
shared_err.writeError(err); shared_err.writeError(err);
std.process.exit(1); std.process.exit(1);
}; };
std.process.exit(0); std.process.exit(0);
} }
_ = std.posix.waitpid(session_pid, 0); _ = std.posix.waitpid(session_pid, 0);
} else |err| {
shared_err.writeError(err);
}
session_pid = -1; session_pid = -1;
} }