;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2019,2020 L p R n d n ;;; ;;; This file is part of GNU Guix. ;;; ;;; GNU Guix is free software; you can redistribute it and/or modify it ;;; under the terms of the GNU General Public License as published by ;;; the Free Software Foundation; either version 3 of the License, or (at ;;; your option) any later version. ;;; ;;; GNU Guix is distributed in the hope that it will be useful, but ;;; WITHOUT ANY WARRANTY; without even the implied warranty of ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;;; GNU General Public License for more details. ;;; ;;; You should have received a copy of the GNU General Public License ;;; along with GNU Guix. If not, see . (define-module (gnu services lightdm) #:use-module (guix gexp) #:use-module (guix records) #:use-module (gnu system pam) #:use-module (gnu system shadow) #:use-module (gnu services) #:use-module (gnu services dbus) #:use-module (gnu services desktop) #:use-module (gnu services shepherd) #:use-module (gnu services xorg) #:use-module (gnu packages admin) #:use-module (gnu packages display-managers) #:use-module (gnu packages freedesktop) #:use-module (gnu packages gnome) #:use-module (gnu packages xorg) #:export (lightdm-configuration lightdm-configuration? lightdm-service-type lightdm-gtk-greeter-configuration lightdm-gtk-greeter-configuration-file)) ;; GREETERS (define-record-type* lightdm-gtk-greeter-configuration make-lightdm-gtk-greeter-configuration lightdm-gtk-greeter-configuration? (theme-name lightdm-gtk-greeter-configuration-theme-name (default "Adwaita")) (icon-theme-name lightdm-gtk-greeter-configuration-icon-theme-name (default "Adwaita")) (cursor-theme-name lightdm-gtk-greeter-configuration-cursor-theme-name (default "Adwaita")) (cursor-size lightdm-gtk-greeter-configuration-cursor-size (default 16)) (background lightdm-gtk-greeter-configuration-background (default "")) (extra-config lightdm-gtk-greeter-configuration-extra-config (default ""))) (define (lightdm-gtk-greeter-configuration-file config) (mixed-text-file "lightdm-gtk-greeter.conf" " [greeter] theme-name = " (lightdm-gtk-greeter-configuration-theme-name config) " icon-theme-name = " (lightdm-gtk-greeter-configuration-icon-theme-name config) " cursor-theme-name = " (lightdm-gtk-greeter-configuration-cursor-theme-name config) " cursor-theme-size = " (number->string (lightdm-gtk-greeter-configuration-cursor-size config)) (if (string-null? (lightdm-gtk-greeter-configuration-background config)) "" (string-append " background = " (lightdm-gtk-greeter-configuration-background config))) " " (lightdm-gtk-greeter-configuration-extra-config config))) ;; LIGHTDM (define-record-type* lightdm-configuration make-lightdm-configuration lightdm-configuration? (lightdm lightdm-configuration-lightdm (default lightdm)) (sessions-directory lightdm-configuration-sessions-directory (default (string-append "/run/current-system/profile/share/xsessions" ":/run/current-system/profile/share/wayland-sessions"))) (allow-empty-passwords? lightdm-configuration-allow-empty-passwords? (default #f)) ;; [Seat] (xorg-configuration lightdm-configuration-xorg (default (xorg-configuration))) (session-wrapper lightdm-configuration-session-wrapper (default (xinitrc))) (default-session-name lightdm-configuration-default-session (default "")) ;; [Autologin] (autologin-user lightdm-configuration-autologin-user (default "")) (autologin-timeout lightdm-configuration-autologin-timeout (default #f)) ;; [Greeter] (greeter-name lightdm-configuration-greeter-name (default "lightdm-gtk-greeter")) (greeter-package lightdm-configuration-greeter-package (default lightdm-gtk-greeter)) (greeter-assets lightdm-configuration-greeter-assets (default (list adwaita-icon-theme gnome-themes-standard))) (greeter-configuration-file lightdm-configuration-greeter-configuration-file (default (lightdm-gtk-greeter-configuration-file (lightdm-gtk-greeter-configuration)))) (extra-config lightdm-configuration-extra-config (default ""))) (define %lightdm-accounts (list (user-group (name "lightdm") (system? #t)) (user-account (name "lightdm") (group "lightdm") (system? #t) (comment "LightDM user") (home-directory "/var/lib/lightdm") (shell (file-append shadow "/sbin/nologin"))))) (define %lightdm-activation ;; Ensure /var/lib/lightdm is owned by the "lightdm" user. ;; Mimics what is done for gdm ;; see a43e9157ef479e94c19951cc9d228cf153bf78ee (with-imported-modules '((guix build utils)) #~(begin (use-modules (guix build utils)) (define (ensure-ownership directory) (let* ((lightdm (getpwnam "lightdm")) (uid (passwd:uid lightdm)) (gid (passwd:gid lightdm)) (st (stat directory #f))) ;; Recurse into directory only if it has wrong ownership. (when (and st (or (not (= uid (stat:uid st))) (not (= gid (stat:gid st))))) (for-each (lambda (file) (chown file uid gid)) (find-files "directory" #:directories? #t))))) (when (not (stat "/var/lib/lightdm-data" #f)) (mkdir-p "/var/lib/lightdm-data")) (for-each ensure-ownership '("/var/lib/lightdm" "/var/lib/lightdm-data"))))) (define (lightdm-configuration-file config) (mixed-text-file "lightdm.conf" " [LightDM] greeter-user = lightdm greeters-directory = /run/current-system/profile/share/xgreeters sessions-directory = " (lightdm-configuration-sessions-directory config) " [Seat:*] xserver-command = " (xorg-start-command (lightdm-configuration-xorg config)) " greeter-session = " (lightdm-configuration-greeter-name config) " user-session = " (lightdm-configuration-default-session config) (if (string-null? (lightdm-configuration-autologin-user config)) "" (string-append " autologin-user = " (lightdm-configuration-autologin-user config))) (if (string-null? (lightdm-configuration-default-session config)) "" (string-append " autologin-session = " (lightdm-configuration-default-session config))) (if (lightdm-configuration-autologin-timeout config) (string-append " autologin-user-timeout = " (number->string (lightdm-configuration-autologin-timeout config))) "") " session-wrapper = " (lightdm-configuration-session-wrapper config) " " (lightdm-configuration-extra-config config))) (define (lightdm-pam-service config) "Return a PAM service for @command{lightdm}." (unix-pam-service "lightdm" #:allow-empty-passwords? (lightdm-configuration-allow-empty-passwords? config))) (define (lightdm-greeter-pam-service) "Return a PAM service for @command{lightdm-greeter}}." (pam-service (name "lightdm-greeter") (auth (list ;; Load environment from /etc/environment and ~/.pam_environment (pam-entry (control "required") (module "pam_env.so")) ;; Always let the greeter start without authentication (pam-entry (control "required") (module "pam_permit.so")))) ;; No action required for account management (account (list (pam-entry (control "required") (module "pam_permit.so")))) ;; Can't change password (password (list (pam-entry (control "required") (module "pam_deny.so")))) ;; Setup session (session (list (pam-entry (control "required") (module "pam_unix.so")) (pam-entry (control "required") (module "pam_env.so")))))) (define (lightdm-autologin-pam-service) "Return a PAM service for @command{lightdm-autologin}}." (pam-service (name "lightdm-autologin") (auth (list ;; Block login if they are globally disabled (pam-entry (control "required") (module "pam_nologin.so")) ;; Load environment from /etc/environment and ~/.pam_environment (pam-entry (control "required") (module "pam_env.so")) ;; Allow access without authentication (pam-entry (control "required") (module "pam_permit.so")))) ;; Stop autologin if account requires action (account (list (pam-entry (control "required") (module "pam_unix.so")))) ;; Can't change password (password (list (pam-entry (control "required") (module "pam_deny.so")))) ;; Setup session (session (list (pam-entry (control "required") (module "pam_unix.so")))))) (define (lightdm-shepherd-service config) "Return a for LightDM with CONFIG." (define lightdm-command #~(list #$(file-append (lightdm-configuration-lightdm config) "/sbin/lightdm"))) (list (shepherd-service (documentation "LightDM display manager.") (requirement '(dbus-system user-processes host-name)) (provision '(display-manager)) (respawn? #f) (start #~(lambda () (fork+exec-command #$lightdm-command #:environment-variables (list (string-append "PATH=/run/current-system/profile/sbin" ":/run/current-system/profile/bin"))))) (stop #~(make-kill-destructor))))) (define (lightdm-etc-service config) (let ((lightdm-conf-file (lightdm-configuration-file config)) (greeter-conf-file (lightdm-configuration-greeter-configuration-file config))) (if greeter-conf-file (list `("xdg/lightdm/lightdm.conf.d/lightdm.conf" ,lightdm-conf-file) `(,(string-append "xdg/lightdm/" (computed-file-name greeter-conf-file)) ,greeter-conf-file)) (list `("xdg/lightdm/lightdm.conf.d/lightdm.conf" ,lightdm-conf-file))))) (define (lightdm-pam-services config) (list (lightdm-pam-service config) (lightdm-greeter-pam-service) (lightdm-autologin-pam-service))) (define (lightdm-profile-service config) (append (list lightdm (lightdm-configuration-greeter-package config)) (lightdm-configuration-greeter-assets config))) (define lightdm-service-type (handle-xorg-configuration lightdm-configuration (service-type (name 'lightdm) (extensions (list (service-extension shepherd-root-service-type lightdm-shepherd-service) (service-extension activation-service-type (const %lightdm-activation)) (service-extension etc-service-type lightdm-etc-service) (service-extension pam-root-service-type lightdm-pam-services) (service-extension dbus-root-service-type (compose list lightdm-configuration-lightdm)) (service-extension account-service-type (const %lightdm-accounts)) (service-extension profile-service-type lightdm-profile-service))) (default-value (lightdm-configuration)) (description "Return a service that spawns the LightDM graphical login manager."))))