gnu: guile-simple-zmq: Update to 0.0.0-10.ff0b39a.
[jackhill/guix/guix.git] / gnu / system / pam.scm
CommitLineData
0ded70f3 1;;; GNU Guix --- Functional package management for GNU
671e6a81 2;;; Copyright © 2013-2017, 2019-2021 Ludovic Courtès <ludo@gnu.org>
0ded70f3
LC
3;;;
4;;; This file is part of GNU Guix.
5;;;
6;;; GNU Guix is free software; you can redistribute it and/or modify it
7;;; under the terms of the GNU General Public License as published by
8;;; the Free Software Foundation; either version 3 of the License, or (at
9;;; your option) any later version.
10;;;
11;;; GNU Guix is distributed in the hope that it will be useful, but
12;;; WITHOUT ANY WARRANTY; without even the implied warranty of
13;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14;;; GNU General Public License for more details.
15;;;
16;;; You should have received a copy of the GNU General Public License
17;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
18
6e828634 19(define-module (gnu system pam)
0ded70f3
LC
20 #:use-module (guix records)
21 #:use-module (guix derivations)
b5f4e686 22 #:use-module (guix gexp)
0adfe95a 23 #:use-module (gnu services)
0ded70f3
LC
24 #:use-module (ice-9 match)
25 #:use-module (srfi srfi-1)
909147e4 26 #:use-module (srfi srfi-9)
12c00bca 27 #:use-module (srfi srfi-11)
0ded70f3
LC
28 #:use-module (srfi srfi-26)
29 #:use-module ((guix utils) #:select (%current-system))
b948ab8b 30 #:use-module (gnu packages linux)
0ded70f3 31 #:export (pam-service
d7bce31c
LC
32 pam-service-name
33 pam-service-account
34 pam-service-auth
35 pam-service-password
36 pam-service-session
37
0ded70f3 38 pam-entry
d7bce31c
LC
39 pam-entry-control
40 pam-entry-module
41 pam-entry-arguments
42
909147e4
RW
43 pam-limits-entry
44 pam-limits-entry-domain
45 pam-limits-entry-type
46 pam-limits-entry-item
47 pam-limits-entry-value
48 pam-limits-entry->string
49
0ded70f3 50 pam-services->directory
09e028f4 51 unix-pam-service
0adfe95a
LC
52 base-pam-services
53
fbc31dc1
LC
54 session-environment-service
55 session-environment-service-type
56
0adfe95a
LC
57 pam-root-service-type
58 pam-root-service))
0ded70f3
LC
59
60;;; Commentary:
61;;;
6e828634 62;;; Configuration of the pluggable authentication modules (PAM).
0ded70f3
LC
63;;;
64;;; Code:
65
66;; PAM services (see
67;; <http://www.linux-pam.org/Linux-PAM-html/sag-configuration-file.html>.)
68(define-record-type* <pam-service> pam-service
69 make-pam-service
70 pam-service?
71 (name pam-service-name) ; string
72
73 ;; The four "management groups".
74 (account pam-service-account ; list of <pam-entry>
75 (default '()))
76 (auth pam-service-auth
77 (default '()))
78 (password pam-service-password
79 (default '()))
80 (session pam-service-session
81 (default '())))
82
83(define-record-type* <pam-entry> pam-entry
84 make-pam-entry
85 pam-entry?
b5f4e686
LC
86 (control pam-entry-control) ; string
87 (module pam-entry-module) ; file name
88 (arguments pam-entry-arguments ; list of string-valued g-expressions
0ded70f3
LC
89 (default '())))
90
909147e4
RW
91;; PAM limits entries are used by the pam_limits PAM module to set or override
92;; limits on system resources for user sessions. The format is specified
93;; here: http://linux-pam.org/Linux-PAM-html/sag-pam_limits.html
94(define-record-type <pam-limits-entry>
95 (make-pam-limits-entry domain type item value)
96 pam-limits-entry?
97 (domain pam-limits-entry-domain) ; string
98 (type pam-limits-entry-type) ; symbol
99 (item pam-limits-entry-item) ; symbol
100 (value pam-limits-entry-value)) ; symbol or number
101
102(define (pam-limits-entry domain type item value)
103 "Construct a pam-limits-entry ensuring that the provided values are valid."
104 (define (valid? value)
105 (case item
106 ((priority) (number? value))
107 ((nice) (and (number? value)
108 (>= value -20)
109 (<= value 19)))
110 (else (or (and (number? value)
111 (>= value -1))
112 (member value '(unlimited infinity))))))
113 (define items
114 (list 'core 'data 'fsize
115 'memlock 'nofile 'rss
116 'stack 'cpu 'nproc
117 'as 'maxlogins 'maxsyslogins
118 'priority 'locks 'sigpending
119 'msgqueue 'nice 'rtprio))
120 (when (not (member type '(hard soft both)))
121 (error "invalid limit type" type))
122 (when (not (member item items))
123 (error "invalid limit item" item))
124 (when (not (valid? value))
125 (error "invalid limit value" value))
126 (make-pam-limits-entry domain type item value))
127
128(define (pam-limits-entry->string entry)
129 "Convert a pam-limits-entry record to a string."
130 (match entry
131 (($ <pam-limits-entry> domain type item value)
132 (string-join (list domain
133 (if (eq? type 'both)
134 "-"
135 (symbol->string type))
136 (symbol->string item)
137 (cond
138 ((symbol? value)
139 (symbol->string value))
140 (else
141 (number->string value))))
142 " "))))
143
0ded70f3 144(define (pam-service->configuration service)
b5f4e686
LC
145 "Return the derivation building the configuration file for SERVICE, to be
146dumped in /etc/pam.d/NAME, where NAME is the name of SERVICE."
147 (define (entry->gexp type entry)
0ded70f3
LC
148 (match entry
149 (($ <pam-entry> control module (arguments ...))
b5f4e686
LC
150 #~(format #t "~a ~a ~a ~a~%"
151 #$type #$control #$module
152 (string-join (list #$@arguments))))))
0ded70f3
LC
153
154 (match service
155 (($ <pam-service> name account auth password session)
b5f4e686
LC
156 (define builder
157 #~(begin
158 (with-output-to-file #$output
159 (lambda ()
160 #$@(append (map (cut entry->gexp "account" <>) account)
161 (map (cut entry->gexp "auth" <>) auth)
162 (map (cut entry->gexp "password" <>) password)
163 (map (cut entry->gexp "session" <>) session))
164 #t))))
165
23afe939 166 (computed-file name builder))))
0ded70f3 167
d9f0a237 168(define (pam-services->directory services)
0ded70f3
LC
169 "Return the derivation to build the configuration directory to be used as
170/etc/pam.d for SERVICES."
23afe939
LC
171 (let ((names (map pam-service-name services))
172 (files (map pam-service->configuration services)))
0ded70f3 173 (define builder
b5f4e686 174 #~(begin
11dddd8a
LC
175 (use-modules (ice-9 match)
176 (srfi srfi-1))
0ded70f3 177
b5f4e686
LC
178 (mkdir #$output)
179 (for-each (match-lambda
0adfe95a
LC
180 ((name file)
181 (symlink file (string-append #$output "/" name))))
11dddd8a
LC
182
183 ;; Since <pam-service> objects cannot be compared with
184 ;; 'equal?' since they contain gexps, which contain
185 ;; closures, use 'delete-duplicates' on the build-side
186 ;; instead. See <http://bugs.gnu.org/20037>.
187 (delete-duplicates '#$(zip names files)))))
0ded70f3 188
23afe939 189 (computed-file "pam.d" builder)))
0ded70f3
LC
190
191(define %pam-other-services
192 ;; The "other" PAM configuration, which denies everything (see
193 ;; <http://www.linux-pam.org/Linux-PAM-html/sag-configuration-example.html>.)
194 (let ((deny (pam-entry
195 (control "required")
196 (module "pam_deny.so"))))
197 (pam-service
198 (name "other")
199 (account (list deny))
200 (auth (list deny))
201 (password (list deny))
202 (session (list deny)))))
203
204(define unix-pam-service
205 (let ((unix (pam-entry
206 (control "required")
af9908ff
SB
207 (module "pam_unix.so")))
208 (env (pam-entry ; to honor /etc/environment.
209 (control "required")
210 (module "pam_env.so"))))
b948ab8b
OP
211 (lambda* (name #:key allow-empty-passwords? allow-root? motd
212 login-uid? gnupg?)
0ded70f3 213 "Return a standard Unix-style PAM service for NAME. When
e586257b
RW
214ALLOW-EMPTY-PASSWORDS? is true, allow empty passwords. When ALLOW-ROOT? is
215true, allow root to run the command without authentication. When MOTD is
af55ca48
LC
216true, it should be a file-like object used as the message-of-the-day.
217When LOGIN-UID? is true, require the 'pam_loginuid' module; that module sets
b948ab8b
OP
218/proc/self/loginuid, which the libc 'getlogin' function relies on. When
219GNUPG? is true, require the 'pam_gnupg.so' module; that module hands over
220the login password to 'gpg-agent'."
0ded70f3 221 ;; See <http://www.linux-pam.org/Linux-PAM-html/sag-configuration-example.html>.
af55ca48
LC
222 (pam-service
223 (name name)
224 (account (list unix))
225 (auth (append (if allow-root?
226 (list (pam-entry
227 (control "sufficient")
228 (module "pam_rootok.so")))
229 '())
230 (list (if allow-empty-passwords?
231 (pam-entry
232 (control "required")
233 (module "pam_unix.so")
234 (arguments '("nullok")))
b948ab8b
OP
235 unix))
236 (if gnupg?
237 (list (pam-entry
238 (control "required")
239 (module (file-append pam-gnupg "/lib/security/pam_gnupg.so"))))
240 '())))
af55ca48
LC
241 (password (list (pam-entry
242 (control "required")
243 (module "pam_unix.so")
244 ;; Store SHA-512 encrypted passwords in /etc/shadow.
245 (arguments '("sha512" "shadow")))))
246 (session `(,@(if motd
247 (list (pam-entry
248 (control "optional")
249 (module "pam_motd.so")
250 (arguments
251 (list #~(string-append "motd=" #$motd)))))
252 '())
253 ,@(if login-uid?
254 (list (pam-entry ;to fill in /proc/self/loginuid
255 (control "required")
256 (module "pam_loginuid.so")))
257 '())
b948ab8b
OP
258 ,@(if gnupg?
259 (list (pam-entry
260 (control "required")
261 (module (file-append pam-gnupg "/lib/security/pam_gnupg.so"))))
262 '())
af55ca48 263 ,env ,unix))))))
0ded70f3 264
da417ffe
LC
265(define (rootok-pam-service command)
266 "Return a PAM service for COMMAND such that 'root' does not need to
267authenticate to run COMMAND."
268 (let ((unix (pam-entry
269 (control "required")
270 (module "pam_unix.so"))))
271 (pam-service
272 (name command)
273 (account (list unix))
274 (auth (list (pam-entry
275 (control "sufficient")
276 (module "pam_rootok.so"))))
277 (password (list unix))
278 (session (list unix)))))
279
09e028f4
LC
280(define* (base-pam-services #:key allow-empty-passwords?)
281 "Return the list of basic PAM services everyone would want."
da417ffe
LC
282 ;; TODO: Add other Shadow programs?
283 (append (list %pam-other-services)
284
285 ;; These programs are setuid-root.
286 (map (cut unix-pam-service <>
287 #:allow-empty-passwords? allow-empty-passwords?)
671e6a81 288 '("passwd" "chfn" "sudo"))
e586257b
RW
289 ;; This is setuid-root, as well. Allow root to run "su" without
290 ;; authenticating.
291 (list (unix-pam-service "su"
292 #:allow-empty-passwords? allow-empty-passwords?
293 #:allow-root? #t))
da417ffe
LC
294
295 ;; These programs are not setuid-root, and we want root to be able
296 ;; to run them without having to authenticate (notably because
297 ;; 'useradd' and 'groupadd' are run during system activation.)
298 (map rootok-pam-service
299 '("useradd" "userdel" "usermod"
300 "groupadd" "groupdel" "groupmod"))))
09e028f4 301
0adfe95a 302\f
fbc31dc1
LC
303;;;
304;;; System-wide environment variables.
305;;;
306
307(define (environment-variables->environment-file vars)
308 "Return a file for pam_env(8) that contains environment variables VARS."
309 (apply mixed-text-file "environment"
310 (append-map (match-lambda
311 ((key . value)
312 (list key "=" value "\n")))
313 vars)))
314
315(define session-environment-service-type
316 (service-type
317 (name 'session-environment)
318 (extensions
319 (list (service-extension
320 etc-service-type
321 (lambda (vars)
322 (list `("environment"
323 ,(environment-variables->environment-file vars)))))))
324 (compose concatenate)
325 (extend append)
326 (description
327 "Populate @file{/etc/environment}, which is honored by @code{pam_env},
328with the specified environment variables. The value of this service is a list
329of name/value pairs for environments variables, such as:
330
331@example
332'((\"TZ\" . \"Canada/Pacific\"))
333@end example\n")))
334
335(define (session-environment-service vars)
336 "Return a service that builds the @file{/etc/environment}, which can be read
337by PAM-aware applications to set environment variables for sessions.
338
339VARS should be an association list in which both the keys and the values are
340strings or string-valued gexps."
341 (service session-environment-service-type vars))
342
343
344\f
0adfe95a
LC
345;;;
346;;; PAM root service.
347;;;
348
12c00bca
LC
349;; Overall PAM configuration: a list of services, plus a procedure that takes
350;; one <pam-service> and returns a <pam-service>. The procedure is used to
351;; implement cross-cutting concerns such as the use of the 'elogind.so'
352;; session module that keeps track of logged-in users.
353(define-record-type* <pam-configuration>
354 pam-configuration make-pam-configuration? pam-configuration?
355 (services pam-configuration-services) ;list of <pam-service>
356 (transform pam-configuration-transform)) ;procedure
357
358(define (/etc-entry config)
359 "Return the /etc/pam.d entry corresponding to CONFIG."
360 (match config
361 (($ <pam-configuration> services transform)
362 (let ((services (map transform services)))
363 `(("pam.d" ,(pam-services->directory services)))))))
364
365(define (extend-configuration initial extensions)
366 "Extend INITIAL with NEW."
367 (let-values (((services procs)
368 (partition pam-service? extensions)))
369 (pam-configuration
370 (services (append (pam-configuration-services initial)
371 services))
372 (transform (apply compose
373 (pam-configuration-transform initial)
374 procs)))))
0adfe95a
LC
375
376(define pam-root-service-type
377 (service-type (name 'pam)
378 (extensions (list (service-extension etc-service-type
379 /etc-entry)))
12c00bca
LC
380
381 ;; Arguments include <pam-service> as well as procedures.
0adfe95a 382 (compose concatenate)
dd0804c6
LC
383 (extend extend-configuration)
384 (description
385 "Configure the Pluggable Authentication Modules (PAM) for all
386the specified @dfn{PAM services}. Each PAM service corresponds to a program,
387such as @command{login} or @command{sshd}, and specifies for instance how the
388program may authenticate users or what it should do when opening a new
389session.")))
0adfe95a 390
12c00bca 391(define* (pam-root-service base #:key (transform identity))
0adfe95a 392 "The \"root\" PAM service, which collects <pam-service> instance and turns
12c00bca
LC
393them into a /etc/pam.d directory, including the <pam-service> listed in BASE.
394TRANSFORM is a procedure that takes a <pam-service> and returns a
395<pam-service>. It can be used to implement cross-cutting concerns that affect
396all the PAM services."
397 (service pam-root-service-type
398 (pam-configuration (services base)
399 (transform transform))))
0adfe95a 400
290ad224 401