title:Status Update April 2022
date: 2022-04-01 18:00
tags: jmp.chat
summary: Status Update
---

I am back to working on various records to support `<opensmtpd-configuration>`
for the `opensmtpd-service-type`.  I decided about a week ago, to just do some
of the changes in the records that I want to do.  Once I am satisfied with the
updates, then I will work on making the code output the `smtpd.conf` file.  I am
fairly please with some of the changes to the records that I have made.

Feel free to play with the examples below from my repo!

    https://notabug.org/jbranso/linode-guix-system-configuration.git
    guile -L .
    scheme@(guile-user)> ,use (opensmtpd-records)
    scheme@(guile-user)> ,m (opensmtpd-records)
    (opensmtpd-table (name "table") (values (list "hello" "world")))

Please note, that I am still working on changing the record names, so various
things that work as described in the blog post may not work in a week or two.

## a pretty useful `<opensmtpd-configuration>` gives no errors

    (define example-opensmtpd-configuration
      (let ([interface "lo"]
            [creds-table (opensmtpd-table
                          (name "creds")
                          (values
                           (list
                            (cons "joshua"
                                  "$some$encrypted$password"))))]
            [receive-action (opensmtpd-action-local-delivery-configuration
                             (name "receive")
                             (method (opensmtpd-maildir-configuration
                                      (pathname "/home/%{rcpt.user}/Maildir")
                                      (junk #t)))
                             (virtual (opensmtpd-table
                                       (name "virtual")
                                       (values (list "josh" "jbranso@dismail.de")))))]
            [filter-dkimsign (opensmtpd-filter
                              (name "dkimsign")
                              (exec #t)
                              (proc (string-append "/path/to/dkimsign  -d gnucode.me -s 2021-09-22 -c relaxed/relaxed -k "
                                                   "/path/to/dkimsign-key user nobody group nobody")))]
            [smtp.gnucode.me (opensmtpd-pki
                              (domain "smtp.gnucode.me")
                              (cert "opensmtpd.scm")
                              (key "opensmtpd.scm"))])
        (opensmtpd-configuration
         (mta-max-deferred 50)
         (queue
          (opensmtpd-queue-configuration
           (compression #t)))
         (smtp
          (opensmtpd-smtp-configuration
           (max-message-size "10M")))
         (srs
          (opensmtpd-srs-configuration
           (ttl-delay "5d")))
         (listen-ons
          (list
           (opensmtpd-listen-on
            (interface interface)
            (port 25)
            (secure-connection "tls")
            (filters (list (opensmtpd-filter-phase
                            (name "noFRDNS")
                            (phase "commit")
                            (conditions (list (opensmtpd-conditions-configuration
                                               (condition "fcrdns")
                                               (not #t))))
                            (decision "disconnect")
                            (message "No FCRDNS"))))
            (pki smtp.gnucode.me))
           ;; this lets local users logged into the system via ssh send email
           (opensmtpd-listen-on
            (interface interface)
            (port 465)
            (secure-connection "smtps")
            (pki smtp.gnucode.me)
            (auth creds-table)
            (filters (list filter-dkimsign)))
           (opensmtpd-listen-on
            (interface interface)
            (port 587)
            (secure-connection "tls-require")
            (pki smtp.gnucode.me)
            (auth creds-table)
            (filters (list filter-dkimsign)))))
         (matches (list
                   (opensmtpd-match
                    (action (opensmtpd-action-relay-configuration
                             (name "relay")))
                    (for (opensmtpd-match-configuration
                          (option "for any")))
                    (from (opensmtpd-match-configuration
                           (option "from any")))
                    (auth (opensmtpd-match-configuration
                           (option "auth"))))
                   (opensmtpd-match
                    (action receive-action)
                    (from (opensmtpd-match-configuration
                           (option "from any")))
                    (for (opensmtpd-match-configuration
                          (option "for domain")
                          (value (opensmtpd-table
                                  (name "domain-table")
                                  (values (list "gnucode.me" "gnu-hurd.com")))))))
                   (opensmtpd-match
                    (action receive-action)
                    (for (opensmtpd-match-configuration
                          (option "for local")))))))))

However there&rsquo;s still some work to do because this doesn&rsquo;t work:

    (opensmtpd-configuration->mixed-text-file example-opensmtpd-configuration)

    ice-9/boot-9.scm:1685:16: In procedure raise-exception:
    error: value: unbound variable
    
    Entering a new prompt.  Type `,bt' for a backtrace or `,q' to continue.
    scheme@(opensmtpd-records) [12]> ,bt
    In /home/joshua/prog/gnu/guix/guix-config/linode-guix-system-configuration/opensmtpd-records.scm:
       1667:3  4 (opensmtpd-configuration->mixed-text-file #<<opensmtpd-configuration> package: #<package opensmtpd@6.8.0p2 gnu/packages/mail.scm:2979 7f1e1a3…>)
       1628:9  3 (opensmtpd-configuration-fieldname->string _ _ _)
      1634:10  2 (list-of-records->string _ _)
      1669:99  1 (_ _)
    In ice-9/boot-9.scm:
      1685:16  0 (raise-exception _ #:continuable? _)


## I have also sanitized the `<opensmtpd-conditions-configuration>` 

If you type in various incorrectly written
`<opensmtpd-conditions-configuration>` records, then you will get some helpful
error messages:

1.  if condition is rdns, src, helo, mail-from, rcpt-to, then they must also provide a table
    
    What is interesting, is that I do not know how to sanitize a whole record when
    the record is initiated.  I can only have a parent record sanitize it.  For
    example the following record is invalid, because if the &rsquo;condition&rsquo; is &ldquo;src&rdquo;,
    then you need to provide a table. However, the following works in a REPL.
    
        (opensmtpd-conditions-configuration
            (condition "src"))
    
    `$11 = #<<opensmtpd-conditions-configuration> condition: "src" not: #f regex: #f table: #f>`
    
    But when you put the same incorrect `<opensmtpd-conditions-configuration>`
    into an `<opensmtpd-filter-phase>`, then you get the right error message.
    
        (opensmtpd-filter-phase
         (name "filter")
         (phase "helo")
         (decision "bypass")
         (conditions
          (list
           (opensmtpd-conditions-configuration
            (condition "src")))))
    
        <opensmtpd-conditions-configuration>'s fieldname 'condition' values of
        'src', 'helo', 'mail-from', or 'rcpt-to' need a corresponding 'table'
         of type <opensmtpd-table>. eg:
        (opensmtpd-conditions-configuration
           (condition "src")
           (table (opensmtpd-table
                      (name "src-table")
                      (values (list "hello" "cat")))))
        ice-9/boot-9.scm:1685:16: In procedure raise-exception:
        Throw to key `bad!' with args `((#<<opensmtpd-conditions-configuration> condition: "mail-from" not: #f regex: #f table: #f>))'.
        
        Entering a new prompt.  Type `,bt' for a backtrace or `,q' to continue.
2.  make sure that there are no duplicate conditions
    
        (opensmtpd-filter-phase
         (name "noFRDNS")
         (phase "commit")
         (conditions (list (opensmtpd-conditions-configuration
                            (condition "fcrdns")
                            (not #t))
                           (opensmtpd-conditions-configuration
                            (condition "fcrdns")
                            (not #t))))
         (decision "disconnect")
         (message "No FCRDNS"))
    
        <opensmtpd-filter-phase> fieldname: 'conditions' is a list of unique
        <opensmtpd-conditions-configuration> records.
        ice-9/boot-9.scm:1685:16: In procedure raise-exception:
        Throw to key `bad!' with args `((#<<opensmtpd-conditions-configuration> condition: "fcrdns" not: #t regex: #f table: #f> #<<opensmtpd-conditions-configuration> condition: "fcrdns" not: #t regex: #f table: #f>))'.
        
        Entering a new prompt.  Type `,bt' for a backtrace or `,q' to continue.
3.  sanitize the phase-name
    
        (opensmtpd-filter-phase
         (name "filter")
         (phase "hello")
         (decision "bypass")
         (conditions
          (list
           (opensmtpd-conditions-configuration
            (condition "auth")))))
    
        <opensmtpd-filter-phase> fieldname: 'phase' is of type string.  The string can be either 'connect', 'helo', 'mail-from', 'rcpt-to', 'data', or 'commit.'
         ice-9/boot-9.scm:1685:16: In procedure raise-exception:
        Throw to key `bad!' with args `("hello")'.
        
        Entering a new prompt.  Type `,bt' for a backtrace or `,q' to continue.


## Changes to the records eleminate potential errors like

misspelling a table name, or calling an action that is not defined.

The `<opensmtpd-configuration>` used to be defined this way:

    (service opensmtpd-service
             (opensmtpd-configuration
              (includes ...)
              (tables ...)
              (pkis ...)
              (filters ...)
              (listen-on ...)
              (actions ...)
              (matches ...)))

It would be possible to give a table a name of &ldquo;password-table&rdquo;, but then later
to refer to it as &ldquo;passwords-table&rdquo;, which would NOT have worked.  Like so:

    (service opensmtpd-service
             (opensmtpd-configuration
              (tables (list (opensmtpd-table
                             (name "<passwords-table>")
                             (values
                              (list
                               (cons "joshua"
                                     "$encrypted$password"))))))
              (listen-on
               (list (opensmtpd-listen-on
                      (auth "<password-table>" ))))
              (actions ...)
              (matches ...)))

Now instead, you define the table where it is used!

    (opensmtpd-listen-on
     (interface interface)
     (port 587)
     (secure-connection "tls-require")
     (pki smtp.gnucode.me)
     (auth (opensmtpd-table
            (name "creds")
            (values
             (list
              (cons "joshua"
                    "$encrypted$password")))))
     (filters (list filter-dkimsign)))


