mirror of https://github.com/fairyglade/ly.git
Reduce libc usage & move more stuff to interop
Signed-off-by: AnErrupTion <anerruption@disroot.org>
This commit is contained in:
parent
336847d418
commit
7cfb947187
|
@ -6,17 +6,17 @@ const Ini = ini.Ini;
|
|||
|
||||
pub const DesktopEntry = struct {
|
||||
Exec: []const u8 = "",
|
||||
Name: [:0]const u8 = "",
|
||||
DesktopNames: ?[:0]u8 = null,
|
||||
Name: []const u8 = "",
|
||||
DesktopNames: ?[]u8 = null,
|
||||
Terminal: ?bool = null,
|
||||
};
|
||||
|
||||
pub const Entry = struct { @"Desktop Entry": DesktopEntry = .{} };
|
||||
|
||||
entry_ini: ?Ini(Entry) = null,
|
||||
name: [:0]const u8 = "",
|
||||
xdg_session_desktop: ?[:0]const u8 = null,
|
||||
xdg_desktop_names: ?[:0]const u8 = null,
|
||||
name: []const u8 = "",
|
||||
xdg_session_desktop: ?[]const u8 = null,
|
||||
xdg_desktop_names: ?[]const u8 = null,
|
||||
cmd: []const u8 = "",
|
||||
specifier: []const u8 = "",
|
||||
display_server: DisplayServer = .wayland,
|
||||
|
|
|
@ -2,5 +2,5 @@ const std = @import("std");
|
|||
|
||||
// We set both values to 0 by default so that, in case they aren't present in
|
||||
// the login.defs for some reason, then only the root username will be shown
|
||||
uid_min: std.c.uid_t = 0,
|
||||
uid_max: std.c.uid_t = 0,
|
||||
uid_min: std.posix.uid_t = 0,
|
||||
uid_max: std.posix.uid_t = 0,
|
||||
|
|
180
src/auth.zig
180
src/auth.zig
|
@ -14,7 +14,7 @@ const Utmp = utmp.utmpx;
|
|||
pub const AuthOptions = struct {
|
||||
tty: u8,
|
||||
service_name: [:0]const u8,
|
||||
path: ?[:0]const u8,
|
||||
path: ?[]const u8,
|
||||
session_log: ?[]const u8,
|
||||
xauth_cmd: []const u8,
|
||||
setup_cmd: []const u8,
|
||||
|
@ -33,15 +33,15 @@ pub fn sessionSignalHandler(i: c_int) callconv(.c) void {
|
|||
if (child_pid > 0) _ = std.c.kill(child_pid, i);
|
||||
}
|
||||
|
||||
pub fn authenticate(options: AuthOptions, current_environment: Environment, login: [:0]const u8, password: [:0]const u8) !void {
|
||||
pub fn authenticate(allocator: std.mem.Allocator, options: AuthOptions, current_environment: Environment, login: [:0]const u8, password: [:0]const u8) !void {
|
||||
var tty_buffer: [3]u8 = undefined;
|
||||
const tty_str = try std.fmt.bufPrintZ(&tty_buffer, "{d}", .{options.tty});
|
||||
const tty_str = try std.fmt.bufPrint(&tty_buffer, "{d}", .{options.tty});
|
||||
|
||||
var pam_tty_buffer: [6]u8 = undefined;
|
||||
const pam_tty_str = try std.fmt.bufPrintZ(&pam_tty_buffer, "tty{d}", .{options.tty});
|
||||
|
||||
// Set the XDG environment variables
|
||||
try setXdgEnv(tty_str, current_environment);
|
||||
try setXdgEnv(allocator, tty_str, current_environment);
|
||||
|
||||
// Open the PAM session
|
||||
var credentials = [_:null]?[*:0]const u8{ login, password };
|
||||
|
@ -75,27 +75,23 @@ pub fn authenticate(options: AuthOptions, current_environment: Environment, logi
|
|||
if (status != interop.pam.PAM_SUCCESS) return pamDiagnose(status);
|
||||
defer status = interop.pam.pam_close_session(handle, 0);
|
||||
|
||||
var pwd: *interop.pwd.passwd = undefined;
|
||||
var user_entry: interop.UsernameEntry = undefined;
|
||||
{
|
||||
defer interop.pwd.endpwent();
|
||||
defer interop.closePasswordDatabase();
|
||||
|
||||
// Get password structure from username
|
||||
pwd = interop.pwd.getpwnam(login) orelse return error.GetPasswordNameFailed;
|
||||
user_entry = interop.getUsernameEntry(login) orelse return error.GetPasswordNameFailed;
|
||||
}
|
||||
|
||||
// Set user shell if it hasn't already been set
|
||||
if (pwd.pw_shell == null) {
|
||||
interop.unistd.setusershell();
|
||||
pwd.pw_shell = interop.unistd.getusershell();
|
||||
interop.unistd.endusershell();
|
||||
}
|
||||
if (user_entry.shell == null) interop.setUserShell(&user_entry);
|
||||
|
||||
var shared_err = try SharedError.init();
|
||||
defer shared_err.deinit();
|
||||
|
||||
child_pid = try std.posix.fork();
|
||||
if (child_pid == 0) {
|
||||
startSession(options, tty_str, pwd, handle, current_environment) catch |e| {
|
||||
startSession(allocator, options, tty_str, user_entry, handle, current_environment) catch |e| {
|
||||
shared_err.writeError(e);
|
||||
std.process.exit(1);
|
||||
};
|
||||
|
@ -119,7 +115,7 @@ pub fn authenticate(options: AuthOptions, current_environment: Environment, logi
|
|||
};
|
||||
std.posix.sigaction(std.posix.SIG.TERM, &act, null);
|
||||
|
||||
try addUtmpEntry(&entry, pwd.pw_name.?, child_pid);
|
||||
try addUtmpEntry(&entry, user_entry.username.?, child_pid);
|
||||
}
|
||||
// Wait for the session to stop
|
||||
_ = std.posix.waitpid(child_pid, 0);
|
||||
|
@ -130,99 +126,89 @@ pub fn authenticate(options: AuthOptions, current_environment: Environment, logi
|
|||
}
|
||||
|
||||
fn startSession(
|
||||
allocator: std.mem.Allocator,
|
||||
options: AuthOptions,
|
||||
tty_str: [:0]u8,
|
||||
pwd: *interop.pwd.passwd,
|
||||
tty_str: []u8,
|
||||
user_entry: interop.UsernameEntry,
|
||||
handle: ?*interop.pam.pam_handle,
|
||||
current_environment: Environment,
|
||||
) !void {
|
||||
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 = interop.pwd.setusercontext(null, pwd, pwd.pw_uid, interop.pwd.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;
|
||||
}
|
||||
// Set the user's GID & PID
|
||||
try interop.setUserContext(allocator, user_entry);
|
||||
|
||||
// Set up the environment
|
||||
try initEnv(pwd, options.path);
|
||||
try initEnv(allocator, user_entry, options.path);
|
||||
|
||||
// Reset the XDG environment variables
|
||||
try setXdgEnv(tty_str, current_environment);
|
||||
try setXdgEnv(allocator, tty_str, current_environment);
|
||||
|
||||
// Set the PAM variables
|
||||
const pam_env_vars: ?[*:null]?[*:0]u8 = interop.pam.pam_getenvlist(handle);
|
||||
if (pam_env_vars == null) return error.GetEnvListFailed;
|
||||
|
||||
const env_list = std.mem.span(pam_env_vars.?);
|
||||
for (env_list) |env_var| _ = interop.stdlib.putenv(env_var);
|
||||
for (env_list) |env_var| try interop.putEnvironmentVariable(env_var);
|
||||
|
||||
// Change to the user's home directory
|
||||
std.posix.chdirZ(pwd.pw_dir.?) catch return error.ChangeDirectoryFailed;
|
||||
std.posix.chdir(user_entry.home.?) catch return error.ChangeDirectoryFailed;
|
||||
|
||||
// Signal to the session process to give up control on the TTY
|
||||
std.posix.kill(options.session_pid, std.posix.SIG.CHLD) catch return error.TtyControlTransferFailed;
|
||||
|
||||
// Execute what the user requested
|
||||
switch (current_environment.display_server) {
|
||||
.wayland => try executeWaylandCmd(pwd.pw_shell.?, options, current_environment.cmd),
|
||||
.shell => try executeShellCmd(pwd.pw_shell.?, options),
|
||||
.wayland => try executeWaylandCmd(allocator, user_entry.shell.?, options, current_environment.cmd),
|
||||
.shell => try executeShellCmd(allocator, user_entry.shell.?, options),
|
||||
.xinitrc, .x11 => if (build_options.enable_x11_support) {
|
||||
var vt_buf: [5]u8 = undefined;
|
||||
const vt = try std.fmt.bufPrint(&vt_buf, "vt{d}", .{options.tty});
|
||||
try executeX11Cmd(pwd.pw_shell.?, pwd.pw_dir.?, options, current_environment.cmd, vt);
|
||||
try executeX11Cmd(allocator, user_entry.shell.?, user_entry.home.?, options, current_environment.cmd, vt);
|
||||
},
|
||||
.custom => try executeCustomCmd(pwd.pw_shell.?, options, current_environment.is_terminal, current_environment.cmd),
|
||||
.custom => try executeCustomCmd(allocator, user_entry.shell.?, options, current_environment.is_terminal, current_environment.cmd),
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
fn initEnv(allocator: std.mem.Allocator, entry: interop.UsernameEntry, path_env: ?[]const u8) !void {
|
||||
if (entry.home) |home| {
|
||||
try interop.setEnvironmentVariable(allocator, "HOME", home, true);
|
||||
try interop.setEnvironmentVariable(allocator, "PWD", home, true);
|
||||
} else return error.NoHomeDirectory;
|
||||
|
||||
try interop.setEnvironmentVariable(allocator, "SHELL", entry.shell.?, true);
|
||||
try interop.setEnvironmentVariable(allocator, "USER", entry.username.?, true);
|
||||
try interop.setEnvironmentVariable(allocator, "LOGNAME", entry.username.?, true);
|
||||
|
||||
if (path_env) |path| {
|
||||
const status = interop.stdlib.setenv("PATH", path, 1);
|
||||
if (status != 0) return error.SetPathFailed;
|
||||
interop.setEnvironmentVariable(allocator, "PATH", path, true) catch return error.SetPathFailed;
|
||||
}
|
||||
}
|
||||
|
||||
fn setXdgEnv(tty_str: [:0]u8, environment: Environment) !void {
|
||||
_ = interop.stdlib.setenv("XDG_SESSION_TYPE", switch (environment.display_server) {
|
||||
fn setXdgEnv(allocator: std.mem.Allocator, tty_str: []u8, environment: Environment) !void {
|
||||
try interop.setEnvironmentVariable(allocator, "XDG_SESSION_TYPE", switch (environment.display_server) {
|
||||
.wayland => "wayland",
|
||||
.shell => "tty",
|
||||
.xinitrc, .x11 => "x11",
|
||||
.custom => "unspecified",
|
||||
}, 0);
|
||||
}, false);
|
||||
|
||||
// The "/run/user/%d" directory is not available on FreeBSD. It is much
|
||||
// better to stick to the defaults and let applications using
|
||||
// XDG_RUNTIME_DIR to fall back to directories inside user's home
|
||||
// directory.
|
||||
if (builtin.os.tag != .freebsd) {
|
||||
const uid = interop.unistd.getuid();
|
||||
const uid = std.posix.getuid();
|
||||
var uid_buffer: [32]u8 = undefined; // No UID can be larger than this
|
||||
const uid_str = try std.fmt.bufPrintZ(&uid_buffer, "/run/user/{d}", .{uid});
|
||||
const uid_str = try std.fmt.bufPrint(&uid_buffer, "/run/user/{d}", .{uid});
|
||||
|
||||
_ = interop.stdlib.setenv("XDG_RUNTIME_DIR", uid_str, 0);
|
||||
try interop.setEnvironmentVariable(allocator, "XDG_RUNTIME_DIR", uid_str, false);
|
||||
}
|
||||
|
||||
if (environment.xdg_desktop_names) |xdg_desktop_names| _ = 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);
|
||||
if (environment.xdg_session_desktop) |desktop_name| _ = interop.stdlib.setenv("XDG_SESSION_DESKTOP", desktop_name, 0);
|
||||
_ = interop.stdlib.setenv("XDG_SEAT", "seat0", 0);
|
||||
_ = interop.stdlib.setenv("XDG_VTNR", tty_str, 0);
|
||||
if (environment.xdg_desktop_names) |xdg_desktop_names| try interop.setEnvironmentVariable(allocator, "XDG_CURRENT_DESKTOP", xdg_desktop_names, false);
|
||||
try interop.setEnvironmentVariable(allocator, "XDG_SESSION_CLASS", "user", false);
|
||||
try interop.setEnvironmentVariable(allocator, "XDG_SESSION_ID", "1", false);
|
||||
if (environment.xdg_session_desktop) |desktop_name| try interop.setEnvironmentVariable(allocator, "XDG_SESSION_DESKTOP", desktop_name, false);
|
||||
try interop.setEnvironmentVariable(allocator, "XDG_SEAT", "seat0", false);
|
||||
try interop.setEnvironmentVariable(allocator, "XDG_VTNR", tty_str, false);
|
||||
}
|
||||
|
||||
fn loginConv(
|
||||
|
@ -274,8 +260,8 @@ fn loginConv(
|
|||
if (status != interop.pam.PAM_SUCCESS) {
|
||||
// Memory is freed by pam otherwise
|
||||
allocator.free(response);
|
||||
if (username != null) allocator.free(username.?);
|
||||
if (password != null) allocator.free(password.?);
|
||||
if (username) |str| allocator.free(str);
|
||||
if (password) |str| allocator.free(str);
|
||||
} else {
|
||||
resp.?.* = response.ptr;
|
||||
}
|
||||
|
@ -310,7 +296,7 @@ fn getXPid(display_num: u8) !i32 {
|
|||
return std.fmt.parseInt(i32, std.mem.trim(u8, buffer[0..written], " "), 10);
|
||||
}
|
||||
|
||||
fn createXauthFile(pwd: [:0]const u8) ![:0]const u8 {
|
||||
fn createXauthFile(pwd: [:0]const u8) ![]const u8 {
|
||||
var xauth_buf: [100]u8 = undefined;
|
||||
var xauth_dir: [:0]const u8 = undefined;
|
||||
const xdg_rt_dir = std.posix.getenv("XDG_RUNTIME_DIR");
|
||||
|
@ -351,8 +337,8 @@ fn createXauthFile(pwd: [:0]const u8) ![:0]const u8 {
|
|||
const trimmed_xauth_dir = xauth_dir[0 .. i + 1];
|
||||
|
||||
var buf: [256]u8 = undefined;
|
||||
const xauthority: [:0]u8 = try std.fmt.bufPrintZ(&buf, "{s}/{s}", .{ trimmed_xauth_dir, xauth_file });
|
||||
const file = try std.fs.createFileAbsoluteZ(xauthority, .{});
|
||||
const xauthority: []u8 = try std.fmt.bufPrint(&buf, "{s}/{s}", .{ trimmed_xauth_dir, xauth_file });
|
||||
const file = try std.fs.createFileAbsolute(xauthority, .{});
|
||||
file.close();
|
||||
|
||||
return xauthority;
|
||||
|
@ -368,13 +354,13 @@ fn mcookie() [Md5.digest_length * 2]u8 {
|
|||
return std.fmt.bytesToHex(&out, .lower);
|
||||
}
|
||||
|
||||
fn xauth(display_name: [:0]u8, shell: [*:0]const u8, pw_dir: [*:0]const u8, options: AuthOptions) !void {
|
||||
fn xauth(allocator: std.mem.Allocator, display_name: []u8, shell: [*:0]const u8, pw_dir: [*:0]const u8, options: AuthOptions) !void {
|
||||
var pwd_buf: [100]u8 = undefined;
|
||||
const pwd = try std.fmt.bufPrintZ(&pwd_buf, "{s}", .{pw_dir});
|
||||
|
||||
const xauthority = try createXauthFile(pwd);
|
||||
_ = interop.stdlib.setenv("XAUTHORITY", xauthority, 1);
|
||||
_ = interop.stdlib.setenv("DISPLAY", display_name, 1);
|
||||
try interop.setEnvironmentVariable(allocator, "XAUTHORITY", xauthority, true);
|
||||
try interop.setEnvironmentVariable(allocator, "DISPLAY", display_name, true);
|
||||
|
||||
const magic_cookie = mcookie();
|
||||
|
||||
|
@ -391,40 +377,53 @@ fn xauth(display_name: [:0]u8, shell: [*:0]const u8, pw_dir: [*:0]const u8, opti
|
|||
if (status.status != 0) return error.XauthFailed;
|
||||
}
|
||||
|
||||
fn executeShellCmd(shell: [*:0]const u8, options: AuthOptions) !void {
|
||||
fn executeShellCmd(allocator: std.mem.Allocator, shell: []const u8, options: AuthOptions) !void {
|
||||
// We don't want to redirect stdout and stderr in a shell session
|
||||
|
||||
const shell_z = try allocator.dupeZ(u8, shell);
|
||||
defer allocator.free(shell_z);
|
||||
|
||||
var cmd_buffer: [1024]u8 = undefined;
|
||||
const cmd_str = try std.fmt.bufPrintZ(&cmd_buffer, "{s} {s} {s}", .{ options.setup_cmd, options.login_cmd orelse "", shell });
|
||||
const args = [_:null]?[*:0]const u8{ shell, "-c", cmd_str };
|
||||
return std.posix.execveZ(shell, &args, std.c.environ);
|
||||
const args = [_:null]?[*:0]const u8{ shell_z, "-c", cmd_str };
|
||||
return std.posix.execveZ(shell_z, &args, std.c.environ);
|
||||
}
|
||||
|
||||
fn executeWaylandCmd(shell: [*:0]const u8, options: AuthOptions, desktop_cmd: []const u8) !void {
|
||||
fn executeWaylandCmd(allocator: std.mem.Allocator, shell: []const u8, options: AuthOptions, desktop_cmd: []const u8) !void {
|
||||
var maybe_log_file: ?std.fs.File = null;
|
||||
if (options.session_log) |log_path| {
|
||||
maybe_log_file = try redirectStandardStreams(log_path, true);
|
||||
}
|
||||
defer if (maybe_log_file) |log_file| log_file.close();
|
||||
|
||||
const shell_z = try allocator.dupeZ(u8, shell);
|
||||
defer allocator.free(shell_z);
|
||||
|
||||
var cmd_buffer: [1024]u8 = undefined;
|
||||
const cmd_str = try std.fmt.bufPrintZ(&cmd_buffer, "{s} {s} {s}", .{ options.setup_cmd, options.login_cmd orelse "", desktop_cmd });
|
||||
const args = [_:null]?[*:0]const u8{ shell, "-c", cmd_str };
|
||||
return std.posix.execveZ(shell, &args, std.c.environ);
|
||||
const args = [_:null]?[*:0]const u8{ shell_z, "-c", cmd_str };
|
||||
return std.posix.execveZ(shell_z, &args, std.c.environ);
|
||||
}
|
||||
|
||||
fn executeX11Cmd(shell: [*:0]const u8, pw_dir: [*:0]const u8, options: AuthOptions, desktop_cmd: []const u8, vt: []const u8) !void {
|
||||
fn executeX11Cmd(allocator: std.mem.Allocator, shell: []const u8, home: []const u8, options: AuthOptions, desktop_cmd: []const u8, vt: []const u8) !void {
|
||||
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, options);
|
||||
const display_name = try std.fmt.bufPrint(&buf, ":{d}", .{display_num});
|
||||
|
||||
const shell_z = try allocator.dupeZ(u8, shell);
|
||||
defer allocator.free(shell_z);
|
||||
|
||||
const home_z = try allocator.dupeZ(u8, home);
|
||||
defer allocator.free(home_z);
|
||||
|
||||
try xauth(allocator, display_name, shell_z, home_z, options);
|
||||
|
||||
const pid = try std.posix.fork();
|
||||
if (pid == 0) {
|
||||
var cmd_buffer: [1024]u8 = undefined;
|
||||
const cmd_str = std.fmt.bufPrintZ(&cmd_buffer, "{s} {s} {s}", .{ options.x_cmd, display_name, vt }) catch std.process.exit(1);
|
||||
const args = [_:null]?[*:0]const u8{ shell, "-c", cmd_str };
|
||||
std.posix.execveZ(shell, &args, std.c.environ) catch {};
|
||||
const args = [_:null]?[*:0]const u8{ shell_z, "-c", cmd_str };
|
||||
std.posix.execveZ(shell_z, &args, std.c.environ) catch {};
|
||||
std.process.exit(1);
|
||||
}
|
||||
|
||||
|
@ -446,8 +445,8 @@ fn executeX11Cmd(shell: [*:0]const u8, pw_dir: [*:0]const u8, options: AuthOptio
|
|||
if (xorg_pid == 0) {
|
||||
var cmd_buffer: [1024]u8 = undefined;
|
||||
const cmd_str = std.fmt.bufPrintZ(&cmd_buffer, "{s} {s} {s}", .{ options.setup_cmd, options.login_cmd orelse "", desktop_cmd }) catch std.process.exit(1);
|
||||
const args = [_:null]?[*:0]const u8{ shell, "-c", cmd_str };
|
||||
std.posix.execveZ(shell, &args, std.c.environ) catch {};
|
||||
const args = [_:null]?[*:0]const u8{ shell_z, "-c", cmd_str };
|
||||
std.posix.execveZ(shell_z, &args, std.c.environ) catch {};
|
||||
std.process.exit(1);
|
||||
}
|
||||
|
||||
|
@ -467,11 +466,10 @@ fn executeX11Cmd(shell: [*:0]const u8, pw_dir: [*:0]const u8, options: AuthOptio
|
|||
std.Thread.sleep(std.time.ns_per_s * 1); // Wait 1 second before sending SIGKILL
|
||||
std.posix.kill(x_pid, std.posix.SIG.KILL) catch return;
|
||||
|
||||
var status: c_int = 0;
|
||||
_ = std.c.waitpid(x_pid, &status, 0);
|
||||
_ = std.posix.waitpid(x_pid, 0);
|
||||
}
|
||||
|
||||
fn executeCustomCmd(shell: [*:0]const u8, options: AuthOptions, is_terminal: bool, exec_cmd: []const u8) !void {
|
||||
fn executeCustomCmd(allocator: std.mem.Allocator, shell: []const u8, options: AuthOptions, is_terminal: bool, exec_cmd: []const u8) !void {
|
||||
var maybe_log_file: ?std.fs.File = null;
|
||||
if (!is_terminal) {
|
||||
// For custom desktop entries, the "Terminal" value here determines if
|
||||
|
@ -483,10 +481,13 @@ fn executeCustomCmd(shell: [*:0]const u8, options: AuthOptions, is_terminal: boo
|
|||
}
|
||||
defer if (maybe_log_file) |log_file| log_file.close();
|
||||
|
||||
const shell_z = try allocator.dupeZ(u8, shell);
|
||||
defer allocator.free(shell_z);
|
||||
|
||||
var cmd_buffer: [1024]u8 = undefined;
|
||||
const cmd_str = try std.fmt.bufPrintZ(&cmd_buffer, "{s} {s} {s}", .{ options.setup_cmd, options.login_cmd orelse "", exec_cmd });
|
||||
const args = [_:null]?[*:0]const u8{ shell, "-c", cmd_str };
|
||||
return std.posix.execveZ(shell, &args, std.c.environ);
|
||||
const args = [_:null]?[*:0]const u8{ shell_z, "-c", cmd_str };
|
||||
return std.posix.execveZ(shell_z, &args, std.c.environ);
|
||||
}
|
||||
|
||||
fn redirectStandardStreams(session_log: []const u8, create: bool) !std.fs.File {
|
||||
|
@ -498,7 +499,7 @@ fn redirectStandardStreams(session_log: []const u8, create: bool) !std.fs.File {
|
|||
return log_file;
|
||||
}
|
||||
|
||||
fn addUtmpEntry(entry: *Utmp, username: [*:0]const u8, pid: c_int) !void {
|
||||
fn addUtmpEntry(entry: *Utmp, username: []const u8, pid: c_int) !void {
|
||||
entry.ut_type = utmp.USER_PROCESS;
|
||||
entry.ut_pid = pid;
|
||||
|
||||
|
@ -520,12 +521,11 @@ fn addUtmpEntry(entry: *Utmp, username: [*:0]const u8, pid: c_int) !void {
|
|||
host[0] = 0;
|
||||
entry.ut_host = host;
|
||||
|
||||
var tv: interop.system_time.timeval = undefined;
|
||||
_ = interop.system_time.gettimeofday(&tv, null);
|
||||
const time = try interop.getTimeOfDay();
|
||||
|
||||
entry.ut_tv = .{
|
||||
.tv_sec = @intCast(tv.tv_sec),
|
||||
.tv_usec = @intCast(tv.tv_usec),
|
||||
.tv_sec = @intCast(time.seconds),
|
||||
.tv_usec = @intCast(time.microseconds),
|
||||
};
|
||||
entry.ut_addr_v6[0] = 0;
|
||||
|
||||
|
|
|
@ -11,13 +11,11 @@ pub const WIDTH = Lang.WIDTH;
|
|||
pub const HEIGHT = Lang.HEIGHT;
|
||||
pub const SIZE = Lang.SIZE;
|
||||
|
||||
pub fn clockCell(animate: bool, char: u8, fg: u32, bg: u32, bigclock: Bigclock) [SIZE]Cell {
|
||||
pub fn clockCell(animate: bool, char: u8, fg: u32, bg: u32, bigclock: Bigclock) ![SIZE]Cell {
|
||||
var cells: [SIZE]Cell = undefined;
|
||||
|
||||
var tv: interop.system_time.timeval = undefined;
|
||||
_ = interop.system_time.gettimeofday(&tv, null);
|
||||
|
||||
const clock_chars = toBigNumber(if (animate and char == ':' and @divTrunc(tv.tv_usec, 500000) != 0) ' ' else char, bigclock);
|
||||
const time = try interop.getTimeOfDay();
|
||||
const clock_chars = toBigNumber(if (animate and char == ':' and @divTrunc(time.microseconds, 500000) != 0) ' ' else char, bigclock);
|
||||
for (0..cells.len) |i| cells[i] = Cell.init(clock_chars[i], fg, bg);
|
||||
|
||||
return cells;
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
const builtin = @import("builtin");
|
||||
const interop = @import("../interop.zig");
|
||||
|
||||
pub const WIDTH = 5;
|
||||
pub const HEIGHT = 5;
|
||||
pub const SIZE = WIDTH * HEIGHT;
|
||||
|
||||
pub const X: u32 = if (builtin.os.tag == .linux or builtin.os.tag.isBSD()) 0x2593 else '#';
|
||||
pub const X: u32 = if (interop.supportsUnicode()) 0x2593 else '#';
|
||||
pub const O: u32 = 0;
|
||||
|
||||
// zig fmt: off
|
||||
|
|
|
@ -61,7 +61,7 @@ margin_box_h: u8 = 2,
|
|||
margin_box_v: u8 = 1,
|
||||
min_refresh_delta: u16 = 5,
|
||||
numlock: bool = false,
|
||||
path: ?[:0]const u8 = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
|
||||
path: ?[]const u8 = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
|
||||
restart_cmd: []const u8 = "/sbin/shutdown -r now",
|
||||
restart_key: []const u8 = "F2",
|
||||
save: bool = true,
|
||||
|
|
156
src/interop.zig
156
src/interop.zig
|
@ -2,6 +2,19 @@ const std = @import("std");
|
|||
const builtin = @import("builtin");
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
pub const TimeOfDay = struct {
|
||||
seconds: i64,
|
||||
microseconds: i64,
|
||||
};
|
||||
|
||||
pub const UsernameEntry = struct {
|
||||
username: ?[]const u8,
|
||||
uid: std.posix.uid_t,
|
||||
gid: std.posix.gid_t,
|
||||
home: ?[]const u8,
|
||||
shell: ?[]const u8,
|
||||
};
|
||||
|
||||
pub const termbox = @import("termbox2");
|
||||
|
||||
pub const pam = @cImport({
|
||||
|
@ -17,44 +30,44 @@ pub const xcb = @cImport({
|
|||
@cInclude("xcb/xcb.h");
|
||||
});
|
||||
|
||||
pub const unistd = @cImport({
|
||||
@cInclude("unistd.h");
|
||||
});
|
||||
|
||||
pub const time = @cImport({
|
||||
@cInclude("time.h");
|
||||
});
|
||||
|
||||
pub const system_time = @cImport({
|
||||
@cInclude("sys/time.h");
|
||||
});
|
||||
|
||||
pub const stdlib = @cImport({
|
||||
@cInclude("stdlib.h");
|
||||
});
|
||||
|
||||
pub const pwd = @cImport({
|
||||
const pwd = @cImport({
|
||||
@cInclude("pwd.h");
|
||||
// We include a FreeBSD-specific header here since login_cap.h references
|
||||
// the passwd struct directly, so we can't import it separately
|
||||
if (builtin.os.tag == .freebsd) @cInclude("login_cap.h");
|
||||
});
|
||||
|
||||
pub const grp = @cImport({
|
||||
const stdlib = @cImport({
|
||||
@cInclude("stdlib.h");
|
||||
});
|
||||
|
||||
const unistd = @cImport({
|
||||
@cInclude("unistd.h");
|
||||
});
|
||||
|
||||
const grp = @cImport({
|
||||
@cInclude("grp.h");
|
||||
});
|
||||
|
||||
const system_time = @cImport({
|
||||
@cInclude("sys/time.h");
|
||||
});
|
||||
|
||||
const time = @cImport({
|
||||
@cInclude("time.h");
|
||||
});
|
||||
|
||||
// BSD-specific headers
|
||||
pub const kbio = @cImport({
|
||||
const kbio = @cImport({
|
||||
@cInclude("sys/kbio.h");
|
||||
});
|
||||
|
||||
// Linux-specific headers
|
||||
pub const kd = @cImport({
|
||||
const kd = @cImport({
|
||||
@cInclude("sys/kd.h");
|
||||
});
|
||||
|
||||
pub const vt = @cImport({
|
||||
const vt = @cImport({
|
||||
@cInclude("sys/vt.h");
|
||||
});
|
||||
|
||||
|
@ -65,6 +78,10 @@ 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 supportsUnicode() bool {
|
||||
return builtin.os.tag == .linux or builtin.os.tag.isBSD();
|
||||
}
|
||||
|
||||
pub fn timeAsString(buf: [:0]u8, format: [:0]const u8) []u8 {
|
||||
const timer = std.time.timestamp();
|
||||
const tm_info = time.localtime(&timer);
|
||||
|
@ -73,11 +90,23 @@ pub fn timeAsString(buf: [:0]u8, format: [:0]const u8) []u8 {
|
|||
return buf[0..len];
|
||||
}
|
||||
|
||||
pub fn getTimeOfDay() !TimeOfDay {
|
||||
var tv: system_time.timeval = undefined;
|
||||
const status = system_time.gettimeofday(&tv, null);
|
||||
|
||||
if (status != 0) return error.FailedToGetTimeOfDay;
|
||||
|
||||
return .{
|
||||
.seconds = @intCast(tv.tv_sec),
|
||||
.microseconds = @intCast(tv.tv_usec),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn switchTty(tty: u8) !void {
|
||||
var status = std.c.ioctl(std.c.STDIN_FILENO, vt.VT_ACTIVATE, tty);
|
||||
var status = std.c.ioctl(std.posix.STDIN_FILENO, vt.VT_ACTIVATE, tty);
|
||||
if (status != 0) return error.FailedToActivateTty;
|
||||
|
||||
status = std.c.ioctl(std.c.STDIN_FILENO, vt.VT_WAITACTIVE, tty);
|
||||
status = std.c.ioctl(std.posix.STDIN_FILENO, vt.VT_WAITACTIVE, tty);
|
||||
if (status != 0) return error.FailedToWaitForActiveTty;
|
||||
}
|
||||
|
||||
|
@ -86,7 +115,7 @@ pub fn getLockState() !struct {
|
|||
capslock: bool,
|
||||
} {
|
||||
var led: LedState = undefined;
|
||||
const status = std.c.ioctl(std.c.STDIN_FILENO, get_led_state, &led);
|
||||
const status = std.c.ioctl(std.posix.STDIN_FILENO, get_led_state, &led);
|
||||
if (status != 0) return error.FailedToGetLockState;
|
||||
|
||||
return .{
|
||||
|
@ -97,7 +126,7 @@ pub fn getLockState() !struct {
|
|||
|
||||
pub fn setNumlock(val: bool) !void {
|
||||
var led: LedState = undefined;
|
||||
var status = std.c.ioctl(std.c.STDIN_FILENO, get_led_state, &led);
|
||||
var status = std.c.ioctl(std.posix.STDIN_FILENO, get_led_state, &led);
|
||||
if (status != 0) return error.FailedToGetNumlock;
|
||||
|
||||
const numlock = (led & numlock_led) != 0;
|
||||
|
@ -106,3 +135,80 @@ pub fn setNumlock(val: bool) !void {
|
|||
if (status != 0) return error.FailedToSetNumlock;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn setUserContext(allocator: std.mem.Allocator, entry: UsernameEntry) !void {
|
||||
const username_z = try allocator.dupeZ(u8, entry.username.?);
|
||||
defer allocator.free(username_z);
|
||||
|
||||
if (builtin.os.tag == .freebsd) {
|
||||
// FreeBSD has initgroups() in unistd
|
||||
const status = unistd.initgroups(username_z.ptr, @intCast(entry.gid));
|
||||
if (status != 0) return error.GroupInitializationFailed;
|
||||
|
||||
// FreeBSD sets the GID and UID with setusercontext()
|
||||
// TODO
|
||||
const result = pwd.setusercontext(null, entry, @intCast(entry.uid), pwd.LOGIN_SETALL);
|
||||
if (result != 0) return error.SetUserUidFailed;
|
||||
} else {
|
||||
const status = grp.initgroups(username_z.ptr, @intCast(entry.gid));
|
||||
if (status != 0) return error.GroupInitializationFailed;
|
||||
|
||||
std.posix.setgid(@intCast(entry.gid)) catch return error.SetUserGidFailed;
|
||||
std.posix.setuid(@intCast(entry.uid)) catch return error.SetUserUidFailed;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn setUserShell(entry: *UsernameEntry) void {
|
||||
unistd.setusershell();
|
||||
|
||||
const shell = unistd.getusershell();
|
||||
entry.shell = shell[0..std.mem.len(shell)];
|
||||
|
||||
unistd.endusershell();
|
||||
}
|
||||
|
||||
pub fn setEnvironmentVariable(allocator: std.mem.Allocator, name: []const u8, value: []const u8, replace: bool) !void {
|
||||
const name_z = try allocator.dupeZ(u8, name);
|
||||
defer allocator.free(name_z);
|
||||
|
||||
const value_z = try allocator.dupeZ(u8, value);
|
||||
defer allocator.free(value_z);
|
||||
|
||||
const status = stdlib.setenv(name_z.ptr, value_z.ptr, @intFromBool(replace));
|
||||
if (status != 0) return error.SetEnvironmentVariableFailed;
|
||||
}
|
||||
|
||||
pub fn putEnvironmentVariable(name_and_value: [*c]u8) !void {
|
||||
const status = stdlib.putenv(name_and_value);
|
||||
if (status != 0) return error.PutEnvironmentVariableFailed;
|
||||
}
|
||||
|
||||
pub fn getNextUsernameEntry() ?UsernameEntry {
|
||||
const entry = pwd.getpwent();
|
||||
if (entry == null) return null;
|
||||
|
||||
return .{
|
||||
.username = if (entry.*.pw_name) |name| name[0..std.mem.len(name)] else null,
|
||||
.uid = @intCast(entry.*.pw_uid),
|
||||
.gid = @intCast(entry.*.pw_gid),
|
||||
.home = if (entry.*.pw_dir) |dir| dir[0..std.mem.len(dir)] else null,
|
||||
.shell = if (entry.*.pw_shell) |shell| shell[0..std.mem.len(shell)] else null,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn getUsernameEntry(username: [:0]const u8) ?UsernameEntry {
|
||||
const entry = pwd.getpwnam(username);
|
||||
if (entry == null) return null;
|
||||
|
||||
return .{
|
||||
.username = if (entry.*.pw_name) |name| name[0..std.mem.len(name)] else null,
|
||||
.uid = @intCast(entry.*.pw_uid),
|
||||
.gid = @intCast(entry.*.pw_gid),
|
||||
.home = if (entry.*.pw_dir) |dir| dir[0..std.mem.len(dir)] else null,
|
||||
.shell = if (entry.*.pw_shell) |shell| shell[0..std.mem.len(shell)] else null,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn closePasswordDatabase() void {
|
||||
pwd.endpwent();
|
||||
}
|
||||
|
|
53
src/main.zig
53
src/main.zig
|
@ -31,7 +31,6 @@ const Ini = ini.Ini;
|
|||
const DisplayServer = enums.DisplayServer;
|
||||
const Entry = Environment.Entry;
|
||||
const termbox = interop.termbox;
|
||||
const unistd = interop.unistd;
|
||||
const temporary_allocator = std.heap.page_allocator;
|
||||
const ly_top_str = "Ly version " ++ build_options.version;
|
||||
|
||||
|
@ -85,8 +84,7 @@ pub fn main() !void {
|
|||
defer _ = gpa.deinit();
|
||||
|
||||
// Allows stopping an animation after some time
|
||||
var tv_zero: interop.system_time.timeval = undefined;
|
||||
_ = interop.system_time.gettimeofday(&tv_zero, null);
|
||||
const time_start = try interop.getTimeOfDay();
|
||||
var animation_timed_out: bool = false;
|
||||
|
||||
const allocator = gpa.allocator();
|
||||
|
@ -547,7 +545,8 @@ pub fn main() !void {
|
|||
const clock_str = interop.timeAsString(&clock_buf, format);
|
||||
|
||||
for (clock_str, 0..) |c, i| {
|
||||
const clock_cell = bigclock.clockCell(animate, c, buffer.fg, buffer.bg, config.bigclock);
|
||||
// TODO: Show error
|
||||
const clock_cell = try bigclock.clockCell(animate, c, buffer.fg, buffer.bg, config.bigclock);
|
||||
bigclock.alphaBlit(xo + i * (bigclock.WIDTH + 1), yo, buffer.width, buffer.height, clock_cell);
|
||||
}
|
||||
}
|
||||
|
@ -682,24 +681,21 @@ pub fn main() !void {
|
|||
if (animate and !animation_timed_out) {
|
||||
timeout = config.min_refresh_delta;
|
||||
|
||||
// check how long we have been running so we can turn off the animation
|
||||
var tv: interop.system_time.timeval = undefined;
|
||||
_ = interop.system_time.gettimeofday(&tv, null);
|
||||
// Check how long we've been running so we can turn off the animation
|
||||
const time = try interop.getTimeOfDay();
|
||||
|
||||
if (config.animation_timeout_sec > 0 and tv.tv_sec - tv_zero.tv_sec > config.animation_timeout_sec) {
|
||||
if (config.animation_timeout_sec > 0 and time.seconds - time_start.seconds > config.animation_timeout_sec) {
|
||||
animation_timed_out = true;
|
||||
animation.deinit();
|
||||
}
|
||||
} else if (config.bigclock != .none and config.clock == null) {
|
||||
var tv: interop.system_time.timeval = undefined;
|
||||
_ = interop.system_time.gettimeofday(&tv, null);
|
||||
const time = try interop.getTimeOfDay();
|
||||
|
||||
timeout = @intCast((60 - @rem(tv.tv_sec, 60)) * 1000 - @divTrunc(tv.tv_usec, 1000) + 1);
|
||||
timeout = @intCast((60 - @rem(time.seconds, 60)) * 1000 - @divTrunc(time.microseconds, 1000) + 1);
|
||||
} else if (config.clock != null or auth_fails >= config.auth_fails) {
|
||||
var tv: interop.system_time.timeval = undefined;
|
||||
_ = interop.system_time.gettimeofday(&tv, null);
|
||||
const time = try interop.getTimeOfDay();
|
||||
|
||||
timeout = @intCast(1000 - @divTrunc(tv.tv_usec, 1000) + 1);
|
||||
timeout = @intCast(1000 - @divTrunc(time.microseconds, 1000) + 1);
|
||||
}
|
||||
|
||||
const event_error = if (timeout == -1) termbox.tb_poll_event(&event) else termbox.tb_peek_event(&event, timeout);
|
||||
|
@ -864,7 +860,7 @@ pub fn main() !void {
|
|||
};
|
||||
std.posix.sigaction(std.posix.SIG.CHLD, &tty_control_transfer_act, null);
|
||||
|
||||
auth.authenticate(auth_options, current_environment, login_text, password_text) catch |err| {
|
||||
auth.authenticate(allocator, auth_options, current_environment, login_text, password_text) catch |err| {
|
||||
shared_err.writeError(err);
|
||||
std.process.exit(1);
|
||||
};
|
||||
|
@ -1016,7 +1012,7 @@ fn crawl(session: *Session, lang: Lang, path: []const u8, display_server: Displa
|
|||
|
||||
// Prepare the XDG_CURRENT_DESKTOP environment variable here
|
||||
const entry = entry_ini.data.@"Desktop Entry";
|
||||
var maybe_xdg_desktop_names: ?[:0]const u8 = null;
|
||||
var maybe_xdg_desktop_names: ?[]const u8 = null;
|
||||
if (entry.DesktopNames) |desktop_names| {
|
||||
for (desktop_names) |*c| {
|
||||
if (c.* == ';') c.* = ':';
|
||||
|
@ -1024,13 +1020,10 @@ fn crawl(session: *Session, lang: Lang, path: []const u8, display_server: Displa
|
|||
maybe_xdg_desktop_names = desktop_names;
|
||||
}
|
||||
|
||||
const maybe_session_desktop = if (maybe_xdg_session_desktop) |xdg_session_desktop| try session.label.allocator.dupeZ(u8, xdg_session_desktop) else null;
|
||||
errdefer if (maybe_session_desktop) |session_desktop| session.label.allocator.free(session_desktop);
|
||||
|
||||
try session.addEnvironment(.{
|
||||
.entry_ini = entry_ini,
|
||||
.name = entry.Name,
|
||||
.xdg_session_desktop = maybe_session_desktop,
|
||||
.xdg_session_desktop = maybe_xdg_session_desktop,
|
||||
.xdg_desktop_names = maybe_xdg_desktop_names,
|
||||
.cmd = entry.Exec,
|
||||
.specifier = switch (display_server) {
|
||||
|
@ -1049,24 +1042,20 @@ fn getAllUsernames(allocator: std.mem.Allocator, login_defs_path: []const u8) !S
|
|||
const uid_range = try getUserIdRange(allocator, login_defs_path);
|
||||
|
||||
var usernames: StringList = .empty;
|
||||
var maybe_entry = interop.pwd.getpwent();
|
||||
|
||||
while (maybe_entry != null) {
|
||||
const entry = maybe_entry.*;
|
||||
var maybe_entry = interop.getNextUsernameEntry();
|
||||
|
||||
while (maybe_entry) |entry| {
|
||||
// We check if the UID is equal to 0 because we always want to add root
|
||||
// as a username (even if you can't log into it)
|
||||
if (entry.pw_uid >= uid_range.uid_min and entry.pw_uid <= uid_range.uid_max or entry.pw_uid == 0) {
|
||||
const pw_name_slice = entry.pw_name[0..std.mem.len(entry.pw_name)];
|
||||
const username = try allocator.dupe(u8, pw_name_slice);
|
||||
|
||||
if (entry.uid >= uid_range.uid_min and entry.uid <= uid_range.uid_max or entry.uid == 0 and entry.username != null) {
|
||||
const username = try allocator.dupe(u8, entry.username.?);
|
||||
try usernames.append(allocator, username);
|
||||
}
|
||||
|
||||
maybe_entry = interop.pwd.getpwent();
|
||||
maybe_entry = interop.getNextUsernameEntry();
|
||||
}
|
||||
|
||||
interop.pwd.endpwent();
|
||||
interop.closePasswordDatabase();
|
||||
return usernames;
|
||||
}
|
||||
|
||||
|
@ -1086,9 +1075,9 @@ fn getUserIdRange(allocator: std.mem.Allocator, login_defs_path: []const u8) !Ui
|
|||
const trimmed_line = std.mem.trim(u8, line, " \n\r\t");
|
||||
|
||||
if (std.mem.startsWith(u8, trimmed_line, "UID_MIN")) {
|
||||
uid_range.uid_min = try parseValue(std.c.uid_t, "UID_MIN", trimmed_line);
|
||||
uid_range.uid_min = try parseValue(std.posix.uid_t, "UID_MIN", trimmed_line);
|
||||
} else if (std.mem.startsWith(u8, trimmed_line, "UID_MAX")) {
|
||||
uid_range.uid_max = try parseValue(std.c.uid_t, "UID_MAX", trimmed_line);
|
||||
uid_range.uid_max = try parseValue(std.posix.uid_t, "UID_MAX", trimmed_line);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const interop = @import("../interop.zig");
|
||||
const Cell = @import("Cell.zig");
|
||||
|
||||
|
@ -82,7 +81,7 @@ pub fn init(options: InitOptions, labels_max_length: usize, random: Random) Term
|
|||
.fg = options.fg,
|
||||
.bg = options.bg,
|
||||
.border_fg = options.border_fg,
|
||||
.box_chars = if (builtin.os.tag == .linux or builtin.os.tag.isBSD()) .{
|
||||
.box_chars = if (interop.supportsUnicode()) .{
|
||||
.left_up = 0x250C,
|
||||
.left_down = 0x2514,
|
||||
.right_up = 0x2510,
|
||||
|
|
|
@ -23,7 +23,6 @@ pub fn init(allocator: Allocator, buffer: *TerminalBuffer) Session {
|
|||
pub fn deinit(self: *Session) void {
|
||||
for (self.label.list.items) |*environment| {
|
||||
if (environment.entry_ini) |*entry_ini| entry_ini.deinit();
|
||||
if (environment.xdg_session_desktop) |session_desktop| self.label.allocator.free(session_desktop);
|
||||
}
|
||||
|
||||
self.label.deinit();
|
||||
|
|
Loading…
Reference in New Issue