Support GDM, SDDM, and LightDM for PAM integration. Detect which display manager is running and configure the correct PAM file. Show manual instructions if no supported DM is found. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
251 lines
11 KiB
Bash
Executable File
251 lines
11 KiB
Bash
Executable File
#!/bin/bash
|
|
#
|
|
# Linux Hello — One-command installer
|
|
#
|
|
# Usage:
|
|
# git clone https://gitea.lab48.be/eliott/Linux-Hello.git && cd Linux-Hello && ./install.sh
|
|
#
|
|
# What this does:
|
|
# 1. Installs build dependencies
|
|
# 2. Builds everything (daemon, CLI, PAM module, ONNX models)
|
|
# 3. Installs system files (daemon, PAM, systemd, config)
|
|
# 4. Sets up IR emitter (interactive — you'll confirm when it lights up)
|
|
# 5. Enrolls your face
|
|
# 6. Enables face unlock on the lock screen
|
|
#
|
|
# Your password always works as fallback. To uninstall: ./install.sh --uninstall
|
|
#
|
|
set -e
|
|
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
CYAN='\033[0;36m'
|
|
BOLD='\033[1m'
|
|
NC='\033[0m'
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
cd "$SCRIPT_DIR"
|
|
|
|
# ─── Uninstall ────────────────────────────────────────────────────────────────
|
|
|
|
if [ "$1" = "--uninstall" ]; then
|
|
echo -e "${CYAN}${BOLD}Uninstalling Linux Hello...${NC}"
|
|
sudo sed -i '/pam_linux_hello/d' /etc/pam.d/gdm-password /etc/pam.d/sddm /etc/pam.d/lightdm 2>/dev/null || true
|
|
sudo systemctl disable --now linux-hello.service 2>/dev/null || true
|
|
sudo rm -f /usr/libexec/linux-hello-daemon /usr/local/bin/linux-hello
|
|
sudo rm -f /lib/x86_64-linux-gnu/security/pam_linux_hello.so /lib/security/pam_linux_hello.so
|
|
sudo rm -f /etc/systemd/system/linux-hello.service
|
|
sudo rm -f /etc/pam.d/gdm-linux-hello
|
|
sudo rm -f /etc/dbus-1/system.d/org.linuxhello.Daemon.conf
|
|
sudo rm -rf /etc/linux-hello /var/lib/linux-hello /usr/share/linux-hello
|
|
sudo rm -rf /usr/local/lib/linux-hello
|
|
sudo systemctl daemon-reload 2>/dev/null || true
|
|
echo -e "${GREEN}Uninstalled.${NC}"
|
|
exit 0
|
|
fi
|
|
|
|
# ─── Checks ───────────────────────────────────────────────────────────────────
|
|
|
|
echo -e "${CYAN}${BOLD}"
|
|
echo " ╔═══════════════════════════════════╗"
|
|
echo " ║ Linux Hello Installer ║"
|
|
echo " ║ Face unlock for your laptop ║"
|
|
echo " ╚═══════════════════════════════════╝"
|
|
echo -e "${NC}"
|
|
|
|
# Check we're not root (we'll sudo when needed)
|
|
if [ "$EUID" -eq 0 ]; then
|
|
echo -e "${RED}Don't run as root — the script will sudo when needed.${NC}"
|
|
exit 1
|
|
fi
|
|
|
|
# Check for Rust
|
|
if ! command -v cargo &>/dev/null; then
|
|
echo -e "${RED}Rust not found. Install it first:${NC}"
|
|
echo " curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh"
|
|
exit 1
|
|
fi
|
|
|
|
# Check for IR camera
|
|
echo -e "${YELLOW}[1/8]${NC} Checking hardware..."
|
|
if ! v4l2-ctl --list-devices 2>/dev/null | grep -qi "ir\|infrared\|integrated i"; then
|
|
echo -e "${YELLOW} Warning: No IR camera detected. Face unlock will work but won't block photo attacks.${NC}"
|
|
echo -e "${YELLOW} (Tested on: Lenovo Yoga Pro 7 with Chicony IR camera)${NC}"
|
|
HAS_IR=false
|
|
else
|
|
echo -e "${GREEN} IR camera found.${NC}"
|
|
HAS_IR=true
|
|
fi
|
|
|
|
# ─── Dependencies ─────────────────────────────────────────────────────────────
|
|
|
|
echo -e "${YELLOW}[2/8]${NC} Installing dependencies..."
|
|
sudo apt-get update -qq
|
|
sudo apt-get install -y -qq libpam0g-dev v4l-utils build-essential wget >/dev/null 2>&1
|
|
echo -e "${GREEN} Done.${NC}"
|
|
|
|
# ─── Build ────────────────────────────────────────────────────────────────────
|
|
|
|
echo -e "${YELLOW}[3/8]${NC} Downloading ONNX models..."
|
|
./scripts/download-models.sh
|
|
|
|
echo -e "${YELLOW}[4/8]${NC} Building (this takes a minute)..."
|
|
cargo build --release --features onnx 2>&1 | tail -1
|
|
cd pam-module && make -s 2>&1 && cd ..
|
|
echo -e "${GREEN} Built successfully.${NC}"
|
|
|
|
# ─── ONNX Runtime ─────────────────────────────────────────────────────────────
|
|
|
|
echo -e "${YELLOW}[5/8]${NC} Setting up ONNX Runtime..."
|
|
GLIBC_VER=$(ldd --version 2>&1 | head -1 | grep -oP '\d+\.\d+$')
|
|
if [ -f "$HOME/.local/lib/linux-hello/libonnxruntime.so" ]; then
|
|
echo -e "${GREEN} Already installed.${NC}"
|
|
elif echo "$GLIBC_VER" | awk '{ exit ($1 >= 2.38) ? 0 : 1 }'; then
|
|
echo "y" | ./scripts/install-onnx-runtime.sh --user 2>&1 | grep -E "^\[|^$" | head -5
|
|
else
|
|
./scripts/install-onnx-runtime.sh --user 2>&1 | grep -E "^\[|^$" | head -5
|
|
fi
|
|
|
|
# ─── System Install ──────────────────────────────────────────────────────────
|
|
|
|
echo -e "${YELLOW}[6/8]${NC} Installing system files (needs sudo)..."
|
|
|
|
# Stop existing service if running
|
|
sudo systemctl stop linux-hello.service 2>/dev/null || true
|
|
|
|
# Binaries
|
|
sudo install -m 755 target/release/linux-hello-daemon /usr/libexec/linux-hello-daemon
|
|
sudo install -m 755 target/release/linux-hello /usr/local/bin/linux-hello
|
|
|
|
# ONNX models
|
|
sudo install -d /usr/share/linux-hello/models
|
|
for model in models/*.onnx; do
|
|
[ -f "$model" ] && sudo install -m 644 "$model" /usr/share/linux-hello/models/
|
|
done
|
|
|
|
# ONNX Runtime library
|
|
ORT_LIB="$HOME/.local/lib/linux-hello/libonnxruntime.so"
|
|
if [ -f "$ORT_LIB" ]; then
|
|
sudo install -d /usr/local/lib/linux-hello
|
|
sudo install -m 755 "$ORT_LIB" /usr/local/lib/linux-hello/libonnxruntime.so
|
|
fi
|
|
|
|
# Config
|
|
sudo install -d /etc/linux-hello
|
|
if [ ! -f /etc/linux-hello/config.toml ]; then
|
|
sudo install -m 644 dist/config.toml /etc/linux-hello/config.toml
|
|
fi
|
|
|
|
# D-Bus policy
|
|
sudo install -m 644 dist/org.linuxhello.Daemon.conf /etc/dbus-1/system.d/
|
|
|
|
# PAM module
|
|
PAM_DIR="/lib/x86_64-linux-gnu/security"
|
|
[ ! -d "$PAM_DIR" ] && PAM_DIR="/lib/security"
|
|
sudo install -m 755 pam-module/pam_linux_hello.so "$PAM_DIR/"
|
|
|
|
# Systemd service
|
|
sudo cp dist/linux-hello.service /etc/systemd/system/linux-hello.service
|
|
sudo systemctl daemon-reload
|
|
|
|
echo -e "${GREEN} Installed.${NC}"
|
|
|
|
# ─── IR Emitter ───────────────────────────────────────────────────────────────
|
|
|
|
if [ "$HAS_IR" = true ]; then
|
|
echo -e "${YELLOW}[7/8]${NC} Configuring IR emitter..."
|
|
if ! command -v linux-enable-ir-emitter &>/dev/null; then
|
|
echo " Building linux-enable-ir-emitter..."
|
|
IR_DIR=$(mktemp -d)
|
|
git clone -q https://github.com/EmixamPP/linux-enable-ir-emitter.git "$IR_DIR" 2>/dev/null
|
|
(cd "$IR_DIR" && cargo build --release -q 2>/dev/null)
|
|
sudo install -m 755 "$IR_DIR/target/release/linux-enable-ir-emitter" /usr/local/bin/
|
|
rm -rf "$IR_DIR"
|
|
fi
|
|
echo ""
|
|
echo -e "${BOLD} The IR emitter setup is interactive.${NC}"
|
|
echo -e " It will show your IR camera feed and try different settings."
|
|
echo -e " ${BOLD}Press 'y' when you see a bright red/white IR light, 'n' otherwise.${NC}"
|
|
echo ""
|
|
read -p " Ready? (press Enter) " _
|
|
sudo linux-enable-ir-emitter configure || echo -e "${YELLOW} IR emitter setup skipped or failed. You can retry later with: sudo linux-enable-ir-emitter configure${NC}"
|
|
else
|
|
echo -e "${YELLOW}[7/8]${NC} Skipping IR emitter (no IR camera detected)."
|
|
fi
|
|
|
|
# ─── Enable & Enroll ─────────────────────────────────────────────────────────
|
|
|
|
echo -e "${YELLOW}[8/8]${NC} Starting daemon and enrolling your face..."
|
|
sudo systemctl enable --now linux-hello.service
|
|
|
|
echo ""
|
|
echo -e "${BOLD} Look at the camera — enrolling your face now.${NC}"
|
|
echo ""
|
|
sudo ORT_DYLIB_PATH=/usr/local/lib/linux-hello/libonnxruntime.so linux-hello enroll --label default
|
|
|
|
# ─── PAM Integration ─────────────────────────────────────────────────────────
|
|
|
|
# Detect display manager and configure PAM accordingly
|
|
DM_NAME=""
|
|
PAM_CONFIGURED=false
|
|
|
|
if systemctl is-active --quiet gdm.service 2>/dev/null || systemctl is-active --quiet gdm3.service 2>/dev/null; then
|
|
DM_NAME="GDM"
|
|
PAM_FILE="/etc/pam.d/gdm-password"
|
|
if [ -f "$PAM_FILE" ] && ! grep -q "pam_linux_hello" "$PAM_FILE"; then
|
|
sudo sed -i '/@include common-auth/i auth sufficient pam_linux_hello.so timeout=5' "$PAM_FILE"
|
|
PAM_CONFIGURED=true
|
|
elif grep -q "pam_linux_hello" "$PAM_FILE" 2>/dev/null; then
|
|
PAM_CONFIGURED=true
|
|
fi
|
|
elif systemctl is-active --quiet sddm.service 2>/dev/null; then
|
|
DM_NAME="SDDM"
|
|
PAM_FILE="/etc/pam.d/sddm"
|
|
if [ -f "$PAM_FILE" ] && ! grep -q "pam_linux_hello" "$PAM_FILE"; then
|
|
sudo sed -i '/auth.*include.*system-login\|auth.*include.*common-auth\|@include common-auth/i auth sufficient pam_linux_hello.so timeout=5' "$PAM_FILE"
|
|
PAM_CONFIGURED=true
|
|
elif grep -q "pam_linux_hello" "$PAM_FILE" 2>/dev/null; then
|
|
PAM_CONFIGURED=true
|
|
fi
|
|
elif systemctl is-active --quiet lightdm.service 2>/dev/null; then
|
|
DM_NAME="LightDM"
|
|
PAM_FILE="/etc/pam.d/lightdm"
|
|
if [ -f "$PAM_FILE" ] && ! grep -q "pam_linux_hello" "$PAM_FILE"; then
|
|
sudo sed -i '/@include common-auth\|auth.*include.*system-login/i auth sufficient pam_linux_hello.so timeout=5' "$PAM_FILE"
|
|
PAM_CONFIGURED=true
|
|
elif grep -q "pam_linux_hello" "$PAM_FILE" 2>/dev/null; then
|
|
PAM_CONFIGURED=true
|
|
fi
|
|
fi
|
|
|
|
# ─── Done ─────────────────────────────────────────────────────────────────────
|
|
|
|
echo ""
|
|
echo -e "${GREEN}${BOLD} ╔═══════════════════════════════════╗"
|
|
echo " ║ Installation complete! ║"
|
|
echo " ╚═══════════════════════════════════╝${NC}"
|
|
echo ""
|
|
|
|
if [ "$PAM_CONFIGURED" = true ]; then
|
|
echo " Lock your screen and look at the camera to unlock."
|
|
echo " Your password always works as a fallback."
|
|
echo " Display manager: $DM_NAME ($PAM_FILE)"
|
|
elif [ -n "$DM_NAME" ]; then
|
|
echo -e " ${YELLOW}Could not configure $DM_NAME automatically.${NC}"
|
|
echo " Add this line to $PAM_FILE before the auth include:"
|
|
echo " auth sufficient pam_linux_hello.so timeout=5"
|
|
else
|
|
echo -e " ${YELLOW}No supported display manager detected (GDM, SDDM, LightDM).${NC}"
|
|
echo " To enable face unlock, add this line to your display manager's PAM config:"
|
|
echo " auth sufficient pam_linux_hello.so timeout=5"
|
|
fi
|
|
|
|
echo ""
|
|
echo " Commands:"
|
|
echo " linux-hello test — test face recognition"
|
|
echo " linux-hello enroll — re-enroll your face"
|
|
echo " linux-hello status — check system status"
|
|
echo " ./install.sh --uninstall — remove everything"
|
|
echo ""
|