diff --git a/res/config.ini b/res/config.ini index 619dd6a..d420af0 100644 --- a/res/config.ini +++ b/res/config.ini @@ -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 diff --git a/res/lang/en.ini b/res/lang/en.ini index 21ccc30..511200e 100644 --- a/res/lang/en.ini +++ b/res/lang/en.ini @@ -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 diff --git a/res/lang/fr.ini b/res/lang/fr.ini index c6c6761..32e5598 100644 --- a/res/lang/fr.ini +++ b/res/lang/fr.ini @@ -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 diff --git a/src/auth.zig b/src/auth.zig index c05b9b3..f9bc28d 100644 --- a/src/auth.zig +++ b/src/auth.zig @@ -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 (status != 0) return error.GroupInitializationFailed; - 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; + // 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); - } - - 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; + return std.fmt.bytesToHex(&out, .lower); } -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) { diff --git a/src/config/Config.zig b/src/config/Config.zig index 64718e4..d20c871 100644 --- a/src/config/Config.zig +++ b/src/config/Config.zig @@ -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", diff --git a/src/config/Lang.zig b/src/config/Lang.zig index 5598c30..3a81108 100644 --- a/src/config/Lang.zig +++ b/src/config/Lang.zig @@ -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", diff --git a/src/config/migrator.zig b/src/config/migrator.zig index 569cdf8..66d4cfc 100644 --- a/src/config/migrator.zig +++ b/src/config/migrator.zig @@ -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; diff --git a/src/interop.zig b/src/interop.zig index beba61c..882c375 100644 --- a/src/interop.zig +++ b/src/interop.zig @@ -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; - 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; + const numlock = (led & numlock_led) != 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; } } diff --git a/src/main.zig b/src/main.zig index 3cd9ac5..1f0b0e8 100644 --- a/src/main.zig +++ b/src/main.zig @@ -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,