Make code more portable + remove mcookie usage

Signed-off-by: AnErrupTion <anerruption@disroot.org>
This commit is contained in:
AnErrupTion 2024-08-01 13:15:54 +02:00
parent 1314c57796
commit 61f3fadfbf
No known key found for this signature in database
GPG Key ID: 3E85EB44F610AD7F
9 changed files with 82 additions and 132 deletions

View File

@ -158,9 +158,6 @@ term_reset_cmd = $PREFIX_DIRECTORY/bin/tput reset
# Terminal restore cursor command
term_restore_cursor_cmd = $PREFIX_DIRECTORY/bin/tput cnorm
# Cookie generator
mcookie_cmd = $PREFIX_DIRECTORY/bin/mcookie
# Wayland setup command
wayland_cmd = $CONFIG_DIRECTORY/ly/wsetup.sh

View File

@ -11,7 +11,6 @@ err_dgn_oob = log message
err_domain = invalid domain
err_envlist = failed to get envlist
err_hostname = failed to get hostname
err_mcookie = mcookie command failed
err_mlock = failed to lock password memory
err_null = null pointer
err_pam = pam transaction failed

View File

@ -11,7 +11,6 @@ err_dgn_oob = message
err_domain = domaine invalide
err_envlist = échec de lecture de la liste d'environnement
err_hostname = échec de lecture du nom d'hôte
err_mcookie = échec de la commande mcookie
err_mlock = échec du verrouillage mémoire
err_null = pointeur null
err_pam = échec de la transaction pam

View File

