Skip to content

Commit

Permalink
Fix processing wrt fingerprint login
Browse files Browse the repository at this point in the history
This also involves a major split of the authentication code, which allows
the fingerprint and password logins to use the same code.
  • Loading branch information
JAicewizard committed Jul 18, 2024
1 parent db25ee8 commit 3f43e14
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 124 deletions.
132 changes: 23 additions & 109 deletions src/auth.zig
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,7 @@ 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: Desktop.Environment, login: [:0]const u8, password: [:0]const u8) !void {
var tty_buffer: [2]u8 = undefined;
const tty_str = try std.fmt.bufPrintZ(&tty_buffer, "{d}", .{config.tty});

// 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 "");

pub fn authenticate(config: Config, login: [:0]const u8, password: [:0]const u8) !*interop.pam.pam_handle {
// Open the PAM session
var credentials = [_:null]?[*:0]const u8{ login, password };

Expand All @@ -37,24 +30,41 @@ pub fn authenticate(config: Config, current_environment: Desktop.Environment, lo
};
var handle: ?*interop.pam.pam_handle = undefined;

// Do the PAM routine
var status = interop.pam.pam_start(config.service_name.ptr, null, &conv, &handle);
defer {
if (status != interop.pam.PAM_SUCCESS) _ = interop.pam.pam_end(handle, status);
}
if (status != interop.pam.PAM_SUCCESS) return pamDiagnose(status);
defer _ = interop.pam.pam_end(handle, 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);
defer {
if (status != interop.pam.PAM_SUCCESS) _ = interop.pam.pam_end(handle, status);
}
if (status != interop.pam.PAM_SUCCESS) return pamDiagnose(status);
defer status = interop.pam.pam_setcred(handle, interop.pam.PAM_DELETE_CRED);
return handle.?;
}

pub fn finaliseAuth(config: Config, current_environment: Desktop.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});

status = interop.pam.pam_open_session(handle, 0);
// 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_close_session(handle, 0);
defer status = interop.pam.pam_setcred(handle, interop.pam.PAM_DELETE_CRED);
defer status = interop.pam.pam_end(handle, status);

// 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;
{
Expand Down Expand Up @@ -112,102 +122,6 @@ pub fn authenticate(config: Config, current_environment: Desktop.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.passwd,
Expand Down
77 changes: 62 additions & 15 deletions src/main.zig
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,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;
}
Expand Down Expand Up @@ -515,18 +515,60 @@ 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, desktop, 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);
//const current_environment = desktop.environments.items[desktop.current];
//if (auth.finaliseAuth(config, current_environment, handle, currentLogin.?)) |_| {
// try info_line.setText(lang.logout);
// } else |err| {
// active_input = .password;
// try info_line.setText(getAuthErrorMsg(err, lang));
// }

// try std.posix.tcsetattr(std.posix.STDIN_FILENO, .FLUSH, tb_termios);
// _ = termbox.tb_clear();
// _ = termbox.tb_present();*/
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 = desktop.environments.items[desktop.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;
Expand Down Expand Up @@ -639,16 +681,21 @@ pub fn main() !void {
_ = termbox.tb_present();

session_pid = try std.posix.fork();
if (session_pid == 0) {
const current_environment = desktop.environments.items[desktop.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 = desktop.environments.items[desktop.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;
}

Expand Down

0 comments on commit 3f43e14

Please sign in to comment.