sway: replace "greetd" with "unl0kr"-based login process
This commit is contained in:
parent
0009e5ca4c
commit
f5c88853ee
|
@ -104,6 +104,9 @@ in
|
|||
# bindkey '^E' end-of-line
|
||||
# bindkey "^''${key[Left]}" backward-word
|
||||
# bindkey "^''${key[Right]}" forward-word
|
||||
|
||||
# run any additional, sh-generic commands (useful for e.g. launching a login manager on login)
|
||||
test -e ~/.profile && source ~/.profile
|
||||
'';
|
||||
};
|
||||
})
|
||||
|
|
|
@ -14,6 +14,7 @@ in
|
|||
./sway
|
||||
./sxmo
|
||||
./theme
|
||||
./unl0kr
|
||||
];
|
||||
|
||||
sane.programs.gameApps = declPackageSet [
|
||||
|
|
|
@ -213,25 +213,34 @@ in
|
|||
# sane.gui.gtk.icon-theme = lib.mkDefault "rose-pine-dawn"; # 2.5/5 coverage on moby
|
||||
# sane.gui.gtk.icon-theme = lib.mkDefault "Flat-Remix-Grey-Light"; # requires qtbase
|
||||
|
||||
# swap in these lines to use SDDM instead of `services.greetd`.
|
||||
sane.gui.unl0kr = lib.mkIf cfg.useGreeter {
|
||||
enable = true;
|
||||
afterLogin = "sway";
|
||||
user = "colin";
|
||||
};
|
||||
|
||||
# swap in these lines to use `greetd`+`gtkgreet` instead:
|
||||
# sane.gui.greetd = lib.mkIf cfg.useGreeter {
|
||||
# enable = true;
|
||||
# sway.enable = true; # have greetd launch a sway compositor in which we host a greeter
|
||||
# sway.gtkgreet = {
|
||||
# enable = true;
|
||||
# session.name = "sway-on-gtkgreet";
|
||||
# session.command = "${cfg.package}/bin/sway"; #< works, simplest way to run sway
|
||||
# # session.command = "${pkgs.libcap}/bin/capsh --print"; # DEBUGGING
|
||||
|
||||
# # instead, want to run sway as a systemd user service.
|
||||
# # this seems silly, but it allows the launched sway to access any linux capabilities which the systemd --user manager is granted.
|
||||
# # notably, that means CAP_NET_ADMIN, CAP_NET_RAW; necessary for wireshark.
|
||||
# # these capabilities are granted to systemd --user by pam. see the user definition in hosts/common/users/colin.nix for more.
|
||||
# # session.command = "${pkgs.systemd}/bin/systemd-run --user --wait --collect --service-type=exec ${cfg.package}/bin/sway"; #< works, but can't launch terminals, etc ("exec: no such file" (sh))
|
||||
# # session.command = ''${pkgs.systemd}/bin/systemd-run --user --wait --collect --service-type=exec -E "PATH=$PATH" -p AmbientCapabilities="cap_net_admin cap_net_raw" ${cfg.package}/bin/sway'';
|
||||
# };
|
||||
# };
|
||||
|
||||
# swap in these lines to use SDDM instead:
|
||||
# services.xserver.displayManager.sddm.enable = true;
|
||||
# services.xserver.enable = true;
|
||||
sane.gui.greetd = lib.mkIf cfg.useGreeter {
|
||||
enable = true;
|
||||
sway.enable = true; # have greetd launch a sway compositor in which we host a greeter
|
||||
sway.gtkgreet = {
|
||||
enable = true;
|
||||
session.name = "sway-on-gtkgreet";
|
||||
# session.command = "${cfg.package}/bin/sway"; #< works, simplest way to run sway
|
||||
|
||||
# instead, want to run sway as a systemd user service.
|
||||
# this seems silly, but it allows the launched sway to access any linux capabilities which the systemd --user manager is granted.
|
||||
# notably, that means CAP_NET_ADMIN, CAP_NET_RAW; necessary for wireshark.
|
||||
# these capabilities are granted to systemd --user by pam. see the user definition in hosts/common/users/colin.nix for more.
|
||||
# session.command = "${pkgs.systemd}/bin/systemd-run --user --wait --collect --service-type=exec ${cfg.package}/bin/sway"; #< works, but can't launch terminals, etc ("exec: no such file" (sh))
|
||||
session.command = ''${pkgs.systemd}/bin/systemd-run --user --wait --collect --service-type=exec -E "PATH=$PATH" -p AmbientCapabilities="cap_net_admin cap_net_raw" ${cfg.package}/bin/sway'';
|
||||
};
|
||||
};
|
||||
|
||||
# unlike other DEs, sway configures no audio stack
|
||||
# administer with pw-cli, pw-mon, pw-top commands
|
||||
|
|
128
hosts/modules/gui/unl0kr/default.nix
Normal file
128
hosts/modules/gui/unl0kr/default.nix
Normal file
|
@ -0,0 +1,128 @@
|
|||
{ config, lib, pkgs, ... }:
|
||||
let
|
||||
cfg = config.sane.gui.unl0kr;
|
||||
tty = "tty${builtins.toString cfg.vt}";
|
||||
redirect-tty = pkgs.static-nix-shell.mkPython3Bin {
|
||||
pname = "redirect-tty";
|
||||
src = ./.;
|
||||
};
|
||||
launcher = pkgs.writeShellApplication {
|
||||
name = "unl0kr-login";
|
||||
runtimeInputs = [
|
||||
cfg.package
|
||||
pkgs.shadow
|
||||
redirect-tty
|
||||
];
|
||||
text = ''
|
||||
# TODO: on auth failure, this will sit here indefinitely
|
||||
# (well, user can use /dev/stdin to auth -- if that's wired to a usable input device)
|
||||
# could either:
|
||||
# - reduce login tries to 1.
|
||||
# - wait on `unl0kr` to complete _before_ starting `login`
|
||||
# i.e. `pw=$(unl0kr); (sleep 1 && echo "$pw" | redirect-tty "/dev/(tty)") &; login -p <user>`
|
||||
# but modified to not leak pword to CLI
|
||||
# - implement some sort of watchdog (e.g. detect spawned children?)
|
||||
set -x
|
||||
set +o errexit
|
||||
set +o nounset
|
||||
set +o pipefail
|
||||
|
||||
# login -p: preserve environment
|
||||
# TODO: try getty --init-string to relay the password into `login`?
|
||||
# lets me ditch `unbuffer` and the like, though it places the password on the CLI
|
||||
# ( unl0kr; cat /dev/stdin; sleep 30 ) | socat EXEC:'login -p ${cfg.user}',pty STDIO
|
||||
# unl0kr | socat EXEC:'login -p ${cfg.user}',pty STDIN
|
||||
# (unl0kr ; sleep 60) | exec unbuffer -p login -p ${cfg.user}
|
||||
|
||||
redirect-tty "/dev/${tty}" unl0kr &
|
||||
login -p ${cfg.user}
|
||||
'';
|
||||
};
|
||||
in
|
||||
{
|
||||
options = with lib; {
|
||||
sane.gui.unl0kr.enable = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
whether to launch unl0kr at boot.
|
||||
unl0kr takes the role of a greeter, presenting a virtual keyboard to the framebuffer
|
||||
and allowing password auth via either keyboard, mouse, or touch.
|
||||
'';
|
||||
};
|
||||
sane.gui.unl0kr.vt = mkOption {
|
||||
type = types.int;
|
||||
default = 1;
|
||||
};
|
||||
sane.gui.unl0kr.user = mkOption {
|
||||
type = types.str;
|
||||
default = "colin";
|
||||
};
|
||||
sane.gui.unl0kr.afterLogin = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = ''
|
||||
shell code to run after a successful login (via .profile).
|
||||
'';
|
||||
};
|
||||
sane.gui.unl0kr.delay = mkOption {
|
||||
type = types.int;
|
||||
default = 3;
|
||||
description = ''
|
||||
seconds to wait between successful login and running the `afterLogin` command.
|
||||
this is a safety mechanism, to allow users an exit in case DE is broken.
|
||||
'';
|
||||
};
|
||||
sane.gui.unl0kr.package = mkOption {
|
||||
type = types.package;
|
||||
default = pkgs.unl0kr;
|
||||
};
|
||||
sane.gui.unl0kr.launcher = mkOption {
|
||||
type = types.package;
|
||||
default = launcher;
|
||||
description = ''
|
||||
script to tie `unl0kr` and `login` together.
|
||||
exposed for debugging.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
# prevent nixos-rebuild from killing us after a redeploy
|
||||
systemd.services."autovt@${tty}".enable = false;
|
||||
systemd.services.unl0kr = {
|
||||
# --skip-login is funny here: it *doesn't* skip the login; rather it has getty not try to read the username for itself
|
||||
# and instead launch --login-program *immediately*
|
||||
# N.B.: exec paths here must be absolute. neither systemd nor agetty query PATH.
|
||||
serviceConfig.ExecStart = "${pkgs.util-linux}/bin/agetty --login-program '${cfg.launcher}/bin/unl0kr-login' --noclear --skip-login --keep-baud ${tty} 115200,38400,9600 $TERM";
|
||||
|
||||
serviceConfig.Type = "simple";
|
||||
serviceConfig.Restart = "always";
|
||||
serviceConfig.RestartSec = "5";
|
||||
# XXX: unsure which of these are necessary nor what they do.
|
||||
# copied from greetd and agetty services.
|
||||
serviceConfig.TTYPath = "/dev/${tty}";
|
||||
serviceConfig.TTYReset = "yes";
|
||||
serviceConfig.StandardInput = "tty";
|
||||
serviceConfig.StandardOutput = "tty";
|
||||
|
||||
# copied from greetd; not sure how `after` and `conflict` being identical makes any sense.
|
||||
after = [ "getty@${tty}.service" ];
|
||||
conflicts = [ "getty@${tty}.service" ];
|
||||
wantedBy = [ "graphical.target" ];
|
||||
|
||||
# don't kill session on nixos re-deploy
|
||||
restartIfChanged = false;
|
||||
};
|
||||
|
||||
systemd.defaultUnit = "graphical.target";
|
||||
|
||||
sane.users."${cfg.user}".fs.".profile".symlink.text = lib.optionalString (cfg.afterLogin != null) ''
|
||||
# if already running a desktop environment, or if running from ssh, then `tty` will show /dev/pts/NN.
|
||||
if [ "$(tty)" = "/dev/${tty}" ]; then
|
||||
echo 'launching default session in ${builtins.toString cfg.delay}s'
|
||||
sleep ${builtins.toString cfg.delay} && exec ${cfg.afterLogin}
|
||||
fi
|
||||
'';
|
||||
};
|
||||
}
|
30
hosts/modules/gui/unl0kr/redirect-tty
Executable file
30
hosts/modules/gui/unl0kr/redirect-tty
Executable file
|
@ -0,0 +1,30 @@
|
|||
#!/usr/bin/env nix-shell
|
||||
#!nix-shell -i python3 -p "python3.withPackages (ps: [ ])"
|
||||
# vim: set filetype=python :
|
||||
|
||||
"""
|
||||
launch some program, and redirect its output to appear as if it
|
||||
were *input* by the user, on some TTY.
|
||||
this allows piping into programs which expect to be running directly on a TTY (like `login`, or `sway`).
|
||||
|
||||
based on: <https://unix.stackexchange.com/a/345572>
|
||||
"""
|
||||
import fcntl
|
||||
import subprocess
|
||||
import sys
|
||||
import termios
|
||||
|
||||
def write_to(text: bytes, dest_path: str) -> None:
|
||||
with open(dest_path, "w") as f:
|
||||
for byte in text:
|
||||
fcntl.ioctl(f.fileno(), termios.TIOCSTI, bytes([byte]))
|
||||
|
||||
def main(argv: list[str]):
|
||||
dest_path = argv[1]
|
||||
cmd = argv[2:]
|
||||
|
||||
cmd_output = subprocess.check_output(cmd)
|
||||
write_to(cmd_output, dest_path)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main(sys.argv)
|
Loading…
Reference in New Issue
Block a user