mirror of
https://github.com/fairyglade/ly.git
synced 2026-09-22 20:10:21 +00:00
auth: Implement password reset after expiration (closes #992)
Signed-off-by: AnErrupTion <anerruption@disroot.org>
This commit is contained in:
15
src/auth.zig
15
src/auth.zig
@@ -29,7 +29,7 @@ pub const AuthOptions = struct {
|
||||
const PamAppdata = struct {
|
||||
username: []const u8,
|
||||
password: []const u8,
|
||||
authreq_requested: bool,
|
||||
new_authtok_requested: bool,
|
||||
authreq_responded: bool,
|
||||
new_password: []const u8,
|
||||
};
|
||||
@@ -52,6 +52,7 @@ pub fn authenticate(
|
||||
current_environment: Environment,
|
||||
login: []const u8,
|
||||
password: []const u8,
|
||||
maybe_new_password: ?[]const u8,
|
||||
) !void {
|
||||
var tty_buffer: [3]u8 = undefined;
|
||||
const tty_str = try std.fmt.bufPrint(&tty_buffer, "{d}", .{options.tty});
|
||||
@@ -69,7 +70,7 @@ pub fn authenticate(
|
||||
var credentials: PamAppdata = .{
|
||||
.username = login,
|
||||
.password = password,
|
||||
.authreq_requested = false,
|
||||
.new_authtok_requested = false,
|
||||
.authreq_responded = false,
|
||||
.new_password = "",
|
||||
};
|
||||
@@ -98,9 +99,11 @@ pub fn authenticate(
|
||||
try log_file.info(io, "auth/pam", "validating account", .{});
|
||||
status = interop.pam.pam_acct_mgmt(handle, 0);
|
||||
if (status == interop.pam.PAM_NEW_AUTHTOK_REQD) {
|
||||
// credentials.authreq_requested = true;
|
||||
// credentials.new_password = "";
|
||||
// status = interop.pam.pam_chauthtok(handle, interop.pam.PAM_CHANGE_EXPIRED_AUTHTOK);
|
||||
if (maybe_new_password) |new_passwsord| {
|
||||
credentials.new_authtok_requested = true;
|
||||
credentials.new_password = new_passwsord;
|
||||
status = interop.pam.pam_chauthtok(handle, interop.pam.PAM_CHANGE_EXPIRED_AUTHTOK);
|
||||
}
|
||||
}
|
||||
if (status != interop.pam.PAM_SUCCESS) return pamDiagnose(status);
|
||||
|
||||
@@ -334,7 +337,7 @@ fn loginConv(
|
||||
},
|
||||
interop.pam.PAM_PROMPT_ECHO_OFF => {
|
||||
var pass = data.password;
|
||||
if (data.authreq_requested) {
|
||||
if (data.new_authtok_requested) {
|
||||
if (data.authreq_responded) {
|
||||
pass = data.new_password;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// NOTE: After editing this file, please run `/res/lang/normalize_lang_files.py`
|
||||
// NOTE: After editing this file, please run `res/lang/normalize_lang_files.py`
|
||||
// to update all the language files accordingly.
|
||||
//
|
||||
|
||||
@@ -38,7 +38,6 @@ err_pam_abort: []const u8 = "pam transaction aborted",
|
||||
err_pam_acct_expired: []const u8 = "account expired",
|
||||
err_pam_auth: []const u8 = "authentication error",
|
||||
err_pam_authinfo_unavail: []const u8 = "failed to get user info",
|
||||
err_pam_authok_reqd: []const u8 = "token expired",
|
||||
err_pam_buf: []const u8 = "memory buffer error",
|
||||
err_pam_cred_err: []const u8 = "failed to set credentials",
|
||||
err_pam_cred_expired: []const u8 = "credentials expired",
|
||||
@@ -82,6 +81,7 @@ shell: [:0]const u8 = "shell",
|
||||
shutdown: []const u8 = "shutdown",
|
||||
sleep: []const u8 = "sleep",
|
||||
toggle_password: []const u8 = "toggle password",
|
||||
token_expired: []const u8 = "password expired, please reset",
|
||||
wayland: []const u8 = "wayland",
|
||||
x11: []const u8 = "x11",
|
||||
xinitrc: [:0]const u8 = "xinitrc",
|
||||
|
||||
42
src/main.zig
42
src/main.zig
@@ -113,6 +113,7 @@ const UiState = struct {
|
||||
login_text: ?*Text,
|
||||
password: *Text,
|
||||
password_widget: *Widget,
|
||||
maybe_old_password: ?[]const u8,
|
||||
insert_mode: bool,
|
||||
edge_margin: Position,
|
||||
config: Config,
|
||||
@@ -889,6 +890,9 @@ pub fn main(init: std.process.Init) !void {
|
||||
);
|
||||
defer state.password_label.deinit();
|
||||
|
||||
state.maybe_old_password = null;
|
||||
defer if (state.maybe_old_password) |pass| state.allocator.free(pass);
|
||||
|
||||
state.insert_mode = !state.config.vi_mode or state.config.vi_default_mode == .insert;
|
||||
|
||||
state.password = try Text.init(
|
||||
@@ -1633,7 +1637,8 @@ fn authenticate(ptr: *anyopaque) !bool {
|
||||
auth_options,
|
||||
current_environment,
|
||||
if (state.login_text) |box| box.text.items else state.login.?.getCurrentUsername(),
|
||||
password_text,
|
||||
if (state.maybe_old_password) |pass| pass else password_text,
|
||||
if (state.maybe_old_password != null) password_text else null,
|
||||
) catch |err| {
|
||||
shared_err.writeError(err);
|
||||
|
||||
@@ -1645,12 +1650,19 @@ fn authenticate(ptr: *anyopaque) !bool {
|
||||
std.process.exit(0);
|
||||
}
|
||||
|
||||
var session_status: c_int = undefined;
|
||||
_ = std.posix.system.waitpid(session_pid, &session_status, 0);
|
||||
// HACK: It seems like the session process is not exiting immediately after the waitpid call.
|
||||
// This is a workaround to ensure the session process has exited before re-initializing the TTY.
|
||||
state.io.sleep(.fromSeconds(1), .real) catch {};
|
||||
session_pid = -1;
|
||||
if (state.maybe_old_password) |pass| {
|
||||
state.allocator.free(pass);
|
||||
state.maybe_old_password = null;
|
||||
}
|
||||
|
||||
if (session_pid != -1) {
|
||||
var session_status: c_int = undefined;
|
||||
_ = std.posix.system.waitpid(session_pid, &session_status, 0);
|
||||
// HACK: It seems like the session process is not exiting immediately after the waitpid call.
|
||||
// This is a workaround to ensure the session process has exited before re-initializing the TTY.
|
||||
state.io.sleep(.fromSeconds(1), .real) catch {};
|
||||
session_pid = -1;
|
||||
}
|
||||
|
||||
try state.log_file.reinit(state.io);
|
||||
}
|
||||
@@ -1658,7 +1670,20 @@ fn authenticate(ptr: *anyopaque) !bool {
|
||||
try state.buffer.reclaim();
|
||||
|
||||
const auth_err = shared_err.readError();
|
||||
if (auth_err) |err| {
|
||||
if (auth_err) |err| handle_error: {
|
||||
if (err == error.PamNewAuthTokenRequired) {
|
||||
try state.info_line.addMessage(
|
||||
state.lang.token_expired,
|
||||
state.config.bg,
|
||||
state.config.fg,
|
||||
);
|
||||
|
||||
state.maybe_old_password = try state.allocator.dupe(u8, state.password.text.items);
|
||||
state.password.clear();
|
||||
state.is_autologin = false;
|
||||
break :handle_error;
|
||||
}
|
||||
|
||||
state.auth_fails += 1;
|
||||
state.buffer.setActiveWidget(state.password_widget);
|
||||
|
||||
@@ -2611,7 +2636,6 @@ fn getAuthErrorMsg(err: anyerror, lang: Lang) []const u8 {
|
||||
error.PamCredentialsInsufficient => lang.err_pam_cred_insufficient,
|
||||
error.PamCredentialsUnavailable => lang.err_pam_cred_unavail,
|
||||
error.PamMaximumTries => lang.err_pam_maxtries,
|
||||
error.PamNewAuthTokenRequired => lang.err_pam_authok_reqd,
|
||||
error.PamPermissionDenied => lang.err_pam_perm_denied,
|
||||
error.PamSessionError => lang.err_pam_session,
|
||||
error.PamSystemError => lang.err_pam_sys,
|
||||
|
||||
Reference in New Issue
Block a user