Package: guix-patches;
Reported by: Joshua Branson <jbranso <at> dismail.de>
Date: Fri, 17 Jun 2022 21:47:01 UTC
Severity: normal
Tags: patch
View this message in rfc822 format
From: Liliana Marie Prikler <liliana.prikler <at> gmail.com> To: Joshua Branson <joshua <at> gnucode.me>, 56046 <at> debbugs.gnu.org Cc: Joshua Branson <jbranso <at> dismail.de> Subject: [bug#56046] [PATCH opensmtpd-records v3] services (opensmtpd): add opensmtpd records to enhance opensmtpd-configuration. Date: Mon, 26 Dec 2022 20:34:43 +0100
Am Freitag, dem 23.12.2022 um 08:52 -0500 schrieb Joshua Branson: > > * gnu/services/mail.scm: > (opensmtpd-table, > opensmtpd-ca, > opensmtpd-pki, > opensmtpd-action-local-delivery, > opensmtpd-maildir, > opensmtpd-mda, > opensmtpd-lmtp, > opensmtpd-relay, > opensmtpd-option, > opensmtpd-filter-phase, > opensmtpd-filter, > opensmtpd-interface, > opensmtpd-socket, > opensmtpd-match, > opensmtpd-smtp, > opensmtpd-srs, > opensmtpd-queue, and > opensmtpd-configuration): New records. Don't forget to put closing parentheses at the end of lines. Also, feel free to group them to save vertical space. > (false?, is-value-right-type, add-comma-or-string, > list-of-procedures->string, string-in-list?, my-sanitize, > opensmtpd-filter-chain?, throw-error-duplicate-option, > sanitize-list-of-options-for-match, sanitize-filters, > list-has-duplicates-or-non-filters?, > filter-phase-has-message-and-value?, > filter-phase-decision-lacks-proper-message?, > filter-phase-lacks-proper-value?, > filter-phase-has-incorrect-junk-or-bypass?, > filter-phase-junks-after-commit?, > list-of-unique-filter-or-filter-phase?, throw-error, > contains-duplicate?, list-of-type?, list-of-strings?, > list-of-unique-opensmtpd-option?, > list-of-opensmtpd-ca?, > list-of-opensmtpd-pki?, > list-of-opensmtpd-listen-on?, > list-of-unique-opensmtpd-match?, list-of-strings->string, > assoc-list? assoc-list, variable->string, > tables-data-are-assoc-list?, > tables-data-are-a-list-of-strings?, > table-data-are-a-nested-list-of-strings?, > assoc-list->string, > opensmtpd-table->string, > opensmtpd-listen-on->string, > opensmtpd-listen-on-socket->string, > opensmtpd-action-relay->string, > opensmtpd-lmtp->string, > opensmtpd-mda->string, > opensmtpd-maildir->string, > opensmtpd-action-local-delivery->string, > opensmtpd-action->string, opensmtpd-option->string, > opensmtpd-match->string, > opensmtpd-ca->string, opensmtpd-pki->string, > generate-filter-chain-name, opensmtpd-filter-chain->string, > opensmtpd-filter-phase->string, opensmtpd-filters->string, > opensmtpd-listen->string, > opensmtpd-srs->string, > opensmtpd-smtp->string, > opensmtpd-queue->string, get-opensmtpd-actions, > get-opensmtpd-pkis, get-opensmtpd-filters, flatten, > get-opensmtpd-tables, opensmtpd-fieldname->string, > list-of-records->string, opensmtpd->mixed-text-file): New > procedures. > > * gnu/tests/mail.scm : new tests for various opensmtpd records. > > * doc/guix.texi (OpenSMTPD Service): Added documentation for the > new records for opensmtpd. > --- > doc/guix.texi | 1065 ++++++++++++++++- > gnu/services/mail.scm | 2560 > ++++++++++++++++++++++++++++++++++++++++- > gnu/tests/mail.scm | 713 ++++++++++++ > 3 files changed, 4310 insertions(+), 28 deletions(-) > > diff --git a/doc/guix.texi b/doc/guix.texi > index 535c8cdfc3..879a2ad233 100644 > --- a/doc/guix.texi > +++ b/doc/guix.texi > @@ -25407,16 +25407,66 @@ could instantiate a dovecot service like > this: > @end lisp > > @subsubheading OpenSMTPD Service > +@cindex opensmtpd > > @deffn {Scheme Variable} opensmtpd-service-type > -This is the type of the @uref{https://www.opensmtpd.org, OpenSMTPD} > -service, whose value should be an @code{opensmtpd-configuration} > object > -as in this example: > +OpenSMTPD is an easy-to-use mail transfer agent (MTA). OpenSMTPD > +@strong{listens} for incoming mail and @strong{matches} the mail to > +@strong{actions}. The following records represent those stages: > > -@lisp > -(service opensmtpd-service-type > - (opensmtpd-configuration > - (config-file (local-file "./my-smtpd.conf")))) > +@multitable {aaaaaaaaa} > {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} I hope this will receive proper documentation. > +@item @strong{listens} > +@tab @code{<opensmtpd-interface>} > +@item > +@tab @code{<opensmtpd-socket>} > +@item > +@tab > +@item @strong{matches} > +@tab @code{<opensmtpd-match>} > +@item > +@tab > +@item @strong{actions} > +@tab @code{<opensmtpd-local-delivery>} > +@item > +@tab @code{<opensmtpd-relay>} > +@end multitable > + > +Additionally, each @code{<opensmtpd-interface>} and > +@code{<opensmtpd-socket>} may use a list of @code{<opensmtpd- > filter>}, > +and/or @code{<opensmtpd-filter-phase>} records to filter > +email/spam. Also numerous records' fieldnames use > +@code{<opensmtpd-table>} records to hold lists or key value pairs of > +data. Be sure to read the @code{<opensmtpd-table>} section to learn > the > +differance between a @code{mapping table} and a @code{list table}. > + > +Finally, both @code{<opensmtpd-match>} and > +@code{<opensmtpd-filter-phase>} use @code{<opensmtpd-option>} to > +configure various options. > + > +A simple example opensmtpd configuration is below: > + > +@lisp > +(let ((smtp.gnu.org (opensmtpd-pki > + (domain "smtp.gnu.org") > + (cert "file.cert") > + (key "file.key")))) > + (service opensmtpd-service-type > + (opensmtpd-configuration > + (interfaces (list > + (opensmtpd-interface > + (pki smtp.gnu.org)) > + (opensmtpd-interface > + (pki smtp.gnu.org) > + (secure-connection "smtps")))) > + (matches (list > + (opensmtpd-match > + (action > + (opensmtpd-local-delivery > + (name "local-delivery")))) > + (opensmtpd-match > + (action > + (opensmtpd-relay > + (name "relay"))))))))) > @end lisp > @end deffn > > @@ -25425,7 +25475,7 @@ Data type representing the configuration of > opensmtpd. > > @table @asis > @item @code{package} (default: @var{opensmtpd}) > -Package object of the OpenSMTPD SMTP server. > +Package object of the OpenSMTPD server. > > @item @code{config-file} (default: @code{%default-opensmtpd-config- > file}) > File-like object of the OpenSMTPD configuration file to use. By > default > @@ -25433,14 +25483,1013 @@ it listens on the loopback network > interface, and allows for mail from > users and daemons on the local machine, as well as permitting email > to > remote servers. Run @command{man smtpd.conf} for more information. > > +@item @code{bounce} (default: @code{(list "4h")}) > +@code{bounce} is a list of strings, which send warning messages to > the > +envelope sender when temporary delivery failures cause a message to > +remain in the queue for longer than a specified delay. Each delay > option > +is a string parameter beginning with a positive decimal integer and > a > +unit, which can be 's', 'm', 'h', or 'd'. At most four delay > parameters > +can be specified. > + > +@item @code{interfaces} default: > +@lisp > +(list > + (opensmtpd-interface > + (interface "lo") > + (port 25))) > +@end lisp > +@code{interfaces} is a list of @code{<opensmtpd-interface>} records. > +This list details what interfaces and ports OpenSMTPD listens on as > well as > +other options. > + > +@item @code{socket} (default: @code{(opensmtpd-socket)}) > +Listens for incoming connections on the Unix domain socket. > + > +@item @code{includes} (default: @code{#f}) > +@code{includes} is a list of string filenames. Each filename's > contents is > +additional configuration that is inserted into the top of the > configuration > +file. Run @code{man smtpd.conf} for more information. > + > +@item @code{matches} default: > +@lisp > +(list (opensmtpd-match > + (action (opensmtpd-local-delivery > + (name "local") > + (method "mbox") > + (options > + (list > + (opensmtpd-option > + (option "for local"))))))) > + (opensmtpd-match > + (action (opensmtpd-relay > + (name "outbound"))) > + (options > + (list > + (opensmtpd-option > + (option "from local")) > + (opensmtpd-option > + (option "for any")))))) > +@end lisp > +@code{matches} is a list of @code{<opensmtpd-match>} records, which > +matches incoming mail and sends it to a correspending action. The > match > +records are evaluated sequentially, with the first match winning. > +Therefore @emph{the order that you arrange your matches is > important}. > +It's a good idea to put specific matches first and an all > emcompassing > +match (like @code{(option "for any")}) @strong{last}. If an incoming > +mail does not match any match records, then it is rejected. > + > +@item @code{mta-max-deferred} (default: @code{100}) > +When delivery to a given host is suspended due to temporary > failures, cache > +at most number envelopes for that host such that they can be > delivered as > +soon as another delivery succeeds to that host. The default is 100. > + > +@item @code{queue} (default: @code{#f}) > +@code{queue} expects an @code{<opensmtpd-queue>} record. With it, > one may > +compress and encrypt queue-ed emails as well as set the default > expiration > +time for temporarily undeliverable messages. > + > +@item @code{smtp} (default: @code{#f}) > +@code{smtp} expects an @code{<opensmtpd-smtp>} record, which lets > one > +specifiy how large email may be along with other settings. > + > +@item @code{srs} (default: @code{#f}) > +@code{srs} expects an @code{<opensmtpd-srs>} record, which lets one > set > +up SRS, the Sender Rewritting Scheme. > + > @item @code{setgid-commands?} (default: @code{#t}) > Make the following commands setgid to @code{smtpq} so they can be > executed: @command{smtpctl}, @command{sendmail}, @command{send- > mail}, > @command{makemap}, @command{mailq}, and @command{newaliases}. > @xref{Setuid Programs}, for more information on setgid programs. > + > @end table > @end deftp > > +@itemize > +@item Data Type: opensmtpd-interface > +Data type representing the configuration of an > +@code{<opensmtpd-interface>}. It listens on the fieldname > +@code{interface} for incoming connections, using the same syntax as > +@code{ifconfig}. The interface parameter may also be an string > interface > +group, an string IP address, or a string domain name. Listening can > +optionally be restricted to a specific address via the fieldname > +@code{family}, which can be either @code{"inet4"} or @code{"inet6"}. > + > +@itemize > +@item @code{interface} (default: @code{"lo"}) > + > +The string interface to listen for incoming connections. This > string > +may be an interface group, an IP address, or a domain name. These > +interfaces can usually be found by the command @code{ip link}. > + > +@item @code{family} (default: @code{#f}) > + > +Only listen on a specific address family. Valid strings are > +@code{"inet4"} or @code{"inet6"}, which will only listen on IPv4 or > IPv6 > +respectfully. If @code{(family #f)}, then opensmtpd will listen on > both > +IPv4 and IPv6. > + > +@item @code{auth} (default: @code{#f}) > +Support SMTPAUTH: clients may only start SMTP transactions after > +successful authentication. If @code{auth} is @code{#t}, then users > are > +authenticated against their own normal login credentials. > Alternatively > +@code{auth} may be a @code{mapping table} that maps usernames to > +encrypted passwords. The password can be encrypted via the > +@code{smtpctl} @code{encrypt} subcommand. > + > +@item @code{auth-optional} (default: @code{#f}) > +Support SMTPAUTH optionally: clients need not authenticate, but may > do > +so. This allows the @code{<opensmtpd-interface>} to both accept > +incoming mail from untrusted senders and permit outgoing mail from > +authenticated users. It can be used in situations where it is not > +possible to listen on a separate port (usually the submission port, > 587) > +for users to authenticate. This option also accepts a @code{mapping > +table} that maps usernames to encrypted passwords. > + > +@item @code{filters} (default: @code{#f}) > +A list of one or many @code{<opensmtpd-filter>} or > +@code{<opensmtpd-filter-phase>} records. The filters are applied > +sequentially. These records listen and filter on connections handled > by this > +listener. > + > +@item @code{hostname} (default: @code{#f}) > +Change the default server name in the greeting banner instead of the > +default one. > + > +@item @code{hostnames} (default: @code{#f}) > +Override the server name for specific addresses. Use a @code{mapping > +table} that maps string IP addresses to string hostnames. If the > address > +on which the connection arrives appears in the mapping, the > associated > +hostname is used. > + > +@item @code{mask-src} (default: @code{#f}) > +If @code{#t}, then omit the from part when prepending “Received” > headers. > + > +@item @code{disable-dsn} (default: @code{#f}) > +When @code{#t}, then disable the DSN (Delivery Status Notification) > extension. > + > +@item @code{pki} (default: @code{#f}) > +For secure connections, use an @code{<opensmtpd-pki>} record to > prove a > +mail server's identity. > + > +@item @code{port} (default: @code{25}) > +Listen on the integer port instead of the default port of 25. > + > +@item @code{proxy-v2} (default: @code{#f}) > +If @code{#t}, then support the PROXYv2 protocol, rewriting > appropriately source > +address received from proxy. > + > +@item @code{received-auth} (default: @code{#f}) > +If @code{#t}, then in “Received” headers, report whether the session > was > +authenticated and by which local user. > + > +@item @code{senders} (default: @code{#f}) > +Look up the authenticated user in the supplied @code{mapping table} > to > +find the email addresses that user is allowed to submit mail as. > + > +@item @code{masquerade} (default: @code{#f}) > +@code{masquerade}, is used in conjunction with @code{senders}. If > +@code{#t}, then the From header is rewritten to match the sender > +provided in the SMTP session. If @code{senders} is @code{#false}, > then > +@code{masquerade} cannot be @code{#t}. > + > +@item @code{secure-connection} (default: @code{#f}) > +This is a string of one of these options: > + > +@multitable {aaaaaaaaaaaaaaaaaaaa} > {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} Same here > +@item @code{"smtps"} > +@tab Support SMTPS, by default on port 465. > +@item @code{"tls"} > +@tab Support STARTTLS, by default on port 25. > +@item @code{"tls-require"} > +@tab Like @code{"tls"}, but force clients to > +@item > +@tab establish a secure connection before being > +@item > +@tab allowed to start an SMTP transaction. > +@item @code{"tls-require-verify"} > +@tab Like @code{"tls-require"}, but clients must > +@item > +@tab also provide a valid certificate > +@item > +@tab to establish an SMTP session. > +@end multitable > + > +@item @code{tag} (default: @code{#f}) > +Clients connecting to the listener are tagged with the given string > tag. > +@end itemize > + > +@item Data Type: opensmtpd-socket > +Data type representing the configuration of an > +@code{<opensmtpd-socket>}. Listen for incoming SMTP connections on > the > +Unix domain socket @samp{/var/run/smtpd.sock}. This is done by > default, > +even if the record is absent. > + > +@itemize > +@item @code{filters} (default: @code{#f}) > +A list of one or many @code{<opensmtpd-filter>} or > +@code{<opensmtpd-filter-phase>} records. These filter incoming > +connections handled by this listener. > + > +@item @code{mask-src} (default: @code{#f}) > +If @code{#t}, then omit the from part when prepending “Received” > headers. > + > +@item @code{tag} (default: @code{#f}) > +Clients connecting to the listener are tagged with the given string > tag. > +@end itemize > + > +@item Data Type: opensmtpd-match > +@cindex opensmtpd-match > +This data type represents the configuration of an > +@code{<opensmtpd-match>} record. > + > +If at least one mail envelope matches the options of one match > record, > +receive the incoming message, put a copy into each matching > envelope, > +and atomically save the envelopes to the mail spool for later > processing > +by the respective @code{<opensmtpd-action>} found in fieldname > +@code{action}. Here is an example @code{opensmtpd-match} > +record. > + > +@lisp > +(opensmtpd-match > + (action (opensmtpd-local-delivery > + (name "receive") > + (method (opensmtpd-maildir > + (pathname "/home/%@{rcpt.user@}/Maildir") > + (junk #t))) > + (virtual (opensmtpd-table > + (name "virt") > + (data '(("carmen" . "carmen@@gnu.org"))))))) > + (options (list (opensmtpd-option > + (option "from any")) > + (opensmtpd-option > + (option "for domain") > + (data (opensmtpd-table > + (name "domain-table") > + (data (list "gnu.org" "fsf.org")))))))) > +@end lisp > + > +@itemize > +@item @code{action} (default: @code{#f}) > + > +If mail matches this match configuration, then do this action. Valid > values > +include @code{<opensmtpd-local-delivery>} or > +@code{<opensmtpd-relay>}. > + > +@item @code{options} (default: @code{#f}) > +The fieldname @code{option} is a list of unique > +@code{<opensmtpd-option>} records. > + > +There are some mutually exclusive options: there can be only one > ``for'' > +and only one ``from'' option. > + > +@multitable {aaaaaaaaaaaaaaaaaaaaaaaaa} > {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} and here. > +@headitem for > +@tab from > +@item only use one of the following: > +@tab only use one of the following: > +@item @code{"for any"} > +@tab @code{"from any"} > +@item @code{"for local"} > +@tab @code{"from auth"} > +@item @code{"for domain"} > +@tab @code{"from local"} > +@item @code{"for rcpt-to"} > +@tab @code{"from mail-from"} > +@item > +@tab @code{"from socket"} > +@item > +@tab @code{"from src"} > +@end multitable > + > +Additionally, some options require additional data via > +@code{<opensmtpd-option>}'s fieldname @code{data}. The following > list > +will explain the below syntax. > + > +@itemize > +@item @code{"for any"} > +This option only requires fieldname @code{option} to have the string > +@code{"for any"}: > + > +@lisp > + (opensmtpd-option > + (option "for any")) > +@end lisp > + > +@item @code{"tag"} _tag_ > +This option only requires fieldname @code{option} to have the string > +@code{"tag"} with a string in fieldname @code{data}: > + > +@lisp > + (opensmtpd-option > + (option "tag") > + (data "this-tag")) > +@end lisp > + > +@item @code{"for rcpt"} _domain_ | <list table> > +This option requires fieldname @code{data} to have a string domain > or > +@code{list table}: > + > +@lisp > + (opensmtpd-option > + (option "for rcpt") > + (data "gnu.org")) > +@end lisp > + > +OR > + > +@lisp > + (opensmtpd-option > + (option "for rcpt") > + (data (list "gnu.org" "fsf.org"))) > +@end lisp > +@end itemize > + > +The following matching options are supported and can all be negated > (via not > +#t). The options that support a table (anything surrounded with '<' > and '>' > +eg: <table>), also support specifying regex via (regex #t). > + > +@itemize > +@item @code{"for any"} > +Specify that session may address any destination. > + > +@item @code{"for local"} > +Specify that session may address any local domain. This is the > default, > +and may be omitted. > + > +@item @code{"for domain"} _domain_ | <domain> > +Specify that session may address the string _domain_ or > +@code{list table} <domain>. > + > +@item @code{"for rcpt-to"} _recipient_ | <recipient> > +Specify that session may address the string _recipient_ or list > table > +<recipient>. > + > +@item @code{"from any"} > +Specify that session may originate from any source. > + > +@item @code{"from auth"} > +Specify that session may originate from any authenticated user, no > matter > +the source IP address. > + > +@item @code{"from auth"} _user_ | <user> > +Specify that the session may originate from authenticated _user_ or > +@code{list table} <user>, no matter the source IP address. > + > +@item @code{"from local"} > +Specify that session may only originate from a local IP address, or > from > +the local enqueuer. This is the default, and may be omitted. > + > +@item @code{"from mail-from"} _sender_ | <sender> > +Specify that session may originate from _sender_ or @code{list > table} > +<sender>, no matter the source IP address. > + > +@item @code{"from rdns"} > +Specify that session may only originate from an IP address that > resolves > +to a reverse DNS@. > + > +@item @samp{"from rdns"} _hostname_ | <hostname> > +Specify that session may only originate from an IP address that > resolves > +to a reverse DNS matching string _hostname_ or @code{list table} > +<hostname>. > + > +@item @samp{"from socket"} > +Specify that session may only originate from the local enqueuer. > + > +@item @code{"from src"} _address_ | <address> > +Specify that session may only originate from string _address_ or > +@code{list table} <address> which can be a specific address or a > subnet > +expressed in CIDR-notation. > + > +@item @code{"auth"} > +Matches transactions which have been authenticated. > + > +@item @code{"auth"} _username_ | <username> > +Matches transactions which have been authenticated for string _user_ > or > +@code{list table} <username>. > + > +@item @code{"helo"} _helo-name_ | <helo-name> > +Specify that session's HELO / EHLO should match the string _helo- > name_ > +or @code{list table} <helo-name>. > + > +@item @code{"mail-from"} _sender_ | <sender> > +Specify that transactions's MAIL FROM should match the string > _sender_ > +or @code{list table} <sender>. > + > +@item @code{"rcpt-to"} _recipient_ | <recipient> > +Specify that transaction's RCPT TO should match the string > _recipient_ > +or @code{list table} <recipient>. > + > +@item @code{"tag"} _tag_ > +Matches transactions tagged with the given tag. > + > +@item @code{"tls"} > +Specify that transaction should take place in a TLS channel. > +@end itemize > + > +@end itemize > + > +@item Data Type: opensmtpd-local-delivery > +This data type represents the configuration of an > +@code{<opensmtpd-local-delivery>} record. > + > +@itemize > +@item @code{name} (default: @code{#f}) > +@code{name} is the string name of the relay action. > + > +@item @code{method} (default: @code{"mbox"}) > +The email delivery option. Valid options are: > + > +@itemize > +@item @code{"mbox"} > +Deliver the message to the user's mbox with mail.local(8). > + > +@item @code{"expand-only"} > +Only accept the message if a delivery method was specified in an > aliases > +or .forward file. > + > +@item @code{"forward-only"} > +Only accept the message if the recipient results in a remote address > after > +the processing of aliases or forward file. > + > +@item @code{<opensmtpd-lmtp>} > +Deliver the message to an LMTP server at @code{<opensmtpd-lmtp>}'s > +fieldname @code{destination}. The location may be expressed as > string > +host:port or as a UNIX socket. Optionally, @code{<opensmtpd-lmtp>}'s > +fieldname @code{rcpt-to} might be specified to use the recipient > email > +address (after expansion) instead of the local user in the LMTP > session > +as RCPT TO. > + > +@item @code{<opensmtpd-maildir>} > +Deliver the message to the maildir in > +@code{<opensmtpd-maildir>}'s fieldname @code{pathname} if specified, > +or by default to @code{"~/Maildir"}. > + > +The pathname may contain format specifiers that are expanded before > use > +(see the below section about Format Specifiers). > + > +If @code{<opensmtpd-maildir>}'s record fieldname @code{junk} is > @code{#t}, > +then message will be moved to the ‘Junk’ folder if it contains a > positive > +‘X-Spam’ header. This folder will be created under fieldname > @code{pathname} if > +it does not yet exist. > + > +@item @code{<opensmtpd-mda>} > +Delegate the delivery to the @code{<opensmtpd-mda>}'s fieldname > +@code{command} (type string) that receives the message on its > standard input. > + > +The @code{command} may contain format specifiers that are expanded > before use > +(see Format Specifiers). > +@end itemize > + > +@item @code{alias} (default: @code{#f}) > +Use the @code{mapping table} for aliases expansion. > + > +@item @code{ttl} (default: @code{#f}) > +@code{ttl} is a string specify how long a message may remain in the > queue. It's > +format is @code{n@{s|m|h|d@}}. eg: @code{"4m"} is four minutes. > + > +@item @code{user} (default: @code{#f} ) > +@code{user} is the string username for performing the delivery, to > be looked up > +with getpwnam(3). > + > +This is used for virtual hosting where a single username is in > charge of > +handling delivery for all virtual users. > + > +This option is not usable with the mbox delivery method. > + > +@item @code{userbase} (default: @code{#f}) > +@code{userbase} is an @code{<opensmtpd-table>} record for mapping > user > +lookups instead of the getpwnam(3) function. > + > +The fieldnames @code{user} and @code{userbase} are mutually > exclusive. > + > +@item @code{virtual} (default: @code{#f}) > +@code{virtual} is an @code{<opensmtpd-table>} record is used for > virtual > +expansion. > +@end itemize > + > +@item Data Type: opensmtpd-relay > +This data type represents the configuration of an > +@code{<opensmtpd-relay>} record. > + > +@itemize > +@item @code{name} (default: @code{#f}) > +@code{name} is the string name of the relay action. > + > +@item @code{backup} (default: @code{#f}) > +When @code{#t}, operate as a backup mail exchanger delivering > messages to any > +mail exchanger with higher priority. > + > +@item @code{backup-mx} (default: @code{#f}) > +Operate as a backup mail exchanger delivering messages to any mail > exchanger > +with higher priority than mail exchanger identified as string name. > + > +@item @code{helo} (default: @code{#f}) > +Advertise string heloname as the hostname to other mail exchangers > during > +the HELO phase. > + > +@item @code{helo-src} (default: @code{#f} ) > + Use the mapping @code{<opensmtpd-table>} to look up a hostname > +matching the source address, to advertise during the HELO phase. > + > +@item @code{domain} (default: @code{#f}) > +Do not perform MX lookups but look up destination domain in an > +@code{<opensmtpd-table>} and use matching relay url as relay host. > + > +@item @code{host} (default: @code{#f}) > +Do not perform MX lookups but relay messages to the relay host > described by > +the string relay-url. The format for relay-url is > +@samp{[proto://[label@@]]host[:port]}. The following protocols are > available: > + > +@multitable {aaaaaaaaaa} > {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA. > +@item @code{smtp} > +@tab Normal SMTP session with opportunistic STARTTLS (the default). > +@item @code{smtp+tls} > +@tab Normal SMTP session with mandatory STARTTLS@. > +@item @code{smtp+notls} > +@tab Plain text SMTP session without TLS@. > +@item @code{lmtp} > +@tab LMTP session. port is required. > +@item @code{smtps} > +@tab SMTP session with forced TLS on connection, default port is > +@item > +@tab 465. > +@end multitable > + > +Unless noted, port defaults to 25. > + > +The label corresponds to an entry in a credentials table, as > documented in > +@code{man table}. It is used with the @code{"smtp+tls"} and > @code{"smtps"} protocols for > +authentication. Server certificates for those protocols are verified > by > +default. > + > +@item @code{pki} (default: @code{#f}) > +For secure connections, use the certificate associated with > +@code{<opensmtpd-pki>} (declared in a pki directive) to prove the > +client's identity to the remote mail server. > + > +@item @code{srs} (default: @code{#f}) > +If @code{#t}, then when relaying a mail resulting from a forward, > use the Sender > +Rewriting Scheme to rewrite sender address. > + > +@item @code{tls} (default: @code{#f}) boolean or string ``no- > verify'' Instead of a string, take 'no-verify as symbol perhaps? > +When @code{#t}, Require TLS to be used when relaying, using > mandatory STARTTLS by > +default. When used with a smarthost, the protocol must not be > +@samp{"smtp+notls://"}. When string @code{"no-verify"}, then do not > require a valid > +certificate. > + > +@item @code{auth} (default: @code{#f}) @code{<opensmtpd-table>} > +Use the alist @code{<opensmtpd-table>} for connecting to relay-url > +using credentials. This option is usable only with fieldname > @code{host} option. > + > +@item @code{mail-from} (default: @code{#f}) string > +Use the string mailaddress as MAIL FROM address within the SMTP > transaction. > + > +@item @code{src} (default: @code{#f}) string | @code{<opensmtpd- > table>} > +Use the string or @code{<opensmtpd-table>} sourceaddr for the > +source IP address, which is useful on machines with multiple > interfaces. If > +the list contains more than one address, all of them are used in > such a way > +that traffic is routed as efficiently as possible. > +@end itemize > + > +@item Data Type: opensmtpd-filter > +This data type represents the configuration of an > +@code{<opensmtpd-filter>}. This is the filter record one should use > +if they want to use an external package to filter email eg: rspamd > or > +spamassassin. > + > +@itemize > +@item @code{name} (default: @code{#f}) > +The string name of the filter. > + > +@item @code{proc} (default: @code{#f}) > +The string command or process name. If @code{proc-exec} is > @code{#t}, @code{proc} is > +treated as a command to execute. Otherwise, it is a process name. > + > +@item @code{proc-exec} (default: @code{#f}) > +If @code{#t}, then execute the command in @code{proc}. > +@end itemize > + > +@item Data Type: opensmtpd-filter-phase > +This data type represents the configuration of an > +@code{<opensmtpd-filter-phase>}. > + > +In a regular workflow, @code{smtpd(8)} may accept or reject a > message > +based only on the content of envelopes. Its decisions are about the > +handling of the message, not about the handling of an active > session. > + > +Filtering extends the decision making process by allowing > +@code{smtpd(8)} to stop at each phase of an SMTP session, check that > +options are met, then decide if a session is allowed to move > forward. > + > +With filtering via an @code{<opensmtpd-filter-phase>} record, a > +session may be interrupted at any phase before an envelope is > complete. A > +message may also be rejected after being submitted, regardless of > whether the > +envelope was accepted or not. > + > +@itemize > +@item @code{name} (default: @code{#f}) > + > +The string name of the filter phase. > + > +@item @code{phase-name} (default: @code{#f}) > +The string name of the phase. Valid values are: > + > +@multitable {aaaaaaaaaaa} > {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} > +@item @code{"connect"} > +@tab upon connection, before a banner is displayed > +@item @code{"helo"} > +@tab after HELO command is submitted > +@item @code{"ehlo"} > +@tab after EHLO command is submitted > +@item @code{"mail-from"} > +@tab after MAIL FROM command is submitted > +@item @code{"rcpt-to"} > +@tab after RCPT TO command is submitted > +@item @code{"data"} > +@tab after DATA command is submitted > +@item @code{"commit"} > +@tab after message is fully is submitted > +@end multitable > + > +@item @code{options} (default @code{#f}) > +A list of unique @code{<opensmtpd-option>} records. > + > +At each phase, various options, specified by a list of > +@code{<opensmtpd-option>}, may be checked. The > +@code{<opensmtpd-option>}'s fieldname @code{option} values of: > +@code{"fcrdns"}, @code{"rdns"}, and @code{"src"} data are available > in > +all phases, but other data must have been already submitted before > they > +are available. Options with a @code{<table>} next to them require > the > +@code{<opensmtpd-option>}'s fieldname @code{data} to be an > +@code{<opensmtpd-table>}. There are the available options: > + > +@multitable {aaaaaaaaaaaaaaaaaaaaaaaaa} > {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} > +@item @code{"fcrdns"} > +@tab forward-confirmed reverse DNS is valid > +@item @code{"rdns"} > +@tab session has a reverse DNS > +@item @code{"rdns"} <table> > +@tab session has a reverse DNS in table > +@item @code{"src"} <table> > +@tab source address is in table > +@item @code{"helo"} <table> > +@tab helo name is in table > +@item @code{"auth"} > +@tab session is authenticated > +@item @code{"auth"} <table> > +@tab session username is in table > +@item @code{"mail-from"} <table> > +@tab sender address is in table > +@item @code{"rcpt-to"} <table> > +@tab recipient address is in table > +@end multitable > + > +These conditions may all be negated by setting > +@code{(opensmtpd-option (bool #f))}. > + > +Any conditions that require a table may indicate that tables include > regexs > +setting @code{(opensmtpd-option (regex #t))}. > + > +@item @code{decision} > +A string decision to be taken. Some decisions require an > @code{message} > +or @code{value}. The value and message may be put in the > +@code{<opensmtpd-option>}'s fieldname @code{data}. Valid strings > are: > + > +@multitable {aaaaaaaaaaaaaaaaaaaaaa} > {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} > +@item @code{"bypass"} > +@tab the session or transaction bypasses filters > +@item @code{"disconnect"} message > +@tab the session is disconnected with message > +@item @code{"junk"} > +@tab the session or transaction is junked, > +@item > +@tab i.e., an ‘X-Spam: yes’ header is added to > +@item > +@tab any messages > +@item @code{"reject"} message > +@tab the command is rejected with message > +@item @code{"rewrite"} value > +@tab the command parameter is rewritten with value > +@end multitable > + > +Decisions that involve a message require that the message be RFC > valid, > +meaning that they should either start with a 4xx or 5xx status code. > +Descisions can be taken at any phase, though junking can only happen > before > +a message is committed. > + > +@item @code{message} (default @code{#f}) > +A string message beginning with a 4xx or 5xx status code. > + > +@item @code{value} (default: @code{#f}) > +A number value. @code{value} and @code{message} are mutually > exclusive. > +@end itemize > + > +@item Data Type: opensmtpd-option > +This data type represents the configuration of an > +@code{<opensmtpd-option>}, which is used by > +@code{<opensmtpd-filter-phase>} and @code{<opensmtpd-match>} > +to match various options for email. > + > +@itemize > +@item @code{option} (default @code{#f}) string > + > +A string option to be taken. Some options require the fieldname > +@code{data} to have a string or an @code{<opensmtpd-table>}. When > the > +option record is used inside of an @code{<opensmtpd-filter-phase>}, > then > +valid strings for fieldname @code{option} are: > + > +@itemize > +@item @code {"fcrdns"} > +@item @code {"rdns"} > +@item @code {"src"} > +@item @code {"helo"} > +@item @code {"auth"} > +@item @code {"mail-from"} > +@item @code {"rcpt-to"} > +@end itemize > + > +When @code{<opensmtpd-option>} is used inside of an > +@code{<opensmtpd-match>}, then valid strings for fieldname > @code{option} > +are: > + > +@itemize > +@item @code {"for"} > +@item @code {"for any"} > +@item @code {"for local"} > +@item @code {"for domain"} > +@item @code {"for rcpt-to"} > +@item @code {"from any"} > +@item @code {"from auth"} > +@item @code {"from local"} > +@item @code {"from mail-from"} > +@item @code {"from rdns"} > +@item @code {"from socket"} > +@item @code {"from src"} > +@item @code {"auth"} > +@item @code {"helo"} > +@item @code {"mail-from"} > +@item @code {"rcpt-to"} > +@item @code {"tag"} > +@item @code {"tls"} > +@end itemize > + > +@item @code{data} (default @code{#f}) string | @code{<opensmtpd- > table>} > +Some options require a string or @code{<opensmtpd-table>} to be > +present. One would specify that table here. > + > +@item @code{regex} (default: @code{#f}) boolean > +Any options using a table may indicate that tables hold regular > +expressions by setting this option to @code{#t}. > + > +@item @code{bool} (default: @code{#t}) boolean > +When @code{(bool #f)}, this option record is negated. > +@end itemize > + > +@item Data Type: opensmtpd-table > +This data type represents the configuration of an > +@code{<opensmtpd-table>}. > + > +@itemize > +@item @code{name} (default @code{#f}) > +@code{name} is the name of the @code{<opensmtpd-table>} record. > + > +@item @code{data} (default: @code{#f}) string | list | alist | > nested-list > +@code{data} expects a string, a list of strings, an alist of > strings, or > +a nested list of strings. > +eg: > + > +@itemize > + > +@item string > +@lisp > +(data "dev@@gnu.org") > +@end lisp > + > +A table of this type is called a @code{string table}. > + > +@item list > +@lisp > +(data (list ("gnu.org" "fsf.org"))) > +@end lisp > + > +A table of this type is called a @code{list table}. > + > +@item alist > +@lisp > +(data '(("james" . "$encryptedPassword") > + ("jennifer" . "$encryptedPassword2))) > +@end lisp > + > +A table of this type is called a @code{mapping table}. > + > +@item nested-list > +@lisp > +(data '(("user1" "root@@gnu.org" "admin@@gnu.org") > + ("user2" "james@@guix.gnu.org" "sarah@@fsf.org"))) > +@end lisp > + > +A table of this type is also called a @code{mapping table}. > + > +@end itemize > +@end itemize > + > +@item Data Type: opensmtpd-pki > +This data type represents the configuration of an > +@code{<opensmtpd-pki>}. > + > +@itemize > +@item @code{domain} (default @code{#f}) > +@code{domain} is the string name of the @code{<opensmtpd-pki>} > record. > + > +@item @code{cert} (default: @code{#f}) > +@code{cert} (default: @code{#f}) > + > +@code{cert} is the string certificate filename to use for this pki. > + > +@item @code{key} (default: @code{#f}) > +@code{key} is the string certificate falename to use for this pki. > + > +@item @code{dhe} (default: @code{"none"}) > +Specify the DHE string parameter to use for DHE cipher suites with > host > +pkiname. Valid parameter values are @code{"none"}, @code{"legacy"}, > or > +@code{"auto"}. For @code{"legacy"}, a fixed key length of 1024 bits > is > +used, whereas for @code{"auto"}, the key length is determined > +automatically. The default is @code{"none"}, which disables DHE > cipher > +suites. > +@end itemize > + > +@item Data Type: opensmtpd-maildir > +@itemize > +@item @code{pathname} (default: @code{"~/Maildir"}) > +Deliver the message to the maildir if pathname if specified, or by > default > +to @code{"~/Maildir"}. > + > +The pathname may contain format specifiers that are expanded before > use > +(see FORMAT SPECIFIERS). > + > +@item @code{junk} (default: @code{#f}) > +If the junk argument is @code{#t}, then the message will be moved to > the @samp{‘Junk’} > +folder if it contains a positive @samp{‘X-Spam’} header. This folder > will be > +created under pathname if it does not yet exist. > +@end itemize > + > +@item Data Type: opensmtpd-mda > +This record lets you delegate the delivery to a command that > receives > +the message on its standard input. > + > +@itemize > +@item @code{name} > +The string name for this MDA command. > + > +@item @code{command} > +The command to that delivers the mail. > + > +The command may contain format specifiers that are expanded before > use (see > +FORMAT SPECIFIERS). > +@end itemize > + > +@item Data Type: opensmtpd-queue > +@itemize > +@item @code{compression} (default @code{#f}) > +Store queue files in a compressed format. This may be useful to save > disk > +space. > + > +@item @code{encryption} (default @code{#f}) > +Encrypt queue files with EVP <at> math{_aes}@math{_256}@math{_gcm}(3). If > no key is specified, it is > +read with getpass(3). If the string stdin or a single dash (‘-’) is > given > +instead of a key, the key is read from the standard input. > + > +@item @code{ttl-delay} (default @code{#f}) > +Set the default expiration time for temporarily undeliverable > messages, > +given as a positive decimal integer followed by a unit s, m, h, or > d. The > +default is four days (@code{"4d"}). > +@end itemize > + > +@item Data Type: opensmtpd-smtp > +Data type representing an @code{<opensmtpd-smtp>} record. > + > +@itemize > +@item @code{ciphers} (default: @code{#f}) > +Set the control string for > SSL <at> math{_CTX}@math{_set}@math{_cipher}@math{_list}(3). The default > is > + ``HIGH:!aNULL:!MD5''. > + > +@item @code{limit-max-mails} (default: @code{100}) > +Limit the number of messages to count for each sessio > + > +@item @code{limit-max-rcpt} (default: @code{1000}) > +Limit the number of recipients to count for each transaction. > + > +@item @code{max-message-size} (default: @code{35M}) > +Reject messages larger than size, given as a positive number of > bytes or as > +a string to be parsed with scan <at> math{_scaled}(3). > + > +@item @code{sub-addr-delim character} (default: @code{+}) > +When resolving the local part of a local email address, ignore the > ASCII > +character and all characters following it. This is helpful for email > +filters. @samp{"admin+bills@@gnu.org"} is the same email address as > +@samp{"admin@@gnu.org"}. BUT an email filter can filter emails > addressed to first > +email address into a 'Bills' email folder. > +@end itemize > + > +@item Data Type: opensmtpd-srs > +Use this record to set up the Sender Rewriting Scheme (SRS). > + > +@itemize > +@item @code{key} (default: @code{#f}) > +Set the secret key to use for SRS, the Sender Rewriting Scheme. > + > +@item @code{backup-key} (default: @code{#f}) > +Set a backup secret key to use as a fallback for SRS@. This can be > used to > +implement SRS key rotation. > + > +@item @code{ttl-delay} (default: @code{"4d"}) > +Set the time-to-live delay for SRS envelopes. After this delay, a > bounce > +reply to the SRS address will be discarded to limit risks of forged > +addresses. > +@end itemize > + > +@item Format Specifiers > +Some configuration records support expansion of their parameters at > +runtime. Such records (for example > +@code{<opensmtpd-maildir>}, @code{<opensmtpd-mda>}) may use > +format specifiers which are expanded before delivery or relaying. > The > +following formats are currently supported: > + > +@multitable {aaaaaaaaaaaaaaaaaaa} > {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} > +@item @samp{%@{sender@}} > +@tab sender email address, may be empty string > +@item @samp{%@{sender.user@}} > +@tab user part of the sender email address, may be empty > +@item @samp{%@{sender.domain@}} > +@tab domain part of the sender email address, may be empty > +@item @samp{%@{rcpt@}} > +@tab recipient email address > +@item @samp{%@{rcpt.user@}} > +@tab user part of the recipient email address > +@item @samp{%@{rcpt.domain@}} > +@tab domain part of the recipient email address > +@item @samp{%@{dest@}} > +@tab recipient email address after expansion > +@item @samp{%@{dest.user@}} > +@tab user part after expansion > +@item @samp{%@{dest.domain@}} > +@tab domain part after expansion > +@item @samp{%@{user.username@}} > +@tab local user > +@item @samp{%@{user.directory@}} > +@tab home directory of the local user > +@item @samp{%@{mbox.from@}} > +@tab name used in mbox From separator lines > +@item @samp{%@{mda@}} > +@tab mda command, only available for mda wrappers > +@end multitable > + > +Expansion formats also support partial expansion using the optional > bracket notations > +with substring offset. For example, with recipient domain > @samp{“example.org”}: > + > +@multitable {aaaaaaaaaaaaaaaaaaaaaa} {aaaaaaaaaaaaaaaaaaaa} > +@item @samp{%@{rcpt.domain[0]@}} > +@tab expands to “e” > +@item @samp{%@{rcpt.domain[1]@}} > +@tab expands to “x” > +@item @samp{%@{rcpt.domain[8:]@}} > +@tab expands to “org” > +@item @samp{%@{rcpt.domain[-3:]@}} > +@tab expands to “org” > +@item @samp{%@{rcpt.domain[0:6]@}} > +@tab expands to “example” > +@item @samp{%@{rcpt.domain[0:-4]@}} > +@tab expands to “example” > +@end multitable > + > +In addition, modifiers may be applied to the token. For example, > with recipient > +@samp{“User+Tag@@Example.org”}: > + > +@multitable {aaaaaaaaaaaaaaaaaaaaaaaa} > {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} > +@item @samp{%@{rcpt:lowercase@}} > +@tab expands to “user+tag@@example.org” > +@item @samp{%@{rcpt:uppercase@}} > +@tab expands to “USER+TAG@@EXAMPLE.ORG” > +@item @samp{%@{rcpt:strip@}} > +@tab expands to “User@@Example.org” > +@item @samp{%@{rcpt:lowercasestrip@}} > +@tab expands to “user@@example.org” > +@end multitable > + > +For security concerns, expanded values are sanitized and potentially > dangerous > +characters are replaced with ‘:’. In situations where they are > desirable, the > +“raw” modifier may be applied. For example, with recipient > +@samp{“user+t?g@@example.org”}: > + > +@multitable {aaaaaaaaaaaaa} {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} > +@item @samp{%@{rcpt@}} > +@tab expands to “user+t:g@@example.org” > +@item @samp{%@{rcpt:raw@}} > +@tab expands to “user+t?g@@example.org” > +@end multitable > +@end itemize > + > @subsubheading Exim Service > > @cindex mail transfer agent (MTA) > diff --git a/gnu/services/mail.scm b/gnu/services/mail.scm > index 43f144a42d..4175cab375 100644 > --- a/gnu/services/mail.scm > +++ b/gnu/services/mail.scm > @@ -35,6 +35,10 @@ (define-module (gnu services mail) > #:use-module (gnu packages admin) > #:use-module (gnu packages dav) > #:use-module (gnu packages tls) > + #:use-module (guix i18n) > + #:use-module (guix diagnostics) > + #:use-module (guix ui) > + #:use-module (guix utils) > #:use-module (guix records) > #:use-module (guix packages) > #:use-module (guix gexp) > @@ -58,10 +62,149 @@ (define-module (gnu services mail) > mailbox-configuration > namespace-configuration > > + opensmtpd-table > + opensmtpd-table? > + opensmtpd-table-name > + opensmtpd-table-data > + > + opensmtpd-ca > + opensmtpd-ca? > + opensmtpd-ca-name > + opensmtpd-ca-file > + > + opensmtpd-pki > + opensmtpd-pki? > + opensmtpd-pki-domain > + opensmtpd-pki-cert > + opensmtpd-pki-key > + opensmtpd-pki-dhe > + > + opensmtpd-local-delivery > + opensmtpd-local-delivery? > + opensmtpd-local-delivery-method > + opensmtpd-local-delivery-alias > + opensmtpd-local-delivery-ttl > + opensmtpd-local-delivery-user > + opensmtpd-local-delivery-userbase > + opensmtpd-local-delivery-virtual > + opensmtpd-local-delivery-wrapper > + > + opensmtpd-maildir > + opensmtpd-maildir? > + opensmtpd-maildir-pathname > + opensmtpd-maildir-junk > + > + opensmtpd-mda > + opensmtpd-mda-name > + opensmtpd-mda-command > + > + opensmtpd-lmtp > + opensmtpd-lmtp-destination > + opensmtpd-lmtp-rcpt > + > + opensmtpd-relay > + opensmtpd-relay? > + opensmtpd-relay-name > + opensmtpd-relay-backup > + opensmtpd-relay-backup-mx > + opensmtpd-relay-helo > + opensmtpd-relay-domain > + opensmtpd-relay-host > + opensmtpd-relay-pki > + opensmtpd-relay-srs > + opensmtpd-relay-tls > + opensmtpd-relay-auth > + opensmtpd-relay-mail-from > + opensmtpd-relay-src > + > + opensmtpd-option > + opensmtpd-option? > + opensmtpd-option-option > + opensmtpd-option-bool > + opensmtpd-option-regex > + opensmtpd-option-data > + > + opensmtpd-filter-phase > + opensmtpd-filter-phase? > + opensmtpd-filter-phase-name > + opensmtpd-filter-phase-phase > + opensmtpd-filter-phase-options > + opensmtpd-filter-phase-decision > + opensmtpd-filter-phase-message > + opensmtpd-filter-phase-value > + > + opensmtpd-filter > + opensmtpd-filter? > + opensmtpd-filter-name > + opensmtpd-filter-proc > + > + opensmtpd-interface > + opensmtpd-interface? > + opensmtpd-interface-interface > + opensmtpd-interface-family > + opensmtpd-interface-auth > + opensmtpd-interface-auth-optional > + opensmtpd-interface-filters > + opensmtpd-interface-hostname > + opensmtpd-interface-hostnames > + opensmtpd-interface-mask-src > + opensmtpd-interface-disable-dsn > + opensmtpd-interface-pki > + opensmtpd-interface-port > + opensmtpd-interface-proxy-v2 > + opensmtpd-interface-received-auth > + opensmtpd-interface-senders > + opensmtpd-interface-masquerade > + opensmtpd-interface-secure-connection > + opensmtpd-interface-tag > + > + opensmtpd-socket > + opensmtpd-socket? > + opensmtpd-socket-filters > + opensmtpd-socket-mask-src > + opensmtpd-socket-tag > + > + opensmtpd-match > + opensmtpd-match? > + opensmtpd-match-action > + opensmtpd-match-options > + > + opensmtpd-smtp > + opensmtpd-smtp? > + opensmtpd-smtp-ciphers > + opensmtpd-smtp-limit-max-mails > + opensmtpd-smtp-limit-max-rcpt > + opensmtpd-smtp-max-message-size > + opensmtpd-smtp-sub-addr-delim character > + > + opensmtpd-srs > + opensmtpd-srs? > + opensmtpd-srs-key > + opensmtpd-srs-backup-key > + opensmtpd-srs-ttl-delay > + > + opensmtpd-queue > + opensmtpd-queue? > + opensmtpd-queue-compression > + opensmtpd-queue-encryption > + opensmtpd-queue-ttl-delay > + > opensmtpd-configuration > opensmtpd-configuration? > + opensmtpd-package > + opensmtpd-config-file > + opensmtpd-configuration-bounce > + opensmtpd-configuration-cas > + opensmtpd-configuration-interfaces > + opensmtpd-configuration-socket > + opensmtpd-configuration-includes > + opensmtpd-configuration-matches > + ;;opensmtpd-configuration-mda-wrappers > + opensmtpd-configuration-mta-max-deferred > + opensmtpd-configuration-srs > + opensmtpd-configuration-smtp > + opensmtpd-configuration-queue > opensmtpd-service-type > - %default-opensmtpd-config-file > > mail-aliases-service-type > > @@ -1641,22 +1784,2351 @@ (define (generate-dovecot-documentation) > (listeners unix-listener-configuration fifo-listener- > configuration > inet-listener-configuration)) > (protocol-configuration ,protocol-configuration-fields)) > - 'dovecot-configuration)) > + 'dovecot-configuration)) > > > -;;; > ;;; OpenSMTPD. > ;;; > +;;; This next bit of code helps me create my own sanitizer > functions. > + > +;; some fieldnames have a default value of #f, which is ok. They > cannot have > +;; a value of #t. > +;; for example opensmtpd-table-data can be #f, BUT NOT true. > +;; my/sanitize procedure tests values to see if they are of the > right kind. > +;; procedure false? is needed to allow fields like 'values' to be > blank, > +;; (empty), or #f BUT also have a value like a list of strings. Use less egocentric comments ;) > +(define (false? var) > + (eq? #f var)) > + > +;; TODO I have to have this procedure, or I need to change > my/sanitize > +;; procedure. > +(define (my-file-exists? file) > + (and (string? file) > + (access? file F_OK))) Does file-exists? not work for you? > +;; This procedure takes in a var and a list of procedures. It loops > through > +;; list of procedures passing in var to each. > +;; if one procedure returns #t, the function returns true. > Otherwise #f. > +;; TODO for fun rewrite this using map > +;; If I rewrote it in map, then it may help with sanitizing. > +;; eg: I could then potentially easily sanitize vars with lambda > procedures. > +(define (is-value-right-type? var list-of-procedures record > fieldname) > + (if (null? list-of-procedures) > + #f > + (if ((car list-of-procedures) var) > + #t > + (is-value-right-type? var (cdr list-of-procedures) record > + fieldname)))) Alternatively, (any (cut <> var) list-of-procedures). > +;; converts strings like this: > +;; "apple, ham, cherry" -> "apple, ham, or cherry" > +;; "pineapple" -> "pinneapple". > +;; "cheese, grapefruit, or jam" -> "cheese, grapefruit, or jam" > +(define (add-comma-or string) > + (define last-comma-location (string-rindex string #\,)) > + (if last-comma-location > + (if (string-contains string ", or" last-comma-location) > + string > + (string-replace string ", or" last-comma-location > + (+ 1 last-comma-location))) > + string)) > + > + > +(define (list-of-procedures->string procedures) > + (define string > + (let loop ((procedures procedures)) > + (if (null? procedures) > + "" > + (begin > + (string-append > + (cond ((eq? false? (car procedures)) > + "#f, ") > + ((eq? boolean? (car procedures)) > + "a boolean, ") > + ((eq? string? (car procedures)) > + "a string, ") > + ((eq? integer? (car procedures)) > + "an integer, ") > + ((eq? list-of-strings? (car procedures)) > + "a list of strings, ") > + ((eq? assoc-list? (car procedures)) > + "an association list of strings, ") > + ((eq? nested-list? (car procedures)) > + "a nested-list of strings, ") > + ((eq? opensmtpd-pki? (car procedures)) > + "an <opensmtpd-pki> record, ") > + ((eq? opensmtpd-table? (car procedures)) > + "an <opensmtpd-table> record, ") > + ((eq? list-of-opensmtpd-match? (car procedures)) > + "a list of unique <opensmtpd-match> records, ") > + ((eq? list-of-strings-or-gexps? (car procedures)) > + "a list of strings or gexps, ") > + ;; TODO can I remove the next two procedures? > + ;; tables-data-are-a* ? I think I can. > + ((eq? tables-data-are-assoc-list? (car > procedures)) > + (string-append > + "an <opensmtpd-table> record whose fieldname > 'data' are " > + "an assoc-list.\nFor example: (opensmtpd-table > " > + "(name \"hostnames\") , " > + "(data '((\"124.394.23.1\" . \"gnu.org\"))))")) > + ((eq? tables-data-are-a-list-of-strings? > + (car procedures)) > + (string-append > + "on <opensmtpd-table> record whose fieldname > 'data' is " > + "a list of strings.\n" > + "For example: (opensmtpd-table (name > \"domains\") , " > + "(data (list \"gnu.org\" \"guix.gnu.org\")))")) > + ((eq? my-file-exists? (car procedures)) > + "a file, ") > + (else "has an incorrect value, ")) > + (loop (cdr procedures))))))) > + (add-comma-or (string-append (string-drop-right string 2) ".\n"))) (define (procedure->string) ...) (define (procedures->string list) (define strings (map procedure->string list)) (string-append (string-join (drop-right strings 1) ", ") (if (> (length list) 1) ", or") (last strings) ".\n")) > +(define (list-of-strings-or-gexps? list) > + (and (list? list) > + (cond ((null? list) > + #t) > + ((or (string? (car list)) > + (gexp? (car list)) > + (local-file? (car list)) > + (file-append? (car list)) > + (plain-file? (car list)) > + (computed-file? (car list)) > + (program-file? (car list))) > + (list-of-strings-or-gexps? (cdr list))) > + (else #f)))) > + > +(define (my/sanitize var record fieldname list-of-procedures) > + (define try-string > + (string-append "Try " (list-of-procedures->string list-of- > procedures))) > + (if (is-value-right-type? var list-of-procedures record fieldname) > + var > + (begin > + (cond ((string? var) > + (report-error (G_ "(~a \"~a\") is invalid.~%") > fieldname var)) > + ((or (number? var) (boolean? var)) > + (report-error (G_ "(~a ~a) is invalid.~%") fieldname > var) ) > + (else > + (report-error (G_ "(~a ...) is invalid.~%Value is: > ~a~%") > + fieldname var))) > + (display-hint (G_ try-string)) > + (throw 'bad! var)))) This procedure needs a proper name, like sanitize/check-type, but more importantly, why not simply use define-configuration? Cheers
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.