diff mbox

gnu: Add kerberos service.

Message ID 1478721522-312-1-git-send-email-jmd@gnu.org
State New
Headers show

Commit Message

John Darrington Nov. 9, 2016, 7:58 p.m. UTC
* gnu/services/kerberos.scm (krb5-realm, krb5-configuration,
krb5-service-type): New variables.
---
 gnu/services/kerberos.scm | 230 +++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 229 insertions(+), 1 deletion(-)

Comments

John Darrington Nov. 18, 2016, 3:23 p.m. UTC | #1
Any comments on this before I push it??

On Wed, Nov 09, 2016 at 08:58:42PM +0100, John Darrington wrote:
     * gnu/services/kerberos.scm (krb5-realm, krb5-configuration,
     krb5-service-type): New variables.
     ---
      gnu/services/kerberos.scm | 230 +++++++++++++++++++++++++++++++++++++++++++++-
      1 file changed, 229 insertions(+), 1 deletion(-)
     
     diff --git a/gnu/services/kerberos.scm b/gnu/services/kerberos.scm
     index 144c71b..2147dd8 100644
     --- a/gnu/services/kerberos.scm
     +++ b/gnu/services/kerberos.scm
     @@ -22,9 +22,237 @@
        #:use-module (gnu system pam)
        #:use-module (guix gexp)
        #:use-module (guix records)
     +  #:use-module (srfi srfi-1)
        #:export (pam-krb5-configuration
                  pam-krb5-configuration?
     -            pam-krb5-service-type))
     +            pam-krb5-service-type
     +
     +            krb5-realm
     +            krb5-realm?
     +
     +            krb5-configuration
     +            krb5-configuration?
     +            krb5-service-type))
     +
     +(define-record-type* <krb5-realm>
     +  krb5-realm      make-krb5-realm
     +  krb5-realm?
     +  (name                krb5-realm-name)
     +
     +  (admin-server        krb5-realm-admin-server)
     +  (kdc                 krb5-realm-kdc)
     +  (auth-to-local       krb5-realm-auth-to-local (default '()))
     +  (auth-to-local-names krb5-realm-auth-to-local-names (default '()))
     +  (http-anchors        krb5-realm-http-anchors (default '()))
     +  (default-domain      krb5-realm-default-domain (default #f))
     +  (kpasswd-server      krb5-realm-kpasswd-server (default #f))
     +  (master-kdc          krb5-realm-master-kdc (default #f))
     +  (v4-instance-convert krb5-realm-v4-instance-convert (default '()))
     +  (v4-realm            krb5-realm-v4-realm (default #f)))
     +
     +
     +(define-syntax  guile->krb-cfg
     +  (syntax-rules ()
     +    ((guile->krb-cfg accessor what)
     +     (string-map
     +      (lambda (c) (if (eq? c #\-) #\_ c))
     +      (string-drop (symbol->string accessor)
     +                   (string-length what))))))
     +
     +(define-syntax cfg-opt-string
     +  (syntax-rules ()
     +    ((cfg-opt-string accessor realm)
     +     (if (accessor realm)
     +         (format #f "\n\t~a = ~a"
     +                        (guile->krb-cfg 'accessor "krb5-realm-")
     +                        (accessor realm))
     +         ""))))
     +
     +
     +;; Generates one line of text per list item
     +(define-syntax cfg-opt-list
     +  (syntax-rules ()
     +    ((cfg-opt-list accessor realm)
     +     (if (not (null? (accessor realm)))
     +         (string-concatenate
     +          (map (lambda (item)
     +                 (format #f "\n\t~a = ~a"
     +                         (guile->krb-cfg 'accessor "krb5-realm-")
     +                         item))
     +              (accessor realm)))
     +     ""))))
     +
     +(define (krb5-realm->string realm)
     +  "Return a string suitable for a krb5.conf fragment representing REALM"
     +  (string-append "\n" (krb5-realm-name realm) " = {"
     +                 (cfg-opt-string krb5-realm-kdc realm)
     +                 (cfg-opt-string krb5-realm-admin-server realm)
     +                 (cfg-opt-string krb5-realm-default-domain realm)
     +                 (cfg-opt-list krb5-realm-auth-to-local realm)
     +                 (cfg-opt-list krb5-realm-http-anchors realm)
     +                 (cfg-opt-string krb5-realm-kpasswd-server realm)
     +                 (cfg-opt-string krb5-realm-master-kdc realm)
     +                 (cfg-opt-string krb5-realm-v4-realm realm)
     +                 "\n}"))
     +
     +
     +;; For explanation of these fields see man 5 krb5.conf
     +(define-record-type* <krb5-configuration>
     +  krb5-configuration    make-krb5-configuration
     +  krb5-configuration?
     +
     +  ;; [libdefaults]
     +  (allow-weak-crypto          krb5-configuration-allow-weak-crypto (default #f))
     +  (ap-req-checksum-type       krb5-configuration-ap-req-checksum-type (default #f))
     +  (canonicalize               krb5-configuration-canonicalize (default #f))
     +  (ccache-type                krb5-configuration-ccache-type (default #f))
     +  (clockskew                  krb5-configuration-clockskew (default #f))
     +  (default-ccache-name        krb5-configuration-default-ccache-name (default #f))
     +  (default-client-keytab-name krb5-configuration-default-client-keytab-name
     +                                                                     (default #f))
     +  (default-keytab-name        krb5-configuration-default-keytab-name (default #f))
     +  (default-realm              krb5-configuration-default-realm (default #f))
     +  (default-tgs-enctypes       krb5-configuration-default-tgs-enctypes (default #f))
     +  (default-tkt-enctypes       krb5-configuration-default-tkt-enctypes (default #f))
     +  (dns-canonicalize-hostname  krb5-configuration-dns-canonicalize-hostname
     +                              (default #t))
     +  (dns-lookup-kdc             krb5-configuration-dns-lookup-kdc
     +                              (default #f))
     +  (err-fmt                    krb5-configuration-err-fmt (default #f))
     +  (extra-addresses            krb5-configuration-extra-addresses
     +                              (default #f))
     +  (forwardable                krb5-configuration-forwardable (default #t))
     +  (ignore-acceptor-hostname   krb5-configuration-ignore-acceptor-hostname
     +                              (default #f))
     +  (k5login-authoritative      krb5-configuration-k5login-authoritative (default #t))
     +  (k5login-directory          krb5-configuration-k5login-directory (default #f))
     +  (kcm-mach-service           krb5-configuration-kcm-mach-service
     +                                (default "org.h5l.kcm"))
     +  (kcm-socket                 krb5-configuration-kcm-socket
     +                                (default "/var/run/.heim_org.h5l.kcm-socket"))
     +  (kdc-default-options        krb5-configuration-kdc-default-options
     +                                (default #f))
     +  (kdc-timesync               krb5-configuration-kdc-timesync (default #t))
     +  (kdc-req-checksum-type      krb5-configuration-kdc-req-checksum-type (default #f))
     +  (noaddresses                krb5-configuration-noaddresses
     +                               (default #f))
     +  (permitted-enctypes         krb5-configuration-permitted-enctypes
     +                              (default #f))
     +  (plugin-base-dir            krb5-configuration-plugin-base-dir
     +                                (default #f))
     +  (preferred-preauth-types    krb5-configuration-preferred-preauth-types
     +                              (default #f))
     +  (proxiable                  krb5-configuration-proxiable (default #f))
     +  (rdns                       krb5-configuration-rdns (default #t))
     +  (realm-try-domains          krb5-configuration-realm-try-domains
     +                               (default #f))
     +  (renew-lifetime             krb5-configuration-renew-lifetime
     +                              (default #f))
     +  (safe-checksum-type         krb5-configuration-safe-checksum-type
     +                              (default #f))
     +  (ticket-lifetime            krb5-configuration-ticket-lifetime
     +                              (default #f))
     +  (udp-preference-limit       krb5-configuration-udp-preference-limit
     +                              (default #f))
     +  (verify-ap-req-nofail       krb5-configuration-verify-ap-req-nofail
     +                              (default #f))
     +
     +  ;;[realms]
     +  (realms                     krb5-configuration-realms)
     +
     +  ;;[domain_realm]
     +  (domain-realm-map           krb5-configuration-domain-realm-map (default '())))
     +
     +
     +(define-syntax cfg-string
     +  (syntax-rules ()
     +    ((cfg-string accessor config)
     +     (if (accessor config)
     +         (format #f "\n\t~a = ~a"
     +                 (guile->krb-cfg 'accessor "krb5-configuration-")
     +                 (accessor config))
     +         ""))))
     +
     +(define-syntax cfg-boolean
     +  (syntax-rules ()
     +    ((cfg-string accessor config)
     +     (format #f "\n\t~a = ~a"
     +                    (guile->krb-cfg 'accessor "krb5-configuration-")
     +                    (if (accessor config) "true" "false")))))
     +
     +;; Generates a comma separated list
     +(define-syntax cfg-list
     +  (syntax-rules ()
     +    ((cfg-string accessor config)
     +     (if (accessor config)
     +         (format #f "\n\t~a = ~a"
     +                 (guile->krb-cfg 'accessor "krb5-configuration-")
     +                 (fold (lambda (i prev)
     +                         (string-append prev
     +                                        (if (zero? (string-length prev))
     +                                            ""  ", ") i)) ""
     +                                            (accessor config))) ""))))
     +
     +(define (krb5-configuration-file config)
     +  "Create a Kerberos 5 configuration file based on CONFIG"
     +  (mixed-text-file "krb5.conf"
     +
     +"[libdefaults]"
     +(cfg-string  krb5-configuration-default-realm config)
     +(cfg-boolean krb5-configuration-allow-weak-crypto config)
     +(cfg-string  krb5-configuration-ap-req-checksum-type config)
     +(cfg-boolean krb5-configuration-canonicalize config)
     +(cfg-string  krb5-configuration-ccache-type config)
     +(cfg-string  krb5-configuration-clockskew config)
     +(cfg-string  krb5-configuration-default-ccache-name config)
     +(cfg-string  krb5-configuration-default-client-keytab-name config)
     +(cfg-string  krb5-configuration-default-keytab-name config)
     +(cfg-string  krb5-configuration-default-tgs-enctypes config)
     +(cfg-string  krb5-configuration-default-tkt-enctypes config)
     +(cfg-boolean krb5-configuration-dns-canonicalize-hostname config)
     +(cfg-boolean krb5-configuration-dns-lookup-kdc config)
     +(cfg-string  krb5-configuration-err-fmt config)
     +(cfg-list    krb5-configuration-extra-addresses config)
     +(cfg-boolean krb5-configuration-ignore-acceptor-hostname config)
     +(cfg-boolean krb5-configuration-k5login-authoritative config)
     +(cfg-string  krb5-configuration-k5login-directory config)
     +(cfg-boolean krb5-configuration-forwardable config)
     +(cfg-string  krb5-configuration-kcm-mach-service config)
     +(cfg-string  krb5-configuration-kcm-socket config)
     +(cfg-string  krb5-configuration-kdc-default-options config)
     +(cfg-boolean krb5-configuration-kdc-timesync config)
     +(cfg-boolean krb5-configuration-proxiable config)
     +(cfg-string  krb5-configuration-kdc-req-checksum-type config)
     +(cfg-boolean krb5-configuration-noaddresses config)
     +(cfg-list    krb5-configuration-permitted-enctypes config)
     +(cfg-string  krb5-configuration-plugin-base-dir config)
     +(cfg-list    krb5-configuration-preferred-preauth-types config)
     +(cfg-boolean krb5-configuration-rdns config)
     +(cfg-string  krb5-configuration-realm-try-domains config)
     +(cfg-string  krb5-configuration-renew-lifetime config)
     +(cfg-string  krb5-configuration-safe-checksum-type config)
     +(cfg-string  krb5-configuration-ticket-lifetime config)
     +(cfg-string  krb5-configuration-udp-preference-limit config)
     +(cfg-boolean krb5-configuration-verify-ap-req-nofail config)
     +
     +"\n\n[realms]"
     +(string-concatenate (map krb5-realm->string (krb5-configuration-realms config)))
     +
     +"\n"))
     +
     +
     +(define (krb5-etc-service config)
     +  (list `("krb5.conf" ,(krb5-configuration-file config))))
     +
     +
     +(define krb5-service-type
     +  (service-type (name 'krb5)
     +                (extensions
     +                 (list (service-extension etc-service-type
     +                                          krb5-etc-service)))))
     +
     +
     +
      
      (define-record-type* <pam-krb5-configuration>
        pam-krb5-configuration  make-pam-krb5-configuration
     -- 
     2.1.4
Ludovic Courtès Nov. 18, 2016, 10:51 p.m. UTC | #2
Hello!

John Darrington <jmd@gnu.org> skribis:

> * gnu/services/kerberos.scm (krb5-realm, krb5-configuration,
> krb5-service-type): New variables.

Could you add documentation in guix.texi, along with an example of how
to use it?

I very strongly encourage you to write a system test for this as well.
Essentially, it’s just about writing down in a file a test that you’ve
already run anyway.  I’m happy to help if needed.  The main ideas are
described in
<https://www.gnu.org/software/guix/news/guixsd-system-tests.html>.

(I think this will become a requirement for future patches.  :-))

> +(define-record-type* <krb5-realm>
> +  krb5-realm      make-krb5-realm
> +  krb5-realm?
> +  (name                krb5-realm-name)
> +
> +  (admin-server        krb5-realm-admin-server)
> +  (kdc                 krb5-realm-kdc)
> +  (auth-to-local       krb5-realm-auth-to-local (default '()))
> +  (auth-to-local-names krb5-realm-auth-to-local-names (default '()))
> +  (http-anchors        krb5-realm-http-anchors (default '()))
> +  (default-domain      krb5-realm-default-domain (default #f))
> +  (kpasswd-server      krb5-realm-kpasswd-server (default #f))
> +  (master-kdc          krb5-realm-master-kdc (default #f))
> +  (v4-instance-convert krb5-realm-v4-instance-convert (default '()))
> +  (v4-realm            krb5-realm-v4-realm (default #f)))

I find it helpful to add a one- or two-line comment above stating what
this is, and margin comments next to the fields to give an idea of what
their type is.

Could you try something along these lines?

> +(define-syntax  guile->krb-cfg
> +  (syntax-rules ()
> +    ((guile->krb-cfg accessor what)
> +     (string-map
> +      (lambda (c) (if (eq? c #\-) #\_ c))
> +      (string-drop (symbol->string accessor)
> +                   (string-length what))))))
> +
> +(define-syntax cfg-opt-string
> +  (syntax-rules ()
> +    ((cfg-opt-string accessor realm)
> +     (if (accessor realm)
> +         (format #f "\n\t~a = ~a"
> +                        (guile->krb-cfg 'accessor "krb5-realm-")
> +                        (accessor realm))
> +         ""))))
> +
> +
> +;; Generates one line of text per list item
> +(define-syntax cfg-opt-list
> +  (syntax-rules ()
> +    ((cfg-opt-list accessor realm)
> +     (if (not (null? (accessor realm)))
> +         (string-concatenate
> +          (map (lambda (item)
> +                 (format #f "\n\t~a = ~a"
> +                         (guile->krb-cfg 'accessor "krb5-realm-")
> +                         item))
> +              (accessor realm)))
> +     ""))))

Would Andy’s ‘define-configuration’ (in mail.scm and cups.scm) be usable
here, possibly with some adjustments?  It has the advantage that
configuration fields, their types, and their docstring all appear at the
same place.  I think we should consolidate it into a single API.

If not, please mind the naming convention (info "(guix) Formatting
Code"), and use ‘define-syntax-rule’ for macros with a single pattern.

Perhaps pass the whole file through M-x indent-region to fix
inconsistencies.

> +;; For explanation of these fields see man 5 krb5.conf
> +(define-record-type* <krb5-configuration>
> +  krb5-configuration    make-krb5-configuration
> +  krb5-configuration?
> +
> +  ;; [libdefaults]
> +  (allow-weak-crypto          krb5-configuration-allow-weak-crypto (default #f))
> +  (ap-req-checksum-type       krb5-configuration-ap-req-checksum-type (default #f))
> +  (canonicalize               krb5-configuration-canonicalize (default #f))
> +  (ccache-type                krb5-configuration-ccache-type (default #f))
> +  (clockskew                  krb5-configuration-clockskew (default #f))
> +  (default-ccache-name        krb5-configuration-default-ccache-name (default #f))
> +  (default-client-keytab-name krb5-configuration-default-client-keytab-name
> +                                                                     (default #f))
> +  (default-keytab-name        krb5-configuration-default-keytab-name (default #f))
> +  (default-realm              krb5-configuration-default-realm (default #f))
> +  (default-tgs-enctypes       krb5-configuration-default-tgs-enctypes (default #f))
> +  (default-tkt-enctypes       krb5-configuration-default-tkt-enctypes (default #f))
> +  (dns-canonicalize-hostname  krb5-configuration-dns-canonicalize-hostname
> +                              (default #t))
> +  (dns-lookup-kdc             krb5-configuration-dns-lookup-kdc
> +                              (default #f))
> +  (err-fmt                    krb5-configuration-err-fmt (default #f))
> +  (extra-addresses            krb5-configuration-extra-addresses
> +                              (default #f))
> +  (forwardable                krb5-configuration-forwardable (default #t))
> +  (ignore-acceptor-hostname   krb5-configuration-ignore-acceptor-hostname
> +                              (default #f))
> +  (k5login-authoritative      krb5-configuration-k5login-authoritative (default #t))
> +  (k5login-directory          krb5-configuration-k5login-directory (default #f))
> +  (kcm-mach-service           krb5-configuration-kcm-mach-service
> +                                (default "org.h5l.kcm"))
> +  (kcm-socket                 krb5-configuration-kcm-socket
> +                                (default "/var/run/.heim_org.h5l.kcm-socket"))
> +  (kdc-default-options        krb5-configuration-kdc-default-options
> +                                (default #f))
> +  (kdc-timesync               krb5-configuration-kdc-timesync (default #t))
> +  (kdc-req-checksum-type      krb5-configuration-kdc-req-checksum-type (default #f))
> +  (noaddresses                krb5-configuration-noaddresses
> +                               (default #f))
> +  (permitted-enctypes         krb5-configuration-permitted-enctypes
> +                              (default #f))
> +  (plugin-base-dir            krb5-configuration-plugin-base-dir
> +                                (default #f))
> +  (preferred-preauth-types    krb5-configuration-preferred-preauth-types
> +                              (default #f))
> +  (proxiable                  krb5-configuration-proxiable (default #f))
> +  (rdns                       krb5-configuration-rdns (default #t))
> +  (realm-try-domains          krb5-configuration-realm-try-domains
> +                               (default #f))
> +  (renew-lifetime             krb5-configuration-renew-lifetime
> +                              (default #f))
> +  (safe-checksum-type         krb5-configuration-safe-checksum-type
> +                              (default #f))
> +  (ticket-lifetime            krb5-configuration-ticket-lifetime
> +                              (default #f))
> +  (udp-preference-limit       krb5-configuration-udp-preference-limit
> +                              (default #f))
> +  (verify-ap-req-nofail       krb5-configuration-verify-ap-req-nofail
> +                              (default #f))
> +
> +  ;;[realms]
> +  (realms                     krb5-configuration-realms)
> +
> +  ;;[domain_realm]
> +  (domain-realm-map           krb5-configuration-domain-realm-map (default '())))

Woow!  :-)  Please use full separate words; use question marks for
Boolean fields.

> +(define (krb5-etc-service config)
> +  (list `("krb5.conf" ,(krb5-configuration-file config))))
> +
> +
> +(define krb5-service-type
> +  (service-type (name 'krb5)
> +                (extensions
> +                 (list (service-extension etc-service-type
> +                                          krb5-etc-service)))))

So this service doesn’t do anything by itself.  Perhaps it should also
create a Shepherd service for the Kerberos daemon, or something like
that?

Thank you!

Ludo’.
John Darrington Nov. 19, 2016, 6:57 a.m. UTC | #3
On Fri, Nov 18, 2016 at 11:51:16PM +0100, Ludovic Court??s wrote:
     Hello!
     
     John Darrington <jmd@gnu.org> skribis:
     
     > * gnu/services/kerberos.scm (krb5-realm, krb5-configuration,
     > krb5-service-type): New variables.
     
     Could you add documentation in guix.texi, along with an example of how
     to use it?

I can make an attempt to do that.   Kerberos however is a complicated thing
with a large number of options - not all of which I pretend to understand.
I think it is better to have something undocumented rather than documented
wrong.   - and I can give an example of how *I* use it - but that should
not be regarded as a canonical example of how everyone should use it.
     
     I very strongly encourage you to write a system test for this as well.
     Essentially, it???s just about writing down in a file a test that you???ve
     already run anyway.  I???m happy to help if needed.  The main ideas are
     described in
     <https://www.gnu.org/software/guix/news/guixsd-system-tests.html>.
     
You are right.  Tests for things like this are needed.  But we have a chicken
and egg situation.  We can't really write a test for the client without a server.
And we can't write a test for the server without a client. ... something has
to come first.   Of course I could, wait until I have absolutely everything
done before I commit, but then I a) run the risk of losing everything, if  I
have a disk crash; and b) rule out all possibility of getting any contribution
from others.

     > +(define-record-type* <krb5-realm>
     > +  krb5-realm      make-krb5-realm
     > +  krb5-realm?
     > +  (name                krb5-realm-name)
     > +
     > +  (admin-server        krb5-realm-admin-server)
     > +  (kdc                 krb5-realm-kdc)
     > +  (auth-to-local       krb5-realm-auth-to-local (default '()))
     > +  (auth-to-local-names krb5-realm-auth-to-local-names (default '()))
     > +  (http-anchors        krb5-realm-http-anchors (default '()))
     > +  (default-domain      krb5-realm-default-domain (default #f))
     > +  (kpasswd-server      krb5-realm-kpasswd-server (default #f))
     > +  (master-kdc          krb5-realm-master-kdc (default #f))
     > +  (v4-instance-convert krb5-realm-v4-instance-convert (default '()))
     > +  (v4-realm            krb5-realm-v4-realm (default #f)))
     
     I find it helpful to add a one- or two-line comment above stating what
     this is, and margin comments next to the fields to give an idea of what
     their type is.
     
     Could you try something along these lines?

Again most of the info would be copied from the manpage krb5.conf(5).  I can 
do that if you think it would be useful.
     
     > +(define-syntax  guile->krb-cfg
     > +  (syntax-rules ()
     > +    ((guile->krb-cfg accessor what)
     > +     (string-map
     > +      (lambda (c) (if (eq? c #\-) #\_ c))
     > +      (string-drop (symbol->string accessor)
     > +                   (string-length what))))))
     > +
     > +(define-syntax cfg-opt-string
     > +  (syntax-rules ()
     > +    ((cfg-opt-string accessor realm)
     > +     (if (accessor realm)
     > +         (format #f "\n\t~a = ~a"
     > +                        (guile->krb-cfg 'accessor "krb5-realm-")
     > +                        (accessor realm))
     > +         ""))))
     > +
     > +
     > +;; Generates one line of text per list item
     > +(define-syntax cfg-opt-list
     > +  (syntax-rules ()
     > +    ((cfg-opt-list accessor realm)
     > +     (if (not (null? (accessor realm)))
     > +         (string-concatenate
     > +          (map (lambda (item)
     > +                 (format #f "\n\t~a = ~a"
     > +                         (guile->krb-cfg 'accessor "krb5-realm-")
     > +                         item))
     > +              (accessor realm)))
     > +     ""))))
     
     Would Andy???s ???define-configuration??? (in mail.scm and cups.scm) be usable
     here, possibly with some adjustments?  It has the advantage that
     configuration fields, their types, and their docstring all appear at the
     same place.  I think we should consolidate it into a single API.

I will have a look to see if I can a) understand it; and b) use it in any way.
     
     
     > +;; For explanation of these fields see man 5 krb5.conf
     > +(define-record-type* <krb5-configuration>
     > +  krb5-configuration    make-krb5-configuration
     > +  krb5-configuration?
     > +
     > +  ;; [libdefaults]
     > +  (allow-weak-crypto          krb5-configuration-allow-weak-crypto (default #f))
     > +  (ap-req-checksum-type       krb5-configuration-ap-req-checksum-type (default #f))
     > +  (canonicalize               krb5-configuration-canonicalize (default #f))
     > +  (ccache-type                krb5-configuration-ccache-type (default #f))
     > +  (clockskew                  krb5-configuration-clockskew (default #f))
     > +  (default-ccache-name        krb5-configuration-default-ccache-name (default #f))
     > +  (default-client-keytab-name krb5-configuration-default-client-keytab-name
     > +                                                                     (default #f))
     > +  (default-keytab-name        krb5-configuration-default-keytab-name (default #f))
     > +  (default-realm              krb5-configuration-default-realm (default #f))
     > +  (default-tgs-enctypes       krb5-configuration-default-tgs-enctypes (default #f))
     > +  (default-tkt-enctypes       krb5-configuration-default-tkt-enctypes (default #f))
     > +  (dns-canonicalize-hostname  krb5-configuration-dns-canonicalize-hostname
     > +                              (default #t))
     > +  (dns-lookup-kdc             krb5-configuration-dns-lookup-kdc
     > +                              (default #f))
     > +  (err-fmt                    krb5-configuration-err-fmt (default #f))
     > +  (extra-addresses            krb5-configuration-extra-addresses
     > +                              (default #f))
     > +  (forwardable                krb5-configuration-forwardable (default #t))
     > +  (ignore-acceptor-hostname   krb5-configuration-ignore-acceptor-hostname
     > +                              (default #f))
     > +  (k5login-authoritative      krb5-configuration-k5login-authoritative (default #t))
     > +  (k5login-directory          krb5-configuration-k5login-directory (default #f))
     > +  (kcm-mach-service           krb5-configuration-kcm-mach-service
     > +                                (default "org.h5l.kcm"))
     > +  (kcm-socket                 krb5-configuration-kcm-socket
     > +                                (default "/var/run/.heim_org.h5l.kcm-socket"))
     > +  (kdc-default-options        krb5-configuration-kdc-default-options
     > +                                (default #f))
     > +  (kdc-timesync               krb5-configuration-kdc-timesync (default #t))
     > +  (kdc-req-checksum-type      krb5-configuration-kdc-req-checksum-type (default #f))
     > +  (noaddresses                krb5-configuration-noaddresses
     > +                               (default #f))
     > +  (permitted-enctypes         krb5-configuration-permitted-enctypes
     > +                              (default #f))
     > +  (plugin-base-dir            krb5-configuration-plugin-base-dir
     > +                                (default #f))
     > +  (preferred-preauth-types    krb5-configuration-preferred-preauth-types
     > +                              (default #f))
     > +  (proxiable                  krb5-configuration-proxiable (default #f))
     > +  (rdns                       krb5-configuration-rdns (default #t))
     > +  (realm-try-domains          krb5-configuration-realm-try-domains
     > +                               (default #f))
     > +  (renew-lifetime             krb5-configuration-renew-lifetime
     > +                              (default #f))
     > +  (safe-checksum-type         krb5-configuration-safe-checksum-type
     > +                              (default #f))
     > +  (ticket-lifetime            krb5-configuration-ticket-lifetime
     > +                              (default #f))
     > +  (udp-preference-limit       krb5-configuration-udp-preference-limit
     > +                              (default #f))
     > +  (verify-ap-req-nofail       krb5-configuration-verify-ap-req-nofail
     > +                              (default #f))
     > +
     > +  ;;[realms]
     > +  (realms                     krb5-configuration-realms)
     > +
     > +  ;;[domain_realm]
     > +  (domain-realm-map           krb5-configuration-domain-realm-map (default '())))
     
     Woow!  :-)  Please use full separate words; use question marks for
     Boolean fields.
ok.
     
     > +(define (krb5-etc-service config)
     > +  (list `("krb5.conf" ,(krb5-configuration-file config))))
     > +
     > +
     > +(define krb5-service-type
     > +  (service-type (name 'krb5)
     > +                (extensions
     > +                 (list (service-extension etc-service-type
     > +                                          krb5-etc-service)))))
     
     So this service doesn???t do anything by itself.  Perhaps it should also
     create a Shepherd service for the Kerberos daemon, or something like
     that?

Kerberos is three headed dog.  There is the client, the "key distribution center",
the admin server, the ticket granting server, and the application server.
Ooops! that's 5 heads.

But this service is sufficient to get a client machine up and running and ready to
make requests and receive services from an external KDC and application server.

As you say, once we have a KDC and some simple kerberos enabled service in Guix, then
we can write some end to end tests.  It would be really great if someone can help with
those things.  In the meantime, this is a start.

J'
Ludovic Courtès Nov. 21, 2016, 8:59 a.m. UTC | #4
Hi!

John Darrington <john@darrington.wattle.id.au> skribis:

> On Fri, Nov 18, 2016 at 11:51:16PM +0100, Ludovic Court??s wrote:
>      Hello!
>      
>      John Darrington <jmd@gnu.org> skribis:
>      
>      > * gnu/services/kerberos.scm (krb5-realm, krb5-configuration,
>      > krb5-service-type): New variables.
>      
>      Could you add documentation in guix.texi, along with an example of how
>      to use it?
>
> I can make an attempt to do that.   Kerberos however is a complicated thing
> with a large number of options - not all of which I pretend to understand.
> I think it is better to have something undocumented rather than documented
> wrong.   - and I can give an example of how *I* use it - but that should
> not be regarded as a canonical example of how everyone should use it.

Maybe just give a rough overview in a couple of sentences, then an
example that makes sense to you, and then cross-references to the
upstream manual or documentation.

BTW, is this config file honored by any Kerberos implementation, or just
mit-krb5?

>      I very strongly encourage you to write a system test for this as well.
>      Essentially, it???s just about writing down in a file a test that you???ve
>      already run anyway.  I???m happy to help if needed.  The main ideas are
>      described in
>      <https://www.gnu.org/software/guix/news/guixsd-system-tests.html>.
>      
> You are right.  Tests for things like this are needed.  But we have a chicken
> and egg situation.  We can't really write a test for the client without a server.
> And we can't write a test for the server without a client. ... something has
> to come first.   Of course I could, wait until I have absolutely everything
> done before I commit, but then I a) run the risk of losing everything, if  I
> have a disk crash; and b) rule out all possibility of getting any contribution
> from others.

No you’re right, we can’t delay the contribution endlessly, so we have
to be flexible.  What I want to avoid is simply having big chunks of
code that we don’t really how to use and can’t tell if it works.

>      > +(define-record-type* <krb5-realm>
>      > +  krb5-realm      make-krb5-realm
>      > +  krb5-realm?
>      > +  (name                krb5-realm-name)
>      > +
>      > +  (admin-server        krb5-realm-admin-server)
>      > +  (kdc                 krb5-realm-kdc)
>      > +  (auth-to-local       krb5-realm-auth-to-local (default '()))
>      > +  (auth-to-local-names krb5-realm-auth-to-local-names (default '()))
>      > +  (http-anchors        krb5-realm-http-anchors (default '()))
>      > +  (default-domain      krb5-realm-default-domain (default #f))
>      > +  (kpasswd-server      krb5-realm-kpasswd-server (default #f))
>      > +  (master-kdc          krb5-realm-master-kdc (default #f))
>      > +  (v4-instance-convert krb5-realm-v4-instance-convert (default '()))
>      > +  (v4-realm            krb5-realm-v4-realm (default #f)))
>      
>      I find it helpful to add a one- or two-line comment above stating what
>      this is, and margin comments next to the fields to give an idea of what
>      their type is.
>      
>      Could you try something along these lines?
>
> Again most of the info would be copied from the manpage krb5.conf(5).  I can 
> do that if you think it would be useful.

Just one or two lines, whatever makes sense.

>      > +(define (krb5-etc-service config)
>      > +  (list `("krb5.conf" ,(krb5-configuration-file config))))
>      > +
>      > +
>      > +(define krb5-service-type
>      > +  (service-type (name 'krb5)
>      > +                (extensions
>      > +                 (list (service-extension etc-service-type
>      > +                                          krb5-etc-service)))))
>      
>      So this service doesn???t do anything by itself.  Perhaps it should also
>      create a Shepherd service for the Kerberos daemon, or something like
>      that?
>
> Kerberos is three headed dog.  There is the client, the "key distribution center",
> the admin server, the ticket granting server, and the application server.
> Ooops! that's 5 heads.
>
> But this service is sufficient to get a client machine up and running and ready to
> make requests and receive services from an external KDC and application server.
>
> As you say, once we have a KDC and some simple kerberos enabled service in Guix, then
> we can write some end to end tests.  It would be really great if someone can help with
> those things.  In the meantime, this is a start.

Heh, OK.

So client libraries of Kerberos implementations read that file?  IOW, is
it useful on its own already?

If the answer is “yes”, then it’s obviously OK to commit, and if it’s
client functionality, we cannot write tests yet, so that’s fine.

Thank you,
Ludo’.
diff mbox

Patch

diff --git a/gnu/services/kerberos.scm b/gnu/services/kerberos.scm
index 144c71b..2147dd8 100644
--- a/gnu/services/kerberos.scm
+++ b/gnu/services/kerberos.scm
@@ -22,9 +22,237 @@ 
   #:use-module (gnu system pam)
   #:use-module (guix gexp)
   #:use-module (guix records)
+  #:use-module (srfi srfi-1)
   #:export (pam-krb5-configuration
             pam-krb5-configuration?
-            pam-krb5-service-type))
+            pam-krb5-service-type
+
+            krb5-realm
+            krb5-realm?
+
+            krb5-configuration
+            krb5-configuration?
+            krb5-service-type))
+
+(define-record-type* <krb5-realm>
+  krb5-realm      make-krb5-realm
+  krb5-realm?
+  (name                krb5-realm-name)
+
+  (admin-server        krb5-realm-admin-server)
+  (kdc                 krb5-realm-kdc)
+  (auth-to-local       krb5-realm-auth-to-local (default '()))
+  (auth-to-local-names krb5-realm-auth-to-local-names (default '()))
+  (http-anchors        krb5-realm-http-anchors (default '()))
+  (default-domain      krb5-realm-default-domain (default #f))
+  (kpasswd-server      krb5-realm-kpasswd-server (default #f))
+  (master-kdc          krb5-realm-master-kdc (default #f))
+  (v4-instance-convert krb5-realm-v4-instance-convert (default '()))
+  (v4-realm            krb5-realm-v4-realm (default #f)))
+
+
+(define-syntax  guile->krb-cfg
+  (syntax-rules ()
+    ((guile->krb-cfg accessor what)
+     (string-map
+      (lambda (c) (if (eq? c #\-) #\_ c))
+      (string-drop (symbol->string accessor)
+                   (string-length what))))))
+
+(define-syntax cfg-opt-string
+  (syntax-rules ()
+    ((cfg-opt-string accessor realm)
+     (if (accessor realm)
+         (format #f "\n\t~a = ~a"
+                        (guile->krb-cfg 'accessor "krb5-realm-")
+                        (accessor realm))
+         ""))))
+
+
+;; Generates one line of text per list item
+(define-syntax cfg-opt-list
+  (syntax-rules ()
+    ((cfg-opt-list accessor realm)
+     (if (not (null? (accessor realm)))
+         (string-concatenate
+          (map (lambda (item)
+                 (format #f "\n\t~a = ~a"
+                         (guile->krb-cfg 'accessor "krb5-realm-")
+                         item))
+              (accessor realm)))
+     ""))))
+
+(define (krb5-realm->string realm)
+  "Return a string suitable for a krb5.conf fragment representing REALM"
+  (string-append "\n" (krb5-realm-name realm) " = {"
+                 (cfg-opt-string krb5-realm-kdc realm)
+                 (cfg-opt-string krb5-realm-admin-server realm)
+                 (cfg-opt-string krb5-realm-default-domain realm)
+                 (cfg-opt-list krb5-realm-auth-to-local realm)
+                 (cfg-opt-list krb5-realm-http-anchors realm)
+                 (cfg-opt-string krb5-realm-kpasswd-server realm)
+                 (cfg-opt-string krb5-realm-master-kdc realm)
+                 (cfg-opt-string krb5-realm-v4-realm realm)
+                 "\n}"))
+
+
+;; For explanation of these fields see man 5 krb5.conf
+(define-record-type* <krb5-configuration>
+  krb5-configuration    make-krb5-configuration
+  krb5-configuration?
+
+  ;; [libdefaults]
+  (allow-weak-crypto          krb5-configuration-allow-weak-crypto (default #f))
+  (ap-req-checksum-type       krb5-configuration-ap-req-checksum-type (default #f))
+  (canonicalize               krb5-configuration-canonicalize (default #f))
+  (ccache-type                krb5-configuration-ccache-type (default #f))
+  (clockskew                  krb5-configuration-clockskew (default #f))
+  (default-ccache-name        krb5-configuration-default-ccache-name (default #f))
+  (default-client-keytab-name krb5-configuration-default-client-keytab-name
+                                                                     (default #f))
+  (default-keytab-name        krb5-configuration-default-keytab-name (default #f))
+  (default-realm              krb5-configuration-default-realm (default #f))
+  (default-tgs-enctypes       krb5-configuration-default-tgs-enctypes (default #f))
+  (default-tkt-enctypes       krb5-configuration-default-tkt-enctypes (default #f))
+  (dns-canonicalize-hostname  krb5-configuration-dns-canonicalize-hostname
+                              (default #t))
+  (dns-lookup-kdc             krb5-configuration-dns-lookup-kdc
+                              (default #f))
+  (err-fmt                    krb5-configuration-err-fmt (default #f))
+  (extra-addresses            krb5-configuration-extra-addresses
+                              (default #f))
+  (forwardable                krb5-configuration-forwardable (default #t))
+  (ignore-acceptor-hostname   krb5-configuration-ignore-acceptor-hostname
+                              (default #f))
+  (k5login-authoritative      krb5-configuration-k5login-authoritative (default #t))
+  (k5login-directory          krb5-configuration-k5login-directory (default #f))
+  (kcm-mach-service           krb5-configuration-kcm-mach-service
+                                (default "org.h5l.kcm"))
+  (kcm-socket                 krb5-configuration-kcm-socket
+                                (default "/var/run/.heim_org.h5l.kcm-socket"))
+  (kdc-default-options        krb5-configuration-kdc-default-options
+                                (default #f))
+  (kdc-timesync               krb5-configuration-kdc-timesync (default #t))
+  (kdc-req-checksum-type      krb5-configuration-kdc-req-checksum-type (default #f))
+  (noaddresses                krb5-configuration-noaddresses
+                               (default #f))
+  (permitted-enctypes         krb5-configuration-permitted-enctypes
+                              (default #f))
+  (plugin-base-dir            krb5-configuration-plugin-base-dir
+                                (default #f))
+  (preferred-preauth-types    krb5-configuration-preferred-preauth-types
+                              (default #f))
+  (proxiable                  krb5-configuration-proxiable (default #f))
+  (rdns                       krb5-configuration-rdns (default #t))
+  (realm-try-domains          krb5-configuration-realm-try-domains
+                               (default #f))
+  (renew-lifetime             krb5-configuration-renew-lifetime
+                              (default #f))
+  (safe-checksum-type         krb5-configuration-safe-checksum-type
+                              (default #f))
+  (ticket-lifetime            krb5-configuration-ticket-lifetime
+                              (default #f))
+  (udp-preference-limit       krb5-configuration-udp-preference-limit
+                              (default #f))
+  (verify-ap-req-nofail       krb5-configuration-verify-ap-req-nofail
+                              (default #f))
+
+  ;;[realms]
+  (realms                     krb5-configuration-realms)
+
+  ;;[domain_realm]
+  (domain-realm-map           krb5-configuration-domain-realm-map (default '())))
+
+
+(define-syntax cfg-string
+  (syntax-rules ()
+    ((cfg-string accessor config)
+     (if (accessor config)
+         (format #f "\n\t~a = ~a"
+                 (guile->krb-cfg 'accessor "krb5-configuration-")
+                 (accessor config))
+         ""))))
+
+(define-syntax cfg-boolean
+  (syntax-rules ()
+    ((cfg-string accessor config)
+     (format #f "\n\t~a = ~a"
+                    (guile->krb-cfg 'accessor "krb5-configuration-")
+                    (if (accessor config) "true" "false")))))
+
+;; Generates a comma separated list
+(define-syntax cfg-list
+  (syntax-rules ()
+    ((cfg-string accessor config)
+     (if (accessor config)
+         (format #f "\n\t~a = ~a"
+                 (guile->krb-cfg 'accessor "krb5-configuration-")
+                 (fold (lambda (i prev)
+                         (string-append prev
+                                        (if (zero? (string-length prev))
+                                            ""  ", ") i)) ""
+                                            (accessor config))) ""))))
+
+(define (krb5-configuration-file config)
+  "Create a Kerberos 5 configuration file based on CONFIG"
+  (mixed-text-file "krb5.conf"
+
+"[libdefaults]"
+(cfg-string  krb5-configuration-default-realm config)
+(cfg-boolean krb5-configuration-allow-weak-crypto config)
+(cfg-string  krb5-configuration-ap-req-checksum-type config)
+(cfg-boolean krb5-configuration-canonicalize config)
+(cfg-string  krb5-configuration-ccache-type config)
+(cfg-string  krb5-configuration-clockskew config)
+(cfg-string  krb5-configuration-default-ccache-name config)
+(cfg-string  krb5-configuration-default-client-keytab-name config)
+(cfg-string  krb5-configuration-default-keytab-name config)
+(cfg-string  krb5-configuration-default-tgs-enctypes config)
+(cfg-string  krb5-configuration-default-tkt-enctypes config)
+(cfg-boolean krb5-configuration-dns-canonicalize-hostname config)
+(cfg-boolean krb5-configuration-dns-lookup-kdc config)
+(cfg-string  krb5-configuration-err-fmt config)
+(cfg-list    krb5-configuration-extra-addresses config)
+(cfg-boolean krb5-configuration-ignore-acceptor-hostname config)
+(cfg-boolean krb5-configuration-k5login-authoritative config)
+(cfg-string  krb5-configuration-k5login-directory config)
+(cfg-boolean krb5-configuration-forwardable config)
+(cfg-string  krb5-configuration-kcm-mach-service config)
+(cfg-string  krb5-configuration-kcm-socket config)
+(cfg-string  krb5-configuration-kdc-default-options config)
+(cfg-boolean krb5-configuration-kdc-timesync config)
+(cfg-boolean krb5-configuration-proxiable config)
+(cfg-string  krb5-configuration-kdc-req-checksum-type config)
+(cfg-boolean krb5-configuration-noaddresses config)
+(cfg-list    krb5-configuration-permitted-enctypes config)
+(cfg-string  krb5-configuration-plugin-base-dir config)
+(cfg-list    krb5-configuration-preferred-preauth-types config)
+(cfg-boolean krb5-configuration-rdns config)
+(cfg-string  krb5-configuration-realm-try-domains config)
+(cfg-string  krb5-configuration-renew-lifetime config)
+(cfg-string  krb5-configuration-safe-checksum-type config)
+(cfg-string  krb5-configuration-ticket-lifetime config)
+(cfg-string  krb5-configuration-udp-preference-limit config)
+(cfg-boolean krb5-configuration-verify-ap-req-nofail config)
+
+"\n\n[realms]"
+(string-concatenate (map krb5-realm->string (krb5-configuration-realms config)))
+
+"\n"))
+
+
+(define (krb5-etc-service config)
+  (list `("krb5.conf" ,(krb5-configuration-file config))))
+
+
+(define krb5-service-type
+  (service-type (name 'krb5)
+                (extensions
+                 (list (service-extension etc-service-type
+                                          krb5-etc-service)))))
+
+
+
 
 (define-record-type* <pam-krb5-configuration>
   pam-krb5-configuration  make-pam-krb5-configuration