mapped-devices: Cope with delayed appearance of LUKS source.
[jackhill/guix/guix.git] / gnu / system / pam.scm
CommitLineData
0ded70f3 1;;; GNU Guix --- Functional package management for GNU
d7bce31c 2;;; Copyright © 2013, 2014, 2015, 2016 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))
30 #:export (pam-service
d7bce31c
LC
31 pam-service-name
32 pam-service-account
33 pam-service-auth
34 pam-service-password
35 pam-service-session
36
0ded70f3 37 pam-entry
d7bce31c
LC
38 pam-entry-control
39 pam-entry-module
40 pam-entry-arguments
41
909147e4
RW
42 pam-limits-entry
43 pam-limits-entry-domain
44 pam-limits-entry-type
45 pam-limits-entry-item
46 pam-limits-entry-value
47 pam-limits-entry->string
48
0ded70f3 49 pam-services->directory
09e028f4 50 unix-pam-service
0adfe95a
LC
51 base-pam-services
52
53 pam-root-service-type
54 pam-root-service))
0ded70f3
LC
55
56;;; Commentary:
57;;;
6e828634 58;;; Configuration of the pluggable authentication modules (PAM).
0ded70f3
LC
59;;;
60;;; Code:
61
62;; PAM services (see
63;; <http://www.linux-pam.org/Linux-PAM-html/sag-configuration-file.html>.)
64(define-record-type* <pam-service> pam-service
65 make-pam-service
66 pam-service?
67 (name pam-service-name) ; string
68
69 ;; The four "management groups".
70 (account pam-service-account ; list of <pam-entry>
71 (default '()))
72 (auth pam-service-auth
73 (default '()))
74 (password pam-service-password
75 (default '()))
76 (session pam-service-session
77 (default '())))
78
79(define-record-type* <pam-entry> pam-entry
80 make-pam-entry
81 pam-entry?
b5f4e686
LC
82 (control pam-entry-control) ; string
83 (module pam-entry-module) ; file name
84 (arguments pam-entry-arguments ; list of string-valued g-expressions
0ded70f3
LC
85 (default '())))
86
909147e4
RW
87;; PAM limits entries are used by the pam_limits PAM module to set or override
88;; limits on system resources for user sessions. The format is specified
89;; here: http://linux-pam.org/Linux-PAM-html/sag-pam_limits.html
90(define-record-type <pam-limits-entry>
91 (make-pam-limits-entry domain type item value)
92 pam-limits-entry?
93 (domain pam-limits-entry-domain) ; string
94 (type pam-limits-entry-type) ; symbol
95 (item pam-limits-entry-item) ; symbol
96 (value pam-limits-entry-value)) ; symbol or number
97
98(define (pam-limits-entry domain type item value)
99 "Construct a pam-limits-entry ensuring that the provided values are valid."
100 (define (valid? value)
101 (case item
102 ((priority) (number? value))
103 ((nice) (and (number? value)
104 (>= value -20)
105 (<= value 19)))
106 (else (or (and (number? value)
107 (>= value -1))
108 (member value '(unlimited infinity))))))
109 (define items
110 (list 'core 'data 'fsize
111 'memlock 'nofile 'rss
112 'stack 'cpu 'nproc
113 'as 'maxlogins 'maxsyslogins
114 'priority 'locks 'sigpending
115 'msgqueue 'nice 'rtprio))
116 (when (not (member type '(hard soft both)))
117 (error "invalid limit type" type))
118 (when (not (member item items))
119 (error "invalid limit item" item))
120 (when (not (valid? value))
121 (error "invalid limit value" value))
122 (make-pam-limits-entry domain type item value))
123
124(define (pam-limits-entry->string entry)
125 "Convert a pam-limits-entry record to a string."
126 (match entry
127 (($ <pam-limits-entry> domain type item value)
128 (string-join (list domain
129 (if (eq? type 'both)
130 "-"
131 (symbol->string type))
132 (symbol->string item)
133 (cond
134 ((symbol? value)
135 (symbol->string value))
136 (else
137 (number->string value))))
138 " "))))
139
0ded70f3 140(define (pam-service->configuration service)
b5f4e686
LC
141 "Return the derivation building the configuration file for SERVICE, to be
142dumped in /etc/pam.d/NAME, where NAME is the name of SERVICE."
143 (define (entry->gexp type entry)
0ded70f3
LC
144 (match entry
145 (($ <pam-entry> control module (arguments ...))
b5f4e686
LC
146 #~(format #t "~a ~a ~a ~a~%"
147 #$type #$control #$module
148 (string-join (list #$@arguments))))))
0ded70f3
LC
149
150 (match service
151 (($ <pam-service> name account auth password session)
b5f4e686
LC
152 (define builder
153 #~(begin
154 (with-output-to-file #$output
155 (lambda ()
156 #$@(append (map (cut entry->gexp "account" <>) account)
157 (map (cut entry->gexp "auth" <>) auth)
158 (map (cut entry->gexp "password" <>) password)
159 (map (cut entry->gexp "session" <>) session))
160 #t))))
161
23afe939 162 (computed-file name builder))))
0ded70f3 163
d9f0a237 164(define (pam-services->directory services)
0ded70f3
LC
165 "Return the derivation to build the configuration directory to be used as
166/etc/pam.d for SERVICES."
23afe939
LC
167 (let ((names (map pam-service-name services))
168 (files (map pam-service->configuration services)))
0ded70f3 169 (define builder
b5f4e686 170 #~(begin
11dddd8a
LC
171 (use-modules (ice-9 match)
172 (srfi srfi-1))
0ded70f3 173
b5f4e686
LC
174 (mkdir #$output)
175 (for-each (match-lambda
0adfe95a
LC
176 ((name file)
177 (symlink file (string-append #$output "/" name))))
11dddd8a
LC
178
179 ;; Since <pam-service> objects cannot be compared with
180 ;; 'equal?' since they contain gexps, which contain
181 ;; closures, use 'delete-duplicates' on the build-side
182 ;; instead. See <http://bugs.gnu.org/20037>.
183 (delete-duplicates '#$(zip names files)))))
0ded70f3 184
23afe939 185 (computed-file "pam.d" builder)))
0ded70f3
LC
186
187(define %pam-other-services
188 ;; The "other" PAM configuration, which denies everything (see
189 ;; <http://www.linux-pam.org/Linux-PAM-html/sag-configuration-example.html>.)
190 (let ((deny (pam-entry
191 (control "required")
192 (module "pam_deny.so"))))
193 (pam-service
194 (name "other")
195 (account (list deny))
196 (auth (list deny))
197 (password (list deny))
198 (session (list deny)))))
199
200(define unix-pam-service
201 (let ((unix (pam-entry
202 (control "required")
af9908ff
SB
203 (module "pam_unix.so")))
204 (env (pam-entry ; to honor /etc/environment.
205 (control "required")
206 (module "pam_env.so"))))
e586257b 207 (lambda* (name #:key allow-empty-passwords? (allow-root? #f) motd)
0ded70f3 208 "Return a standard Unix-style PAM service for NAME. When
e586257b
RW
209ALLOW-EMPTY-PASSWORDS? is true, allow empty passwords. When ALLOW-ROOT? is
210true, allow root to run the command without authentication. When MOTD is
211true, it should be a file-like object used as the message-of-the-day."
0ded70f3
LC
212 ;; See <http://www.linux-pam.org/Linux-PAM-html/sag-configuration-example.html>.
213 (let ((name* name))
214 (pam-service
215 (name name*)
216 (account (list unix))
e586257b
RW
217 (auth (append (if allow-root?
218 (list (pam-entry
219 (control "sufficient")
220 (module "pam_rootok.so")))
221 '())
222 (list (if allow-empty-passwords?
223 (pam-entry
224 (control "required")
225 (module "pam_unix.so")
226 (arguments '("nullok")))
227 unix))))
9297065a
SB
228 (password (list (pam-entry
229 (control "required")
230 (module "pam_unix.so")
231 ;; Store SHA-512 encrypted passwords in /etc/shadow.
232 (arguments '("sha512" "shadow")))))
43a27798 233 (session (if motd
af9908ff 234 (list env unix
43a27798
LC
235 (pam-entry
236 (control "optional")
237 (module "pam_motd.so")
b5f4e686
LC
238 (arguments
239 (list #~(string-append "motd=" #$motd)))))
af9908ff 240 (list env unix))))))))
0ded70f3 241
da417ffe
LC
242(define (rootok-pam-service command)
243 "Return a PAM service for COMMAND such that 'root' does not need to
244authenticate to run COMMAND."
245 (let ((unix (pam-entry
246 (control "required")
247 (module "pam_unix.so"))))
248 (pam-service
249 (name command)
250 (account (list unix))
251 (auth (list (pam-entry
252 (control "sufficient")
253 (module "pam_rootok.so"))))
254 (password (list unix))
255 (session (list unix)))))
256
09e028f4
LC
257(define* (base-pam-services #:key allow-empty-passwords?)
258 "Return the list of basic PAM services everyone would want."
da417ffe
LC
259 ;; TODO: Add other Shadow programs?
260 (append (list %pam-other-services)
261
262 ;; These programs are setuid-root.
263 (map (cut unix-pam-service <>
264 #:allow-empty-passwords? allow-empty-passwords?)
e586257b
RW
265 '("passwd" "sudo"))
266 ;; This is setuid-root, as well. Allow root to run "su" without
267 ;; authenticating.
268 (list (unix-pam-service "su"
269 #:allow-empty-passwords? allow-empty-passwords?
270 #:allow-root? #t))
da417ffe
LC
271
272 ;; These programs are not setuid-root, and we want root to be able
273 ;; to run them without having to authenticate (notably because
274 ;; 'useradd' and 'groupadd' are run during system activation.)
275 (map rootok-pam-service
276 '("useradd" "userdel" "usermod"
277 "groupadd" "groupdel" "groupmod"))))
09e028f4 278
0adfe95a
LC
279\f
280;;;
281;;; PAM root service.
282;;;
283
12c00bca
LC
284;; Overall PAM configuration: a list of services, plus a procedure that takes
285;; one <pam-service> and returns a <pam-service>. The procedure is used to
286;; implement cross-cutting concerns such as the use of the 'elogind.so'
287;; session module that keeps track of logged-in users.
288(define-record-type* <pam-configuration>
289 pam-configuration make-pam-configuration? pam-configuration?
290 (services pam-configuration-services) ;list of <pam-service>
291 (transform pam-configuration-transform)) ;procedure
292
293(define (/etc-entry config)
294 "Return the /etc/pam.d entry corresponding to CONFIG."
295 (match config
296 (($ <pam-configuration> services transform)
297 (let ((services (map transform services)))
298 `(("pam.d" ,(pam-services->directory services)))))))
299
300(define (extend-configuration initial extensions)
301 "Extend INITIAL with NEW."
302 (let-values (((services procs)
303 (partition pam-service? extensions)))
304 (pam-configuration
305 (services (append (pam-configuration-services initial)
306 services))
307 (transform (apply compose
308 (pam-configuration-transform initial)
309 procs)))))
0adfe95a
LC
310
311(define pam-root-service-type
312 (service-type (name 'pam)
313 (extensions (list (service-extension etc-service-type
314 /etc-entry)))
12c00bca
LC
315
316 ;; Arguments include <pam-service> as well as procedures.
0adfe95a 317 (compose concatenate)
12c00bca 318 (extend extend-configuration)))
0adfe95a 319
12c00bca 320(define* (pam-root-service base #:key (transform identity))
0adfe95a 321 "The \"root\" PAM service, which collects <pam-service> instance and turns
12c00bca
LC
322them into a /etc/pam.d directory, including the <pam-service> listed in BASE.
323TRANSFORM is a procedure that takes a <pam-service> and returns a
324<pam-service>. It can be used to implement cross-cutting concerns that affect
325all the PAM services."
326 (service pam-root-service-type
327 (pam-configuration (services base)
328 (transform transform))))
0adfe95a 329
290ad224 330