| 1 | |
| 2 | |
| 3 | |
| 4 | |
| 5 | |
| 6 | |
| 7 | |
| 8 | |
| 9 | |
| 10 | |
| 11 | |
| 12 | |
| 13 | |
| 14 | |
| 15 | |
| 16 | |
| 17 | |
| 18 | |
| 19 | |
| 20 | |
| 21 | |
| 22 | |
| 23 | |
| 24 | |
| 25 | |
| 26 | |
| 27 | |
| 28 | |
| 29 |
|
| 30 | |
| 31 | |
| 32 | |
| 33 | |
| 34 | |
| 35 | |
| 36 |
|
| 37 | (define-module (gnu services mail)
|
| 38 | #:use-module (gnu services)
|
| 39 | #:use-module (gnu services base)
|
| 40 | #:use-module (gnu services configuration)
|
| 41 | #:use-module (gnu services shepherd)
|
| 42 | #:use-module (gnu system pam)
|
| 43 | #:use-module (gnu system privilege)
|
| 44 | #:use-module (gnu system shadow)
|
| 45 | #:use-module (gnu packages mail)
|
| 46 | #:use-module (gnu packages admin)
|
| 47 | #:use-module (gnu packages dav)
|
| 48 | #:use-module (gnu packages tls)
|
| 49 | #:use-module (guix deprecation)
|
| 50 | #:use-module ((guix diagnostics) #:select (source-properties->location))
|
| 51 | #:use-module (guix modules)
|
| 52 | #:use-module (guix records)
|
| 53 | #:use-module (guix packages)
|
| 54 | #:use-module (guix gexp)
|
| 55 | #:use-module (ice-9 curried-definitions)
|
| 56 | #:use-module (ice-9 match)
|
| 57 | #:use-module (ice-9 format)
|
| 58 | #:use-module (srfi srfi-1)
|
| 59 | #:export (dovecot-service |
| 60 | dovecot-service-type
|
| 61 | dovecot-configuration
|
| 62 | opaque-dovecot-configuration
|
| 63 |
|
| 64 | dict-configuration
|
| 65 | passdb-configuration
|
| 66 | userdb-configuration
|
| 67 | unix-listener-configuration
|
| 68 | fifo-listener-configuration
|
| 69 | inet-listener-configuration
|
| 70 | service-configuration
|
| 71 | protocol-configuration
|
| 72 | plugin-configuration
|
| 73 | mailbox-configuration
|
| 74 | namespace-configuration
|
| 75 |
|
| 76 | opensmtpd-configuration
|
| 77 | opensmtpd-configuration?
|
| 78 | opensmtpd-service-type
|
| 79 | %default-opensmtpd-config-file
|
| 80 |
|
| 81 | mail-aliases-service-type
|
| 82 |
|
| 83 | exim-configuration
|
| 84 | exim-configuration?
|
| 85 | exim-service-type
|
| 86 | %default-exim-config-file
|
| 87 |
|
| 88 | imap4d-configuration
|
| 89 | imap4d-configuration?
|
| 90 | imap4d-service-type
|
| 91 | %default-imap4d-config-file
|
| 92 |
|
| 93 | radicale-auth-configuration
|
| 94 | radicale-auth-configuration?
|
| 95 | radicale-encoding-configuration
|
| 96 | radicale-encoding-configuration?
|
| 97 | radicale-logging-configuration
|
| 98 | radicale-logging-configuration?
|
| 99 | radicale-rights-configuration
|
| 100 | radicale-rights-configuration?
|
| 101 | radicale-server-configuration
|
| 102 | radicale-server-configuration?
|
| 103 | radicale-storage-configuration
|
| 104 | radicale-storage-configuration?
|
| 105 | radicale-configuration
|
| 106 | radicale-configuration?
|
| 107 | radicale-service-type
|
| 108 |
|
| 109 | rspamd-configuration
|
| 110 | rspamd-service-type
|
| 111 | %default-rspamd-account
|
| 112 | %default-rspamd-config-file
|
| 113 | %default-rspamd-group))
|
| 114 |
|
| 115 | (define (uglify-field-name field-name)
|
| 116 | (let ((str (symbol->string field-name)))
|
| 117 | (string-join (string-split (if (string-suffix? "?" str)
|
| 118 | (substring str 0 (1- (string-length str)))
|
| 119 | str)
|
| 120 | #\-)
|
| 121 | "_")))
|
| 122 |
|
| 123 | (define (serialize-field field-name val)
|
| 124 | (format #t "~a=~a\n" (uglify-field-name field-name) val))
|
| 125 |
|
| 126 | (define (serialize-string field-name val)
|
| 127 | (serialize-field field-name val))
|
| 128 |
|
| 129 | (define (space-separated-string-list? val)
|
| 130 | (and (list? val)
|
| 131 | (and-map (lambda (x)
|
| 132 | (and (string? x) (not (string-index x #\space))))
|
| 133 | val)))
|
| 134 | (define (serialize-space-separated-string-list field-name val)
|
| 135 | (match val
|
| 136 | (() #f)
|
| 137 | (_ (serialize-field field-name (string-join val " ")))))
|
| 138 |
|
| 139 | (define (comma-separated-string-list? val)
|
| 140 | (and (list? val)
|
| 141 | (and-map (lambda (x)
|
| 142 | (and (string? x) (not (string-index x #\,))))
|
| 143 | val)))
|
| 144 | (define (serialize-comma-separated-string-list field-name val)
|
| 145 | (serialize-field field-name (string-join val ",")))
|
| 146 |
|
| 147 | (define (file-name? val)
|
| 148 | (and (string? val)
|
| 149 | (string-prefix? "/" val)))
|
| 150 | (define (serialize-file-name field-name val)
|
| 151 | (serialize-string field-name val))
|
| 152 |
|
| 153 | (define (colon-separated-file-name-list? val)
|
| 154 | (and (list? val)
|
| 155 | |
| 156 | (and-map file-name? val)))
|
| 157 | (define (serialize-colon-separated-file-name-list field-name val)
|
| 158 | (serialize-field field-name (string-join val ":")))
|
| 159 |
|
| 160 | (define (serialize-boolean field-name val)
|
| 161 | (serialize-string field-name (if val "yes" "no")))
|
| 162 |
|
| 163 | (define (non-negative-integer? val)
|
| 164 | (and (exact-integer? val) (not (negative? val))))
|
| 165 | (define (serialize-non-negative-integer field-name val)
|
| 166 | (serialize-field field-name val))
|
| 167 |
|
| 168 | (define (hours? val) (non-negative-integer? val))
|
| 169 | (define (serialize-hours field-name val)
|
| 170 | (serialize-field field-name (format #f "~a hours" val)))
|
| 171 |
|
| 172 | (define (free-form-fields? val)
|
| 173 | (match val
|
| 174 | (() #t)
|
| 175 | ((((? symbol?) . (? string?)) . val) (free-form-fields? val))
|
| 176 | (_ #f)))
|
| 177 | (define (serialize-free-form-fields field-name val)
|
| 178 | (for-each (match-lambda ((k . v) (serialize-field k v))) val))
|
| 179 |
|
| 180 | (define (free-form-args? val)
|
| 181 | (match val
|
| 182 | (() #t)
|
| 183 | ((((? symbol?) . (? string?)) . val) (free-form-args? val))
|
| 184 | (_ #f)))
|
| 185 | (define (serialize-free-form-args field-name val)
|
| 186 | (serialize-field field-name
|
| 187 | (string-join
|
| 188 | (map (match-lambda ((k . v) (format #f "~a=~a" k v))) val)
|
| 189 | " ")))
|
| 190 |
|
| 191 | (define-configuration dict-configuration
|
| 192 | (entries
|
| 193 | (free-form-fields '())
|
| 194 | "A list of key-value pairs that this dict should hold."))
|
| 195 |
|
| 196 | (define (serialize-dict-configuration field-name val)
|
| 197 | (format #t "dict {\n")
|
| 198 | (serialize-configuration val dict-configuration-fields)
|
| 199 | (format #t "}\n"))
|
| 200 |
|
| 201 | (define-configuration passdb-configuration
|
| 202 | (driver
|
| 203 | (string "pam")
|
| 204 | "The driver that the passdb should use. Valid values include
|
| 205 | @samp{pam}, @samp{passwd}, @samp{shadow}, @samp{bsdauth}, and
|
| 206 | @samp{static}.")
|
| 207 | (args
|
| 208 | (space-separated-string-list '())
|
| 209 | "Space separated list of arguments to the passdb driver."))
|
| 210 |
|
| 211 | (define (serialize-passdb-configuration field-name val)
|
| 212 | (format #t "passdb {\n")
|
| 213 | (serialize-configuration val passdb-configuration-fields)
|
| 214 | (format #t "}\n"))
|
| 215 | (define (passdb-configuration-list? val)
|
| 216 | (and (list? val) (and-map passdb-configuration? val)))
|
| 217 | (define (serialize-passdb-configuration-list field-name val)
|
| 218 | (for-each (lambda (val) (serialize-passdb-configuration field-name val)) val))
|
| 219 |
|
| 220 | (define-configuration userdb-configuration
|
| 221 | (driver
|
| 222 | (string "passwd")
|
| 223 | "The driver that the userdb should use. Valid values include
|
| 224 | @samp{passwd} and @samp{static}.")
|
| 225 | (args
|
| 226 | (space-separated-string-list '())
|
| 227 | "Space separated list of arguments to the userdb driver.")
|
| 228 | (override-fields
|
| 229 | (free-form-args '())
|
| 230 | "Override fields from passwd."))
|
| 231 |
|
| 232 | (define (serialize-userdb-configuration field-name val)
|
| 233 | (format #t "userdb {\n")
|
| 234 | (serialize-configuration val userdb-configuration-fields)
|
| 235 | (format #t "}\n"))
|
| 236 | (define (userdb-configuration-list? val)
|
| 237 | (and (list? val) (and-map userdb-configuration? val)))
|
| 238 | (define (serialize-userdb-configuration-list field-name val)
|
| 239 | (for-each (lambda (val) (serialize-userdb-configuration field-name val)) val))
|
| 240 |
|
| 241 | (define-configuration unix-listener-configuration
|
| 242 | (path
|
| 243 | (string (configuration-missing-field 'unix-listener 'path))
|
| 244 | "Path to the file, relative to @code{base-dir} field. This is also used as
|
| 245 | the section name.")
|
| 246 | (mode
|
| 247 | (string "0600")
|
| 248 | "The access mode for the socket.")
|
| 249 | (user
|
| 250 | (string "")
|
| 251 | "The user to own the the socket.")
|
| 252 | (group
|
| 253 | (string "")
|
| 254 | "The group to own the socket."))
|
| 255 |
|
| 256 | (define (serialize-unix-listener-configuration field-name val)
|
| 257 | (format #t "unix_listener ~a {\n" (unix-listener-configuration-path val))
|
| 258 | (serialize-configuration val (cdr unix-listener-configuration-fields))
|
| 259 | (format #t "}\n"))
|
| 260 |
|
| 261 | (define-configuration fifo-listener-configuration
|
| 262 | (path
|
| 263 | (string (configuration-missing-field 'fifo-listener 'path))
|
| 264 | "Path to the file, relative to @code{base-dir} field. This is also used as
|
| 265 | the section name.")
|
| 266 | (mode
|
| 267 | (string "0600")
|
| 268 | "The access mode for the socket.")
|
| 269 | (user
|
| 270 | (string "")
|
| 271 | "The user to own the the socket.")
|
| 272 | (group
|
| 273 | (string "")
|
| 274 | "The group to own the socket."))
|
| 275 |
|
| 276 | (define (serialize-fifo-listener-configuration field-name val)
|
| 277 | (format #t "fifo_listener ~a {\n" (fifo-listener-configuration-path val))
|
| 278 | (serialize-configuration val (cdr fifo-listener-configuration-fields))
|
| 279 | (format #t "}\n"))
|
| 280 |
|
| 281 | (define-configuration inet-listener-configuration
|
| 282 | (protocol
|
| 283 | (string (configuration-missing-field 'inet-listener 'protocol))
|
| 284 | "The protocol to listen for.")
|
| 285 | (address
|
| 286 | (string "")
|
| 287 | "The address on which to listen, or empty for all addresses.")
|
| 288 | (port
|
| 289 | (non-negative-integer
|
| 290 | (configuration-missing-field 'inet-listener 'port))
|
| 291 | "The port on which to listen.")
|
| 292 | (ssl?
|
| 293 | (boolean #t)
|
| 294 | "Whether to use SSL for this service; @samp{yes}, @samp{no}, or
|
| 295 | @samp{required}."))
|
| 296 |
|
| 297 | (define (serialize-inet-listener-configuration field-name val)
|
| 298 | (format #t "inet_listener ~a {\n" (inet-listener-configuration-protocol val))
|
| 299 | (serialize-configuration val (cdr inet-listener-configuration-fields))
|
| 300 | (format #t "}\n"))
|
| 301 |
|
| 302 | (define (listener-configuration? val)
|
| 303 | (or (unix-listener-configuration? val)
|
| 304 | (fifo-listener-configuration? val)
|
| 305 | (inet-listener-configuration? val)))
|
| 306 | (define (serialize-listener-configuration field-name val)
|
| 307 | (cond
|
| 308 | ((unix-listener-configuration? val)
|
| 309 | (serialize-unix-listener-configuration field-name val))
|
| 310 | ((fifo-listener-configuration? val)
|
| 311 | (serialize-fifo-listener-configuration field-name val))
|
| 312 | ((inet-listener-configuration? val)
|
| 313 | (serialize-inet-listener-configuration field-name val))
|
| 314 | (else (configuration-field-error #f field-name val))))
|
| 315 | (define (listener-configuration-list? val)
|
| 316 | (and (list? val) (and-map listener-configuration? val)))
|
| 317 | (define (serialize-listener-configuration-list field-name val)
|
| 318 | (for-each (lambda (val)
|
| 319 | (serialize-listener-configuration field-name val))
|
| 320 | val))
|
| 321 |
|
| 322 | (define-configuration service-configuration
|
| 323 | (kind
|
| 324 | (string (configuration-missing-field 'service 'kind))
|
| 325 | "The service kind. Valid values include @code{director},
|
| 326 | @code{imap-login}, @code{pop3-login}, @code{lmtp}, @code{imap},
|
| 327 | @code{pop3}, @code{auth}, @code{auth-worker}, @code{dict},
|
| 328 | @code{tcpwrap}, @code{quota-warning}, or anything else.")
|
| 329 | (listeners
|
| 330 | (listener-configuration-list '())
|
| 331 | "Listeners for the service. A listener is either an
|
| 332 | @code{unix-listener-configuration}, a @code{fifo-listener-configuration}, or
|
| 333 | an @code{inet-listener-configuration}.")
|
| 334 | (client-limit
|
| 335 | (non-negative-integer 0)
|
| 336 | "Maximum number of simultaneous client connections per process. Once this
|
| 337 | number of connections is received, the next incoming connection will prompt
|
| 338 | Dovecot to spawn another process. If set to 0, @code{default-client-limit} is
|
| 339 | used instead.")
|
| 340 | (service-count
|
| 341 | (non-negative-integer 1)
|
| 342 | "Number of connections to handle before starting a new process.
|
| 343 | Typically the only useful values are 0 (unlimited) or 1. 1 is more
|
| 344 | secure, but 0 is faster. <doc/wiki/LoginProcess.txt>.")
|
| 345 | (process-limit
|
| 346 | (non-negative-integer 0)
|
| 347 | "Maximum number of processes that can exist for this service. If set to 0,
|
| 348 | @code{default-process-limit} is used instead.")
|
| 349 | (process-min-avail
|
| 350 | (non-negative-integer 0)
|
| 351 | "Number of processes to always keep waiting for more connections.")
|
| 352 | |
| 353 | |
| 354 | (vsz-limit
|
| 355 | (non-negative-integer #e256e6)
|
| 356 | "If you set @samp{service-count 0}, you probably need to grow
|
| 357 | this."))
|
| 358 |
|
| 359 | (define (serialize-service-configuration field-name val)
|
| 360 | (format #t "service ~a {\n" (service-configuration-kind val))
|
| 361 | (serialize-configuration val (cdr service-configuration-fields))
|
| 362 | (format #t "}\n"))
|
| 363 | (define (service-configuration-list? val)
|
| 364 | (and (list? val) (and-map service-configuration? val)))
|
| 365 | (define (serialize-service-configuration-list field-name val)
|
| 366 | (for-each (lambda (val)
|
| 367 | (serialize-service-configuration field-name val))
|
| 368 | val))
|
| 369 |
|
| 370 | (define-configuration protocol-configuration
|
| 371 | (name
|
| 372 | (string (configuration-missing-field 'protocol 'name))
|
| 373 | "The name of the protocol.")
|
| 374 | (auth-socket-path
|
| 375 | (string "/var/run/dovecot/auth-userdb")
|
| 376 | "UNIX socket path to master authentication server to find users.
|
| 377 | This is used by imap (for shared users) and lda.")
|
| 378 | (mail-plugins
|
| 379 | (space-separated-string-list '("$mail_plugins"))
|
| 380 | "Space separated list of plugins to load.")
|
| 381 | (mail-max-userip-connections
|
| 382 | (non-negative-integer 10)
|
| 383 | "Maximum number of IMAP connections allowed for a user from each IP
|
| 384 | address. NOTE: The username is compared case-sensitively.")
|
| 385 | (imap-metadata?
|
| 386 | (boolean #f)
|
| 387 | "Whether to enable the @code{IMAP METADATA} extension as defined in
|
| 388 | @uref{https://tools.ietf.org/html/rfc5464, RFC@tie{}5464}, which provides
|
| 389 | a means for clients to set and retrieve per-mailbox, per-user metadata
|
| 390 | and annotations over IMAP.
|
| 391 |
|
| 392 | If this is @samp{#t}, you must also specify a dictionary @i{via} the
|
| 393 | @code{mail-attribute-dict} setting.")
|
| 394 | (managesieve-notify-capability
|
| 395 | (space-separated-string-list '())
|
| 396 | "Which NOTIFY capabilities to report to clients that first connect to
|
| 397 | the ManageSieve service, before authentication. These may differ from the
|
| 398 | capabilities offered to authenticated users. If this field is left empty,
|
| 399 | report what the Sieve interpreter supports by default.")
|
| 400 | (managesieve-sieve-capability
|
| 401 | (space-separated-string-list '())
|
| 402 | "Which SIEVE capabilities to report to clients that first connect to
|
| 403 | the ManageSieve service, before authentication. These may differ from the
|
| 404 | capabilities offered to authenticated users. If this field is left empty,
|
| 405 | report what the Sieve interpreter supports by default."))
|
| 406 |
|
| 407 | (define (serialize-protocol-configuration field-name val)
|
| 408 | (format #t "protocol ~a {\n" (protocol-configuration-name val))
|
| 409 | (serialize-configuration val (cdr protocol-configuration-fields))
|
| 410 | (format #t "}\n"))
|
| 411 | (define (protocol-configuration-list? val)
|
| 412 | (and (list? val) (and-map protocol-configuration? val)))
|
| 413 | (define (serialize-protocol-configuration-list field-name val)
|
| 414 | (serialize-field 'protocols
|
| 415 | (string-join (map protocol-configuration-name val) " "))
|
| 416 | (for-each (lambda (val)
|
| 417 | (serialize-protocol-configuration field-name val))
|
| 418 | val))
|
| 419 |
|
| 420 | (define-configuration plugin-configuration
|
| 421 | (entries
|
| 422 | (free-form-fields '())
|
| 423 | "A list of key-value pairs that this dict should hold."))
|
| 424 |
|
| 425 | (define (serialize-plugin-configuration field-name val)
|
| 426 | (format #t "plugin {\n")
|
| 427 | (serialize-configuration val plugin-configuration-fields)
|
| 428 | (format #t "}\n"))
|
| 429 |
|
| 430 | (define-configuration mailbox-configuration
|
| 431 | (name
|
| 432 | (string (error "mailbox name is required"))
|
| 433 | "Name for this mailbox.")
|
| 434 |
|
| 435 | (auto
|
| 436 | (string "no")
|
| 437 | "@samp{create} will automatically create this mailbox.
|
| 438 | @samp{subscribe} will both create and subscribe to the mailbox.")
|
| 439 |
|
| 440 | (special-use
|
| 441 | (space-separated-string-list '())
|
| 442 | "List of IMAP @code{SPECIAL-USE} attributes as specified by RFC 6154.
|
| 443 | Valid values are @code{\\All}, @code{\\Archive}, @code{\\Drafts},
|
| 444 | @code{\\Flagged}, @code{\\Junk}, @code{\\Sent}, and @code{\\Trash}."))
|
| 445 |
|
| 446 | (define (serialize-mailbox-configuration field-name val)
|
| 447 | (format #t "mailbox \"~a\" {\n" (mailbox-configuration-name val))
|
| 448 | (serialize-configuration val (cdr mailbox-configuration-fields))
|
| 449 | (format #t "}\n"))
|
| 450 | (define (mailbox-configuration-list? val)
|
| 451 | (and (list? val) (and-map mailbox-configuration? val)))
|
| 452 | (define (serialize-mailbox-configuration-list field-name val)
|
| 453 | (for-each (lambda (val)
|
| 454 | (serialize-mailbox-configuration field-name val))
|
| 455 | val))
|
| 456 |
|
| 457 | (define-configuration namespace-configuration
|
| 458 | (name
|
| 459 | (string (error "namespace name is required"))
|
| 460 | "Name for this namespace.")
|
| 461 |
|
| 462 | (type
|
| 463 | (string "private")
|
| 464 | "Namespace type: @samp{private}, @samp{shared} or @samp{public}.")
|
| 465 |
|
| 466 | (separator
|
| 467 | (string "")
|
| 468 | "Hierarchy separator to use. You should use the same separator for
|
| 469 | all namespaces or some clients get confused. @samp{/} is usually a good
|
| 470 | one. The default however depends on the underlying mail storage
|
| 471 | format.")
|
| 472 |
|
| 473 | (prefix
|
| 474 | (string "")
|
| 475 | "Prefix required to access this namespace. This needs to be
|
| 476 | different for all namespaces. For example @samp{Public/}.")
|
| 477 |
|
| 478 | (location
|
| 479 | (string "")
|
| 480 | "Physical location of the mailbox. This is in same format as
|
| 481 | mail_location, which is also the default for it.")
|
| 482 |
|
| 483 | (inbox?
|
| 484 | (boolean #f)
|
| 485 | "There can be only one INBOX, and this setting defines which
|
| 486 | namespace has it.")
|
| 487 |
|
| 488 | (hidden?
|
| 489 | (boolean #f)
|
| 490 | "If namespace is hidden, it's not advertised to clients via NAMESPACE
|
| 491 | extension. You'll most likely also want to set @samp{list? #f}. This is mostly
|
| 492 | useful when converting from another server with different namespaces
|
| 493 | which you want to deprecate but still keep working. For example you can
|
| 494 | create hidden namespaces with prefixes @samp{~/mail/}, @samp{~%u/mail/}
|
| 495 | and @samp{mail/}.")
|
| 496 |
|
| 497 | (list?
|
| 498 | (boolean #t)
|
| 499 | "Show the mailboxes under this namespace with LIST command. This
|
| 500 | makes the namespace visible for clients that don't support NAMESPACE
|
| 501 | extension. The special @code{children} value lists child mailboxes, but
|
| 502 | hides the namespace prefix.")
|
| 503 |
|
| 504 | (subscriptions?
|
| 505 | (boolean #t)
|
| 506 | "Namespace handles its own subscriptions. If set to @code{#f}, the
|
| 507 | parent namespace handles them. The empty prefix should always have this
|
| 508 | as @code{#t}.)")
|
| 509 |
|
| 510 | (mailboxes
|
| 511 | (mailbox-configuration-list '())
|
| 512 | "List of predefined mailboxes in this namespace."))
|
| 513 |
|
| 514 | (define (serialize-namespace-configuration field-name val)
|
| 515 | (format #t "namespace ~a {\n" (namespace-configuration-name val))
|
| 516 | (serialize-configuration val (cdr namespace-configuration-fields))
|
| 517 | (format #t "}\n"))
|
| 518 | (define (list-of-namespace-configuration? val)
|
| 519 | (and (list? val) (and-map namespace-configuration? val)))
|
| 520 | (define (serialize-list-of-namespace-configuration field-name val)
|
| 521 | (for-each (lambda (val)
|
| 522 | (serialize-namespace-configuration field-name val))
|
| 523 | val))
|
| 524 |
|
| 525 | (define (package-list? val)
|
| 526 | (and (list? val) (and-map package? val)))
|
| 527 | (define (serialize-package-list field-name val)
|
| 528 | #f)
|
| 529 |
|
| 530 | (define-configuration dovecot-configuration
|
| 531 | (dovecot
|
| 532 | (file-like dovecot)
|
| 533 | "The dovecot package.")
|
| 534 |
|
| 535 | (extensions
|
| 536 | (package-list '())
|
| 537 | "Plugins and extensions to the Dovecot package. Specify a list of dovecot
|
| 538 | plugins that needs to be available for dovecot and its modules.")
|
| 539 |
|
| 540 | (listen
|
| 541 | (comma-separated-string-list '("*" "::"))
|
| 542 | "A list of IPs or hosts where to listen in for connections. @samp{*}
|
| 543 | listens in all IPv4 interfaces, @samp{::} listens in all IPv6
|
| 544 | interfaces. If you want to specify non-default ports or anything more
|
| 545 | complex, customize the address and port fields of the
|
| 546 | @samp{inet-listener} of the specific services you are interested in.")
|
| 547 |
|
| 548 | (dict
|
| 549 | (dict-configuration (dict-configuration))
|
| 550 | "Dict configuration, as created by the @code{dict-configuration}
|
| 551 | constructor.")
|
| 552 |
|
| 553 | (passdbs
|
| 554 | (passdb-configuration-list (list (passdb-configuration (driver "pam"))))
|
| 555 | "List of passdb configurations, each one created by the
|
| 556 | @code{passdb-configuration} constructor.")
|
| 557 |
|
| 558 | (userdbs
|
| 559 | (userdb-configuration-list (list (userdb-configuration (driver "passwd"))))
|
| 560 | "List of userdb configurations, each one created by the
|
| 561 | @code{userdb-configuration} constructor.")
|
| 562 |
|
| 563 | (plugin-configuration
|
| 564 | (plugin-configuration (plugin-configuration))
|
| 565 | "Plug-in configuration, created by the @code{plugin-configuration}
|
| 566 | constructor.")
|
| 567 |
|
| 568 | (namespaces
|
| 569 | (list-of-namespace-configuration
|
| 570 | (list
|
| 571 | (namespace-configuration
|
| 572 | (name "inbox")
|
| 573 | (prefix "")
|
| 574 | (inbox? #t)
|
| 575 | (mailboxes
|
| 576 | (list
|
| 577 | (mailbox-configuration (name "Junk") (special-use '("\\Junk")))
|
| 578 | (mailbox-configuration (name "Trash") (special-use '("\\Trash")))
|
| 579 | (mailbox-configuration (name "Sent") (special-use '("\\Sent")))
|
| 580 | (mailbox-configuration (name "Sent Messages") (special-use '("\\Sent")))
|
| 581 | (mailbox-configuration (name "Drafts") (special-use '("\\Drafts"))))))))
|
| 582 | "List of namespaces. Each item in the list is created by the
|
| 583 | @code{namespace-configuration} constructor.")
|
| 584 |
|
| 585 | (base-dir
|
| 586 | (file-name "/var/run/dovecot/")
|
| 587 | "Base directory where to store runtime data.")
|
| 588 |
|
| 589 | (login-greeting
|
| 590 | (string "Dovecot ready.")
|
| 591 | "Greeting message for clients.")
|
| 592 |
|
| 593 | (login-trusted-networks
|
| 594 | (space-separated-string-list '())
|
| 595 | "List of trusted network ranges. Connections from these IPs are
|
| 596 | allowed to override their IP addresses and ports (for logging and for
|
| 597 | authentication checks). @samp{disable-plaintext-auth} is also ignored
|
| 598 | for these networks. Typically you'd specify your IMAP proxy servers
|
| 599 | here.")
|
| 600 |
|
| 601 | (login-access-sockets
|
| 602 | (space-separated-string-list '())
|
| 603 | "List of login access check sockets (e.g. tcpwrap).")
|
| 604 |
|
| 605 | (verbose-proctitle?
|
| 606 | (boolean #f)
|
| 607 | "Show more verbose process titles (in ps). Currently shows user name
|
| 608 | and IP address. Useful for seeing who are actually using the IMAP
|
| 609 | processes (e.g. shared mailboxes or if same uid is used for multiple
|
| 610 | accounts).")
|
| 611 |
|
| 612 | (shutdown-clients?
|
| 613 | (boolean #t)
|
| 614 | "Should all processes be killed when Dovecot master process shuts down.
|
| 615 | Setting this to @code{#f} means that Dovecot can be upgraded without
|
| 616 | forcing existing client connections to close (although that could also
|
| 617 | be a problem if the upgrade is e.g. because of a security fix).")
|
| 618 |
|
| 619 | (doveadm-worker-count
|
| 620 | (non-negative-integer 0)
|
| 621 | "If non-zero, run mail commands via this many connections to doveadm
|
| 622 | server, instead of running them directly in the same process.")
|
| 623 |
|
| 624 | (doveadm-socket-path
|
| 625 | (string "doveadm-server")
|
| 626 | "UNIX socket or host:port used for connecting to doveadm server.")
|
| 627 |
|
| 628 | (import-environment
|
| 629 | (space-separated-string-list '("TZ"))
|
| 630 | "List of environment variables that are preserved on Dovecot startup
|
| 631 | and passed down to all of its child processes. You can also give
|
| 632 | key=value pairs to always set specific settings.")
|
| 633 |
|
| 634 | |
| 635 |
|
| 636 | (disable-plaintext-auth?
|
| 637 | (boolean #t)
|
| 638 | "Disable LOGIN command and all other plaintext authentications unless
|
| 639 | SSL/TLS is used (LOGINDISABLED capability). Note that if the remote IP
|
| 640 | matches the local IP (i.e. you're connecting from the same computer),
|
| 641 | the connection is considered secure and plaintext authentication is
|
| 642 | allowed. See also ssl=required setting.")
|
| 643 |
|
| 644 | (auth-cache-size
|
| 645 | (non-negative-integer 0)
|
| 646 | "Authentication cache size (e.g. @samp{#e10e6}). 0 means it's disabled.
|
| 647 | Note that bsdauth, PAM and vpopmail require @samp{cache-key} to be set
|
| 648 | for caching to be used.")
|
| 649 |
|
| 650 | (auth-cache-ttl
|
| 651 | (string "1 hour")
|
| 652 | "Time to live for cached data. After TTL expires the cached record
|
| 653 | is no longer used, *except* if the main database lookup returns internal
|
| 654 | failure. We also try to handle password changes automatically: If
|
| 655 | user's previous authentication was successful, but this one wasn't, the
|
| 656 | cache isn't used. For now this works only with plaintext
|
| 657 | authentication.")
|
| 658 |
|
| 659 | (auth-cache-negative-ttl
|
| 660 | (string "1 hour")
|
| 661 | "TTL for negative hits (user not found, password mismatch).
|
| 662 | 0 disables caching them completely.")
|
| 663 |
|
| 664 | (auth-realms
|
| 665 | (space-separated-string-list '())
|
| 666 | "List of realms for SASL authentication mechanisms that need them.
|
| 667 | You can leave it empty if you don't want to support multiple realms.
|
| 668 | Many clients simply use the first one listed here, so keep the default
|
| 669 | realm first.")
|
| 670 |
|
| 671 | (auth-default-realm
|
| 672 | (string "")
|
| 673 | "Default realm/domain to use if none was specified. This is used for
|
| 674 | both SASL realms and appending @@domain to username in plaintext
|
| 675 | logins.")
|
| 676 |
|
| 677 | (auth-username-chars
|
| 678 | (string
|
| 679 | "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890.-_@")
|
| 680 | "List of allowed characters in username. If the user-given username
|
| 681 | contains a character not listed in here, the login automatically fails.
|
| 682 | This is just an extra check to make sure user can't exploit any
|
| 683 | potential quote escaping vulnerabilities with SQL/LDAP databases. If
|
| 684 | you want to allow all characters, set this value to empty.")
|
| 685 |
|
| 686 | (auth-username-translation
|
| 687 | (string "")
|
| 688 | "Username character translations before it's looked up from
|
| 689 | databases. The value contains series of from -> to characters. For
|
| 690 | example @samp{#@@/@@} means that @samp{#} and @samp{/} characters are
|
| 691 | translated to @samp{@@}.")
|
| 692 |
|
| 693 | (auth-username-format
|
| 694 | (string "%Lu")
|
| 695 | "Username formatting before it's looked up from databases. You can
|
| 696 | use the standard variables here, e.g. %Lu would lowercase the username,
|
| 697 | %n would drop away the domain if it was given, or @samp{%n-AT-%d} would
|
| 698 | change the @samp{@@} into @samp{-AT-}. This translation is done after
|
| 699 | @samp{auth-username-translation} changes.")
|
| 700 |
|
| 701 | (auth-master-user-separator
|
| 702 | (string "")
|
| 703 | "If you want to allow master users to log in by specifying the master
|
| 704 | username within the normal username string (i.e. not using SASL
|
| 705 | mechanism's support for it), you can specify the separator character
|
| 706 | here. The format is then <username><separator><master username>.
|
| 707 | UW-IMAP uses @samp{*} as the separator, so that could be a good
|
| 708 | choice.")
|
| 709 |
|
| 710 | (auth-anonymous-username
|
| 711 | (string "anonymous")
|
| 712 | "Username to use for users logging in with ANONYMOUS SASL
|
| 713 | mechanism.")
|
| 714 |
|
| 715 | (auth-worker-max-count
|
| 716 | (non-negative-integer 30)
|
| 717 | "Maximum number of dovecot-auth worker processes. They're used to
|
| 718 | execute blocking passdb and userdb queries (e.g. MySQL and PAM).
|
| 719 | They're automatically created and destroyed as needed.")
|
| 720 |
|
| 721 | (auth-gssapi-hostname
|
| 722 | (string "")
|
| 723 | "Host name to use in GSSAPI principal names. The default is to use
|
| 724 | the name returned by gethostname(). Use @samp{$ALL} (with quotes) to
|
| 725 | allow all keytab entries.")
|
| 726 |
|
| 727 | (auth-krb5-keytab
|
| 728 | (string "")
|
| 729 | "Kerberos keytab to use for the GSSAPI mechanism. Will use the
|
| 730 | system default (usually /etc/krb5.keytab) if not specified. You may
|
| 731 | need to change the auth service to run as root to be able to read this
|
| 732 | file.")
|
| 733 |
|
| 734 | (auth-use-winbind?
|
| 735 | (boolean #f)
|
| 736 | "Do NTLM and GSS-SPNEGO authentication using Samba's winbind daemon
|
| 737 | and @samp{ntlm-auth} helper.
|
| 738 | <doc/wiki/Authentication/Mechanisms/Winbind.txt>.")
|
| 739 |
|
| 740 | (auth-winbind-helper-path
|
| 741 | (file-name "/usr/bin/ntlm_auth")
|
| 742 | "Path for Samba's @samp{ntlm-auth} helper binary.")
|
| 743 |
|
| 744 | (auth-failure-delay
|
| 745 | (string "2 secs")
|
| 746 | "Time to delay before replying to failed authentications.")
|
| 747 |
|
| 748 | (auth-ssl-require-client-cert?
|
| 749 | (boolean #f)
|
| 750 | "Require a valid SSL client certificate or the authentication
|
| 751 | fails.")
|
| 752 |
|
| 753 | (auth-ssl-username-from-cert?
|
| 754 | (boolean #f)
|
| 755 | "Take the username from client's SSL certificate, using
|
| 756 | @code{X509_NAME_get_text_by_NID()} which returns the subject's DN's
|
| 757 | CommonName.")
|
| 758 |
|
| 759 | (auth-mechanisms
|
| 760 | (space-separated-string-list '("plain"))
|
| 761 | "List of wanted authentication mechanisms. Supported mechanisms are:
|
| 762 | @samp{plain}, @samp{login}, @samp{digest-md5}, @samp{cram-md5},
|
| 763 | @samp{ntlm}, @samp{rpa}, @samp{apop}, @samp{anonymous}, @samp{gssapi},
|
| 764 | @samp{otp}, @samp{skey}, and @samp{gss-spnego}. NOTE: See also
|
| 765 | @samp{disable-plaintext-auth} setting.")
|
| 766 |
|
| 767 | (director-servers
|
| 768 | (space-separated-string-list '())
|
| 769 | "List of IPs or hostnames to all director servers, including ourself.
|
| 770 | Ports can be specified as ip:port. The default port is the same as what
|
| 771 | director service's @samp{inet-listener} is using.")
|
| 772 |
|
| 773 | (director-mail-servers
|
| 774 | (space-separated-string-list '())
|
| 775 | "List of IPs or hostnames to all backend mail servers. Ranges are
|
| 776 | allowed too, like 10.0.0.10-10.0.0.30.")
|
| 777 |
|
| 778 | (director-user-expire
|
| 779 | (string "15 min")
|
| 780 | "How long to redirect users to a specific server after it no longer
|
| 781 | has any connections.")
|
| 782 |
|
| 783 | (director-username-hash
|
| 784 | (string "%Lu")
|
| 785 | "How the username is translated before being hashed. Useful values
|
| 786 | include %Ln if user can log in with or without @@domain, %Ld if mailboxes
|
| 787 | are shared within domain.")
|
| 788 |
|
| 789 | |
| 790 |
|
| 791 | (log-path
|
| 792 | (string "syslog")
|
| 793 | "Log file to use for error messages. @samp{syslog} logs to syslog,
|
| 794 | @samp{/dev/stderr} logs to stderr.")
|
| 795 |
|
| 796 | (info-log-path
|
| 797 | (string "")
|
| 798 | "Log file to use for informational messages. Defaults to
|
| 799 | @samp{log-path}.")
|
| 800 |
|
| 801 | (debug-log-path
|
| 802 | (string "")
|
| 803 | "Log file to use for debug messages. Defaults to
|
| 804 | @samp{info-log-path}.")
|
| 805 |
|
| 806 | (syslog-facility
|
| 807 | (string "mail")
|
| 808 | "Syslog facility to use if you're logging to syslog. Usually if you
|
| 809 | don't want to use @samp{mail}, you'll use local0..local7. Also other
|
| 810 | standard facilities are supported.")
|
| 811 |
|
| 812 | (auth-verbose?
|
| 813 | (boolean #f)
|
| 814 | "Log unsuccessful authentication attempts and the reasons why they
|
| 815 | failed.")
|
| 816 |
|
| 817 | (auth-verbose-passwords
|
| 818 | (string "no")
|
| 819 | "In case of password mismatches, log the attempted password. Valid
|
| 820 | values are no, plain and sha1. sha1 can be useful for detecting brute
|
| 821 | force password attempts vs. user simply trying the same password over
|
| 822 | and over again. You can also truncate the value to n chars by appending
|
| 823 | \":n\" (e.g. sha1:6).")
|
| 824 |
|
| 825 | (auth-debug?
|
| 826 | (boolean #f)
|
| 827 | "Even more verbose logging for debugging purposes. Shows for example
|
| 828 | SQL queries.")
|
| 829 |
|
| 830 | (auth-debug-passwords?
|
| 831 | (boolean #f)
|
| 832 | "In case of password mismatches, log the passwords and used scheme so
|
| 833 | the problem can be debugged. Enabling this also enables
|
| 834 | @samp{auth-debug}.")
|
| 835 |
|
| 836 | (mail-debug?
|
| 837 | (boolean #f)
|
| 838 | "Enable mail process debugging. This can help you figure out why
|
| 839 | Dovecot isn't finding your mails.")
|
| 840 |
|
| 841 | (verbose-ssl?
|
| 842 | (boolean #f)
|
| 843 | "Show protocol level SSL errors.")
|
| 844 |
|
| 845 | (log-timestamp
|
| 846 | (string "\"%b %d %H:%M:%S \"")
|
| 847 | "Prefix for each line written to log file. % codes are in
|
| 848 | strftime(3) format.")
|
| 849 |
|
| 850 | (login-log-format-elements
|
| 851 | (space-separated-string-list
|
| 852 | '("user=<%u>" "method=%m" "rip=%r" "lip=%l" "mpid=%e" "%c"))
|
| 853 | "List of elements we want to log. The elements which have a
|
| 854 | non-empty variable value are joined together to form a comma-separated
|
| 855 | string.")
|
| 856 |
|
| 857 | (login-log-format
|
| 858 | (string "%$: %s")
|
| 859 | "Login log format. %s contains @samp{login-log-format-elements}
|
| 860 | string, %$ contains the data we want to log.")
|
| 861 |
|
| 862 | (mail-log-prefix
|
| 863 | (string "\"%s(%u)<%{pid}><%{session}>: \"")
|
| 864 | "Log prefix for mail processes. See doc/wiki/Variables.txt for list
|
| 865 | of possible variables you can use.")
|
| 866 |
|
| 867 | (deliver-log-format
|
| 868 | (string "msgid=%m: %$")
|
| 869 | "Format to use for logging mail deliveries. You can use variables:
|
| 870 | @table @code
|
| 871 | @item %$
|
| 872 | Delivery status message (e.g. @samp{saved to INBOX})
|
| 873 | @item %m
|
| 874 | Message-ID
|
| 875 | @item %s
|
| 876 | Subject
|
| 877 | @item %f
|
| 878 | From address
|
| 879 | @item %p
|
| 880 | Physical size
|
| 881 | @item %w
|
| 882 | Virtual size.
|
| 883 | @end table")
|
| 884 |
|
| 885 | |
| 886 |
|
| 887 | (mail-location
|
| 888 | (string "")
|
| 889 | "Location for users' mailboxes. The default is empty, which means
|
| 890 | that Dovecot tries to find the mailboxes automatically. This won't work
|
| 891 | if the user doesn't yet have any mail, so you should explicitly tell
|
| 892 | Dovecot the full location.
|
| 893 |
|
| 894 | If you're using mbox, giving a path to the INBOX
|
| 895 | file (e.g. /var/mail/%u) isn't enough. You'll also need to tell Dovecot
|
| 896 | where the other mailboxes are kept. This is called the \"root mail
|
| 897 | directory\", and it must be the first path given in the
|
| 898 | @samp{mail-location} setting.
|
| 899 |
|
| 900 | There are a few special variables you can use, eg.:
|
| 901 |
|
| 902 | @table @samp
|
| 903 | @item %u
|
| 904 | username
|
| 905 | @item %n
|
| 906 | user part in user@@domain, same as %u if there's no domain
|
| 907 | @item %d
|
| 908 | domain part in user@@domain, empty if there's no domain
|
| 909 | @item %h
|
| 910 | home director
|
| 911 | @end table
|
| 912 |
|
| 913 | See doc/wiki/Variables.txt for full list. Some examples:
|
| 914 | @table @samp
|
| 915 | @item maildir:~/Maildir
|
| 916 | @item mbox:~/mail:INBOX=/var/mail/%u
|
| 917 | @item mbox:/var/mail/%d/%1n/%n:INDEX=/var/indexes/%d/%1n/%
|
| 918 | @end table")
|
| 919 |
|
| 920 | (mail-uid
|
| 921 | (string "")
|
| 922 | "System user and group used to access mails. If you use multiple,
|
| 923 | userdb can override these by returning uid or gid fields. You can use
|
| 924 | either numbers or names. <doc/wiki/UserIds.txt>.")
|
| 925 |
|
| 926 | (mail-gid
|
| 927 | (string "")
|
| 928 | "")
|
| 929 |
|
| 930 | (mail-privileged-group
|
| 931 | (string "")
|
| 932 | "Group to enable temporarily for privileged operations. Currently
|
| 933 | this is used only with INBOX when either its initial creation or
|
| 934 | dotlocking fails. Typically this is set to \"mail\" to give access to
|
| 935 | /var/mail.")
|
| 936 |
|
| 937 | (mail-access-groups
|
| 938 | (string "")
|
| 939 | "Grant access to these supplementary groups for mail processes.
|
| 940 | Typically these are used to set up access to shared mailboxes. Note
|
| 941 | that it may be dangerous to set these if users can create
|
| 942 | symlinks (e.g. if \"mail\" group is set here, ln -s /var/mail ~/mail/var
|
| 943 | could allow a user to delete others' mailboxes, or ln -s
|
| 944 | /secret/shared/box ~/mail/mybox would allow reading it).")
|
| 945 |
|
| 946 | (mail-full-filesystem-access?
|
| 947 | (boolean #f)
|
| 948 | "Allow full file system access to clients. There's no access checks
|
| 949 | other than what the operating system does for the active UID/GID. It
|
| 950 | works with both maildir and mboxes, allowing you to prefix mailboxes
|
| 951 | names with e.g. /path/ or ~user/.")
|
| 952 |
|
| 953 | |
| 954 |
|
| 955 | (mmap-disable?
|
| 956 | (boolean #f)
|
| 957 | "Don't use mmap() at all. This is required if you store indexes to
|
| 958 | shared file systems (NFS or clustered file system).")
|
| 959 |
|
| 960 | (dotlock-use-excl?
|
| 961 | (boolean #t)
|
| 962 | "Rely on @samp{O_EXCL} to work when creating dotlock files. NFS
|
| 963 | supports @samp{O_EXCL} since version 3, so this should be safe to use
|
| 964 | nowadays by default.")
|
| 965 |
|
| 966 | (mail-fsync
|
| 967 | (string "optimized")
|
| 968 | "When to use fsync() or fdatasync() calls:
|
| 969 | @table @code
|
| 970 | @item optimized
|
| 971 | Whenever necessary to avoid losing important data
|
| 972 | @item always
|
| 973 | Useful with e.g. NFS when write()s are delayed
|
| 974 | @item never
|
| 975 | Never use it (best performance, but crashes can lose data).
|
| 976 | @end table")
|
| 977 |
|
| 978 | (mail-nfs-storage?
|
| 979 | (boolean #f)
|
| 980 | "Mail storage exists in NFS. Set this to yes to make Dovecot flush
|
| 981 | NFS caches whenever needed. If you're using only a single mail server
|
| 982 | this isn't needed.")
|
| 983 |
|
| 984 | (mail-nfs-index?
|
| 985 | (boolean #f)
|
| 986 | "Mail index files also exist in NFS. Setting this to yes requires
|
| 987 | @samp{mmap-disable? #t} and @samp{fsync-disable? #f}.")
|
| 988 |
|
| 989 | (lock-method
|
| 990 | (string "fcntl")
|
| 991 | "Locking method for index files. Alternatives are fcntl, flock and
|
| 992 | dotlock. Dotlocking uses some tricks which may create more disk I/O
|
| 993 | than other locking methods. NFS users: flock doesn't work, remember to
|
| 994 | change @samp{mmap-disable}.")
|
| 995 |
|
| 996 | (mail-temp-dir
|
| 997 | (file-name "/tmp")
|
| 998 | "Directory in which LDA/LMTP temporarily stores incoming mails >128
|
| 999 | kB.")
|
| 1000 |
|
| 1001 | (first-valid-uid
|
| 1002 | (non-negative-integer 500)
|
| 1003 | "Valid UID range for users. This is mostly to make sure that users can't
|
| 1004 | log in as daemons or other system users. Note that denying root logins is
|
| 1005 | hardcoded to dovecot binary and can't be done even if @samp{first-valid-uid}
|
| 1006 | is set to 0.")
|
| 1007 |
|
| 1008 | (last-valid-uid
|
| 1009 | (non-negative-integer 0)
|
| 1010 | "")
|
| 1011 |
|
| 1012 | (first-valid-gid
|
| 1013 | (non-negative-integer 1)
|
| 1014 | "Valid GID range for users. Users having non-valid GID as primary group ID
|
| 1015 | aren't allowed to log in. If user belongs to supplementary groups with
|
| 1016 | non-valid GIDs, those groups are not set.")
|
| 1017 |
|
| 1018 | (last-valid-gid
|
| 1019 | (non-negative-integer 0)
|
| 1020 | "")
|
| 1021 |
|
| 1022 | (mail-max-keyword-length
|
| 1023 | (non-negative-integer 50)
|
| 1024 | "Maximum allowed length for mail keyword name. It's only forced when
|
| 1025 | trying to create new keywords.")
|
| 1026 |
|
| 1027 | (valid-chroot-dirs
|
| 1028 | (colon-separated-file-name-list '())
|
| 1029 | "List of directories under which chrooting is allowed for mail
|
| 1030 | processes (i.e. /var/mail will allow chrooting to /var/mail/foo/bar
|
| 1031 | too). This setting doesn't affect @samp{login-chroot}
|
| 1032 | @samp{mail-chroot} or auth chroot settings. If this setting is empty,
|
| 1033 | \"/./\" in home dirs are ignored. WARNING: Never add directories here
|
| 1034 | which local users can modify, that may lead to root exploit. Usually
|
| 1035 | this should be done only if you don't allow shell access for users.
|
| 1036 | <doc/wiki/Chrooting.txt>.")
|
| 1037 |
|
| 1038 | (mail-chroot
|
| 1039 | (string "")
|
| 1040 | "Default chroot directory for mail processes. This can be overridden
|
| 1041 | for specific users in user database by giving /./ in user's home
|
| 1042 | directory (e.g. /home/./user chroots into /home). Note that usually
|
| 1043 | there is no real need to do chrooting, Dovecot doesn't allow users to
|
| 1044 | access files outside their mail directory anyway. If your home
|
| 1045 | directories are prefixed with the chroot directory, append \"/.\" to
|
| 1046 | @samp{mail-chroot}. <doc/wiki/Chrooting.txt>.")
|
| 1047 |
|
| 1048 | (auth-socket-path
|
| 1049 | (file-name "/var/run/dovecot/auth-userdb")
|
| 1050 | "UNIX socket path to master authentication server to find users.
|
| 1051 | This is used by imap (for shared users) and lda.")
|
| 1052 |
|
| 1053 | (mail-plugin-dir
|
| 1054 | (file-name "/usr/lib/dovecot")
|
| 1055 | "Directory where to look up mail plugins.")
|
| 1056 |
|
| 1057 | (mail-plugins
|
| 1058 | (space-separated-string-list '())
|
| 1059 | "List of plugins to load for all services. Plugins specific to IMAP,
|
| 1060 | LDA, etc. are added to this list in their own .conf files.")
|
| 1061 |
|
| 1062 |
|
| 1063 | (mail-cache-min-mail-count
|
| 1064 | (non-negative-integer 0)
|
| 1065 | "The minimum number of mails in a mailbox before updates are done to
|
| 1066 | cache file. This allows optimizing Dovecot's behavior to do less disk
|
| 1067 | writes at the cost of more disk reads.")
|
| 1068 |
|
| 1069 | (mailbox-idle-check-interval
|
| 1070 | (string "30 secs")
|
| 1071 | "When IDLE command is running, mailbox is checked once in a while to
|
| 1072 | see if there are any new mails or other changes. This setting defines
|
| 1073 | the minimum time to wait between those checks. Dovecot can also use
|
| 1074 | dnotify, inotify and kqueue to find out immediately when changes
|
| 1075 | occur.")
|
| 1076 |
|
| 1077 | (mail-save-crlf?
|
| 1078 | (boolean #f)
|
| 1079 | "Save mails with CR+LF instead of plain LF. This makes sending those
|
| 1080 | mails take less CPU, especially with sendfile() syscall with Linux and
|
| 1081 | FreeBSD. But it also creates a bit more disk I/O which may just make it
|
| 1082 | slower. Also note that if other software reads the mboxes/maildirs,
|
| 1083 | they may handle the extra CRs wrong and cause problems.")
|
| 1084 |
|
| 1085 | (maildir-stat-dirs?
|
| 1086 | (boolean #f)
|
| 1087 | "By default LIST command returns all entries in maildir beginning
|
| 1088 | with a dot. Enabling this option makes Dovecot return only entries
|
| 1089 | which are directories. This is done by stat()ing each entry, so it
|
| 1090 | causes more disk I/O.
|
| 1091 | (For systems setting struct @samp{dirent->d_type} this check is free
|
| 1092 | and it's done always regardless of this setting).")
|
| 1093 |
|
| 1094 | (maildir-copy-with-hardlinks?
|
| 1095 | (boolean #t)
|
| 1096 | "When copying a message, do it with hard links whenever possible.
|
| 1097 | This makes the performance much better, and it's unlikely to have any
|
| 1098 | side effects.")
|
| 1099 |
|
| 1100 | (maildir-very-dirty-syncs?
|
| 1101 | (boolean #f)
|
| 1102 | "Assume Dovecot is the only MUA accessing Maildir: Scan cur/
|
| 1103 | directory only when its mtime changes unexpectedly or when we can't find
|
| 1104 | the mail otherwise.")
|
| 1105 |
|
| 1106 | (mbox-read-locks
|
| 1107 | (space-separated-string-list '("fcntl"))
|
| 1108 | "Which locking methods to use for locking mbox. There are four
|
| 1109 | available:
|
| 1110 |
|
| 1111 | @table @code
|
| 1112 | @item dotlock
|
| 1113 | Create <mailbox>.lock file. This is the oldest and most NFS-safe
|
| 1114 | solution. If you want to use /var/mail/ like directory, the users will
|
| 1115 | need write access to that directory.
|
| 1116 | @item dotlock-try
|
| 1117 | Same as dotlock, but if it fails because of permissions or because there
|
| 1118 | isn't enough disk space, just skip it.
|
| 1119 | @item fcntl
|
| 1120 | Use this if possible. Works with NFS too if lockd is used.
|
| 1121 | @item flock
|
| 1122 | May not exist in all systems. Doesn't work with NFS.
|
| 1123 | @item lockf
|
| 1124 | May not exist in all systems. Doesn't work with NFS.
|
| 1125 | @end table
|
| 1126 |
|
| 1127 | You can use multiple locking methods; if you do the order they're declared
|
| 1128 | in is important to avoid deadlocks if other MTAs/MUAs are using multiple
|
| 1129 | locking methods as well. Some operating systems don't allow using some of
|
| 1130 | them simultaneously.")
|
| 1131 |
|
| 1132 | (mbox-write-locks
|
| 1133 | (space-separated-string-list '("dotlock" "fcntl"))
|
| 1134 | "")
|
| 1135 |
|
| 1136 | (mbox-lock-timeout
|
| 1137 | (string "5 mins")
|
| 1138 | "Maximum time to wait for lock (all of them) before aborting.")
|
| 1139 |
|
| 1140 | (mbox-dotlock-change-timeout
|
| 1141 | (string "2 mins")
|
| 1142 | "If dotlock exists but the mailbox isn't modified in any way,
|
| 1143 | override the lock file after this much time.")
|
| 1144 |
|
| 1145 | (mbox-dirty-syncs?
|
| 1146 | (boolean #t)
|
| 1147 | "When mbox changes unexpectedly we have to fully read it to find out
|
| 1148 | what changed. If the mbox is large this can take a long time. Since
|
| 1149 | the change is usually just a newly appended mail, it'd be faster to
|
| 1150 | simply read the new mails. If this setting is enabled, Dovecot does
|
| 1151 | this but still safely fallbacks to re-reading the whole mbox file
|
| 1152 | whenever something in mbox isn't how it's expected to be. The only real
|
| 1153 | downside to this setting is that if some other MUA changes message
|
| 1154 | flags, Dovecot doesn't notice it immediately. Note that a full sync is
|
| 1155 | done with SELECT, EXAMINE, EXPUNGE and CHECK commands.")
|
| 1156 |
|
| 1157 | (mbox-very-dirty-syncs?
|
| 1158 | (boolean #f)
|
| 1159 | "Like @samp{mbox-dirty-syncs}, but don't do full syncs even with SELECT,
|
| 1160 | EXAMINE, EXPUNGE or CHECK commands. If this is set,
|
| 1161 | @samp{mbox-dirty-syncs} is ignored.")
|
| 1162 |
|
| 1163 | (mbox-lazy-writes?
|
| 1164 | (boolean #t)
|
| 1165 | "Delay writing mbox headers until doing a full write sync (EXPUNGE
|
| 1166 | and CHECK commands and when closing the mailbox). This is especially
|
| 1167 | useful for POP3 where clients often delete all mails. The downside is
|
| 1168 | that our changes aren't immediately visible to other MUAs.")
|
| 1169 |
|
| 1170 | (mbox-min-index-size
|
| 1171 | (non-negative-integer 0)
|
| 1172 | "If mbox size is smaller than this (e.g. 100k), don't write index
|
| 1173 | files. If an index file already exists it's still read, just not
|
| 1174 | updated.")
|
| 1175 |
|
| 1176 | (mdbox-rotate-size
|
| 1177 | (non-negative-integer #e10e6)
|
| 1178 | "Maximum dbox file size until it's rotated.")
|
| 1179 |
|
| 1180 | (mdbox-rotate-interval
|
| 1181 | (string "1d")
|
| 1182 | "Maximum dbox file age until it's rotated. Typically in days. Day
|
| 1183 | begins from midnight, so 1d = today, 2d = yesterday, etc. 0 = check
|
| 1184 | disabled.")
|
| 1185 |
|
| 1186 | (mdbox-preallocate-space?
|
| 1187 | (boolean #f)
|
| 1188 | "When creating new mdbox files, immediately preallocate their size to
|
| 1189 | @samp{mdbox-rotate-size}. This setting currently works only in Linux
|
| 1190 | with some file systems (ext4, xfs).")
|
| 1191 |
|
| 1192 | (mail-attribute-dict
|
| 1193 | (string "")
|
| 1194 | "The location of a dictionary used to store @code{IMAP METADATA}
|
| 1195 | as defined by @uref{https://tools.ietf.org/html/rfc5464, RFC@tie{}5464}.
|
| 1196 |
|
| 1197 | The IMAP METADATA commands are available only if the ``imap''
|
| 1198 | protocol configuration's @code{imap-metadata?} field is @samp{#t}.")
|
| 1199 |
|
| 1200 | (mail-attachment-dir
|
| 1201 | (string "")
|
| 1202 | "sdbox and mdbox support saving mail attachments to external files,
|
| 1203 | which also allows single instance storage for them. Other backends
|
| 1204 | don't support this for now.
|
| 1205 |
|
| 1206 | WARNING: This feature hasn't been tested much yet. Use at your own risk.
|
| 1207 |
|
| 1208 | Directory root where to store mail attachments. Disabled, if empty.")
|
| 1209 |
|
| 1210 | (mail-attachment-min-size
|
| 1211 | (non-negative-integer #e128e3)
|
| 1212 | "Attachments smaller than this aren't saved externally. It's also
|
| 1213 | possible to write a plugin to disable saving specific attachments
|
| 1214 | externally.")
|
| 1215 |
|
| 1216 | (mail-attachment-fs
|
| 1217 | (string "sis posix")
|
| 1218 | "File system backend to use for saving attachments:
|
| 1219 | @table @code
|
| 1220 | @item posix
|
| 1221 | No SiS done by Dovecot (but this might help FS's own deduplication)
|
| 1222 | @item sis posix
|
| 1223 | SiS with immediate byte-by-byte comparison during saving
|
| 1224 | @item sis-queue posix
|
| 1225 | SiS with delayed comparison and deduplication.
|
| 1226 | @end table")
|
| 1227 |
|
| 1228 | (mail-attachment-hash
|
| 1229 | (string "%{sha1}")
|
| 1230 | "Hash format to use in attachment filenames. You can add any text and
|
| 1231 | variables: @code{%@{md4@}}, @code{%@{md5@}}, @code{%@{sha1@}},
|
| 1232 | @code{%@{sha256@}}, @code{%@{sha512@}}, @code{%@{size@}}. Variables can be
|
| 1233 | truncated, e.g. @code{%@{sha256:80@}} returns only first 80 bits.")
|
| 1234 |
|
| 1235 | (default-process-limit
|
| 1236 | (non-negative-integer 100)
|
| 1237 | "")
|
| 1238 |
|
| 1239 | (default-client-limit
|
| 1240 | (non-negative-integer 1000)
|
| 1241 | "")
|
| 1242 |
|
| 1243 | (default-vsz-limit
|
| 1244 | (non-negative-integer #e256e6)
|
| 1245 | "Default VSZ (virtual memory size) limit for service processes.
|
| 1246 | This is mainly intended to catch and kill processes that leak memory
|
| 1247 | before they eat up everything.")
|
| 1248 |
|
| 1249 | (default-login-user
|
| 1250 | (string "dovenull")
|
| 1251 | "Login user is internally used by login processes. This is the most
|
| 1252 | untrusted user in Dovecot system. It shouldn't have access to anything
|
| 1253 | at all.")
|
| 1254 |
|
| 1255 | (default-internal-user
|
| 1256 | (string "dovecot")
|
| 1257 | "Internal user is used by unprivileged processes. It should be
|
| 1258 | separate from login user, so that login processes can't disturb other
|
| 1259 | processes.")
|
| 1260 |
|
| 1261 | (ssl?
|
| 1262 | (string "required")
|
| 1263 | "SSL/TLS support: yes, no, required. <doc/wiki/SSL.txt>.")
|
| 1264 |
|
| 1265 | (ssl-cert
|
| 1266 | (string "</etc/dovecot/default.pem")
|
| 1267 | "PEM encoded X.509 SSL/TLS certificate (public key).")
|
| 1268 |
|
| 1269 | (ssl-key
|
| 1270 | (string "</etc/dovecot/private/default.pem")
|
| 1271 | "PEM encoded SSL/TLS private key. The key is opened before
|
| 1272 | dropping root privileges, so keep the key file unreadable by anyone but
|
| 1273 | root.")
|
| 1274 |
|
| 1275 | (ssl-key-password
|
| 1276 | (string "")
|
| 1277 | "If key file is password protected, give the password here.
|
| 1278 | Alternatively give it when starting dovecot with -p parameter. Since
|
| 1279 | this file is often world-readable, you may want to place this setting
|
| 1280 | instead to a different.")
|
| 1281 |
|
| 1282 | (ssl-ca
|
| 1283 | (string "")
|
| 1284 | "PEM encoded trusted certificate authority. Set this only if you
|
| 1285 | intend to use @samp{ssl-verify-client-cert? #t}. The file should
|
| 1286 | contain the CA certificate(s) followed by the matching
|
| 1287 | CRL(s). (e.g. @samp{ssl-ca </etc/ssl/certs/ca.pem}).")
|
| 1288 | (ssl-require-crl?
|
| 1289 | (boolean #t)
|
| 1290 | "Require that CRL check succeeds for client certificates.")
|
| 1291 | (ssl-verify-client-cert?
|
| 1292 | (boolean #f)
|
| 1293 | "Request client to send a certificate. If you also want to require
|
| 1294 | it, set @samp{auth-ssl-require-client-cert? #t} in auth section.")
|
| 1295 |
|
| 1296 | (ssl-cert-username-field
|
| 1297 | (string "commonName")
|
| 1298 | "Which field from certificate to use for username. commonName and
|
| 1299 | x500UniqueIdentifier are the usual choices. You'll also need to set
|
| 1300 | @samp{auth-ssl-username-from-cert? #t}.")
|
| 1301 |
|
| 1302 | (ssl-min-protocol
|
| 1303 | (string "TLSv1")
|
| 1304 | "Minimum SSL protocol version to accept.")
|
| 1305 |
|
| 1306 | (ssl-cipher-list
|
| 1307 | (string "ALL:!kRSA:!SRP:!kDHd:!DSS:!aNULL:!eNULL:!EXPORT:!DES:!3DES:!MD5:!PSK:!RC4:!ADH:!LOW@STRENGTH")
|
| 1308 | "SSL ciphers to use.")
|
| 1309 |
|
| 1310 | (ssl-crypto-device
|
| 1311 | (string "")
|
| 1312 | "SSL crypto device to use, for valid values run \"openssl engine\".")
|
| 1313 |
|
| 1314 | (postmaster-address
|
| 1315 | (string "postmaster@%d")
|
| 1316 | "Address to use when sending rejection mails.
|
| 1317 | Default is postmaster@@<your domain>. %d expands to recipient domain.")
|
| 1318 |
|
| 1319 | (hostname
|
| 1320 | (string "")
|
| 1321 | "Hostname to use in various parts of sent mails (e.g. in Message-Id)
|
| 1322 | and in LMTP replies. Default is the system's real hostname@@domain.")
|
| 1323 |
|
| 1324 | (quota-full-tempfail?
|
| 1325 | (boolean #f)
|
| 1326 | "If user is over quota, return with temporary failure instead of
|
| 1327 | bouncing the mail.")
|
| 1328 |
|
| 1329 | (sendmail-path
|
| 1330 | (file-name "/usr/sbin/sendmail")
|
| 1331 | "Binary to use for sending mails.")
|
| 1332 |
|
| 1333 | (submission-host
|
| 1334 | (string "")
|
| 1335 | "If non-empty, send mails via this SMTP host[:port] instead of
|
| 1336 | sendmail.")
|
| 1337 |
|
| 1338 | (rejection-subject
|
| 1339 | (string "Rejected: %s")
|
| 1340 | "Subject: header to use for rejection mails. You can use the same
|
| 1341 | variables as for @samp{rejection-reason} below.")
|
| 1342 |
|
| 1343 | (rejection-reason
|
| 1344 | (string "Your message to <%t> was automatically rejected:%n%r")
|
| 1345 | "Human readable error message for rejection mails. You can use
|
| 1346 | variables:
|
| 1347 |
|
| 1348 | @table @code
|
| 1349 | @item %n
|
| 1350 | CRLF
|
| 1351 | @item %r
|
| 1352 | reason
|
| 1353 | @item %s
|
| 1354 | original subject
|
| 1355 | @item %t
|
| 1356 | recipient
|
| 1357 | @end table")
|
| 1358 |
|
| 1359 | (recipient-delimiter
|
| 1360 | (string "+")
|
| 1361 | "Delimiter character between local-part and detail in email
|
| 1362 | address.")
|
| 1363 |
|
| 1364 | (lda-original-recipient-header
|
| 1365 | (string "")
|
| 1366 | "Header where the original recipient address (SMTP's RCPT TO:
|
| 1367 | address) is taken from if not available elsewhere. With dovecot-lda -a
|
| 1368 | parameter overrides this. A commonly used header for this is
|
| 1369 | X-Original-To.")
|
| 1370 |
|
| 1371 | (lda-mailbox-autocreate?
|
| 1372 | (boolean #f)
|
| 1373 | "Should saving a mail to a nonexistent mailbox automatically create
|
| 1374 | it?.")
|
| 1375 |
|
| 1376 | (lda-mailbox-autosubscribe?
|
| 1377 | (boolean #f)
|
| 1378 | "Should automatically created mailboxes be also automatically
|
| 1379 | subscribed?.")
|
| 1380 |
|
| 1381 |
|
| 1382 | (imap-max-line-length
|
| 1383 | (non-negative-integer #e64e3)
|
| 1384 | "Maximum IMAP command line length. Some clients generate very long
|
| 1385 | command lines with huge mailboxes, so you may need to raise this if you
|
| 1386 | get \"Too long argument\" or \"IMAP command line too large\" errors
|
| 1387 | often.")
|
| 1388 |
|
| 1389 | (imap-logout-format
|
| 1390 | (string "in=%i out=%o deleted=%{deleted} expunged=%{expunged} trashed=%{trashed} hdr_count=%{fetch_hdr_count} hdr_bytes=%{fetch_hdr_bytes} body_count=%{fetch_body_count} body_bytes=%{fetch_body_bytes}")
|
| 1391 | "IMAP logout format string:
|
| 1392 | @table @code
|
| 1393 | @item %i
|
| 1394 | total number of bytes read from client
|
| 1395 | @item %o
|
| 1396 | total number of bytes sent to client.
|
| 1397 | @end table
|
| 1398 | See @file{doc/wiki/Variables.txt} for a list of all the variables you can use.")
|
| 1399 |
|
| 1400 | (imap-capability
|
| 1401 | (string "")
|
| 1402 | "Override the IMAP CAPABILITY response. If the value begins with '+',
|
| 1403 | add the given capabilities on top of the defaults (e.g. +XFOO XBAR).")
|
| 1404 |
|
| 1405 | (imap-idle-notify-interval
|
| 1406 | (string "2 mins")
|
| 1407 | "How long to wait between \"OK Still here\" notifications when client
|
| 1408 | is IDLEing.")
|
| 1409 |
|
| 1410 | (imap-id-send
|
| 1411 | (string "")
|
| 1412 | "ID field names and values to send to clients. Using * as the value
|
| 1413 | makes Dovecot use the default value. The following fields have default
|
| 1414 | values currently: name, version, os, os-version, support-url,
|
| 1415 | support-email.")
|
| 1416 |
|
| 1417 | (imap-id-log
|
| 1418 | (string "")
|
| 1419 | "ID fields sent by client to log. * means everything.")
|
| 1420 |
|
| 1421 | (imap-client-workarounds
|
| 1422 | (space-separated-string-list '())
|
| 1423 | "Workarounds for various client bugs:
|
| 1424 |
|
| 1425 | @table @code
|
| 1426 | @item delay-newmail
|
| 1427 | Send EXISTS/RECENT new mail notifications only when replying to NOOP and
|
| 1428 | CHECK commands. Some clients ignore them otherwise, for example OSX
|
| 1429 | Mail (<v2.1). Outlook Express breaks more badly though, without this it
|
| 1430 | may show user \"Message no longer in server\" errors. Note that OE6
|
| 1431 | still breaks even with this workaround if synchronization is set to
|
| 1432 | \"Headers Only\".
|
| 1433 |
|
| 1434 | @item tb-extra-mailbox-sep
|
| 1435 | Thunderbird gets somehow confused with LAYOUT=fs (mbox and dbox) and
|
| 1436 | adds extra @samp{/} suffixes to mailbox names. This option causes Dovecot to
|
| 1437 | ignore the extra @samp{/} instead of treating it as invalid mailbox name.
|
| 1438 |
|
| 1439 | @item tb-lsub-flags
|
| 1440 | Show \\Noselect flags for LSUB replies with LAYOUT=fs (e.g. mbox).
|
| 1441 | This makes Thunderbird realize they aren't selectable and show them
|
| 1442 | greyed out, instead of only later giving \"not selectable\" popup error.
|
| 1443 | @end table
|
| 1444 | ")
|
| 1445 |
|
| 1446 | (imap-urlauth-host
|
| 1447 | (string "")
|
| 1448 | "Host allowed in URLAUTH URLs sent by client. \"*\" allows all.")
|
| 1449 |
|
| 1450 | (protocols
|
| 1451 | (protocol-configuration-list
|
| 1452 | (list (protocol-configuration
|
| 1453 | (name "imap"))))
|
| 1454 | "List of protocols we want to serve. Available protocols include
|
| 1455 | @samp{imap}, @samp{pop3}, and @samp{lmtp}.")
|
| 1456 |
|
| 1457 | (services
|
| 1458 | (service-configuration-list
|
| 1459 | (list
|
| 1460 | (service-configuration
|
| 1461 | (kind "imap-login")
|
| 1462 | (client-limit 0)
|
| 1463 | (process-limit 0)
|
| 1464 | (listeners
|
| 1465 | (list
|
| 1466 | (inet-listener-configuration (protocol "imap") (port 143) (ssl? #f))
|
| 1467 | (inet-listener-configuration (protocol "imaps") (port 993) (ssl? #t)))))
|
| 1468 | (service-configuration
|
| 1469 | (kind "pop3-login")
|
| 1470 | (listeners
|
| 1471 | (list
|
| 1472 | (inet-listener-configuration (protocol "pop3") (port 110) (ssl? #f))
|
| 1473 | (inet-listener-configuration (protocol "pop3s") (port 995) (ssl? #t)))))
|
| 1474 | (service-configuration
|
| 1475 | (kind "lmtp")
|
| 1476 | (client-limit 1)
|
| 1477 | (process-limit 0)
|
| 1478 | (listeners
|
| 1479 | (list (unix-listener-configuration (path "lmtp") (mode "0666")))))
|
| 1480 | (service-configuration
|
| 1481 | (kind "imap")
|
| 1482 | (client-limit 1)
|
| 1483 | (process-limit 1024))
|
| 1484 | (service-configuration
|
| 1485 | (kind "pop3")
|
| 1486 | (client-limit 1)
|
| 1487 | (process-limit 1024))
|
| 1488 | (service-configuration
|
| 1489 | (kind "auth")
|
| 1490 | (service-count 0)
|
| 1491 | (client-limit 0)
|
| 1492 | (process-limit 1)
|
| 1493 | (listeners
|
| 1494 | (list (unix-listener-configuration (path "auth-userdb")))))
|
| 1495 | (service-configuration
|
| 1496 | (kind "auth-worker")
|
| 1497 | (client-limit 1)
|
| 1498 | (process-limit 0))
|
| 1499 | (service-configuration
|
| 1500 | (kind "dict")
|
| 1501 | (client-limit 1)
|
| 1502 | (process-limit 0)
|
| 1503 | (listeners (list (unix-listener-configuration (path "dict")))))))
|
| 1504 | "List of services to enable. Available services include @samp{imap},
|
| 1505 | @samp{imap-login}, @samp{pop3}, @samp{pop3-login}, @samp{auth}, and
|
| 1506 | @samp{lmtp}."))
|
| 1507 |
|
| 1508 | (define-configuration opaque-dovecot-configuration
|
| 1509 | (dovecot
|
| 1510 | (file-like dovecot)
|
| 1511 | "The dovecot package.")
|
| 1512 |
|
| 1513 | (extensions
|
| 1514 | (package-list '())
|
| 1515 | "Plugins and extensions to the Dovecot package. Specify a list of dovecot
|
| 1516 | plugins that needs to be available for dovecot and its modules.")
|
| 1517 |
|
| 1518 | (string
|
| 1519 | (string (configuration-missing-field 'opaque-dovecot-configuration
|
| 1520 | 'string))
|
| 1521 | "The contents of the @code{dovecot.conf} to use."))
|
| 1522 |
|
| 1523 | (define %dovecot-accounts
|
| 1524 | |
| 1525 | (list (user-group (name "dovecot") (system? #t))
|
| 1526 | (user-account
|
| 1527 | (name "dovecot")
|
| 1528 | (group "dovecot")
|
| 1529 | (system? #t)
|
| 1530 | (comment "Dovecot daemon user")
|
| 1531 | (home-directory "/var/empty")
|
| 1532 | (shell (file-append shadow "/sbin/nologin")))
|
| 1533 |
|
| 1534 | (user-group (name "dovenull") (system? #t))
|
| 1535 | (user-account
|
| 1536 | (name "dovenull")
|
| 1537 | (group "dovenull")
|
| 1538 | (system? #t)
|
| 1539 | (comment "Dovecot daemon login user")
|
| 1540 | (home-directory "/var/empty")
|
| 1541 | (shell (file-append shadow "/sbin/nologin")))))
|
| 1542 |
|
| 1543 | (define (make-dovecot-moduledir packages)
|
| 1544 | "Return a computed file containing a union of Dovecot module directories from PACKAGES.
|
| 1545 | Each package's '/lib/dovecot' directory is combined into a single location."
|
| 1546 | |
| 1547 | (with-imported-modules '((guix build union))
|
| 1548 | (computed-file
|
| 1549 | "dovecot-moduledir"
|
| 1550 | #~(begin
|
| 1551 | (use-modules (guix build union) (srfi srfi-26))
|
| 1552 |
|
| 1553 | (union-build #$output
|
| 1554 | (map (cut string-append <>
|
| 1555 | "/lib/dovecot")
|
| 1556 | (list #$@packages)))))))
|
| 1557 |
|
| 1558 | (define (%dovecot-activation config)
|
| 1559 | |
| 1560 | (let ((config-str
|
| 1561 | (cond
|
| 1562 | ((opaque-dovecot-configuration? config)
|
| 1563 | (opaque-dovecot-configuration-string config))
|
| 1564 | (else
|
| 1565 | (with-output-to-string
|
| 1566 | (lambda ()
|
| 1567 | (serialize-configuration config
|
| 1568 | dovecot-configuration-fields))))))
|
| 1569 | (moduledir-directory
|
| 1570 | (cond
|
| 1571 | ((opaque-dovecot-configuration? config)
|
| 1572 | (make-dovecot-moduledir (cons* (opaque-dovecot-configuration-dovecot config)
|
| 1573 | (opaque-dovecot-configuration-extensions config))))
|
| 1574 | (else
|
| 1575 | (make-dovecot-moduledir (cons* (dovecot-configuration-dovecot config)
|
| 1576 | (dovecot-configuration-extensions config)))))))
|
| 1577 | (with-imported-modules (source-module-closure '((gnu build activation)))
|
| 1578 | #~(begin
|
| 1579 | (use-modules (guix build utils) (gnu build activation))
|
| 1580 | (define (build-subject parameters)
|
| 1581 | (string-concatenate
|
| 1582 | (map (lambda (pair)
|
| 1583 | (let ((k (car pair)) (v (cdr pair)))
|
| 1584 | (define (escape-char str chr)
|
| 1585 | (string-join (string-split str chr) (string #\\ chr)))
|
| 1586 | (string-append "/" k "="
|
| 1587 | (escape-char (escape-char v #\=) #\/))))
|
| 1588 | (filter (lambda (pair) (cdr pair)) parameters))))
|
| 1589 | (define* (create-self-signed-certificate-if-absent
|
| 1590 | #:key private-key public-key (owner (getpwnam "root"))
|
| 1591 | (common-name (gethostname))
|
| 1592 | (organization-name "Guix")
|
| 1593 | (organization-unit-name "Default Self-Signed Certificate")
|
| 1594 | (subject-parameters `(("CN" . ,common-name)
|
| 1595 | ("O" . ,organization-name)
|
| 1596 | ("OU" . ,organization-unit-name)))
|
| 1597 | (subject (build-subject subject-parameters)))
|
| 1598 | |
| 1599 | |
| 1600 | (unless (file-exists? private-key)
|
| 1601 | (cond
|
| 1602 | ((zero? (system* (string-append #$openssl "/bin/openssl")
|
| 1603 | "genrsa" "-out" private-key "2048"))
|
| 1604 | (chown private-key (passwd:uid owner) (passwd:gid owner))
|
| 1605 | (chmod private-key #o400))
|
| 1606 | (else
|
| 1607 | (format (current-error-port)
|
| 1608 | "Failed to create private key at ~a.\n" private-key))))
|
| 1609 | (unless (file-exists? public-key)
|
| 1610 | (cond
|
| 1611 | ((zero? (system* (string-append #$openssl "/bin/openssl")
|
| 1612 | "req" "-new" "-x509" "-key" private-key
|
| 1613 | "-out" public-key "-days" "3650"
|
| 1614 | "-batch" "-subj" subject))
|
| 1615 | (chown public-key (passwd:uid owner) (passwd:gid owner))
|
| 1616 | (chmod public-key #o444))
|
| 1617 | (else
|
| 1618 | (format (current-error-port)
|
| 1619 | "Failed to create public key at ~a.\n" public-key)))))
|
| 1620 | (let ((user (getpwnam "dovecot")))
|
| 1621 | (mkdir-p/perms "/var/run/dovecot" user #o755)
|
| 1622 | (mkdir-p/perms "/var/lib/dovecot" user #o755)
|
| 1623 | (mkdir-p/perms "/etc/dovecot" user #o755)
|
| 1624 | (copy-file #$(plain-file "dovecot.conf" config-str)
|
| 1625 | "/etc/dovecot/dovecot.conf")
|
| 1626 | (mkdir-p/perms "/etc/dovecot/private" user #o700)
|
| 1627 | (mkdir-p "/usr/lib")
|
| 1628 | (switch-symlinks "/usr/lib/dovecot" #$moduledir-directory)
|
| 1629 | (create-self-signed-certificate-if-absent
|
| 1630 | #:private-key "/etc/dovecot/private/default.pem"
|
| 1631 | #:public-key "/etc/dovecot/default.pem"
|
| 1632 | #:owner (getpwnam "root")
|
| 1633 | #:common-name (format #f "Dovecot service on ~a" (gethostname))))))))
|
| 1634 |
|
| 1635 | (define (dovecot-shepherd-service config)
|
| 1636 | "Return a list of <shepherd-service> for CONFIG."
|
| 1637 | (let ((dovecot (if (opaque-dovecot-configuration? config)
|
| 1638 | (opaque-dovecot-configuration-dovecot config)
|
| 1639 | (dovecot-configuration-dovecot config))))
|
| 1640 | (list (shepherd-service
|
| 1641 | (documentation "Run the Dovecot POP3/IMAP mail server.")
|
| 1642 | (provision '(dovecot))
|
| 1643 | (requirement '(user-processes pam networking))
|
| 1644 | (start #~(make-forkexec-constructor
|
| 1645 | (list (string-append #$dovecot "/sbin/dovecot")
|
| 1646 | "-F")))
|
| 1647 | (stop #~(lambda _
|
| 1648 | (invoke #$(file-append dovecot "/sbin/dovecot")
|
| 1649 | "stop")
|
| 1650 | #f))))))
|
| 1651 |
|
| 1652 | (define %dovecot-pam-services
|
| 1653 | (list (unix-pam-service "dovecot")))
|
| 1654 |
|
| 1655 | (define dovecot-service-type
|
| 1656 | (service-type (name 'dovecot)
|
| 1657 | (extensions
|
| 1658 | (list (service-extension shepherd-root-service-type
|
| 1659 | dovecot-shepherd-service)
|
| 1660 | (service-extension account-service-type
|
| 1661 | (const %dovecot-accounts))
|
| 1662 | (service-extension pam-root-service-type
|
| 1663 | (const %dovecot-pam-services))
|
| 1664 | (service-extension activation-service-type
|
| 1665 | %dovecot-activation)))
|
| 1666 | (description "Run Dovecot, a mail server that can run POP3,
|
| 1667 | IMAP, and LMTP.")
|
| 1668 | (default-value (dovecot-configuration))))
|
| 1669 |
|
| 1670 | (define-deprecated (dovecot-service #:key (config (dovecot-configuration)))
|
| 1671 | dovecot-service-type
|
| 1672 | "Return a service that runs @command{dovecot}, a mail server that can run
|
| 1673 | POP3, IMAP, and LMTP. @var{config} should be a configuration object created
|
| 1674 | by @code{dovecot-configuration}. @var{config} may also be created by
|
| 1675 | @code{opaque-dovecot-configuration}, which allows specification of the
|
| 1676 | @code{dovecot.conf} as a string."
|
| 1677 | (service dovecot-service-type config))
|
| 1678 |
|
| 1679 | |
| 1680 | (define (generate-dovecot-documentation)
|
| 1681 | (generate-documentation
|
| 1682 | `((dovecot-configuration
|
| 1683 | ,dovecot-configuration-fields
|
| 1684 | (dict dict-configuration)
|
| 1685 | (namespaces namespace-configuration)
|
| 1686 | (plugin plugin-configuration)
|
| 1687 | (passdbs passdb-configuration)
|
| 1688 | (userdbs userdb-configuration)
|
| 1689 | (services service-configuration)
|
| 1690 | (protocols protocol-configuration))
|
| 1691 | (dict-configuration ,dict-configuration-fields)
|
| 1692 | (plugin-configuration ,plugin-configuration-fields)
|
| 1693 | (passdb-configuration ,passdb-configuration-fields)
|
| 1694 | (userdb-configuration ,userdb-configuration-fields)
|
| 1695 | (unix-listener-configuration ,unix-listener-configuration-fields)
|
| 1696 | (fifo-listener-configuration ,fifo-listener-configuration-fields)
|
| 1697 | (inet-listener-configuration ,inet-listener-configuration-fields)
|
| 1698 | (namespace-configuration
|
| 1699 | ,namespace-configuration-fields
|
| 1700 | (mailboxes mailbox-configuration))
|
| 1701 | (mailbox-configuration ,mailbox-configuration-fields)
|
| 1702 | (service-configuration
|
| 1703 | ,service-configuration-fields
|
| 1704 | (listeners unix-listener-configuration fifo-listener-configuration
|
| 1705 | inet-listener-configuration))
|
| 1706 | (protocol-configuration ,protocol-configuration-fields))
|
| 1707 | 'dovecot-configuration))
|
| 1708 |
|
| 1709 |
|
| 1710 | |
| 1711 | |
| 1712 | |
| 1713 |
|
| 1714 | (define-record-type* <opensmtpd-configuration>
|
| 1715 | opensmtpd-configuration make-opensmtpd-configuration
|
| 1716 | opensmtpd-configuration?
|
| 1717 | (package opensmtpd-configuration-package
|
| 1718 | (default opensmtpd))
|
| 1719 | (shepherd-requirement opensmtpd-configuration-shepherd-requirement
|
| 1720 | (default '())) |
| 1721 | (config-file opensmtpd-configuration-config-file
|
| 1722 | (default %default-opensmtpd-config-file))
|
| 1723 | (log-file opensmtpd-configuration-log-file
|
| 1724 | (default "/var/log/mail.log"))
|
| 1725 | (setgid-commands? opensmtpd-setgid-commands? (default #t)))
|
| 1726 |
|
| 1727 | (define %default-opensmtpd-config-file
|
| 1728 | (plain-file "smtpd.conf" "
|
| 1729 | listen on lo
|
| 1730 |
|
| 1731 | action inbound mbox
|
| 1732 | match for local action inbound
|
| 1733 |
|
| 1734 | action outbound relay
|
| 1735 | match from local for any action outbound
|
| 1736 | "))
|
| 1737 |
|
| 1738 | (define (opensmtpd-shepherd-service config)
|
| 1739 | (match-record config <opensmtpd-configuration>
|
| 1740 | (package config-file log-file shepherd-requirement)
|
| 1741 | (list (shepherd-service
|
| 1742 | (provision '(smtpd))
|
| 1743 | (requirement `(pam loopback ,@shepherd-requirement))
|
| 1744 | (documentation "Run the OpenSMTPD daemon.")
|
| 1745 | (start (let ((smtpd (file-append package "/sbin/smtpd")))
|
| 1746 | #~(make-forkexec-constructor
|
| 1747 | (list #$smtpd "-f" #$config-file
|
| 1748 | #$@(if log-file '("-d") '()))
|
| 1749 | #$@(if log-file
|
| 1750 | (list #:log-file log-file)
|
| 1751 | (list #:pid-file "/var/run/smtpd.pid")))))
|
| 1752 | (stop #~(make-kill-destructor))))))
|
| 1753 |
|
| 1754 | (define %opensmtpd-accounts
|
| 1755 | (list (user-group
|
| 1756 | (name "smtpq")
|
| 1757 | (system? #t))
|
| 1758 | (user-account
|
| 1759 | (name "smtpd")
|
| 1760 | (group "nogroup")
|
| 1761 | (system? #t)
|
| 1762 | (comment "SMTP Daemon")
|
| 1763 | (home-directory "/var/empty")
|
| 1764 | (shell (file-append shadow "/sbin/nologin")))
|
| 1765 | (user-account
|
| 1766 | (name "smtpq")
|
| 1767 | (group "smtpq")
|
| 1768 | (system? #t)
|
| 1769 | (comment "SMTPD Queue")
|
| 1770 | (home-directory "/var/empty")
|
| 1771 | (shell (file-append shadow "/sbin/nologin")))))
|
| 1772 |
|
| 1773 | (define (opensmtpd-activation config)
|
| 1774 | (match-record config <opensmtpd-configuration> (package config-file)
|
| 1775 | (let ((smtpd (file-append package "/sbin/smtpd")))
|
| 1776 | #~(begin
|
| 1777 | (use-modules (guix build utils))
|
| 1778 | |
| 1779 | (mkdir-p "/var/mail")
|
| 1780 | (mkdir-p "/var/spool/smtpd")
|
| 1781 | (chmod "/var/spool/smtpd" #o711)
|
| 1782 | (mkdir-p "/var/spool/mail")
|
| 1783 | (chmod "/var/spool/mail" #o711)))))
|
| 1784 |
|
| 1785 | (define %opensmtpd-pam-services
|
| 1786 | (list (unix-pam-service "smtpd")))
|
| 1787 |
|
| 1788 | (define (opensmtpd-privileged-programs config)
|
| 1789 | (match-record config <opensmtpd-configuration> (package config-file setgid-commands?)
|
| 1790 | (append
|
| 1791 | (list
|
| 1792 | (privileged-program
|
| 1793 | (program (file-append package "/libexec/opensmtpd/lockspool"))
|
| 1794 | (setuid? #t)))
|
| 1795 | (if setgid-commands?
|
| 1796 | (map (lambda (command)
|
| 1797 | (privileged-program
|
| 1798 | (program (file-append package "/" command))
|
| 1799 | (setgid? #t)
|
| 1800 | (group "smtpq")))
|
| 1801 | (list "sbin/smtpctl"
|
| 1802 |
|
| 1803 | |
| 1804 | |
| 1805 | "sbin/mailq"
|
| 1806 | "sbin/makemap"
|
| 1807 | "sbin/newaliases"
|
| 1808 | "sbin/sendmail"
|
| 1809 | "sbin/send-mail"))
|
| 1810 | '()))))
|
| 1811 |
|
| 1812 | (define opensmtpd-service-type
|
| 1813 | (service-type
|
| 1814 | (name 'opensmtpd)
|
| 1815 | (extensions
|
| 1816 | (list (service-extension account-service-type
|
| 1817 | (const %opensmtpd-accounts))
|
| 1818 | (service-extension activation-service-type
|
| 1819 | opensmtpd-activation)
|
| 1820 | (service-extension pam-root-service-type
|
| 1821 | (const %opensmtpd-pam-services))
|
| 1822 | (service-extension profile-service-type
|
| 1823 | (compose list opensmtpd-configuration-package))
|
| 1824 | (service-extension shepherd-root-service-type
|
| 1825 | opensmtpd-shepherd-service)
|
| 1826 | (service-extension privileged-program-service-type
|
| 1827 | opensmtpd-privileged-programs)))
|
| 1828 | (description "Run the OpenSMTPD, a lightweight @acronym{SMTP, Simple Mail
|
| 1829 | Transfer Protocol} server.")))
|
| 1830 |
|
| 1831 |
|
| 1832 | |
| 1833 | |
| 1834 | |
| 1835 |
|
| 1836 | (define (mail-aliases-etc aliases)
|
| 1837 | `(("aliases" ,(plain-file "aliases"
|
| 1838 | |
| 1839 | |
| 1840 | |
| 1841 | |
| 1842 | (format #f "~:{~a: ~a\n~}"
|
| 1843 | (map (match-lambda
|
| 1844 | ((alias addresses ...)
|
| 1845 | (list alias (string-join addresses ","))))
|
| 1846 | aliases))))))
|
| 1847 |
|
| 1848 | (define mail-aliases-service-type
|
| 1849 | (service-type
|
| 1850 | (name 'mail-aliases)
|
| 1851 | (extensions
|
| 1852 | (list (service-extension etc-service-type mail-aliases-etc)))
|
| 1853 | (compose concatenate)
|
| 1854 | (extend append)
|
| 1855 | (description "Provide a @file{/etc/aliases} file---an email alias
|
| 1856 | database---computed from the given alias list.")))
|
| 1857 |
|
| 1858 |
|
| 1859 | |
| 1860 | |
| 1861 | |
| 1862 |
|
| 1863 | (define-record-type* <exim-configuration> exim-configuration
|
| 1864 | make-exim-configuration
|
| 1865 | exim-configuration?
|
| 1866 | (package exim-configuration-package |
| 1867 | (default exim))
|
| 1868 | (config-file exim-configuration-config-file |
| 1869 | (default #f)))
|
| 1870 |
|
| 1871 | (define %exim-accounts
|
| 1872 | (list (user-group
|
| 1873 | (name "exim")
|
| 1874 | (system? #t))
|
| 1875 | (user-account
|
| 1876 | (name "exim")
|
| 1877 | (group "exim")
|
| 1878 | (system? #t)
|
| 1879 | (comment "Exim Daemon")
|
| 1880 | (home-directory "/var/empty")
|
| 1881 | (shell (file-append shadow "/sbin/nologin")))))
|
| 1882 |
|
| 1883 | (define (exim-computed-config-file package config-file)
|
| 1884 | (computed-file "exim.conf"
|
| 1885 | #~(call-with-output-file #$output
|
| 1886 | (lambda (port)
|
| 1887 | (format port "
|
| 1888 | exim_user = exim
|
| 1889 | exim_group = exim
|
| 1890 | .include ~a"
|
| 1891 | #$(or config-file
|
| 1892 | (file-append package "/etc/exim.conf")))))))
|
| 1893 |
|
| 1894 | (define exim-shepherd-service
|
| 1895 | (match-lambda
|
| 1896 | (($ <exim-configuration> package config-file)
|
| 1897 | (list (shepherd-service
|
| 1898 | (provision '(exim mta))
|
| 1899 | (documentation "Run the exim daemon.")
|
| 1900 | (requirement '(networking))
|
| 1901 | (start #~(make-forkexec-constructor
|
| 1902 | '(#$(file-append package "/bin/exim")
|
| 1903 | "-bd" "-v" "-C"
|
| 1904 | #$(exim-computed-config-file package config-file))))
|
| 1905 | (stop #~(make-kill-destructor)))))))
|
| 1906 |
|
| 1907 | (define exim-activation
|
| 1908 | (match-lambda
|
| 1909 | (($ <exim-configuration> package config-file)
|
| 1910 | (with-imported-modules '((guix build utils))
|
| 1911 | #~(begin
|
| 1912 | (use-modules (guix build utils))
|
| 1913 |
|
| 1914 | (let ((uid (passwd:uid (getpw "exim")))
|
| 1915 | (gid (group:gid (getgr "exim"))))
|
| 1916 | (mkdir-p "/var/spool/exim")
|
| 1917 | (chown "/var/spool/exim" uid gid))
|
| 1918 |
|
| 1919 | (zero? (system* #$(file-append package "/bin/exim")
|
| 1920 | "-bV" "-C" #$(exim-computed-config-file package config-file))))))))
|
| 1921 |
|
| 1922 | (define exim-profile
|
| 1923 | (compose list exim-configuration-package))
|
| 1924 |
|
| 1925 | (define exim-service-type
|
| 1926 | (service-type
|
| 1927 | (name 'exim)
|
| 1928 | (extensions
|
| 1929 | (list (service-extension shepherd-root-service-type exim-shepherd-service)
|
| 1930 | (service-extension account-service-type (const %exim-accounts))
|
| 1931 | (service-extension activation-service-type exim-activation)
|
| 1932 | (service-extension profile-service-type exim-profile)
|
| 1933 | (service-extension mail-aliases-service-type (const '()))))
|
| 1934 | (description "Run the Exim mail transfer agent (MTA).")))
|
| 1935 |
|
| 1936 |
|
| 1937 | |
| 1938 | |
| 1939 | |
| 1940 |
|
| 1941 | (define %default-imap4d-config-file
|
| 1942 | (plain-file "imap4d.conf" "server localhost {};\n"))
|
| 1943 |
|
| 1944 | (define-record-type* <imap4d-configuration>
|
| 1945 | imap4d-configuration make-imap4d-configuration imap4d-configuration?
|
| 1946 | (package imap4d-configuration-package
|
| 1947 | (default mailutils))
|
| 1948 | (config-file imap4d-configuration-config-file
|
| 1949 | (default %default-imap4d-config-file)))
|
| 1950 |
|
| 1951 | (define imap4d-shepherd-service
|
| 1952 | (match-lambda
|
| 1953 | (($ <imap4d-configuration> package config-file)
|
| 1954 | (list (shepherd-service
|
| 1955 | (provision '(imap4d))
|
| 1956 | (requirement '(user-processes networking syslogd))
|
| 1957 | (documentation "Run the imap4d daemon.")
|
| 1958 | (start (let ((imap4d (file-append package "/sbin/imap4d")))
|
| 1959 | #~(make-forkexec-constructor
|
| 1960 | (list #$imap4d "--daemon" "--foreground"
|
| 1961 | "--config-file" #$config-file))))
|
| 1962 | (stop #~(make-kill-destructor)))))))
|
| 1963 |
|
| 1964 | (define imap4d-service-type
|
| 1965 | (service-type
|
| 1966 | (name 'imap4d)
|
| 1967 | (description
|
| 1968 | "Run the GNU @command{imap4d} to serve e-mail messages through IMAP.")
|
| 1969 | (extensions
|
| 1970 | (list (service-extension
|
| 1971 | shepherd-root-service-type imap4d-shepherd-service)))
|
| 1972 | (default-value (imap4d-configuration))))
|
| 1973 |
|
| 1974 |
|
| 1975 | |
| 1976 | |
| 1977 | |
| 1978 |
|
| 1979 | |
| 1980 |
|
| 1981 | (define (comma-separated-ip-list? lst)
|
| 1982 | (every (lambda (s)
|
| 1983 | (or (string-prefix? "localhost" s)
|
| 1984 | ((@@ (gnu services vpn) ipv4-address?) s)
|
| 1985 | ((@@ (gnu services vpn) ipv6-address?) s)))
|
| 1986 | lst))
|
| 1987 |
|
| 1988 | (define-maybe boolean (prefix radicale-))
|
| 1989 | (define-maybe comma-separated-ip-list (prefix radicale-))
|
| 1990 | (define-maybe file-name (prefix radicale-))
|
| 1991 | (define-maybe non-negative-integer (prefix radicale-))
|
| 1992 | (define-maybe string (prefix radicale-))
|
| 1993 | (define-maybe symbol (prefix radicale-))
|
| 1994 |
|
| 1995 | |
| 1996 |
|
| 1997 | (define (radicale-serialize-field field-name value)
|
| 1998 | |
| 1999 | |
| 2000 | |
| 2001 | |
| 2002 | #~(format #f "~a = ~a\n" #$(uglify-field-name field-name) '#$value))
|
| 2003 |
|
| 2004 | (define (radicale-serialize-boolean field-name value?)
|
| 2005 | (radicale-serialize-field field-name (if value? "True" "False")))
|
| 2006 |
|
| 2007 | (define (radicale-serialize-comma-separated-ip-list field-name value)
|
| 2008 | (radicale-serialize-field field-name (string-join value ", ")))
|
| 2009 |
|
| 2010 | (define radicale-serialize-file-name radicale-serialize-field)
|
| 2011 |
|
| 2012 | (define radicale-serialize-non-negative-integer radicale-serialize-field)
|
| 2013 |
|
| 2014 | (define radicale-serialize-string radicale-serialize-field)
|
| 2015 |
|
| 2016 | (define radicale-serialize-symbol radicale-serialize-field)
|
| 2017 |
|
| 2018 | (define ((sanitize-delimited-symbols syms location field) value)
|
| 2019 | (cond
|
| 2020 | ((not (maybe-value-set? value))
|
| 2021 | value)
|
| 2022 | ((member value syms)
|
| 2023 | (string->symbol (uglify-field-name value)))
|
| 2024 | (else
|
| 2025 | (configuration-field-error (source-properties->location location)
|
| 2026 | field
|
| 2027 | value))))
|
| 2028 |
|
| 2029 | |
| 2030 |
|
| 2031 | (define-configuration radicale-auth-configuration
|
| 2032 | (type
|
| 2033 | maybe-symbol
|
| 2034 | "The method to verify usernames and passwords. Options are @code{none},
|
| 2035 | @code{htpasswd}, @code{remote-user}, and @code{http-x-remote-user}.
|
| 2036 |
|
| 2037 | This value is tied to @code{htpasswd-filename} and @code{htpasswd-encryption}."
|
| 2038 | (sanitizer
|
| 2039 | (sanitize-delimited-symbols '(none htpasswd remote-user http-x-remote-user)
|
| 2040 | (current-source-location)
|
| 2041 | 'type)))
|
| 2042 | (htpasswd-filename
|
| 2043 | maybe-file-name
|
| 2044 | "Path to the htpasswd file. Use htpasswd or similar to generate this file.")
|
| 2045 | (htpasswd-encryption
|
| 2046 | maybe-symbol
|
| 2047 | "Encryption method used in the htpasswd file. Options are @code{plain},
|
| 2048 | @code{bcrypt}, and @code{md5}."
|
| 2049 | (sanitizer
|
| 2050 | (sanitize-delimited-symbols '(plain bcrypt md5)
|
| 2051 | (current-source-location)
|
| 2052 | 'htpasswd-encryption)))
|
| 2053 | (delay
|
| 2054 | maybe-non-negative-integer
|
| 2055 | "Average delay after failed login attempts in seconds.")
|
| 2056 | (realm
|
| 2057 | maybe-string
|
| 2058 | "Message displayed in the client when a password is needed.")
|
| 2059 | (prefix radicale-))
|
| 2060 |
|
| 2061 | (define-configuration radicale-encoding-configuration
|
| 2062 | (request
|
| 2063 | maybe-symbol
|
| 2064 | "Encoding for responding requests.")
|
| 2065 | (stock
|
| 2066 | maybe-symbol
|
| 2067 | "Encoding for storing local collections.")
|
| 2068 | (prefix radicale-))
|
| 2069 |
|
| 2070 | (define-configuration radicale-logging-configuration
|
| 2071 | (level
|
| 2072 | maybe-symbol
|
| 2073 | "Set the logging level. One of @code{debug}, @code{info}, @code{warning},
|
| 2074 | @code{error}, or @code{critical}."
|
| 2075 | (sanitizer (sanitize-delimited-symbols '(debug info warning error critical)
|
| 2076 | (current-source-location)
|
| 2077 | 'level)))
|
| 2078 | (mask-passwords?
|
| 2079 | maybe-boolean
|
| 2080 | "Whether to include passwords in logs.")
|
| 2081 | (prefix radicale-))
|
| 2082 |
|
| 2083 | (define-configuration radicale-rights-configuration
|
| 2084 | (type
|
| 2085 | maybe-symbol
|
| 2086 | "Backend used to check collection access rights. The recommended backend is
|
| 2087 | @code{owner-only}. If access to calendars and address books outside the home
|
| 2088 | directory of users is granted, clients won't detect these collections and will
|
| 2089 | not show them to the user. Choosing any other method is only useful if you
|
| 2090 | access calendars and address books directly via URL. Options are
|
| 2091 | @code{authenticate}, @code{owner-only}, @code{owner-write}, and
|
| 2092 | @code{from-file}."
|
| 2093 | (sanitizer
|
| 2094 | (sanitize-delimited-symbols '(authenticate owner-only owner-write from-file)
|
| 2095 | (current-source-location)
|
| 2096 | 'type)))
|
| 2097 | (file
|
| 2098 | maybe-file-name
|
| 2099 | "File for the rights backend @code{from-file}.")
|
| 2100 | (prefix radicale-))
|
| 2101 |
|
| 2102 | (define-configuration radicale-server-configuration
|
| 2103 | (hosts
|
| 2104 | maybe-comma-separated-ip-list
|
| 2105 | "List of IP addresses that the server will bind to.")
|
| 2106 | (max-connections
|
| 2107 | maybe-non-negative-integer
|
| 2108 | "Maximum number of parallel connections. Set to 0 to disable the limit.")
|
| 2109 | (max-content-length
|
| 2110 | maybe-non-negative-integer
|
| 2111 | "Maximum size of the request body in byetes.")
|
| 2112 | (timeout
|
| 2113 | maybe-non-negative-integer
|
| 2114 | "Socket timeout in seconds.")
|
| 2115 | (ssl?
|
| 2116 | maybe-boolean
|
| 2117 | "Whether to enable transport layer encryption.")
|
| 2118 | (certificate
|
| 2119 | maybe-file-name
|
| 2120 | "Path of the SSL certificate.")
|
| 2121 | (key
|
| 2122 | maybe-file-name
|
| 2123 | "Path to the private key for SSL. Only effective if @code{ssl?} is
|
| 2124 | @code{#t}.")
|
| 2125 | (certificate-authority
|
| 2126 | maybe-file-name
|
| 2127 | "Path to CA certificate for validating client certificates. This can be used
|
| 2128 | to secure TCP traffic between Radicale and a reverse proxy. If you want to
|
| 2129 | authenticate users with client-side certificates, you also have to write an
|
| 2130 | authentication plugin that extracts the username from the certificate.")
|
| 2131 | (prefix radicale-))
|
| 2132 |
|
| 2133 | (define-configuration radicale-storage-configuration
|
| 2134 | (type
|
| 2135 | maybe-symbol
|
| 2136 | "Backend used to store data. Options are @code{multifilesystem} and
|
| 2137 | @code{multifilesystem-nolock}."
|
| 2138 | (sanitizer
|
| 2139 | (sanitize-delimited-symbols '(multifilesystem multifilesystem-nolock)
|
| 2140 | (current-source-location)
|
| 2141 | 'type)))
|
| 2142 | (filesystem-folder
|
| 2143 | maybe-file-name
|
| 2144 | "Folder for storing local collections. Created if not present.")
|
| 2145 | (max-sync-token-age
|
| 2146 | maybe-non-negative-integer
|
| 2147 | "Delete sync-tokens that are older than the specified time in seconds.")
|
| 2148 | (hook
|
| 2149 | maybe-string
|
| 2150 | "Command run after changes to storage.")
|
| 2151 | (prefix radicale-))
|
| 2152 |
|
| 2153 | |
| 2154 |
|
| 2155 | |
| 2156 | (define auth-config? radicale-auth-configuration?)
|
| 2157 | (define encoding-config? radicale-encoding-configuration?)
|
| 2158 | (define headers-file? file-like?)
|
| 2159 | (define logging-config? radicale-logging-configuration?)
|
| 2160 | (define rights-config? radicale-rights-configuration?)
|
| 2161 | (define server-config? radicale-server-configuration?)
|
| 2162 | (define storage-config? radicale-storage-configuration?)
|
| 2163 |
|
| 2164 | (define-maybe auth-config)
|
| 2165 | (define-maybe encoding-config)
|
| 2166 | (define-maybe headers-file)
|
| 2167 | (define-maybe logging-config)
|
| 2168 | (define-maybe rights-config)
|
| 2169 | (define-maybe server-config)
|
| 2170 | (define-maybe storage-config)
|
| 2171 |
|
| 2172 | (define ((serialize-radicale-section fields) name cfg)
|
| 2173 | #~(format #f "[~a]\n~a\n" '#$name #$(serialize-configuration cfg fields)))
|
| 2174 |
|
| 2175 | (define serialize-auth-config
|
| 2176 | (serialize-radicale-section radicale-auth-configuration-fields))
|
| 2177 | (define serialize-encoding-config
|
| 2178 | (serialize-radicale-section radicale-encoding-configuration-fields))
|
| 2179 | (define serialize-logging-config
|
| 2180 | (serialize-radicale-section radicale-logging-configuration-fields))
|
| 2181 | (define serialize-rights-config
|
| 2182 | (serialize-radicale-section radicale-rights-configuration-fields))
|
| 2183 | (define serialize-server-config
|
| 2184 | (serialize-radicale-section radicale-server-configuration-fields))
|
| 2185 | (define serialize-storage-config
|
| 2186 | (serialize-radicale-section radicale-storage-configuration-fields))
|
| 2187 |
|
| 2188 | (define (serialize-radicale-configuration cfg)
|
| 2189 | (mixed-text-file
|
| 2190 | "radicale.conf"
|
| 2191 | (serialize-configuration cfg radicale-configuration-fields)))
|
| 2192 |
|
| 2193 | (define-configuration radicale-configuration
|
| 2194 | |
| 2195 | (package
|
| 2196 | (file-like radicale)
|
| 2197 | "Package that provides @command{radicale}.")
|
| 2198 | (auth
|
| 2199 | maybe-auth-config
|
| 2200 | "Configuration for auth-related variables.")
|
| 2201 | (encoding
|
| 2202 | maybe-encoding-config
|
| 2203 | "Configuration for encoding-related variables.")
|
| 2204 | (headers-file
|
| 2205 | maybe-headers-file
|
| 2206 | "Custom HTTP headers."
|
| 2207 | (serializer
|
| 2208 | (lambda (field-name value)
|
| 2209 | #~(begin
|
| 2210 | (use-modules (ice-9 rdelim))
|
| 2211 | (format #f "[headers]\n~a\n\n"
|
| 2212 | (with-input-from-file #$value read-string))))))
|
| 2213 | (logging
|
| 2214 | maybe-logging-config
|
| 2215 | "Configuration for logging-related variables.")
|
| 2216 | (rights
|
| 2217 | maybe-rights-config
|
| 2218 | "Configuration for rights-related variables.")
|
| 2219 | (server
|
| 2220 | maybe-server-config
|
| 2221 | "Configuration for server-related variables. Ignored if WSGI is used.")
|
| 2222 | (storage
|
| 2223 | maybe-storage-config
|
| 2224 | "Configuration for storage-related variables.")
|
| 2225 | (web-interface?
|
| 2226 | maybe-boolean
|
| 2227 | "Whether to use Radicale's built-in web interface."
|
| 2228 | (serializer
|
| 2229 | (lambda (_ use?)
|
| 2230 | #~(format #f "[web]\ntype = ~a\n\n" #$(if use? "internal" "none"))))))
|
| 2231 |
|
| 2232 | (define %radicale-accounts
|
| 2233 | (list (user-group
|
| 2234 | (name "radicale")
|
| 2235 | (system? #t))
|
| 2236 | (user-account
|
| 2237 | (name "radicale")
|
| 2238 | (group "radicale")
|
| 2239 | (system? #t)
|
| 2240 | (comment "Radicale Daemon")
|
| 2241 | (home-directory "/var/empty")
|
| 2242 | (shell (file-append shadow "/sbin/nologin")))))
|
| 2243 |
|
| 2244 | (define (radicale-shepherd-service cfg)
|
| 2245 | (define config-file
|
| 2246 | (serialize-radicale-configuration cfg))
|
| 2247 |
|
| 2248 | (list (shepherd-service
|
| 2249 | (provision '(radicale))
|
| 2250 | (documentation "Run the radicale daemon.")
|
| 2251 | (requirement '(user-processes networking))
|
| 2252 | (start #~(make-forkexec-constructor
|
| 2253 | (list #$(file-append (radicale-configuration-package cfg)
|
| 2254 | "/bin/radicale")
|
| 2255 | "-C" #$config-file)
|
| 2256 | #:user "radicale"
|
| 2257 | #:group "radicale"))
|
| 2258 | (stop #~(make-kill-destructor))
|
| 2259 | (actions
|
| 2260 | (list
|
| 2261 | (shepherd-configuration-action config-file))))))
|
| 2262 |
|
| 2263 | (define radicale-activation
|
| 2264 | (match-lambda
|
| 2265 | (($ <radicale-configuration> _ auth-config _ _ _ _ _ storage-config _)
|
| 2266 | |
| 2267 | |
| 2268 | (define filesystem-folder-val
|
| 2269 | (if (maybe-value-set? storage-config)
|
| 2270 | (radicale-storage-configuration-filesystem-folder storage-config)
|
| 2271 | storage-config))
|
| 2272 | (define collections-dir
|
| 2273 | (if (maybe-value-set? filesystem-folder-val)
|
| 2274 | filesystem-folder-val
|
| 2275 | "/var/lib/radicale/collections"))
|
| 2276 | (define collections-parent-dir (dirname collections-dir))
|
| 2277 | |
| 2278 | (define auth-value-set? (maybe-value-set? auth-config))
|
| 2279 | |
| 2280 | |
| 2281 | (define auth?
|
| 2282 | (and auth-value-set?
|
| 2283 | (not (eq? (radicale-auth-configuration-type auth-config) 'none))))
|
| 2284 | (define password-file-val
|
| 2285 | (if auth-value-set?
|
| 2286 | (radicale-auth-configuration-htpasswd-filename auth-config)
|
| 2287 | auth-config))
|
| 2288 | (define password-file-dir
|
| 2289 | (if (maybe-value-set? password-file-val)
|
| 2290 | (dirname password-file-val)
|
| 2291 | "/etc/radicale"))
|
| 2292 | (with-imported-modules '((guix build utils))
|
| 2293 | #~(begin
|
| 2294 | (use-modules (guix build utils))
|
| 2295 | (let ((user (getpwnam "radicale")))
|
| 2296 | |
| 2297 | (mkdir-p/perms #$collections-dir user #o700)
|
| 2298 | |
| 2299 | (when #$auth?
|
| 2300 | |
| 2301 | |
| 2302 | (mkdir-p/perms #$password-file-dir user #o700))))))))
|
| 2303 |
|
| 2304 | (define radicale-service-type
|
| 2305 | (service-type
|
| 2306 | (name 'radicale)
|
| 2307 | (description "Run Radicale, a small CalDAV and CardDAV server.")
|
| 2308 | (extensions
|
| 2309 | (list (service-extension shepherd-root-service-type radicale-shepherd-service)
|
| 2310 | (service-extension account-service-type (const %radicale-accounts))
|
| 2311 | (service-extension activation-service-type radicale-activation)))
|
| 2312 | (default-value (radicale-configuration))))
|
| 2313 |
|
| 2314 | (define (generate-radicale-documentation)
|
| 2315 | (generate-documentation
|
| 2316 | `((radicale-configuration
|
| 2317 | ,radicale-configuration-fields
|
| 2318 | (auth radicale-auth-configuration)
|
| 2319 | (encoding radicale-encoding-configuration)
|
| 2320 | (logging radicale-logging-configuration)
|
| 2321 | (rights radicale-rights-configuration)
|
| 2322 | (server radicale-server-configuration)
|
| 2323 | (storage radicale-storage-configuration))
|
| 2324 | (radicale-auth-configuration ,radicale-auth-configuration-fields)
|
| 2325 | (radicale-encoding-configuration ,radicale-encoding-configuration-fields)
|
| 2326 | (radicale-logging-configuration ,radicale-logging-configuration-fields)
|
| 2327 | (radicale-rights-configuration ,radicale-rights-configuration-fields)
|
| 2328 | (radicale-server-configuration ,radicale-server-configuration-fields)
|
| 2329 | (radicale-storage-configuration ,radicale-storage-configuration-fields))
|
| 2330 | 'radicale-configuration))
|
| 2331 |
|
| 2332 | |
| 2333 | |
| 2334 | |
| 2335 |
|
| 2336 | (define (directory-tree? xs)
|
| 2337 | (match xs
|
| 2338 | ((((? string?) (? file-like?)) ...) #t)
|
| 2339 | (_ #f)))
|
| 2340 |
|
| 2341 | (define-configuration/no-serialization rspamd-configuration
|
| 2342 | (package
|
| 2343 | (file-like rspamd)
|
| 2344 | "The package that provides rspamd.")
|
| 2345 | (config-file
|
| 2346 | (file-like %default-rspamd-config-file)
|
| 2347 | "File-like object of the configuration file to use. By default
|
| 2348 | all workers are enabled except fuzzy and they are binded
|
| 2349 | to their usual ports, e.g localhost:11334, localhost:11333 and so on")
|
| 2350 | (local.d-files
|
| 2351 | (directory-tree '())
|
| 2352 | "Configuration files in local.d, provided as a list of two element lists where
|
| 2353 | the first element is the filename and the second one is a file-like object. Settings
|
| 2354 | in these files will be merged with the defaults.")
|
| 2355 | (override.d-files
|
| 2356 | (directory-tree '())
|
| 2357 | "Configuration files in override.d, provided as a list of two element lists where
|
| 2358 | the first element is the filename and the second one is a file-like object. Settings
|
| 2359 | in these files will override the defaults.")
|
| 2360 | (user
|
| 2361 | (user-account %default-rspamd-account)
|
| 2362 | "The user to run rspamd as.")
|
| 2363 | (group
|
| 2364 | (user-group %default-rspamd-group)
|
| 2365 | "The group to run rspamd as.")
|
| 2366 | (debug?
|
| 2367 | (boolean #f)
|
| 2368 | "Force debug output.")
|
| 2369 | (insecure?
|
| 2370 | (boolean #f)
|
| 2371 | "Ignore running workers as privileged users.")
|
| 2372 | (skip-template?
|
| 2373 | (boolean #f)
|
| 2374 | "Do not apply Jinja templates.")
|
| 2375 | (shepherd-requirements
|
| 2376 | (list-of-symbols '(user-processes loopback))
|
| 2377 | "This is a list of symbols naming Shepherd services that this service
|
| 2378 | will depend on."))
|
| 2379 |
|
| 2380 | (define %default-rspamd-account
|
| 2381 | (user-account
|
| 2382 | (name "rspamd")
|
| 2383 | (group "rspamd")
|
| 2384 | (system? #t)
|
| 2385 | (comment "Rspamd daemon")
|
| 2386 | (home-directory "/var/empty")
|
| 2387 | (shell (file-append shadow "/sbin/nologin"))))
|
| 2388 |
|
| 2389 | (define %default-rspamd-group
|
| 2390 | (user-group
|
| 2391 | (name "rspamd")
|
| 2392 | (system? #t)))
|
| 2393 |
|
| 2394 | (define %default-rspamd-config-file
|
| 2395 | (plain-file "rspamd.conf" "
|
| 2396 | .include \"$CONFDIR/common.conf\"
|
| 2397 |
|
| 2398 | options {
|
| 2399 | pidfile = \"$RUNDIR/rspamd.pid\";
|
| 2400 | .include \"$CONFDIR/options.inc\"
|
| 2401 | .include(try=true; priority=1,duplicate=merge) \"$LOCAL_CONFDIR/local.d/options.inc\"
|
| 2402 | .include(try=true; priority=10) \"$LOCAL_CONFDIR/override.d/options.inc\"
|
| 2403 | }
|
| 2404 |
|
| 2405 | logging {
|
| 2406 | type = \"file\";
|
| 2407 | filename = \"$LOGDIR/rspamd.log\";
|
| 2408 | .include \"$CONFDIR/logging.inc\"
|
| 2409 | .include(try=true; priority=1,duplicate=merge) \"$LOCAL_CONFDIR/local.d/logging.inc\"
|
| 2410 | .include(try=true; priority=10) \"$LOCAL_CONFDIR/override.d/logging.inc\"
|
| 2411 | }
|
| 2412 |
|
| 2413 | worker \"normal\" {
|
| 2414 | bind_socket = \"localhost:11333\";
|
| 2415 | .include \"$CONFDIR/worker-normal.inc\"
|
| 2416 | .include(try=true; priority=1,duplicate=merge) \"$LOCAL_CONFDIR/local.d/worker-normal.inc\"
|
| 2417 | .include(try=true; priority=10) \"$LOCAL_CONFDIR/override.d/worker-normal.inc\"
|
| 2418 | }
|
| 2419 |
|
| 2420 | worker \"controller\" {
|
| 2421 | bind_socket = \"localhost:11334\";
|
| 2422 | .include \"$CONFDIR/worker-controller.inc\"
|
| 2423 | .include(try=true; priority=1,duplicate=merge) \"$LOCAL_CONFDIR/local.d/worker-controller.inc\"
|
| 2424 | .include(try=true; priority=10) \"$LOCAL_CONFDIR/override.d/worker-controller.inc\"
|
| 2425 | }
|
| 2426 |
|
| 2427 | worker \"rspamd_proxy\" {
|
| 2428 | bind_socket = \"localhost:11332\";
|
| 2429 | .include \"$CONFDIR/worker-proxy.inc\"
|
| 2430 | .include(try=true; priority=1,duplicate=merge) \"$LOCAL_CONFDIR/local.d/worker-proxy.inc\"
|
| 2431 | .include(try=true; priority=10) \"$LOCAL_CONFDIR/override.d/worker-proxy.inc\"
|
| 2432 | }
|
| 2433 |
|
| 2434 | # Local fuzzy storage is disabled by default
|
| 2435 |
|
| 2436 | worker \"fuzzy\" {
|
| 2437 | bind_socket = \"localhost:11335\";
|
| 2438 | count = -1; # Disable by default
|
| 2439 | .include \"$CONFDIR/worker-fuzzy.inc\"
|
| 2440 | .include(try=true; priority=1,duplicate=merge) \"$LOCAL_CONFDIR/local.d/worker-fuzzy.inc\"
|
| 2441 | .include(try=true; priority=10) \"$LOCAL_CONFDIR/override.d/worker-fuzzy.inc\"
|
| 2442 | }
|
| 2443 | "))
|
| 2444 |
|
| 2445 | (define (rspamd-accounts config)
|
| 2446 | (match-record config <rspamd-configuration>
|
| 2447 | (user group)
|
| 2448 | (list group user)))
|
| 2449 |
|
| 2450 | (define (rspamd-shepherd-service config)
|
| 2451 | (match-record config <rspamd-configuration>
|
| 2452 | (package config-file user group debug? insecure? skip-template?
|
| 2453 | local.d-files override.d-files shepherd-requirements)
|
| 2454 | (list
|
| 2455 | (shepherd-service
|
| 2456 | (provision '(rspamd))
|
| 2457 | (documentation "Run the rspamd daemon.")
|
| 2458 | (requirement shepherd-requirements)
|
| 2459 | (start (let ((rspamd (file-append package "/bin/rspamd"))
|
| 2460 | (local-confdir
|
| 2461 | (file-union
|
| 2462 | "rspamd-local-confdir"
|
| 2463 | `(("local.d" ,(file-union "local.d" local.d-files))
|
| 2464 | ("override.d" ,(file-union "override.d" override.d-files))))))
|
| 2465 | (with-imported-modules (source-module-closure '((gnu build activation)))
|
| 2466 | #~(begin
|
| 2467 | (use-modules (gnu build activation)) |
| 2468 | (let ((user (getpwnam #$(user-account-name user))))
|
| 2469 | (mkdir-p/perms "/var/run/rspamd" user #o755)
|
| 2470 | (mkdir-p/perms "/var/log/rspamd" user #o755)
|
| 2471 | (mkdir-p/perms "/var/lib/rspamd" user #o755))
|
| 2472 | (make-forkexec-constructor
|
| 2473 | (list #$rspamd "--config" #$config-file
|
| 2474 | "--var" (string-append "LOCAL_CONFDIR=" #$local-confdir)
|
| 2475 | "--no-fork"
|
| 2476 | #$@(if debug?
|
| 2477 | '("--debug")
|
| 2478 | '())
|
| 2479 | #$@(if insecure?
|
| 2480 | '("--insecure")
|
| 2481 | '())
|
| 2482 | #$@(if skip-template?
|
| 2483 | '("--skip-template")
|
| 2484 | '()))
|
| 2485 | #:user #$(user-account-name user)
|
| 2486 | #:group #$(user-group-name group))))))
|
| 2487 | (stop #~(make-kill-destructor))
|
| 2488 | (actions
|
| 2489 | (list
|
| 2490 | (shepherd-configuration-action config-file)
|
| 2491 | (shepherd-signal-action
|
| 2492 | 'reload SIGHUP
|
| 2493 | #:documentation "Reload rspamd."
|
| 2494 | #:message "Service rspamd has been reloaded")
|
| 2495 | (shepherd-signal-action
|
| 2496 | 'reopen SIGUSR1
|
| 2497 | #:documentation "Reopen log files."
|
| 2498 | #:message "Reopening the logs for rspamd.")))))))
|
| 2499 |
|
| 2500 | (define rspamd-service-type
|
| 2501 | (service-type
|
| 2502 | (name 'rspamd)
|
| 2503 | (description "Run the rapid spam filtering system.")
|
| 2504 | (extensions
|
| 2505 | (list
|
| 2506 | (service-extension shepherd-root-service-type rspamd-shepherd-service)
|
| 2507 | (service-extension account-service-type rspamd-accounts)))
|
| 2508 | (default-value (rspamd-configuration))))
|