From f300718619cd4279ff9504a333cf6e53cd29fc8b Mon Sep 17 00:00:00 2001 From: L p R n d n Date: Thu, 18 Apr 2019 17:58:56 +0200 Subject: [PATCH 8/9] services: Add lightdm-service-type. * gnu/services/lightdm.scm: Add file (, , ): New record types. (lightdm-seat-configuration->list, lightdm-configuration-file, lightdm-pam-services, lightdm-pam-service, lightdm-etc-service, lightdm-shepherd-service, lightdm-profile-service, lightdm-gtk-greeter-configuration-file, lightdm-gtk-greeter-profile-service, lightdm-gtk-greeter-lightdm-service, lightdm-gtk-greeter-etc-service): New procedures. (%lightdm-accounts, %lightdm-activation, lightdm-greeter-pam-service, lightdm-autologin-pam-service, lightdm-service-type, lightdm-gtk-greeter-service-type): New variables. * doc/guix.texi (X Window): Add documentation. * gnu/local.mk (GNU_SYSTEM_MODULES): Add it. --- doc/guix.texi | 129 ++++++++++++ gnu/local.mk | 1 + gnu/services/lightdm.scm | 422 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 552 insertions(+) create mode 100644 gnu/services/lightdm.scm diff --git a/doc/guix.texi b/doc/guix.texi index ef5f68db24..54eba225d3 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -14726,6 +14726,135 @@ auto-login session. @end table @end deftp +@defvr {Scheme Variable} lightdm-service-type +Service type for the LightDM graphical login manager. +It uses the @code{lightdm-gtk-greeter} as default greeter. +See @code{lightdm-configuration} below for configuration and greeters' +services for their specific configuration. +@end defvr + +@deftp {Data Type} lightdm-configuration +Data type representing the LightDM service configuration. + +@table @asis +@item @code{lightdm} (default: @code{lightdm}) +The LightDM package to use. + +@item @code{allow-empty-passwords?} (default: @code{#f}) +Whether to allow logins with empty passwords. + +@item @code{xorg-configuration} (default: @code{(xorg-configuration)}) +Default configuration of the Xorg graphical server. This configuration +will be used for all seats unless explicitly defined. + +@item @code{sessions-directory} (default:"/run/current-system/profile/share/xsessions:/run/current-system/profile/share/wayland-sessions") +Directories where LightDM will search for sessions' @code{.desktop} files. + +@item @code{remote-sessions-directory} (default:"/run/current-system/profile/share/remote-session") +Directories where LightDM will search for remote sessions' +@code{.desktop} files. + +@item @code{seats} (default: @code{'()}) +A list of @code{lightdm-seat-configuration} records (see below) +to include in configuration. Note that needed additional packages or +configuration will need to be done manually. Thus, we recommend using a +greeter service for defining seats. If none are provided here or by a greeter, +a fallback one is added. + +@item @code{extra-config} (default: @code{'()}) +A list of strings each describing a custom setting to append to the LightDM +configuration. + +@end table +@end deftp + +@deftp {Data Type} lightdm-seat-configuration +Record representing a seat configuration for LightDM. + +@table @asis +@item @code{name-glob} (default: @code{"*"}) +Seat configuration is matched to all seats matching the name glob. + +@item @code{type} (default: @code{"local"}) +Type of seat. @code{"local"} or @code{"xremote"}. + +@item @code{xorg-configuration} (default: @code{#f}) +Configuration of the Xorg graphical server. + +@item @code{session-wrapper} (default: @code{(xinitrc)}) +Script to run before starting a X session. + +@item @code{greeter-session} (default: "lightdm-gtk-greeter") +The name of the greeter to be used for this seat. + +@item @code{default-user-session} (default: "") +The name of the default @code{.desktop} file describing a session. +Will be used for @code{user-session} and @code{autologin-session} if necessary. + +@item @code{autologin-user} (default: "") +If @code{autologin-user} is set, LightDM logs in directly +as @code{autologin-user} to the session defined in +@code{default-user-session}. This user should be part of the +@code{autologin} group. + +@item @code{extra-config} (default: @code{'()}) +A list of strings each describing a custom setting to append to the seat +configuration. + +@end table +@end deftp + +@defvr {Scheme Variable} lightdm-gtk-greeter-service-type +Service type for the @code{lightdm-gtk-greeter} for LightDM. +See @code{lightdm-gtk-greeter-configuration} below for configuration. +@end defvr + +@deftp {Data Type} lightdm-gtk-greeter-configuration +This data type represents the configuration for @code{lightdm-gtk-greeter}. +Use it as an argument of @code{lightdm-gtk-greeter-configuration-file} to +get the corresponding file. + +@table @asis +@item @code{lightdm-gtk-greeter} (default: @code{lightdm-gtk-greeter}) +lightdm-gtk-greeter package to use. + +@item @code{assets} (default: @code{(list adwaita-icon-theme gnome-themes-standard)}) +A list of packages needed by the greeter: icons, themes, fonts etc. + +@item @code{theme-name} (default: "Adwaita") +The name of the GTK+ theme to be used. + +@item @code{icon-theme-name} (default: "Adwaita") +The name of the icon theme to be used for displaying icons. + +@item @code{cursor-theme-name} (default: "Adwaita") +The name of the theme to be used for the cursor. + +@item @code{cursor-size} (default: @code{16}) +The size of the cursor. + +@item @code{background} (default: @code{(file-append %artwork-repository "/grub/GuixSD-fully-black-16-9.svg")}) +Path to the background image to be used. + +@item @code{a11y-state} (default: "contrast; font; keyboard; reader") +String describing states of accessibility features. @code{"name"} saves state +on exit, @code{"-name"} disables at start and @code{"+name"} enables it. + +@item @code{reader} (default: "") +Command to launch screen reader. + +@item @code{seats} (default: @code{'()}) +List of @code{lightdm-seat-configuration} records (see above) to add to +lightdm.conf through extension. @code{greeter-session} fields +will be forced to @code{"lightdm-gtk-greeter"} + +@item @code{extra-config} (default: @code{'()}) +A list of string each describing a custom setting to append to the greeter +configuration. + +@end table +@end deftp + @cindex Xorg, configuration @deftp {Data Type} xorg-configuration This data type represents the configuration of the Xorg graphical display diff --git a/gnu/local.mk b/gnu/local.mk index 952fc55df4..66ceb59777 100644 --- a/gnu/local.mk +++ b/gnu/local.mk @@ -568,6 +568,7 @@ GNU_SYSTEM_MODULES = \ %D%/services/getmail.scm \ %D%/services/guix.scm \ %D%/services/kerberos.scm \ + %D%/services/lightdm.scm \ %D%/services/linux.scm \ %D%/services/lirc.scm \ %D%/services/virtualization.scm \ diff --git a/gnu/services/lightdm.scm b/gnu/services/lightdm.scm new file mode 100644 index 0000000000..fa5330aade --- /dev/null +++ b/gnu/services/lightdm.scm @@ -0,0 +1,422 @@ +;;; 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 (srfi srfi-1) + #:use-module (ice-9 match) + #:use-module (ice-9 receive) + + #:use-module (guix gexp) + #:use-module (guix records) + + #:use-module (gnu artwork) + #: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-seat-configuration + + lightdm-configuration + lightdm-configuration? + lightdm-service-type + + lightdm-gtk-greeter-configuration + lightdm-gtk-greeter-configuration? + lightdm-gtk-greeter-service-type)) + + +;; LIGHTDM + +(define-record-type* + lightdm-seat-configuration make-lightdm-seat-configuration + lightdm-seat-configuration? + (name-glob lightdm-seat-configuration-name-glob + (default "*")) + (type lightdm-seat-configuration-type + (default "local")) + (xorg-configuration lightdm-seat-configuration-xorg-configuration + (default #f)) + (session-wrapper lightdm-seat-configuration-session-wrapper + (default (xinitrc))) + (greeter-session lightdm-seat-configuration-greeter-session + (default "lightdm-gtk-greeter")) + (default-user-session lightdm-seat-configuration-default-user-session + (default "")) + (autologin-user lightdm-seat-configuration-autologin-user + (default "")) + (extra-config lightdm-seat-configuration-extra-config + (default '()))) + + +(define (lightdm-seat-configuration->list seat default-xorg-configuration) + "Given a seat, outputs a list to be used by mixed-text-file through `apply." + (match-record seat + (name-glob + type xorg-configuration session-wrapper + greeter-session default-user-session + autologin-user extra-config) + (list " + [Seat:" name-glob "] + type = " type + ;; If no xorg-configuration is set by the seat use the one provided + ;; by the lightdm service + " + xserver-command = " (xorg-start-command + (or xorg-configuration + default-xorg-configuration)) + " + session-wrapper = " session-wrapper " + greeter-session = " greeter-session + (if (string-null? default-user-session) "" + (string-append " + user-session = " default-user-session)) " + " + ;; Turn autologin ON if autologin-user is set + (if (string-null? autologin-user) "" + (string-append " + autologin-user = " autologin-user " + autologin-session = " default-user-session)) " + " (string-join extra-config "\n")))) + + +(define-record-type* + lightdm-configuration make-lightdm-configuration + lightdm-configuration? + ;; General configuration + (lightdm lightdm-configuration-lightdm + (default lightdm)) + (allow-empty-passwords? lightdm-configuration-allow-empty-passwords? + (default #f)) + (sessions-directory + lightdm-configuration-sessions-directory + (default + "/run/current-system/profile/share/xsessions:/run/current-system/profile/share/wayland-sessions")) + (greeters-directory lightdm-configuration-greeters-directory + (default "/run/current-system/profile/share/xgreeters")) + (remote-sessions-directory lightdm-configuration-remote-sessions-directory + (default + "/run/current-system/profile/share/remote-sessions")) + ;; Having a xorg-configuration field here allows us + ;; to benefit from set-xorg-configuration. + (xorg-configuration lightdm-configuration-xorg-configuration + (default (xorg-configuration))) + (seats lightdm-configuration-seats + (default '())) + (extra-config lightdm-configuration-extra-config + (default '()))) + +(define (lightdm-configuration-file config) + (match-record config + (allow-empty-passwords? + sessions-directory greeters-directory + remote-sessions-directory xorg-configuration + seats extra-config) + ;; Little trick to allow unquote-splicing of seats + (apply mixed-text-file `("lightdm.conf" " +[LightDM] +greeter-user = lightdm +greeters-directory = " ,greeters-directory " +sessions-directory = " ,sessions-directory " +remote-sessions-directory = " ,remote-sessions-directory " + +#Seats + " ,@(if (null? seats) + (lightdm-seat-configuration->list (lightdm-seat-configuration) + xorg-configuration) + (concatenate + (map (lambda (seat) + (lightdm-seat-configuration->list seat xorg-configuration)) + seats))) " +#Extra config +" ,(string-join extra-config "\n"))))) + +(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-pam-service config) + "Return a PAM service for @command{lightdm}." + (unix-pam-service + "lightdm" + #:login-uid? #t + #: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")))))) + + +(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")) + + (pam-entry (control "required") (module "pam_succeed_if.so") + (arguments (list "uid >= 1000"))) + ;; 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-pam-services config) + (list (lightdm-pam-service config) + (lightdm-greeter-pam-service) + (lightdm-autologin-pam-service))) + +(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 xorg-server)) + (respawn? #f) + (start + #~(lambda () + (fork+exec-command + #$lightdm-command + #:environment-variables + (list + "PATH=/run/current-system/profile/sbin:/run/current-system/profile/bin")))) + (stop #~(make-kill-destructor))))) + +(define (lightdm-etc-service config) + `(("xdg/lightdm/lightdm.conf.d/lightdm.conf" + ,(lightdm-configuration-file config)))) + +(define (lightdm-profile-service config) + ;; In case no seats are provided, we fall back on a default one + ;; with lightdm-gtk-greeter. Add necessary packages. + (let ((seats (lightdm-configuration-seats config)) + (lightdm (lightdm-configuration-lightdm config))) + (if (null? seats) + (list lightdm lightdm-gtk-greeter) + (list lightdm)))) + +(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 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 etc-service-type + lightdm-etc-service) + (service-extension profile-service-type + lightdm-profile-service))) + ;; LightDM is extended with lists of seats + ;; or with a xorg-configuration by set-xorg-configuration + ;; Deal with both cases. + (compose + (lambda (extensions) + (receive (xorg-configuration-extensions + seats-extensions) + (partition xorg-configuration? extensions) + (list `("xorg-configuration" . + ;; Mimic handle-xorg-configuration + ,(match xorg-configuration-extensions + (() #f) + ((config . _) config))) + `("seats" . ,(concatenate seats-extensions)))))) + (extend (lambda (config extensions) + (lightdm-configuration + (inherit config) + (xorg-configuration + (or (assoc-ref extensions "xorg-configuration") + (lightdm-configuration-xorg-configuration config))) + (seats (append (assoc-ref extensions "seats") + (lightdm-configuration-seats config)))))) + (default-value (lightdm-configuration)) + (description "Return a service that spawns the + LightDM graphical login manager."))) + +;; GREETERS + +(define-record-type* + lightdm-gtk-greeter-configuration make-lightdm-gtk-greeter-configuration + lightdm-gtk-greeter-configuration? + + (lightdm-gtk-greeter lightdm-gtk-greeter-configuration-lightdm-gtk-greeter + (default lightdm-gtk-greeter)) + (assets lightdm-gtk-greeter-configuration-assets + (default (list adwaita-icon-theme + gnome-themes-standard))) + (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-theme-size lightdm-gtk-greeter-configuration-cursor-theme-size + (default 16)) + (background lightdm-gtk-greeter-configuration-background + (default (file-append %artwork-repository + "/grub/GuixSD-fully-black-16-9.svg"))) + (a11y-states lightdm-gtk-greeter-a11y-states + (default "contrast; font; keyboard; reader")) + (reader lightdm-gtk-greeter-reader + (default #f)) + (seats lightdm-gtk-greeter-configuration-seats + (default (list (lightdm-seat-configuration)))) + (extra-config lightdm-gtk-greeter-configuration-extra-config + (default '()))) + +(define (lightdm-gtk-greeter-configuration-file config) + (match-record config + (theme-name icon-theme-name cursor-theme-name + cursor-theme-size background a11y-states + reader extra-config) + (mixed-text-file "lightdm-gtk-greeter.conf" " +[greeter] +theme-name = " theme-name " +icon-theme-name = " icon-theme-name " +cursor-theme-name = " cursor-theme-name " +cursor-theme-size = " (number->string cursor-theme-size) " +background = " background " +a11y-states = " a11y-states " +" (if reader (string-append "reader = " reader) "") " +" (string-join extra-config "\n")))) + +(define (lightdm-gtk-greeter-lightdm-service config) + ;; Enforce greeter-session field to lightdm-gtk-greeter + (map + (lambda (seat) + (lightdm-seat-configuration + (inherit seat) + (greeter-session "lightdm-gtk-greeter"))) + (lightdm-gtk-greeter-configuration-seats config))) + +(define (lightdm-gtk-greeter-etc-service config) + `(("xdg/lightdm/lightdm-gtk-greeter.conf" + ,(lightdm-gtk-greeter-configuration-file config)))) + +(define (lightdm-gtk-greeter-profile-service config) + (cons (lightdm-gtk-greeter-configuration-lightdm-gtk-greeter config) + (lightdm-gtk-greeter-configuration-assets config))) + +(define lightdm-gtk-greeter-service-type + (service-type (name 'lightdm-gtk-greeter) + (extensions + (list + (service-extension lightdm-service-type + lightdm-gtk-greeter-lightdm-service) + (service-extension etc-service-type + lightdm-gtk-greeter-etc-service) + (service-extension profile-service-type + lightdm-gtk-greeter-profile-service))) + (default-value (lightdm-gtk-greeter-configuration)) + (description + "Set-up lightdm-gtk-greeter as well +as its configuration file and extends LightDM with its seats."))) -- 2.26.1