gnu: Add ghc-aeson-pretty.
[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)
12c00bca 26 #:use-module (srfi srfi-11)
0ded70f3
LC
27 #:use-module (srfi srfi-26)
28 #:use-module ((guix utils) #:select (%current-system))
29 #:export (pam-service
d7bce31c
LC
30 pam-service-name
31 pam-service-account
32 pam-service-auth
33 pam-service-password
34 pam-service-session
35
0ded70f3 36 pam-entry
d7bce31c
LC
37 pam-entry-control
38 pam-entry-module
39 pam-entry-arguments
40
0ded70f3 41 pam-services->directory
09e028f4 42 unix-pam-service
0adfe95a
LC
43 base-pam-services
44
45 pam-root-service-type
46 pam-root-service))
0ded70f3
LC
47
48;;; Commentary:
49;;;
6e828634 50;;; Configuration of the pluggable authentication modules (PAM).
0ded70f3
LC
51;;;
52;;; Code:
53
54;; PAM services (see
55;; <http://www.linux-pam.org/Linux-PAM-html/sag-configuration-file.html>.)
56(define-record-type* <pam-service> pam-service
57 make-pam-service
58 pam-service?
59 (name pam-service-name) ; string
60
61 ;; The four "management groups".
62 (account pam-service-account ; list of <pam-entry>
63 (default '()))
64 (auth pam-service-auth
65 (default '()))
66 (password pam-service-password
67 (default '()))
68 (session pam-service-session
69 (default '())))
70
71(define-record-type* <pam-entry> pam-entry
72 make-pam-entry
73 pam-entry?
b5f4e686
LC
74 (control pam-entry-control) ; string
75 (module pam-entry-module) ; file name
76 (arguments pam-entry-arguments ; list of string-valued g-expressions
0ded70f3
LC
77 (default '())))
78
79(define (pam-service->configuration service)
b5f4e686
LC
80 "Return the derivation building the configuration file for SERVICE, to be
81dumped in /etc/pam.d/NAME, where NAME is the name of SERVICE."
82 (define (entry->gexp type entry)
0ded70f3
LC
83 (match entry
84 (($ <pam-entry> control module (arguments ...))
b5f4e686
LC
85 #~(format #t "~a ~a ~a ~a~%"
86 #$type #$control #$module
87 (string-join (list #$@arguments))))))
0ded70f3
LC
88
89 (match service
90 (($ <pam-service> name account auth password session)
b5f4e686
LC
91 (define builder
92 #~(begin
93 (with-output-to-file #$output
94 (lambda ()
95 #$@(append (map (cut entry->gexp "account" <>) account)
96 (map (cut entry->gexp "auth" <>) auth)
97 (map (cut entry->gexp "password" <>) password)
98 (map (cut entry->gexp "session" <>) session))
99 #t))))
100
23afe939 101 (computed-file name builder))))
0ded70f3 102
d9f0a237 103(define (pam-services->directory services)
0ded70f3
LC
104 "Return the derivation to build the configuration directory to be used as
105/etc/pam.d for SERVICES."
23afe939
LC
106 (let ((names (map pam-service-name services))
107 (files (map pam-service->configuration services)))
0ded70f3 108 (define builder
b5f4e686 109 #~(begin
11dddd8a
LC
110 (use-modules (ice-9 match)
111 (srfi srfi-1))
0ded70f3 112
b5f4e686
LC
113 (mkdir #$output)
114 (for-each (match-lambda
0adfe95a
LC
115 ((name file)
116 (symlink file (string-append #$output "/" name))))
11dddd8a
LC
117
118 ;; Since <pam-service> objects cannot be compared with
119 ;; 'equal?' since they contain gexps, which contain
120 ;; closures, use 'delete-duplicates' on the build-side
121 ;; instead. See <http://bugs.gnu.org/20037>.
122 (delete-duplicates '#$(zip names files)))))
0ded70f3 123
23afe939 124 (computed-file "pam.d" builder)))
0ded70f3
LC
125
126(define %pam-other-services
127 ;; The "other" PAM configuration, which denies everything (see
128 ;; <http://www.linux-pam.org/Linux-PAM-html/sag-configuration-example.html>.)
129 (let ((deny (pam-entry
130 (control "required")
131 (module "pam_deny.so"))))
132 (pam-service
133 (name "other")
134 (account (list deny))
135 (auth (list deny))
136 (password (list deny))
137 (session (list deny)))))
138
139(define unix-pam-service
140 (let ((unix (pam-entry
141 (control "required")
af9908ff
SB
142 (module "pam_unix.so")))
143 (env (pam-entry ; to honor /etc/environment.
144 (control "required")
145 (module "pam_env.so"))))
43a27798 146 (lambda* (name #:key allow-empty-passwords? motd)
0ded70f3 147 "Return a standard Unix-style PAM service for NAME. When
43a27798 148ALLOW-EMPTY-PASSWORDS? is true, allow empty passwords. When MOTD is true, it
ce8a6dfc 149should be a file-like object used as the message-of-the-day."
0ded70f3
LC
150 ;; See <http://www.linux-pam.org/Linux-PAM-html/sag-configuration-example.html>.
151 (let ((name* name))
152 (pam-service
153 (name name*)
154 (account (list unix))
155 (auth (list (if allow-empty-passwords?
156 (pam-entry
157 (control "required")
158 (module "pam_unix.so")
159 (arguments '("nullok")))
160 unix)))
9297065a
SB
161 (password (list (pam-entry
162 (control "required")
163 (module "pam_unix.so")
164 ;; Store SHA-512 encrypted passwords in /etc/shadow.
165 (arguments '("sha512" "shadow")))))
43a27798 166 (session (if motd
af9908ff 167 (list env unix
43a27798
LC
168 (pam-entry
169 (control "optional")
170 (module "pam_motd.so")
b5f4e686
LC
171 (arguments
172 (list #~(string-append "motd=" #$motd)))))
af9908ff 173 (list env unix))))))))
0ded70f3 174
da417ffe
LC
175(define (rootok-pam-service command)
176 "Return a PAM service for COMMAND such that 'root' does not need to
177authenticate to run COMMAND."
178 (let ((unix (pam-entry
179 (control "required")
180 (module "pam_unix.so"))))
181 (pam-service
182 (name command)
183 (account (list unix))
184 (auth (list (pam-entry
185 (control "sufficient")
186 (module "pam_rootok.so"))))
187 (password (list unix))
188 (session (list unix)))))
189
09e028f4
LC
190(define* (base-pam-services #:key allow-empty-passwords?)
191 "Return the list of basic PAM services everyone would want."
da417ffe
LC
192 ;; TODO: Add other Shadow programs?
193 (append (list %pam-other-services)
194
195 ;; These programs are setuid-root.
196 (map (cut unix-pam-service <>
197 #:allow-empty-passwords? allow-empty-passwords?)
6726282b 198 '("su" "passwd" "sudo"))
da417ffe
LC
199
200 ;; These programs are not setuid-root, and we want root to be able
201 ;; to run them without having to authenticate (notably because
202 ;; 'useradd' and 'groupadd' are run during system activation.)
203 (map rootok-pam-service
204 '("useradd" "userdel" "usermod"
205 "groupadd" "groupdel" "groupmod"))))
09e028f4 206
0adfe95a
LC
207\f
208;;;
209;;; PAM root service.
210;;;
211
12c00bca
LC
212;; Overall PAM configuration: a list of services, plus a procedure that takes
213;; one <pam-service> and returns a <pam-service>. The procedure is used to
214;; implement cross-cutting concerns such as the use of the 'elogind.so'
215;; session module that keeps track of logged-in users.
216(define-record-type* <pam-configuration>
217 pam-configuration make-pam-configuration? pam-configuration?
218 (services pam-configuration-services) ;list of <pam-service>
219 (transform pam-configuration-transform)) ;procedure
220
221(define (/etc-entry config)
222 "Return the /etc/pam.d entry corresponding to CONFIG."
223 (match config
224 (($ <pam-configuration> services transform)
225 (let ((services (map transform services)))
226 `(("pam.d" ,(pam-services->directory services)))))))
227
228(define (extend-configuration initial extensions)
229 "Extend INITIAL with NEW."
230 (let-values (((services procs)
231 (partition pam-service? extensions)))
232 (pam-configuration
233 (services (append (pam-configuration-services initial)
234 services))
235 (transform (apply compose
236 (pam-configuration-transform initial)
237 procs)))))
0adfe95a
LC
238
239(define pam-root-service-type
240 (service-type (name 'pam)
241 (extensions (list (service-extension etc-service-type
242 /etc-entry)))
12c00bca
LC
243
244 ;; Arguments include <pam-service> as well as procedures.
0adfe95a 245 (compose concatenate)
12c00bca 246 (extend extend-configuration)))
0adfe95a 247
12c00bca 248(define* (pam-root-service base #:key (transform identity))
0adfe95a 249 "The \"root\" PAM service, which collects <pam-service> instance and turns
12c00bca
LC
250them into a /etc/pam.d directory, including the <pam-service> listed in BASE.
251TRANSFORM is a procedure that takes a <pam-service> and returns a
252<pam-service>. It can be used to implement cross-cutting concerns that affect
253all the PAM services."
254 (service pam-root-service-type
255 (pam-configuration (services base)
256 (transform transform))))
0adfe95a 257
0ded70f3 258;;; linux.scm ends here