gardm Architecture
Overview
gardm is the display manager for the gar desktop suite. It follows a daemon + greeter architecture similar to greetd, providing clean separation between authentication/session management and the user interface.
Components
┌─────────────────────────────────────────────────────────────┐
│ gardmd │
│ (Display Manager Daemon) │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
│ │ PAM │ │ X11/Xorg │ │ Session Manager │ │
│ │ Integration │ │ Control │ │ (systemd-logind) │ │
│ └─────────────┘ └─────────────┘ └─────────────────────┘ │
│ │ │
│ Unix Socket IPC │
│ │ │
└──────────────────────────┼──────────────────────────────────┘
│
┌──────────────────────────┼──────────────────────────────────┐
│ ▼ │
│ gardm-greeter │
│ (Graphical UI) │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
│ │ Cairo/ │ │ garbg │ │ User Input │ │
│ │ Pango │ │ Integration │ │ (login form) │ │
│ └─────────────┘ └─────────────┘ └─────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
gardmd (Daemon)
The privileged daemon that runs as root. Responsibilities:
- X11 Server Management: Start/stop Xorg server on appropriate VT
- PAM Authentication: Verify user credentials via
/etc/pam.d/gardm - Session Launching: Start selected session (gar, other WMs/DEs)
- systemd-logind Integration: Register sessions, handle multi-seat
- IPC Server: Listen on Unix socket for greeter commands
gardm-greeter (Frontend)
The unprivileged graphical interface. Runs as dedicated gardm user. Responsibilities:
- User Interface: Render login form, session selector, power buttons
- garbg Integration: Display same wallpaper that gar session will use
- Visual Effects: Blur background, animations, theming
- IPC Client: Send auth requests to daemon, receive responses
IPC Protocol
JSON-based protocol over Unix socket at /run/gardm.sock:
Requests (Greeter → Daemon)
// Create authentication session
{ "type": "create_session", "username": "user" }
// Attempt authentication
{ "type": "authenticate", "response": "password123" }
// Start session after successful auth
{ "type": "start_session", "cmd": ["gar-session.sh"], "env": [] }
// Cancel current auth attempt
{ "type": "cancel_session" }
// System actions
{ "type": "shutdown" }
{ "type": "reboot" }
{ "type": "suspend" }
Responses (Daemon → Greeter)
// Success
{ "type": "success" }
// Auth prompt (PAM asking for input)
{ "type": "auth_prompt", "prompt": "Password:", "echo": false }
// Auth info message
{ "type": "auth_info", "message": "..." }
// Auth error
{ "type": "auth_error", "message": "Authentication failed" }
// General error
{ "type": "error", "message": "..." }
Session Discovery
Sessions are discovered from standard locations:
/usr/share/xsessions/*.desktop- X11 sessions/usr/share/wayland-sessions/*.desktop- Wayland sessions (future)
gar session file example (/usr/share/xsessions/gar.desktop):
[Desktop Entry]
Name=gar
Comment=Tiling window manager with smart splits
Exec=/usr/local/bin/gar-session.sh
Type=XSession
DesktopNames=gar
User Discovery
Users are enumerated from:
/etc/passwd(filter by UID range, shell, home directory existence)- AccountsService D-Bus interface (if available)
Hidden users (UID < 1000, nologin shell, system accounts) are filtered out.
garbg Integration
The greeter reads garbg's config to display the same wallpaper:
- Read
~/.config/garbg/config.tomlfor default wallpaper source - Or read playlist state from
$XDG_RUNTIME_DIR/garbg-state.json - Apply blur effect for greeter aesthetic
- On successful login, gar session starts garbg which shows same image (seamless transition)
Security Model
- gardmd: Runs as root, handles PAM, minimal attack surface
- gardm-greeter: Runs as unprivileged
gardmuser - IPC: Socket permissions restrict access to gardm user
- X11: Greeter runs on isolated X server started by daemon
Configuration
/etc/gardm/config.toml:
[general]
# Default session if user hasn't selected one
default_session = "gar"
# Greeter command
greeter = "/usr/bin/gardm-greeter"
# VT to use (0 = auto-select)
vt = 0
[greeter]
# Theme settings
blur_radius = 20
blur_brightness = 0.7
# Show/hide elements
show_power_buttons = true
show_session_selector = true
# garbg integration
use_garbg_wallpaper = true
fallback_wallpaper = "/usr/share/gardm/backgrounds/default.jpg"
[security]
# Allow empty passwords
allow_empty_password = false
# Lock after N failed attempts (0 = disabled)
lockout_attempts = 5
lockout_duration = 300
PAM Configuration
/etc/pam.d/gardm:
#%PAM-1.0
auth required pam_securetty.so
auth requisite pam_nologin.so
auth include system-local-login
account include system-local-login
session include system-local-login
password include system-local-login
systemd Integration
/usr/lib/systemd/system/gardm.service:
[Unit]
Description=gar Display Manager
After=systemd-user-sessions.service getty@tty1.service plymouth-quit.service
Conflicts=getty@tty1.service
[Service]
ExecStart=/usr/bin/gardmd
Restart=always
[Install]
Alias=display-manager.service
Key Dependencies
| Component | Crates |
|---|---|
| gardmd | pam, nix, sd-notify, serde, tokio |
| gardm-greeter | x11rb, cairo-rs, pango, image, serde |
References
- freedesktop.org: Writing Display Managers
- greetd - Architecture inspiration
- SDDM - Feature reference
- LightDM - Protocol reference
View source
| 1 | # gardm Architecture |
| 2 | |
| 3 | ## Overview |
| 4 | |
| 5 | gardm is the display manager for the gar desktop suite. It follows a **daemon + greeter** architecture similar to [greetd](https://github.com/kennylevinsen/greetd), providing clean separation between authentication/session management and the user interface. |
| 6 | |
| 7 | ## Components |
| 8 | |
| 9 | ``` |
| 10 | ┌─────────────────────────────────────────────────────────────┐ |
| 11 | │ gardmd │ |
| 12 | │ (Display Manager Daemon) │ |
| 13 | │ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │ |
| 14 | │ │ PAM │ │ X11/Xorg │ │ Session Manager │ │ |
| 15 | │ │ Integration │ │ Control │ │ (systemd-logind) │ │ |
| 16 | │ └─────────────┘ └─────────────┘ └─────────────────────┘ │ |
| 17 | │ │ │ |
| 18 | │ Unix Socket IPC │ |
| 19 | │ │ │ |
| 20 | └──────────────────────────┼──────────────────────────────────┘ |
| 21 | │ |
| 22 | ┌──────────────────────────┼──────────────────────────────────┐ |
| 23 | │ ▼ │ |
| 24 | │ gardm-greeter │ |
| 25 | │ (Graphical UI) │ |
| 26 | │ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │ |
| 27 | │ │ Cairo/ │ │ garbg │ │ User Input │ │ |
| 28 | │ │ Pango │ │ Integration │ │ (login form) │ │ |
| 29 | │ └─────────────┘ └─────────────┘ └─────────────────────┘ │ |
| 30 | └─────────────────────────────────────────────────────────────┘ |
| 31 | ``` |
| 32 | |
| 33 | ### gardmd (Daemon) |
| 34 | |
| 35 | The privileged daemon that runs as root. Responsibilities: |
| 36 | |
| 37 | 1. **X11 Server Management**: Start/stop Xorg server on appropriate VT |
| 38 | 2. **PAM Authentication**: Verify user credentials via `/etc/pam.d/gardm` |
| 39 | 3. **Session Launching**: Start selected session (gar, other WMs/DEs) |
| 40 | 4. **systemd-logind Integration**: Register sessions, handle multi-seat |
| 41 | 5. **IPC Server**: Listen on Unix socket for greeter commands |
| 42 | |
| 43 | ### gardm-greeter (Frontend) |
| 44 | |
| 45 | The unprivileged graphical interface. Runs as dedicated `gardm` user. Responsibilities: |
| 46 | |
| 47 | 1. **User Interface**: Render login form, session selector, power buttons |
| 48 | 2. **garbg Integration**: Display same wallpaper that gar session will use |
| 49 | 3. **Visual Effects**: Blur background, animations, theming |
| 50 | 4. **IPC Client**: Send auth requests to daemon, receive responses |
| 51 | |
| 52 | ## IPC Protocol |
| 53 | |
| 54 | JSON-based protocol over Unix socket at `/run/gardm.sock`: |
| 55 | |
| 56 | ### Requests (Greeter → Daemon) |
| 57 | |
| 58 | ```json |
| 59 | // Create authentication session |
| 60 | { "type": "create_session", "username": "user" } |
| 61 | |
| 62 | // Attempt authentication |
| 63 | { "type": "authenticate", "response": "password123" } |
| 64 | |
| 65 | // Start session after successful auth |
| 66 | { "type": "start_session", "cmd": ["gar-session.sh"], "env": [] } |
| 67 | |
| 68 | // Cancel current auth attempt |
| 69 | { "type": "cancel_session" } |
| 70 | |
| 71 | // System actions |
| 72 | { "type": "shutdown" } |
| 73 | { "type": "reboot" } |
| 74 | { "type": "suspend" } |
| 75 | ``` |
| 76 | |
| 77 | ### Responses (Daemon → Greeter) |
| 78 | |
| 79 | ```json |
| 80 | // Success |
| 81 | { "type": "success" } |
| 82 | |
| 83 | // Auth prompt (PAM asking for input) |
| 84 | { "type": "auth_prompt", "prompt": "Password:", "echo": false } |
| 85 | |
| 86 | // Auth info message |
| 87 | { "type": "auth_info", "message": "..." } |
| 88 | |
| 89 | // Auth error |
| 90 | { "type": "auth_error", "message": "Authentication failed" } |
| 91 | |
| 92 | // General error |
| 93 | { "type": "error", "message": "..." } |
| 94 | ``` |
| 95 | |
| 96 | ## Session Discovery |
| 97 | |
| 98 | Sessions are discovered from standard locations: |
| 99 | |
| 100 | - `/usr/share/xsessions/*.desktop` - X11 sessions |
| 101 | - `/usr/share/wayland-sessions/*.desktop` - Wayland sessions (future) |
| 102 | |
| 103 | gar session file example (`/usr/share/xsessions/gar.desktop`): |
| 104 | ```ini |
| 105 | [Desktop Entry] |
| 106 | Name=gar |
| 107 | Comment=Tiling window manager with smart splits |
| 108 | Exec=/usr/local/bin/gar-session.sh |
| 109 | Type=XSession |
| 110 | DesktopNames=gar |
| 111 | ``` |
| 112 | |
| 113 | ## User Discovery |
| 114 | |
| 115 | Users are enumerated from: |
| 116 | |
| 117 | - `/etc/passwd` (filter by UID range, shell, home directory existence) |
| 118 | - AccountsService D-Bus interface (if available) |
| 119 | |
| 120 | Hidden users (UID < 1000, nologin shell, system accounts) are filtered out. |
| 121 | |
| 122 | ## garbg Integration |
| 123 | |
| 124 | The greeter reads garbg's config to display the same wallpaper: |
| 125 | |
| 126 | 1. Read `~/.config/garbg/config.toml` for default wallpaper source |
| 127 | 2. Or read playlist state from `$XDG_RUNTIME_DIR/garbg-state.json` |
| 128 | 3. Apply blur effect for greeter aesthetic |
| 129 | 4. On successful login, gar session starts garbg which shows same image (seamless transition) |
| 130 | |
| 131 | ## Security Model |
| 132 | |
| 133 | - **gardmd**: Runs as root, handles PAM, minimal attack surface |
| 134 | - **gardm-greeter**: Runs as unprivileged `gardm` user |
| 135 | - **IPC**: Socket permissions restrict access to gardm user |
| 136 | - **X11**: Greeter runs on isolated X server started by daemon |
| 137 | |
| 138 | ## Configuration |
| 139 | |
| 140 | `/etc/gardm/config.toml`: |
| 141 | |
| 142 | ```toml |
| 143 | [general] |
| 144 | # Default session if user hasn't selected one |
| 145 | default_session = "gar" |
| 146 | |
| 147 | # Greeter command |
| 148 | greeter = "/usr/bin/gardm-greeter" |
| 149 | |
| 150 | # VT to use (0 = auto-select) |
| 151 | vt = 0 |
| 152 | |
| 153 | [greeter] |
| 154 | # Theme settings |
| 155 | blur_radius = 20 |
| 156 | blur_brightness = 0.7 |
| 157 | |
| 158 | # Show/hide elements |
| 159 | show_power_buttons = true |
| 160 | show_session_selector = true |
| 161 | |
| 162 | # garbg integration |
| 163 | use_garbg_wallpaper = true |
| 164 | fallback_wallpaper = "/usr/share/gardm/backgrounds/default.jpg" |
| 165 | |
| 166 | [security] |
| 167 | # Allow empty passwords |
| 168 | allow_empty_password = false |
| 169 | |
| 170 | # Lock after N failed attempts (0 = disabled) |
| 171 | lockout_attempts = 5 |
| 172 | lockout_duration = 300 |
| 173 | ``` |
| 174 | |
| 175 | ## PAM Configuration |
| 176 | |
| 177 | `/etc/pam.d/gardm`: |
| 178 | |
| 179 | ``` |
| 180 | #%PAM-1.0 |
| 181 | auth required pam_securetty.so |
| 182 | auth requisite pam_nologin.so |
| 183 | auth include system-local-login |
| 184 | account include system-local-login |
| 185 | session include system-local-login |
| 186 | password include system-local-login |
| 187 | ``` |
| 188 | |
| 189 | ## systemd Integration |
| 190 | |
| 191 | `/usr/lib/systemd/system/gardm.service`: |
| 192 | |
| 193 | ```ini |
| 194 | [Unit] |
| 195 | Description=gar Display Manager |
| 196 | After=systemd-user-sessions.service getty@tty1.service plymouth-quit.service |
| 197 | Conflicts=getty@tty1.service |
| 198 | |
| 199 | [Service] |
| 200 | ExecStart=/usr/bin/gardmd |
| 201 | Restart=always |
| 202 | |
| 203 | [Install] |
| 204 | Alias=display-manager.service |
| 205 | ``` |
| 206 | |
| 207 | ## Key Dependencies |
| 208 | |
| 209 | | Component | Crates | |
| 210 | |-----------|--------| |
| 211 | | gardmd | pam, nix, sd-notify, serde, tokio | |
| 212 | | gardm-greeter | x11rb, cairo-rs, pango, image, serde | |
| 213 | |
| 214 | ## References |
| 215 | |
| 216 | - [freedesktop.org: Writing Display Managers](https://systemd.io/WRITING_DISPLAY_MANAGERS/) |
| 217 | - [greetd](https://github.com/kennylevinsen/greetd) - Architecture inspiration |
| 218 | - [SDDM](https://github.com/sddm/sddm) - Feature reference |
| 219 | - [LightDM](https://github.com/canonical/lightdm) - Protocol reference |