(use-modules (base-system) (gnu build activation) (gnu services authentication) (gnu packages openldap) (gnu system shadow) (gnu system pam) (gnu services) (gnu services shepherd) (gnu packages admin) (gnu packages autotools) (gnu packages databases) (gnu packages linux) (gnu packages pkg-config) (gnu packages compression) (gnu packages perl) (guix packages) (guix gexp) (guix utils) (guix records) (ice-9 match) (ice-9 format) (ice-9 popen) (ice-9 textual-ports) (srfi srfi-1)) (define domain-to-dc (lambda (domain) (string-drop-right (apply string-append (map (lambda (component) (string-append "dc=" component ",")) (string-split domain #\.))) 1))) (define %domain-dc (domain-to-dc %domain-name)) (define slapd-rootpw (get-env-default "SLAPD_ROOTPW" "root")) (define %slapd-accounts (list (user-group (name "slapd") (system? #t)) (user-account (name "slapd") (group "slapd") (system? #t) (comment "OpenLDAP server user") (home-directory "/var/lib/slapd") (shell (file-append shadow "/sbin/nologin"))))) (define openldap-2.6-slapd (package (inherit openldap-2.6) (name "openldap-2.6-slapd") (native-inputs (modify-inputs (package-native-inputs openldap-2.6) (append libltdl unixodbc pkg-config wiredtiger perl lz4 snappy))) (arguments (substitute-keyword-arguments (package-arguments openldap-2.6) ((#:configure-flags flags) `(append '("--enable-modules" "--enable-backends" "--sharedstatedir=/var/lib/slapd" "--localstatedir=/var/lib/slapd" "--runstatedir=/var/run/slapd") ,flags )))))) (define %slapd-package openldap-2.6-slapd) (define %ldap-prefix #~(file-append #$%slapd-package "/etc/openldap/schema/")) (define-record-type* slapd-config-ldif make-slapd-config-ldif slapd-config-ldif? (package slapd-config-ldif-package (default %slapd-package)) (argsfile slapd-config-ldif-argsfile (default "/var/run/slapd/args")) (pidfile slapd-config-ldif-pidfile (default "/var/run/slapd/pid")) (schema-prefix slapd-config-ldif-schema-prefix (default "/var/lib/slapd/schema")) (schemas slapd-config-ldif-schemas (default '("core.ldif"))) (basedn slapd-config-ldif-basedn (default %domain-dc)) (rootdn slapd-config-ldif-rootdn (default "admin")) (rootpw slapd-config-ldif-rootpw (default "password")) (rootpwhash slapd-config-ldif-rootpwhash (default "secret")) (data-directory slapd-config-ldif-data-directory (default "/var/lib/slapd/data")) (conf-directory slapd-config-ldif-conf-directory (default "/var/lib/slapd/config")) (indices slapd-config-ldif-indices (default '("objectClass eq"))) (extra-config slapd-config-ldif-extra-config (default '()))) (define-gexp-compiler (slapd-config-ldif-compiler (file ) system target) (match file (($ package argsfile pidfile schema-prefix schemas basedn rootdn rootpw rootpwhash data-directory conf-directory indices extra-config) (gexp->derivation "cn=config.ldif" #~(call-with-output-file (ungexp output "out") (lambda (port) (display (string-append (ungexp-splicing `( ,@`("dn: cn=config\n") ,@`("objectClass: olcGlobal\n") ,@`("cn: config\n") ,@`("olcArgsFile: " ,argsfile "\n") ,@`("olcPidFile: " ,pidfile "\n\n") ,@`("dn: cn=schema,cn=config\n") ,@`("objectClass: olcSchemaConfig\n") ,@`("cn: schema\n\n") ,@(append-map (lambda (schema) `("include: file://" ,schema-prefix ,schema "\n")) schemas) ,@`("\ndn: olcDatabase=config,cn=config\n") ,@`("objectClass: olcDatabaseConfig\n") ,@`("olcDatabase: config\n") ,@`("olcRootDN: cn=" ,rootdn "," ,basedn "\n\n") ,@`("dn: olcDatabase=mdb,cn=config\n") ,@`("objectClass: olcDatabaseConfig\n") ,@`("objectClass: olcMdbConfig\n") ,@`("olcDatabase: mdb\n") ,@`("olcSuffix: " ,basedn "\n") ,@`("olcRootDN: cn=" ,rootdn "," ,basedn "\n") ,@`("olcRootPW: " ,rootpwhash "\n") ,@`("olcDbDirectory: " ,data-directory "\n") ,@(append-map (lambda (index) `("olcDbIndex: " ,index "\n")) indices) ,@`("\n") ,@extra-config))) port))) #:local-build? #t)))) (define-record-type* slapd-configuration make-slapd-configuration slapd-configuration? (pidfile slapd-configuration-pidfile (default "/var/run/slapd.pid")) (urls slapd-configuration-urls (default "ldap:/// ldapi:///")) (config slapd-configuration-config (default (slapd-config-ldif))) (extra-slapadd slapd-configuration-extra-slapadd (default "")) (extra-ldapadd slapd-configuration-extra-ldapadd (default ""))) (define slapd-shepherd-service (match-lambda (($ pidfile urls config extra-slapadd extra-ldapadd) (match-record config (package conf-directory rootdn rootpw basedn) (list (shepherd-service (documentation "Run the slapd daemon") (provision '(slapd)) (requirement '(networking user-processes syslogd)) (start #~(lambda () (if (directory-exists? (string-append #$conf-directory "/cn=config")) (display "slapd already configured, skipping...") (begin (system (string-join (list #$(file-append sudo "/bin/sudo") "--user=slapd" #$(file-append package "/sbin/slapadd") "-n" "0" "-F" #$conf-directory "-l" #$config))) (system (string-join (list #$(file-append sudo "/bin/sudo") "--user=slapd" #$(file-append package "/sbin/slapadd") "-n" "1" "-F" #$conf-directory "-l" #$(plain-file "base-slap.ldif" extra-slapadd)))))) (fork+exec-command (list #$(file-append package "/libexec/slapd") "-d" "-1" "-F" #$conf-directory "-u" "slapd" "-g" "slapd")) ; TODO figure out how to make it wait for slapd to be ready (if (file-exists? (string-append #$conf-directory "/.initialized")) (display "slapd already initialzed, skipping...") (begin (system (string-join (list #$(file-append sudo "/bin/sudo") "--user=slapd" #$(file-append package "/bin/ldapadd") "-D" (string-append "cn=" #$rootdn "," #$basedn) "-w" #$rootpw "-f" #$(plain-file "base-ldap.ldif" extra-ldapadd)))) (mknod (string-append #$conf-directory "/.initialized") 'regular #o400 0))))) (stop #~(make-kill-destructor)))))))) (define slapd-activation (match-lambda (($ pidfile urls config extra-slapadd) (match-record config (package conf-directory data-directory) #~(begin (use-modules (guix build utils)) (let* ((user (getpw "slapd"))) (mkdir-p/perms "/var/run/slapd" user #o700) (mkdir-p/perms #$data-directory user #o700) (mkdir-p/perms #$conf-directory user #o700))))))) (define slapd-service-type (service-type (name 'slapd) (description "OpenLDAP server daemon") (extensions (list (service-extension shepherd-root-service-type slapd-shepherd-service) (service-extension activation-service-type slapd-activation) (service-extension account-service-type (const %slapd-accounts)))) (default-value (slapd-configuration)))) (define (shell% proc fmt . args) (let* ((port (open-input-pipe (format #f "~?" fmt args))) (output (proc port))) (close-pipe port) output)) (define-public (shell . args) (apply shell% (cons get-string-all args))) (define-public (shell$ . args) (apply shell% (cons get-line args))) (define %slapd-conf (slapd-configuration (extra-ldapadd (string-join (list "dn: olcDatabase={1}mdb,cn=config" "changetype: modify" "replace: olcAccess" (string-append "olcAccess: {0}to attrs=cn,givenName,sn,userPassword,shadowLastChange,mail,loginShell,photo" "by self write by anonymous auth by dn.base=\"cn=admin," %domain-dc "\" write by * none") (string-append "olcAccess: {1}to * by self read by dn.base=\"cn=admin," %domain-dc "\" write by * read") ""))) (extra-slapadd (string-join (list "dn: dc=metznet,dc=ca" "dc: metznet" "o: Organization" "objectClass: dcObject" "objectClass: organization" "" "dn: cn=admin,dc=metznet,dc=ca" "cn: admin" "description: LDAP Administrator" "objectClass: organizationalRole" "objectClass: top" "roleOccupant: dc=metznet,dc=ca" "" "dn: ou=user,dc=metznet,dc=ca" "ou: user" "description: LDAP User" "objectClass: top" "objectClass: organizationalUnit" "" "dn: ou=group,dc=metznet,dc=ca" "ou: group" "description: LDAP Group" "objectClass: top" "objectClass: organizationalUnit" "") "\n")) (config (slapd-config-ldif (rootpw "password") (rootpwhash "{SSHA}620erGNXKg4D67G1xS0hNhr7h75VaIJl") (indices '("objectClass eq" "uid pres,eq" "mail pres,sub,eq" "cn,sn pres,sub,eq" "dc eq")) (schemas '("core.ldif" "cosine.ldif" "inetorgperson.ldif" "nis.ldif")) (schema-prefix #~(string-append #$%slapd-package "/etc/openldap/schema/")))))) (operating-system (inherit base-server-system) (host-name (string-append "ldap." %domain-name)) (packages (append (list strace %slapd-package) %my-server-packages)) (services (append (list (service slapd-service-type %slapd-conf)) %my-server-services)))