@ -8,6 +8,7 @@ const Session = @import("tui/components/Session.zig");
const Text = @import("tui/components/Text.zig");
const Config = @import("config/Config.zig");
const Allocator = std.mem.Allocator;
const Md5 = std.crypto.hash.Md5;
const utmp = interop.utmp;
const Utmp = utmp.utmpx;
const SharedError = @import("SharedError.zig");
@ -42,7 +43,7 @@ pub fn authenticate(config: Config, current_environment: Session.Environment, lo
};
var handle: ?*interop.pam.pam_handle = undefined;
var status = interop.pam.pam_start(config.service_name.ptr, null, &conv, &handle);
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);
@ -65,19 +66,19 @@ pub fn authenticate(config: Config, current_environment: Session.Environment, lo
if (status != interop.pam.PAM_SUCCESS) return pamDiagnose(status);
defer status = interop.pam.pam_close_session(handle, 0);
var pwd: *std.c.passwd = undefined;
var pwd: *interop.pwd.passwd = undefined;
{
defer interop.endpwent();
defer interop.pwd.endpwent();
// Get password structure from username
pwd = std.c.getpwnam(login.ptr) orelse return error.GetPasswordNameFailed;
pwd = interop.pwd.getpwnam(login) orelse return error.GetPasswordNameFailed;
}
// Set user shell if it hasn't already been set
if (pwd.pw_shell == null) {
interop.setusershell();
pwd.pw_shell = interop.getusershell();
interop.endusershell();
interop.unistd.setusershell();
pwd.pw_shell = interop.unistd.getusershell();
interop.unistd.endusershell();
}
var shared_err = try SharedError.init();
@ -123,18 +124,22 @@ pub fn authenticate(config: Config, current_environment: Session.Environment, lo
fn startSession(
config: Config,
pwd: *std.c.passwd,
pwd: *interop.pwd.passwd,
handle: ?*interop.pam.pam_handle,
current_environment: Session.Environment,
) !void {
const status = interop.initgroups(pwd.pw_name.?, pwd.pw_gid);
if (builtin.os.tag == .freebsd) {
// FreeBSD has initgroups() in unistd
const status = interop.unistd.initgroups(pwd.pw_name, pwd.pw_gid);
if (status != 0) return error.GroupInitializationFailed;
if (builtin.os.tag == .freebsd) {
// FreeBSD sets the GID and UID with setusercontext()
const result = std.c.setusercontext(null, pwd, pwd.pw_uid, interop.logincap.LOGIN_SETALL);
if (result != 0) return error.SetUserUidFailed;
} else {
const status = interop.grp.initgroups(pwd.pw_name, pwd.pw_gid);
if (status != 0) return error.GroupInitializationFailed;
std.posix.setgid(pwd.pw_gid) catch return error.SetUserGidFailed;
std.posix.setuid(pwd.pw_uid) catch return error.SetUserUidFailed;
}
@ -147,7 +152,7 @@ fn startSession(
if (pam_env_vars == null) return error.GetEnvListFailed;
const env_list = std.mem.span(pam_env_vars.?);
for (env_list) |env_var| _ = interop.putenv(env_var.?);
for (env_list) |env_var| _ = interop.stdlib.putenv(env_var);
// Execute what the user requested
std.posix.chdirZ(pwd.pw_dir.?) catch return error.ChangeDirectoryFailed;
@ -165,21 +170,21 @@ fn startSession(
}
}
fn initEnv(pwd: *std.c.passwd, path_env: ?[:0]const u8) !void {
_ = interop.setenv("HOME", pwd.pw_dir, 1);
_ = interop.setenv("PWD", pwd.pw_dir, 1);
_ = interop.setenv("SHELL", pwd.pw_shell, 1);
_ = interop.setenv("USER", pwd.pw_name, 1);
_ = interop.setenv("LOGNAME", pwd.pw_name, 1);
fn initEnv(pwd: *interop.pwd.passwd, path_env: ?[:0]const u8) !void {
_ = interop.stdlib.setenv("HOME", pwd.pw_dir, 1);
_ = interop.stdlib.setenv("PWD", pwd.pw_dir, 1);
_ = interop.stdlib.setenv("SHELL", pwd.pw_shell, 1);
_ = interop.stdlib.setenv("USER", pwd.pw_name, 1);
_ = interop.stdlib.setenv("LOGNAME", pwd.pw_name, 1);
if (path_env) |path| {
const status = interop.setenv("PATH", path, 1);
const status = interop.stdlib.setenv("PATH", path, 1);
if (status != 0) return error.SetPathFailed;
}
}
fn setXdgSessionEnv(display_server: enums.DisplayServer) void {
_ = interop.setenv("XDG_SESSION_TYPE", switch (display_server) {
_ = interop.stdlib.setenv("XDG_SESSION_TYPE", switch (display_server) {
.wayland => "wayland",
.shell => "tty",
.xinitrc, .x11 => "x11",
@ -192,19 +197,19 @@ fn setXdgEnv(tty_str: [:0]u8, desktop_name: [:0]const u8, xdg_desktop_names: [:0
// XDG_RUNTIME_DIR to fall back to directories inside user's home
// directory.
if (builtin.os.tag != .freebsd) {
const uid = interop.getuid();
const uid = interop.unistd.getuid();
var uid_buffer: [10 + @sizeOf(u32) + 1]u8 = undefined;
const uid_str = try std.fmt.bufPrintZ(&uid_buffer, "/run/user/{d}", .{uid});
_ = interop.setenv("XDG_RUNTIME_DIR", uid_str.ptr, 0);
_ = interop.stdlib.setenv("XDG_RUNTIME_DIR", uid_str, 0);
}
_ = interop.setenv("XDG_CURRENT_DESKTOP", xdg_desktop_names.ptr, 0);
_ = interop.setenv("XDG_SESSION_CLASS", "user", 0);
_ = interop.setenv("XDG_SESSION_ID", "1", 0);
_ = interop.setenv("XDG_SESSION_DESKTOP", desktop_name.ptr, 0);
_ = interop.setenv("XDG_SEAT", "seat0", 0);
_ = interop.setenv("XDG_VTNR", tty_str.ptr, 0);
_ = interop.stdlib.setenv("XDG_CURRENT_DESKTOP", xdg_desktop_names, 0);
_ = interop.stdlib.setenv("XDG_SESSION_CLASS", "user", 0);
_ = interop.stdlib.setenv("XDG_SESSION_ID", "1", 0);
_ = interop.stdlib.setenv("XDG_SESSION_DESKTOP", desktop_name, 0);
_ = interop.stdlib.setenv("XDG_SEAT", "seat0", 0);
_ = interop.stdlib.setenv("XDG_VTNR", tty_str, 0);
}
fn loginConv(
@ -235,7 +240,7 @@ fn loginConv(
status = interop.pam.PAM_BUF_ERR;
break :set_credentials;
};
response[i].resp = username.?.ptr;
response[i].resp = username.?;
},
interop.pam.PAM_PROMPT_ECHO_OFF => {
const data: [*][*:0]u8 = @ptrCast(@alignCast(appdata_ptr));
@ -243,7 +248,7 @@ fn loginConv(
status = interop.pam.PAM_BUF_ERR;
break :set_credentials;
};
response[i].resp = password.?.ptr;
response[i].resp = password.?;
},
interop.pam.PAM_ERROR_MSG => {
status = interop.pam.PAM_CONV_ERR;
@ -349,49 +354,30 @@ fn createXauthFile(pwd: [:0]const u8) ![:0]const u8 {
return xauthority;
}
pub fn mcookie(cmd: [:0]const u8) ![32]u8 {
const pipe = try std.posix.pipe();
defer std.posix.close(pipe[1]);
fn mcookie() [Md5.digest_length * 2]u8 {
var buf: [4096]u8 = undefined;
std.crypto.random.bytes(&buf);
const output = std.fs.File{ .handle = pipe[0] };
defer output.close();
var out: [Md5.digest_length]u8 = undefined;
Md5.hash(&buf, &out, .{});
const pid = try std.posix.fork();
if (pid == 0) {
std.posix.close(pipe[0]);
std.posix.dup2(pipe[1], std.posix.STDOUT_FILENO) catch std.process.exit(1);
std.posix.close(pipe[1]);
const args = [_:null]?[*:0]u8{};
std.posix.execveZ(cmd.ptr, &args, std.c.environ) catch {};
std.process.exit(1);
return std.fmt.bytesToHex(&out, .lower);
}
const result = std.posix.waitpid(pid, 0);
if (result.status != 0) return error.McookieFailed;
var buf: [32]u8 = undefined;
const len = try output.read(&buf);
if (len != 32) return error.McookieFailed;
return buf;
}
fn xauth(display_name: [:0]u8, shell: [*:0]const u8, pw_dir: [*:0]const u8, xauth_cmd: []const u8, mcookie_cmd: [:0]const u8) !void {
fn xauth(display_name: [:0]u8, shell: [*:0]const u8, pw_dir: [*:0]const u8, xauth_cmd: []const u8) !void {
var pwd_buf: [100]u8 = undefined;
const pwd = try std.fmt.bufPrintZ(&pwd_buf, "{s}", .{pw_dir});
const xauthority = try createXauthFile(pwd);
_ = interop.setenv("XAUTHORITY", xauthority, 1);
_ = interop.setenv("DISPLAY", display_name, 1);
_ = interop.stdlib.setenv("XAUTHORITY", xauthority, 1);
_ = interop.stdlib.setenv("DISPLAY", display_name, 1);
const mcookie_output = try mcookie(mcookie_cmd);
const magic_cookie = mcookie();
const pid = try std.posix.fork();
if (pid == 0) {
var cmd_buffer: [1024]u8 = undefined;
const cmd_str = std.fmt.bufPrintZ(&cmd_buffer, "{s} add {s} . {s}", .{ xauth_cmd, display_name, mcookie_output }) catch std.process.exit(1);
const cmd_str = std.fmt.bufPrintZ(&cmd_buffer, "{s} add {s} . {s}", .{ xauth_cmd, display_name, magic_cookie }) catch std.process.exit(1);
const args = [_:null]?[*:0]const u8{ shell, "-c", cmd_str };
std.posix.execveZ(shell, &args, std.c.environ) catch {};
std.process.exit(1);
@ -417,7 +403,7 @@ fn executeX11Cmd(shell: [*:0]const u8, pw_dir: [*:0]const u8, config: Config, de
const display_num = try getFreeDisplay();
var buf: [5]u8 = undefined;
const display_name = try std.fmt.bufPrintZ(&buf, ":{d}", .{display_num});
try xauth(display_name, shell, pw_dir, config.xauth_cmd, config.mcookie_cmd);
try xauth(display_name, shell, pw_dir, config.xauth_cmd);
const pid = try std.posix.fork();
if (pid == 0) {

View File

@ -28,7 +28,6 @@ lang: []const u8 = "en",
load: bool = true,
margin_box_h: u8 = 2,
margin_box_v: u8 = 1,
mcookie_cmd: [:0]const u8 = build_options.prefix_directory ++ "/bin/mcookie",
min_refresh_delta: u16 = 5,
numlock: bool = false,
path: ?[:0]const u8 = "/sbin:/bin:/usr/local/sbin:/usr/local/bin:/usr/bin:/usr/sbin",

View File

@ -12,7 +12,6 @@ err_dgn_oob: []const u8 = "log message",
err_domain: []const u8 = "invalid domain",
err_envlist: []const u8 = "failed to get envlist",
err_hostname: []const u8 = "failed to get hostname",
err_mcookie: []const u8 = "mcookie command failed",
err_mlock: []const u8 = "failed to lock password memory",
err_null: []const u8 = "null pointer",
err_pam: []const u8 = "pam transaction failed",

View File

@ -62,7 +62,8 @@ pub fn configFieldHandler(_: std.mem.Allocator, field: ini.IniField) ?ini.IniFie
if (std.mem.eql(u8, field.key, "wayland_specifier") or
std.mem.eql(u8, field.key, "max_desktop_len") or
std.mem.eql(u8, field.key, "max_login_len") or
std.mem.eql(u8, field.key, "max_password_len"))
std.mem.eql(u8, field.key, "max_password_len") or
std.mem.eql(u8, field.key, "mcookie_cmd"))
{
// The options don't exist anymore
mapped_config_fields = true;

View File

@ -21,6 +21,22 @@ pub const unistd = @cImport({
@cInclude("unistd.h");
});
pub const time = @cImport({
@cInclude("time.h");
});
pub const stdlib = @cImport({
@cInclude("stdlib.h");
});
pub const pwd = @cImport({
@cInclude("pwd.h");
});
pub const grp = @cImport({
@cInclude("grp.h");
});
// FreeBSD-specific headers
pub const logincap = @cImport({
@cInclude("login_cap.h");
@ -40,38 +56,18 @@ pub const vt = @cImport({
@cInclude("sys/vt.h");
});
pub const c_size = usize;
pub const c_uid = u32;
pub const c_gid = u32;
pub const c_time = c_longlong;
pub const tm = extern struct {
tm_sec: c_int,
tm_min: c_int,
tm_hour: c_int,
tm_mday: c_int,
tm_mon: c_int,
tm_year: c_int,
tm_wday: c_int,
tm_yday: c_int,
tm_isdst: c_int,
};
pub extern "c" fn localtime(timer: *const c_time) *tm;
pub extern "c" fn strftime(str: [*:0]u8, maxsize: c_size, format: [*:0]const u8, timeptr: *const tm) c_size;
pub extern "c" fn setenv(name: [*:0]const u8, value: ?[*:0]const u8, overwrite: c_int) c_int;
pub extern "c" fn putenv(name: [*:0]u8) c_int;
pub extern "c" fn getuid() c_uid;
pub extern "c" fn endpwent() void;
pub extern "c" fn setusershell() void;
pub extern "c" fn getusershell() [*:0]u8;
pub extern "c" fn endusershell() void;
pub extern "c" fn initgroups(user: [*:0]const u8, group: c_gid) c_int;
// Used for getting & setting the lock state
const LedState = if (builtin.os.tag.isBSD()) c_int else c_char;
const get_led_state = if (builtin.os.tag.isBSD()) kbio.KDGETLED else kd.KDGKBLED;
const set_led_state = if (builtin.os.tag.isBSD()) kbio.KDSETLED else kd.KDSKBLED;
const numlock_led = if (builtin.os.tag.isBSD()) kbio.LED_NUM else kd.K_NUMLOCK;
const capslock_led = if (builtin.os.tag.isBSD()) kbio.LED_CAP else kd.K_CAPSLOCK;
pub fn timeAsString(buf: [:0]u8, format: [:0]const u8) ![]u8 {
const timer = std.time.timestamp();
const tm_info = localtime(&timer);
const tm_info = time.localtime(&timer);
const len = strftime(buf, buf.len, format, tm_info);
const len = time.strftime(buf, buf.len, format, tm_info);
if (len < 0) return error.CannotGetFormattedTime;
return buf[0..len];
@ -92,47 +88,22 @@ pub fn getLockState(console_dev: []const u8) !struct {
const fd = try std.posix.open(console_dev, .{ .ACCMODE = .RDONLY }, 0);
defer std.posix.close(fd);
var numlock = false;
var capslock = false;
if (builtin.os.tag.isBSD()) {
var led: c_int = undefined;
_ = std.c.ioctl(fd, kbio.KDGETLED, &led);
numlock = (led & kbio.LED_NUM) != 0;
capslock = (led & kbio.LED_CAP) != 0;
} else {
var led: c_char = undefined;
_ = std.c.ioctl(fd, kd.KDGKBLED, &led);
numlock = (led & kd.K_NUMLOCK) != 0;
capslock = (led & kd.K_CAPSLOCK) != 0;
}
var led: LedState = undefined;
_ = std.c.ioctl(fd, get_led_state, &led);
return .{
.numlock = numlock,
.capslock = capslock,
.numlock = (led & numlock_led) != 0,
.capslock = (led & capslock_led) != 0,
};
}
pub fn setNumlock(val: bool) !void {
if (builtin.os.tag.isBSD()) {
var led: c_int = undefined;
_ = std.c.ioctl(0, kbio.KDGETLED, &led);
var led: LedState = undefined;
_ = std.c.ioctl(0, get_led_state, &led);
const numlock = (led & kbio.LED_NUM) != 0;
const numlock = (led & numlock_led) != 0;
if (numlock != val) {
const status = std.c.ioctl(std.posix.STDIN_FILENO, kbio.KDSETLED, led ^ kbio.LED_NUM);
if (status != 0) return error.FailedToSetNumlock;
}
return;
}
var led: c_char = undefined;
_ = std.c.ioctl(0, kd.KDGKBLED, &led);
const numlock = (led & kd.K_NUMLOCK) != 0;
if (numlock != val) {
const status = std.c.ioctl(std.posix.STDIN_FILENO, kd.KDSKBLED, led ^ kd.K_NUMLOCK);
const status = std.c.ioctl(std.posix.STDIN_FILENO, set_led_state, led ^ numlock_led);
if (status != 0) return error.FailedToSetNumlock;
}
}

View File

@ -215,7 +215,7 @@ pub fn main() !void {
const labels_max_length = @max(lang.login.len, lang.password.len);
var seed: u64 = undefined;
try std.posix.getrandom(std.mem.asBytes(&seed)); // Get a random seed for the PRNG (used by animations)
std.crypto.random.bytes(std.mem.asBytes(&seed)); // Get a random seed for the PRNG (used by animations)
var prng = std.Random.DefaultPrng.init(seed);
const random = prng.random();
@ -770,7 +770,6 @@ fn getAuthErrorMsg(err: anyerror, lang: Lang) []const u8 {
error.GetPasswordNameFailed => lang.err_pwnam,
error.GetEnvListFailed => lang.err_envlist,
error.XauthFailed => lang.err_xauth,
error.McookieFailed => lang.err_mcookie,
error.XcbConnectionFailed => lang.err_xcb_conn,
error.GroupInitializationFailed => lang.err_user_init,
error.SetUserGidFailed => lang.err_user_gid,