From 3714d26837b47ada22609daf932bfdde375e1a90 Mon Sep 17 00:00:00 2001 From: Noah Metz Date: Sat, 17 Sep 2022 19:28:48 -0600 Subject: [PATCH] Moved system files to channel and added libutp --- homelab.scm | 40 ++++ metznet/system/base-system.scm | 219 +++++++++++++++++++ metznet/system/clients/otto.scm | 106 ++++++++++ metznet/system/clients/patrache.scm | 67 ++++++ metznet/system/files/ldap/nmetz.ldif | 23 ++ metznet/system/servers/base.scm | 5 + metznet/system/servers/hypervisor.scm | 12 ++ metznet/system/servers/kadmin.scm | 126 +++++++++++ metznet/system/servers/ldap.scm | 290 ++++++++++++++++++++++++++ 9 files changed, 888 insertions(+) create mode 100644 metznet/system/base-system.scm create mode 100644 metznet/system/clients/otto.scm create mode 100644 metznet/system/clients/patrache.scm create mode 100644 metznet/system/files/ldap/nmetz.ldif create mode 100644 metznet/system/servers/base.scm create mode 100644 metznet/system/servers/hypervisor.scm create mode 100644 metznet/system/servers/kadmin.scm create mode 100644 metznet/system/servers/ldap.scm diff --git a/homelab.scm b/homelab.scm index 5523d1f..fab3215 100644 --- a/homelab.scm +++ b/homelab.scm @@ -183,3 +183,43 @@ (description "A very good space game. You will spend hours playing.") (home-page "https://fractalsoftworks.com") (license licenses:gpl3+))) + +(define-public libutp + (package + (name "libutp") + (version "2") + (source + (origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/bittorrent/libutp") + (commit "2b364cbb0650bdab64a5de2abb4518f9f228ec44"))) + (file-name (git-file-name name version)) + (sha256 + (base32 + "0yaiqksimnhwh14kmsq4kcyq6662b4ask36ni6p5n14dbyq1h2s6")))) + (build-system gnu-build-system) + (arguments + `(#:phases (modify-phases %standard-phases + (delete 'configure) + (replace 'install + (lambda* (#:key outputs #:allow-other-keys) + (let ((lib (string-append (assoc-ref outputs "out") "/lib")) + (include (string-append (assoc-ref outputs "out") "/include"))) + (install-file "libutp.so" lib) + (install-file "utp.h" include) + (install-file "utp_types.h" include) + #t)))) + #:make-flags '("libutp.so") + #:tests? #f)) + (home-page "https://github.com/bittorrent/libutp") + (synopsis "Shared library for libutp implementation of the LEDBAT protocol") + (description +"uTP is a TCP-like implementation of LEDBAT documented as a BitTorrent +extension in BEP-29. uTP provides reliable, ordered delivery while +maintaining minimum extra delay. It is implemented on top of UDP to be +cross-platform and functional today. As a result, uTP is the primary +transport for uTorrent peer-to-peer connections. + +uTP is written in C++, but the external interface is strictly C (ANSI C89).") + (license licenses:expat))) diff --git a/metznet/system/base-system.scm b/metznet/system/base-system.scm new file mode 100644 index 0000000..4899b00 --- /dev/null +++ b/metznet/system/base-system.scm @@ -0,0 +1,219 @@ +(define-module (base-system) + #:use-module (homelab) + #:use-module (gnu) + #:use-module (guix gexp) + #:use-module (nongnu packages linux) + #:use-module (gnu packages vim) + #:use-module (gnu system nss) + #:use-module (gnu packages certs) + #:use-module (gnu services pm) + #:use-module (gnu services vpn) + #:use-module (gnu packages vpn) + #:use-module (gnu services networking) + #:use-module (gnu packages networking) + #:use-module (gnu services ssh) + #:use-module (gnu packages dns) + #:use-module (gnu packages openldap) + #:use-module (gnu services kerberos) + #:use-module (gnu packages kerberos) + #:use-module (gnu packages admin) + #:use-module (gnu packages shells) + #:use-module (gnu services desktop) + #:use-module (gnu packages gnome) + #:use-module (gnu packages wm) + #:use-module (gnu services xorg) + #:use-module (gnu packages suckless) + #:use-module (gnu packages gnuzilla) + #:use-module (gnu packages terminals) + #:use-module (gnu packages virtualization) + #:use-module (gnu packages version-control) + #:use-module (nongnu system linux-initrd) + #:use-module (gnu system setuid) + #:use-module (ice-9 exceptions)) + +(define-public get-env-default + (lambda (env default) + (or + (getenv env) + default))) + +(define kadmin-prefix + (get-env-default "KADMIN_PREFIX" "kadmin.")) + +(define kdc-prefix + (get-env-default "KDC_PREFIX" "kadmin.")) + +(define-public %domain-caps + (get-env-default "DOMAIN_CAPS" "METZNET.CA")) + +(define-public %domain-name + (get-env-default "DOMAIN_NAME" "metznet.ca")) + +(define-public %domain-kadmin (string-append kadmin-prefix %domain-name)) +(define-public %domain-kdc (string-append kdc-prefix %domain-name)) + +(define-public %my-base-user-accounts (append (list + (user-account + (name "root") + (group "root") + (uid 0) + (password (crypt "root" "$6$salt")) + (shell (file-append zsh "/bin/zsh")))) + %base-user-accounts)) + +(define-public %my-base-groups (append (list + (user-group + (system? #t) + (name "realtime")) + (user-group + (system? #t) + (name "usb"))) + %base-groups)) + +(define-public %my-base-packages (append (list metznet-system openldap git neovim zsh nss-certs mit-krb5 openvpn openresolv) %base-packages)) + +(define-public %my-desktop-packages (append (list i3-wm i3status dmenu alacritty icecat) %my-base-packages)) + +(define-public %my-server-packages (append (list isc-dhcp) %my-base-packages)) + +(define-public %desktop-setuid-programs (append + (list (setuid-program + (program #~(string-append #$openvpn "/sbin/openvpn"))) + (setuid-program + (program #~(string-append #$openresolv "/sbin/resolvconf")))) + %setuid-programs)) + +(define (krb5-config kdc-server kadmin) (krb5-configuration + (default-realm %domain-caps) + (allow-weak-crypto? #t) + (rdns? #f) + (realms (list (krb5-realm + (name %domain-caps) + (admin-server kadmin) + (kdc kdc-server)))))) + +(define pam-krb5-config (pam-krb5-configuration + (pam-krb5 pam-krb5) + (minimum-uid 1000))) + +(define-public %default-keyboard-layout (keyboard-layout "us")) + +(define-public %kvm-udev-rule + (udev-rule + "65-kvm.rules" + "KERNEL==\"KVM\", GROUP=\"libvirt\", MODE=\"0660\"")) + +(define-public %usb-udev-rule + (udev-rule + "51-usb.rules" + (string-append "SUBSYSTEM==\"usb\", GROUP=\"usb\"\n" + "SUBSYSTEM==\"usbmisc\", GROUP=\"usb\""))) + +(define %tun-udev-rule + (udev-rule + "90-tun.rules" + "KERNEL==\"tun\", GROUP=\"netdev\", MODE=\"0660\", OPTIONS+=\"static_node=net/tun\"")) + +(define %backlight-udev-rule + (udev-rule + "55-backlight.rules" + "RUN+=\"/bin/chgrp video /sys/class/backlight/intel_backlight/brightness\"")) + +(define-public %my-desktop-services + (append (list (service openssh-service-type) + (service krb5-service-type (krb5-config %domain-kdc %domain-kadmin)) + (service pam-krb5-service-type pam-krb5-config) + ;(set-xorg-configuration + ; (xorg-configuration + ; (keyboard-layout %default-keyboard-layout))) + ) + (modify-services %desktop-services + (guix-service-type config => (guix-configuration + (inherit config) + (substitute-urls + (append (list "https://substitutes.nonguix.org") + %default-substitute-urls)) + (authorized-keys + (append (list (plain-file "nonguix.pub" + "(public-key + (ecc + (curve Ed25519) + (q #C1FD53E5D4CE971933EC50C9F307AE2171A2D3B52C804642A7A35F84F3A4EA98#)))")) + %default-authorized-guix-keys)))) + (elogind-service-type config => + (elogind-configuration (inherit config) + (handle-lid-switch-external-power 'suspend))) + (udev-service-type config => + (udev-configuration (inherit config) + (rules (append (list %tun-udev-rule + %backlight-udev-rule) + (udev-configuration-rules config))))) + (network-manager-service-type config => + (network-manager-configuration (inherit config) + (vpn-plugins (list network-manager-openvpn))))))) + +(define-public %my-base-services (append (list + (service openssh-service-type) + (service krb5-service-type (krb5-config %domain-kdc %domain-kadmin)) + (service pam-krb5-service-type pam-krb5-config)) + %base-services)) + +(define-public %my-server-services (append (list + (service dhcp-client-service-type) + (openvpn-client-service + #:config (openvpn-client-configuration + (openvpn openvpn) + (pid-file "/var/run/openvpn/client.pid") + (persist-key? #f) + (tls-auth "/etc/openvpn/ta.key")))) + %my-base-services)) + +(define-public base-operating-system + (operating-system + ;; Hostname and localization information + (host-name "base") + (timezone "America/Edmonton") + (locale "en_CA.utf8") + (keyboard-layout %default-keyboard-layout) + ;; Kernel and firmware definitions + (kernel linux) + (kernel-arguments (append '("console=ttyS0") %default-kernel-arguments)) + (firmware (list linux-firmware)) + (initrd microcode-initrd) + ;; Grub UEFI Bootloader installed to /boot/efi + (bootloader + (bootloader-configuration + (bootloader grub-efi-bootloader) + (targets '("/boot/efi")) + (keyboard-layout keyboard-layout))) + (file-systems (cons* + (file-system + (mount-point "/boot/efi") + (device "/dev/vda1") + (type "vfat") + (check? #f)) + (file-system + (mount-point "/") + (device "/dev/vda3") + (type "xfs") + (check? #f)) + %base-file-systems)) + (users %my-base-user-accounts) + (groups %my-base-groups) + (packages %my-base-packages) + (services %my-base-services))) + +(define-public base-server-system + (operating-system + (inherit base-operating-system) + (host-name "base-server") + (packages %my-server-packages) + (services %my-server-services))) + +(define-public base-desktop-system + (operating-system + (inherit base-operating-system) + (host-name "base-desktop") + (setuid-programs %desktop-setuid-programs) + (packages %my-desktop-packages) + (services %my-desktop-services))) diff --git a/metznet/system/clients/otto.scm b/metznet/system/clients/otto.scm new file mode 100644 index 0000000..516ad4a --- /dev/null +++ b/metznet/system/clients/otto.scm @@ -0,0 +1,106 @@ +(use-modules + (gnu) + (base-system) + (gnu packages tex) + (nongnu packages mozilla) + (nongnu packages nvidia) + (gnu packages networking) + (gnu packages shells) + (gnu packages pulseaudio) + (gnu packages virtualization) + (gnu packages spice) + (gnu packages vulkan) + (gnu packages pdf) + (gnu packages commencement) + (gnu packages base) + (gnu packages embedded) + (gnu packages linux) + (gnu packages docker) + (gnu services docker) + (gnu packages audio) + (gnu services cups) + (gnu services virtualization) + (gnu services networking) + (gnu services xorg) + (gnu services desktop) + (gnu services dbus) + (gnu services linux) + (gnu packages cups) + (gnu packages python) + (gnu packages xorg) + (gnu packages scanner) + (gnu packages dns) + (gnu services shepherd) + (gnu services base)) + +; (define (nvidia-insmod-shepherd-service config) +; (list (shepherd-service +; (provision '(nvidia-insmod)) +; (requirement '()) +; (start #~(lambda _ (and +; (zero? (system* (string-append #$nvidia-driver "/bin/nvidia-insmod")))))) +; (one-shot? #t) +; (auto-start? #t) +; (respawn? #f)))) +; +;(define nvidia-insmod-service-type +; (service-type +; (name 'nvidia-insmod-name) +; (extensions +; (list (service-extension shepherd-root-service-type nvidia-insmod-shepherd-service))) +; (default-value '()))) + +(operating-system + (inherit base-desktop-system) + (host-name "otto") + (hosts-file + (plain-file "hosts" + (string-append (local-host-aliases host-name) +"# LAN geofff.homelab ip +192.168.86.2 geofff.homelab\n"))) + (kernel-arguments '("modprobe.blacklist=nouveau")) + (packages (append (list blueman bluez bluez-alsa pulseaudio docker python openvswitch + qemu texlive firefox pavucontrol mupdf gcc-toolchain gnu-make + gcc-arm-none-eabi-7-2018-q2-update sane-backends-minimal xsane + cups xf86-video-nv xf86-input-libinput vulkan-loader vulkan-tools + (list isc-bind "utils")) %my-desktop-packages)) + (services (append (list + (simple-service 'blueman dbus-root-service-type (list blueman)) + (bluetooth-service #:auto-enable? #t) + (service docker-service-type) + (service openvswitch-service-type) + (set-xorg-configuration + (xorg-configuration + (keyboard-layout %default-keyboard-layout))) + (service sane-service-type) + (service cups-service-type + (cups-configuration + (web-interface? #t)))) + (modify-services %my-desktop-services + (udev-service-type config => + (udev-configuration (inherit config) + (rules (append (list + %usb-udev-rule) + (udev-configuration-rules config)))))))) + (users (cons* (user-account + (name "nmetz") + (comment "Noah Metz") + (group "users") + (home-directory "/home/nmetz") + (shell (file-append zsh "/bin/zsh")) + (supplementary-groups + `("wheel" "netdev" "audio" "video" "usb" "kvm" "lp" "docker"))) + %my-base-user-accounts)) + (file-systems + (cons* (file-system + (mount-point "/boot/efi") + (device (uuid "6E88-FE62" 'fat32)) + (type "vfat")) + (file-system + (mount-point "/") + (device + (uuid "ba93a043-9e58-466f-b90f-bf2a6bbf91fe" + 'ext4)) + (type "ext4")) + %base-file-systems))) + diff --git a/metznet/system/clients/patrache.scm b/metznet/system/clients/patrache.scm new file mode 100644 index 0000000..2b671cf --- /dev/null +++ b/metznet/system/clients/patrache.scm @@ -0,0 +1,67 @@ +(use-modules + (gnu) + (base-system) + (gnu packages tex) + (nongnu packages mozilla) + (gnu packages networking) + (gnu packages shells) + (gnu packages pulseaudio) + (gnu packages virtualization) + (gnu packages spice) + (gnu packages vulkan) + (gnu packages pdf) + (gnu packages commencement) + (gnu packages base) + (gnu packages embedded) + (gnu services cups) + (gnu services virtualization) + (gnu services xorg) + (gnu services desktop) + (gnu services linux) + (gnu packages cups) + (gnu packages xorg) + (gnu packages scanner) + (gnu packages dns) + (gnu services shepherd) + (gnu services base)) + +(operating-system + (inherit base-desktop-system) + (host-name "patrache") + (packages (append (list autoconf automake qemu texlive firefox pavucontrol mupdf gcc-toolchain gnu-make gcc-arm-none-eabi-7-2018-q2-update sane-backends-minimal xsane cups (list isc-bind "utils")) %my-desktop-packages)) + (services (append (list + (set-xorg-configuration + (xorg-configuration + (keyboard-layout %default-keyboard-layout))) + (service sane-service-type) + (service cups-service-type + (cups-configuration + (web-interface? #t)))) + (modify-services %my-desktop-services + (udev-service-type config => + (udev-configuration (inherit config) + (rules (append (list + %usb-udev-rule) + (udev-configuration-rules config)))))))) + (users (cons* (user-account + (name "nmetz") + (comment "Noah Metz") + (group "users") + (home-directory "/home/nmetz") + (shell (file-append zsh "/bin/zsh")) + (supplementary-groups + `("wheel" "netdev" "audio" "video" "usb" "kvm"))) + %my-base-user-accounts)) + (file-systems + (cons* (file-system + (mount-point "/boot/efi") + (device (uuid "50C2-89C6" 'fat32)) + (type "vfat")) + (file-system + (mount-point "/") + (device + (uuid "817a54a1-a8a9-49b5-883d-33fdfd06404d" + 'ext4)) + (type "ext4")) + %base-file-systems))) + diff --git a/metznet/system/files/ldap/nmetz.ldif b/metznet/system/files/ldap/nmetz.ldif new file mode 100644 index 0000000..8e5219e --- /dev/null +++ b/metznet/system/files/ldap/nmetz.ldif @@ -0,0 +1,23 @@ +dn: cn=nmetz,ou=user,dc=metznet,dc=ca +objectClass: top +objectClass: person +objectClass: organizationalPerson +objectClass: inetOrgPerson +objectClass: posixAccount +objectClass: shadowAccount +uid: nmetz +cn: Noah Metz +sn: Metz +givenName: Noah +userPassword: {SSHA}yUiQKwuRpADPzuT8W9M6gCbnw914VIOD +loginShell: /bin/bash +uidNumber: 1001 +gidNumber: 1001 +homeDirectory: /home/nmetz/ + + +dn: cn=nmetz,ou=group,dc=metznet,dc=ca +objectClass: top +objectClass: posixGroup +cn: nmetz +gidNumber: 1001 diff --git a/metznet/system/servers/base.scm b/metznet/system/servers/base.scm new file mode 100644 index 0000000..236c868 --- /dev/null +++ b/metznet/system/servers/base.scm @@ -0,0 +1,5 @@ +(use-modules (gnu) (base-system)) + +(operating-system + (inherit base-server-system) + (host-name "server")) diff --git a/metznet/system/servers/hypervisor.scm b/metznet/system/servers/hypervisor.scm new file mode 100644 index 0000000..9eb5784 --- /dev/null +++ b/metznet/system/servers/hypervisor.scm @@ -0,0 +1,12 @@ +(use-modules (base-system) + (guix gexp) + (guix records) + (gnu packages virtualization) + (gnu services shepherd) + (ice-9 match)) + +(operating-system + (inherit base-server-system) + (host-name (string-append "qemu." %domain-name)) + (packages (append (list qemu) %my-server-packages)) + (services (append (list (service )) %my-server-services))) diff --git a/metznet/system/servers/kadmin.scm b/metznet/system/servers/kadmin.scm new file mode 100644 index 0000000..e171cd4 --- /dev/null +++ b/metznet/system/servers/kadmin.scm @@ -0,0 +1,126 @@ +(use-modules (base-system) + (guix records) + (guix gexp) + (gnu packages admin) + (gnu packages kerberos) + (gnu packages linux) + (gnu services kerberos) + (gnu services configuration) + (gnu services shepherd) + (ice-9 match)) + +(define-record-type* + kadmin-configuration make-kadmin-configuration + kadmin-configuration? + (pidfile kadmin-configuration-pidfile + (default "/var/run/krb5kdc")) + (package kadmin-configuration-package + (default mit-krb5)) + (directory kadmin-configuration-directory + (default "/var/krb5kdc")) + (kdb-password kadmin-configuration-kdb-password + (default "password")) + (realm kadmin-configuration-realm + (default %domain-caps)) + (root-princ kadmin-configuration-root-princ + (default "root/admin")) + (root-princ-pw kadmin-configuration-root-princ-pw + (default "password"))) + +(define-gexp-compiler (kadmin-configuration-compiler + (file ) system target) + + (match file + (($ pidfile package directory kdb-password realm root-princ root-princ-pw) + (gexp->derivation + "kdc.conf" + #~(call-with-output-file (ungexp output "out") + (lambda (port) + (display (string-append + (ungexp-splicing `( + ,@`("[kdcdefaults]\n") + ,@`(" kdc_ports = 750,88\n") + ,@`("[realms]\n") + ,@`(" " ,realm " = {\n") + ,@`(" database_name = " ,directory "/principal\n") + ,@`(" acl_file = " ,directory "/kadm5.acl\n") + ,@`(" key_stash_file = " ,directory "/.k5." ,realm "\n") + ,@`(" kdc_ports = 750,88\n") + ,@`(" max_life = 10h 0m 0s\n") + ,@`(" max_renewable_life = 7d 0h 0m 0s\n") + ,@`("}\n")))) + port))) + #:local-build? #t)))) + +(define %kadmin-accounts + (list (user-group (name "krb5") (system? #t)) + (user-account (name "krb5") + (group "krb5") + (system? #t) + (comment "kadmin/kdc user account") + (home-directory "/var/krb5kdc") + (shell (file-append shadow "/sbin/nologin"))))) + +(define kadmin-activation-service + (lambda (arg) (match arg + (($ pidfile package directory kdb-password realm root-princ root-princ-pw) + #~(begin + (use-modules (guix build utils)) + (let* ((user (getpw "krb5"))) + (mkdir-p/perms #$directory user #o700) + (symlink #$arg #$(string-append directory "/kdc.conf")))))))) + +(define kadmin-shepherd-services + (match-lambda + (($ pidfile package directory kdb-password realm root-princ root-princ-pw) + (list (shepherd-service + (documentation "Runs the kdc service") + (provision '(kdc)) + (requirement '(user-processes syslogd)) + (start #~(lambda () + (if (system (string-append #$package "/sbin/kdb5_util -r " #$realm " list_mkeys &> /dev/null")) + (begin + (system (string-join (list + #$(file-append package "/sbin/kdb5_util") + "-r" #$realm + "create" "-s" + "-P" #$kdb-password))) + (system (string-join (list + #$(file-append package "/sbin/kadmin.local") + "-r" #$realm + "add_principal" + "-pw" #$root-princ-pw + #$(string-append root-princ "@" %domain-caps)))) + (system (string-join (list + "echo" (string-append "\"" #$root-princ "@" #$realm " *\n\"") + ">" (string-append #$directory "/kadm5.acl")))) + (display "Kdc already initialized, skipping..."))) + (fork+exec-command (list + #$(file-append package "/sbin/krb5kdc") + "-n" + "-P" #$pidfile)))) + (stop #~(make-kill-destructor))) + (shepherd-service + (documentation "Runs the kadmin service") + (provision '(kadmin)) + (requirement '(kdc user-processes syslogd)) + (start #~(make-forkexec-constructor (list + #$(file-append package "/sbin/kadmind") + "-nofork"))) + (stop #~(make-kill-destructor))))))) + +(define kadmin-service-type + (service-type (name 'kadmin) + (description + "Runs the @command{kadmin} server") + (extensions + (list (service-extension shepherd-root-service-type kadmin-shepherd-services) + (service-extension activation-service-type kadmin-activation-service) + (service-extension account-service-type (const %kadmin-accounts)))) + (default-value (kadmin-configuration)))) + +(operating-system + (inherit base-server-system) + (host-name (string-append "kadmin." %domain-name)) + (packages (append (list strace) %my-server-packages)) + (services (append (list (service kadmin-service-type)) %my-server-services))) diff --git a/metznet/system/servers/ldap.scm b/metznet/system/servers/ldap.scm new file mode 100644 index 0000000..5ca4de9 --- /dev/null +++ b/metznet/system/servers/ldap.scm @@ -0,0 +1,290 @@ +(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)))