diff options
author | Vladimír Čunát <vcunat@gmail.com> | 2016-06-19 12:33:04 +0200 |
---|---|---|
committer | Vladimír Čunát <vcunat@gmail.com> | 2016-06-19 12:33:04 +0200 |
commit | e75740455546f85cbf9849907b1f6520fdb487d8 (patch) | |
tree | 02ab162a81b88bcf1e116b6cbb180557c33ba9b9 /nixos | |
parent | a02e5ad9263e508b4df6a3e5841e95bace0e787b (diff) | |
parent | 410aad942fc82bbeb9c30a4fdf826ed33998a593 (diff) | |
download | nixlib-e75740455546f85cbf9849907b1f6520fdb487d8.tar nixlib-e75740455546f85cbf9849907b1f6520fdb487d8.tar.gz nixlib-e75740455546f85cbf9849907b1f6520fdb487d8.tar.bz2 nixlib-e75740455546f85cbf9849907b1f6520fdb487d8.tar.lz nixlib-e75740455546f85cbf9849907b1f6520fdb487d8.tar.xz nixlib-e75740455546f85cbf9849907b1f6520fdb487d8.tar.zst nixlib-e75740455546f85cbf9849907b1f6520fdb487d8.zip |
Merge branch 'master' into staging
Hydra nixpkgs: ?compare=1279790
Diffstat (limited to 'nixos')
30 files changed, 1259 insertions, 443 deletions
diff --git a/nixos/modules/config/users-groups.nix b/nixos/modules/config/users-groups.nix index e643b2d059b5..8231907d7999 100644 --- a/nixos/modules/config/users-groups.nix +++ b/nixos/modules/config/users-groups.nix @@ -468,7 +468,6 @@ in { home = "/root"; shell = mkDefault cfg.defaultUserShell; group = "root"; - extraGroups = [ "grsecurity" ]; initialHashedPassword = mkDefault config.security.initialRootPassword; }; nobody = { @@ -497,7 +496,6 @@ in { nixbld.gid = ids.gids.nixbld; utmp.gid = ids.gids.utmp; adm.gid = ids.gids.adm; - grsecurity.gid = ids.gids.grsecurity; input.gid = ids.gids.input; }; diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix index d421167c859c..61c49f07abbb 100644 --- a/nixos/modules/misc/ids.nix +++ b/nixos/modules/misc/ids.nix @@ -147,7 +147,6 @@ foundationdb = 118; newrelic = 119; starbound = 120; - #grsecurity = 121; # unused hydra = 122; spiped = 123; teamspeak = 124; @@ -396,7 +395,6 @@ foundationdb = 118; newrelic = 119; starbound = 120; - grsecurity = 121; hydra = 122; spiped = 123; teamspeak = 124; diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 509634cf34c1..51c43b8c7c3b 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -125,10 +125,11 @@ ./services/computing/torque/server.nix ./services/computing/torque/mom.nix ./services/computing/slurm/slurm.nix + ./services/continuous-integration/buildkite-agent.nix + ./services/continuous-integration/hydra/default.nix ./services/continuous-integration/jenkins/default.nix - ./services/continuous-integration/jenkins/slave.nix ./services/continuous-integration/jenkins/job-builder.nix - ./services/continuous-integration/hydra/default.nix + ./services/continuous-integration/jenkins/slave.nix ./services/databases/4store-endpoint.nix ./services/databases/4store.nix ./services/databases/couchdb.nix @@ -218,6 +219,7 @@ ./services/misc/confd.nix ./services/misc/devmon.nix ./services/misc/dictd.nix + ./services/misc/dysnomia.nix ./services/misc/disnix.nix ./services/misc/docker-registry.nix ./services/misc/emby.nix @@ -369,6 +371,7 @@ ./services/networking/ostinato.nix ./services/networking/pdnsd.nix ./services/networking/polipo.nix + ./services/networking/pptpd.nix ./services/networking/prayer.nix ./services/networking/privoxy.nix ./services/networking/prosody.nix @@ -431,6 +434,7 @@ ./services/security/haveged.nix ./services/security/hologram.nix ./services/security/munge.nix + ./services/security/oauth2_proxy.nix ./services/security/physlock.nix ./services/security/torify.nix ./services/security/tor.nix @@ -490,6 +494,7 @@ ./services/x11/window-managers/windowlab.nix ./services/x11/window-managers/wmii.nix ./services/x11/window-managers/xmonad.nix + ./services/x11/xbanish.nix ./services/x11/xfs.nix ./services/x11/xserver.nix ./system/activation/activation-script.nix diff --git a/nixos/modules/rename.nix b/nixos/modules/rename.nix index 3440261c3965..634f91a275d3 100644 --- a/nixos/modules/rename.nix +++ b/nixos/modules/rename.nix @@ -114,6 +114,26 @@ with lib; (mkRenamedOptionModule [ "services" "iodined" "extraConfig" ] [ "services" "iodine" "server" "extraConfig" ]) (mkRemovedOptionModule [ "services" "iodined" "client" ]) + # Grsecurity + (mkRemovedOptionModule [ "security" "grsecurity" "kernelPatch" ]) + (mkRemovedOptionModule [ "security" "grsecurity" "config" "mode" ]) + (mkRemovedOptionModule [ "security" "grsecurity" "config" "priority" ]) + (mkRemovedOptionModule [ "security" "grsecurity" "config" "system" ]) + (mkRemovedOptionModule [ "security" "grsecurity" "config" "virtualisationConfig" ]) + (mkRemovedOptionModule [ "security" "grsecurity" "config" "hardwareVirtualisation" ]) + (mkRemovedOptionModule [ "security" "grsecurity" "config" "virtualisationSoftware" ]) + (mkRemovedOptionModule [ "security" "grsecurity" "config" "sysctl" ]) + (mkRemovedOptionModule [ "security" "grsecurity" "config" "denyChrootChmod" ]) + (mkRemovedOptionModule [ "security" "grsecurity" "config" "denyChrootCaps" ]) + (mkRemovedOptionModule [ "security" "grsecurity" "config" "denyUSB" ]) + (mkRemovedOptionModule [ "security" "grsecurity" "config" "restrictProc" ]) + (mkRemovedOptionModule [ "security" "grsecurity" "config" "restrictProcWithGroup" ]) + (mkRemovedOptionModule [ "security" "grsecurity" "config" "unrestrictProcGid" ]) + (mkRemovedOptionModule [ "security" "grsecurity" "config" "disableRBAC" ]) + (mkRemovedOptionModule [ "security" "grsecurity" "config" "disableSimultConnect" ]) + (mkRemovedOptionModule [ "security" "grsecurity" "config" "verboseVersion" ]) + (mkRemovedOptionModule [ "security" "grsecurity" "config" "kernelExtraConfig" ]) + # Options that are obsolete and have no replacement. (mkRemovedOptionModule [ "boot" "initrd" "luks" "enable" ]) (mkRemovedOptionModule [ "programs" "bash" "enable" ]) diff --git a/nixos/modules/security/grsecurity.nix b/nixos/modules/security/grsecurity.nix index 3f24118ea1cb..9d0249820d5d 100644 --- a/nixos/modules/security/grsecurity.nix +++ b/nixos/modules/security/grsecurity.nix @@ -1,312 +1,122 @@ -{ config, lib, pkgs, ... }: +{ config, pkgs, lib, ... }: with lib; let cfg = config.security.grsecurity; - - customGrsecPkg = - (import ../../../pkgs/build-support/grsecurity { - grsecOptions = cfg; - inherit pkgs lib; - }).grsecPackage; + grsecLockPath = "/proc/sys/kernel/grsecurity/grsec_lock"; + + # Ascertain whether ZFS is required for booting the system; grsecurity is + # currently incompatible with ZFS, rendering the system unbootable. + zfsNeededForBoot = filter + (fs: (fs.neededForBoot + || elem fs.mountPoint [ "/" "/nix" "/nix/store" "/var" "/var/log" "/var/lib" "/etc" ]) + && fs.fsType == "zfs") + (attrValues config.fileSystems) != []; in -{ - options = { - security.grsecurity = { - enable = mkOption { - type = types.bool; - default = false; - description = '' - Enable grsecurity support. This enables advanced exploit - hardening for the Linux kernel, and adds support for - administrative Role-Based Acess Control (RBAC) via - <literal>gradm</literal>. It also includes traditional - utilities for PaX. - ''; - }; - - kernelPatch = mkOption { - type = types.attrs; - example = lib.literalExample "pkgs.kernelPatches.grsecurity_4_1"; - description = '' - Grsecurity patch to use. - ''; - }; - - config = { - mode = mkOption { - type = types.enum [ "auto" "custom" ]; - default = "auto"; - description = '' - grsecurity configuration mode. This specifies whether - grsecurity is auto-configured or otherwise completely - manually configured. - ''; - }; - - priority = mkOption { - type = types.enum [ "security" "performance" ]; - default = "security"; - description = '' - grsecurity configuration priority. This specifies whether - the kernel configuration should emphasize speed or - security. - ''; - }; - - system = mkOption { - type = types.enum [ "desktop" "server" ]; - default = "desktop"; - description = '' - grsecurity system configuration. - ''; - }; - virtualisationConfig = mkOption { - type = types.nullOr (types.enum [ "host" "guest" ]); - default = null; - description = '' - grsecurity virtualisation configuration. This specifies - the virtualisation role of the machine - that is, whether - it will be a virtual machine guest, a virtual machine - host, or neither. - ''; - }; - - hardwareVirtualisation = mkOption { - type = types.nullOr types.bool; - default = null; - example = true; - description = '' - grsecurity hardware virtualisation configuration. Set to - <literal>true</literal> if your machine supports hardware - accelerated virtualisation. - ''; - }; - - virtualisationSoftware = mkOption { - type = types.nullOr (types.enum [ "kvm" "xen" "vmware" "virtualbox" ]); - default = null; - description = '' - Configure grsecurity for use with this virtualisation software. - ''; - }; - - sysctl = mkOption { - type = types.bool; - default = false; - description = '' - If true, then set <literal>GRKERN_SYSCTL y</literal>. If - enabled then grsecurity can be controlled using sysctl - (and turned off). You are advised to *never* enable this, - but if you do, make sure to always set the sysctl - <literal>kernel.grsecurity.grsec_lock</literal> to - non-zero as soon as all sysctl options are set. *THIS IS - EXTREMELY IMPORTANT*! - ''; - }; - - denyChrootChmod = mkOption { - type = types.bool; - default = false; - description = '' - If true, then set <literal>GRKERN_CHROOT_CHMOD - y</literal>. If enabled, this denies processes inside a - chroot from setting the suid or sgid bits using - <literal>chmod</literal> or <literal>fchmod</literal>. - - By default this protection is disabled - it makes it - impossible to use Nix to build software on your system, - which is what most users want. +{ + options.security.grsecurity = { + + enable = mkEnableOption "Grsecurity/PaX"; + + lockTunables = mkOption { + type = types.bool; + example = false; + default = true; + description = '' + Whether to automatically lock grsecurity tunables + (<option>boot.kernel.sysctl."kernel.grsecurity.*"</option>). Disable + this to allow configuration of grsecurity features while the system is + running. The lock can be manually engaged by activating the + <literal>grsec-lock</literal> service unit. + ''; + }; - If you are using NixOps to deploy your software to a - remote machine, you're encouraged to enable this as you - won't need to compile code. - ''; - }; + }; - denyChrootCaps = mkOption { - type = types.bool; - default = false; - description = '' - Whether to lower capabilities of all processes within a chroot, - preventing commands that require <literal>CAP_SYS_ADMIN</literal>. + config = mkIf cfg.enable { - This protection is disabled by default because it breaks - <literal>nixos-rebuild</literal>. Whenever possible, it is - highly recommended to enable this protection. - ''; - }; + # Allow the user to select a different package set, subject to the stated + # required kernel config + boot.kernelPackages = mkDefault pkgs.linuxPackages_grsec_nixos; - denyUSB = mkOption { - type = types.bool; - default = false; - description = '' - If true, then set <literal>GRKERNSEC_DENYUSB y</literal>. + system.requiredKernelConfig = with config.lib.kernelConfig; + [ (isEnabled "GRKERNSEC") + (isEnabled "PAX") + (isYES "GRKERNSEC_SYSCTL") + (isYES "GRKERNSEC_SYSCTL_DISTRO") + ]; - This enables a sysctl with name - <literal>kernel.grsecurity.deny_new_usb</literal>. Setting - its value to <literal>1</literal> will prevent any new USB - devices from being recognized by the OS. Any attempted - USB device insertion will be logged. + # Crashing on an overflow in kernel land is user unfriendly and may prevent + # the system from booting, which is too severe for our use case. + boot.kernelParams = [ "pax_size_overflow_report_only" ]; - This option is intended to be used against custom USB - devices designed to exploit vulnerabilities in various USB - device drivers. - ''; - }; + # Install PaX related utillities into the system profile. Eventually, we + # also want to include gradm here. + environment.systemPackages = with pkgs; [ paxctl pax-utils ]; - restrictProc = mkOption { - type = types.bool; - default = false; - description = '' - If true, then set <literal>GRKERN_PROC_USER - y</literal>. This restricts non-root users to only viewing - their own processes and restricts network-related - information, kernel symbols, and module information. - ''; - }; + # Install rules for the grsec device node + services.udev.packages = [ pkgs.gradm ]; - restrictProcWithGroup = mkOption { - type = types.bool; - default = true; - description = '' - If true, then set <literal>GRKERN_PROC_USERGROUP - y</literal>. This is similar to - <literal>restrictProc</literal> except it allows a special - group (specified by <literal>unrestrictProcGid</literal>) - to still access otherwise classified information in - <literal>/proc</literal>. - ''; - }; + # This service unit is responsible for locking the Grsecurity tunables. The + # unit is always defined, but only activated on bootup if lockTunables is + # toggled. When lockTunables is toggled, failure to activate the unit will + # enter emergency mode. The intent is to make it difficult to silently + # enter multi-user mode without having locked the tunables. Some effort is + # made to ensure that starting the unit is an idempotent operation. + systemd.services.grsec-lock = { + description = "Lock grsecurity tunables"; - unrestrictProcGid = mkOption { - type = types.int; - default = config.ids.gids.grsecurity; - description = '' - If set, specifies a GID which is exempt from - <literal>/proc</literal> restrictions (set by - <literal>GRKERN_PROC_USERGROUP</literal>). By default, - this is set to the GID for <literal>grsecurity</literal>, - a predefined NixOS group, which the - <literal>root</literal> account is a member of. You may - conveniently add other users to this group if you need - access to <literal>/proc</literal> - ''; - }; + wantedBy = optional cfg.lockTunables "multi-user.target"; - disableRBAC = mkOption { - type = types.bool; - default = false; - description = '' - If true, then set <literal>GRKERN_NO_RBAC - y</literal>. This disables the - <literal>/dev/grsec</literal> device, which in turn - disables the RBAC system (and <literal>gradm</literal>). - ''; - }; + wants = [ "local-fs.target" "systemd-sysctl.service" ]; + after = [ "local-fs.target" "systemd-sysctl.service" ]; + conflicts = [ "shutdown.target" ]; - disableSimultConnect = mkOption { - type = types.bool; - default = false; - description = '' - Disable TCP simultaneous connect. The TCP simultaneous connect - feature allows two clients to connect without either of them - entering the listening state. This feature of the TCP specification - is claimed to enable an attacker to deny the target access to a given - server by guessing the source port the target would use to make the - connection. + restartIfChanged = false; - This option is OFF by default because TCP simultaneous connect has - some legitimate uses. Enable this option if you know what this TCP - feature is for and know that you do not need it. - ''; - }; + script = '' + if ${pkgs.gnugrep}/bin/grep -Fq 0 ${grsecLockPath} ; then + echo -n 1 > ${grsecLockPath} + fi + ''; - verboseVersion = mkOption { - type = types.bool; - default = false; - description = "Use verbose version in kernel localversion."; - }; + unitConfig = { + ConditionPathIsReadWrite = grsecLockPath; + DefaultDependencies = false; + } // optionalAttrs cfg.lockTunables { + OnFailure = "emergency.target"; + }; - kernelExtraConfig = mkOption { - type = types.str; - default = ""; - description = "Extra kernel configuration parameters."; - }; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; }; }; - }; - config = mkIf cfg.enable { - assertions = - [ - { assertion = (cfg.config.restrictProc -> !cfg.config.restrictProcWithGroup) || - (cfg.config.restrictProcWithGroup -> !cfg.config.restrictProc); - message = "You cannot enable both restrictProc and restrictProcWithGroup"; - } - { assertion = config.boot.kernelPackages.kernel.features ? grsecurity - && config.boot.kernelPackages.kernel.features.grsecurity; - message = "grsecurity enabled, but kernel doesn't have grsec support"; - } - { assertion = (cfg.config.mode == "auto" && (cfg.config.virtualisationConfig != null)) -> - cfg.config.hardwareVirtualisation != null; - message = "when using auto grsec mode with virtualisation, you must specify if your hardware has virtualisation extensions"; - } - { assertion = (cfg.config.mode == "auto" && (cfg.config.virtualisationConfig != null)) -> - cfg.config.virtualisationSoftware != null; - message = "grsecurity configured for virtualisation but no virtualisation software specified"; - } - ]; - - security.grsecurity.kernelPatch = lib.mkDefault pkgs.kernelPatches.grsecurity_latest; - - systemd.services.grsec-lock = mkIf cfg.config.sysctl { - description = "grsecurity sysctl-lock Service"; - wants = [ "systemd-sysctl.service" ]; - after = [ "systemd-sysctl.service" ]; - wantedBy = [ "multi-user.target" ]; - serviceConfig.Type = "oneshot"; - serviceConfig.RemainAfterExit = "yes"; - unitConfig.ConditionPathIsReadWrite = "/proc/sys/kernel/grsecurity/grsec_lock"; - script = '' - locked=`cat /proc/sys/kernel/grsecurity/grsec_lock` - if [ "$locked" == "0" ]; then - echo 1 > /proc/sys/kernel/grsecurity/grsec_lock - echo grsecurity sysctl lock - enabled - else - echo grsecurity sysctl lock already enabled - doing nothing - fi - ''; + # Configure system tunables + boot.kernel.sysctl = { + # Removed under grsecurity + "kernel.kptr_restrict" = mkForce null; + } // optionalAttrs config.nix.useSandbox { + # chroot(2) restrictions that conflict with sandboxed Nix builds + "kernel.grsecurity.chroot_caps" = mkForce 0; + "kernel.grsecurity.chroot_deny_chroot" = mkForce 0; + "kernel.grsecurity.chroot_deny_mount" = mkForce 0; + "kernel.grsecurity.chroot_deny_pivot" = mkForce 0; + } // optionalAttrs config.boot.enableContainers { + # chroot(2) restrictions that conflict with NixOS lightweight containers + "kernel.grsecurity.chroot_deny_chmod" = mkForce 0; + "kernel.grsecurity.chroot_deny_mount" = mkForce 0; + "kernel.grsecurity.chroot_restrict_nice" = mkForce 0; }; -# systemd.services.grsec-learn = { -# description = "grsecurity learning Service"; -# wantedBy = [ "local-fs.target" ]; -# serviceConfig = { -# Type = "oneshot"; -# RemainAfterExit = "yes"; -# ExecStart = "${pkgs.gradm}/sbin/gradm -VFL /etc/grsec/learning.logs"; -# ExecStop = "${pkgs.gradm}/sbin/gradm -D"; -# }; -# }; - - system.activationScripts = lib.optionalAttrs (!cfg.config.disableRBAC) { grsec = '' - mkdir -p /etc/grsec - if [ ! -f /etc/grsec/learn_config ]; then - cp ${pkgs.gradm}/etc/grsec/learn_config /etc/grsec - fi - if [ ! -f /etc/grsec/policy ]; then - cp ${pkgs.gradm}/etc/grsec/policy /etc/grsec - fi - chmod -R 0600 /etc/grsec - ''; }; + assertions = [ + { assertion = !zfsNeededForBoot; + message = "grsecurity is currently incompatible with ZFS"; + } + ]; - # Enable AppArmor, gradm udev rules, and utilities - security.apparmor.enable = true; - boot.kernelPackages = customGrsecPkg; - services.udev.packages = lib.optional (!cfg.config.disableRBAC) pkgs.gradm; - environment.systemPackages = [ pkgs.paxctl pkgs.pax-utils ] ++ lib.optional (!cfg.config.disableRBAC) pkgs.gradm; }; } diff --git a/nixos/modules/services/continuous-integration/buildkite-agent.nix b/nixos/modules/services/continuous-integration/buildkite-agent.nix new file mode 100644 index 000000000000..b1449882b04f --- /dev/null +++ b/nixos/modules/services/continuous-integration/buildkite-agent.nix @@ -0,0 +1,100 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.buildkite-agent; + configFile = pkgs.writeText "buildkite-agent.cfg" + '' + token="${cfg.token}" + name="${cfg.name}" + meta-data="${cfg.meta-data}" + hooks-path="${pkgs.buildkite-agent}/share/hooks" + build-path="/var/lib/buildkite-agent/builds" + bootstrap-script="${pkgs.buildkite-agent}/share/bootstrap.sh" + ''; +in + +{ + options = { + services.buildkite-agent = { + enable = mkEnableOption "buildkite-agent"; + + token = mkOption { + type = types.str; + description = '' + The token from your Buildkite "Agents" page. + ''; + }; + + name = mkOption { + type = types.str; + description = '' + The name of the agent. + ''; + }; + + meta-data = mkOption { + type = types.str; + default = ""; + description = '' + Meta data for the agent. + ''; + }; + + openssh = + { privateKey = mkOption { + type = types.str; + description = '' + Private agent key. + ''; + }; + publicKey = mkOption { + type = types.str; + description = '' + Public agent key. + ''; + }; + }; + }; + }; + + config = mkIf config.services.buildkite-agent.enable { + users.extraUsers.buildkite-agent = + { name = "buildkite-agent"; + home = "/var/lib/buildkite-agent"; + createHome = true; + description = "Buildkite agent user"; + }; + + environment.systemPackages = [ pkgs.buildkite-agent ]; + + systemd.services.buildkite-agent = + { description = "Buildkite Agent"; + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + environment.HOME = "/var/lib/buildkite-agent"; + preStart = '' + ${pkgs.coreutils}/bin/mkdir -m 0700 -p /var/lib/buildkite-agent/.ssh + + if ! [ -f /var/lib/buildkite-agent/.ssh/id_rsa ]; then + echo "${cfg.openssh.privateKey}" > /var/lib/buildkite-agent/.ssh/id_rsa + ${pkgs.coreutils}/bin/chmod 600 /var/lib/buildkite-agent/.ssh/id_rsa + fi + + if ! [ -f /var/lib/buildkite-agent/.ssh/id_rsa.pub ]; then + echo "${cfg.openssh.publicKey}" > /var/lib/buildkite-agent/.ssh/id_rsa.pub + ${pkgs.coreutils}/bin/chmod 600 /var/lib/buildkite-agent/.ssh/id_rsa.pub + fi + ''; + + serviceConfig = + { ExecStart = "${pkgs.buildkite-agent}/bin/buildkite-agent start --config ${configFile}"; + User = "buildkite-agent"; + RestartSec = 5; + Restart = "on-failure"; + TimeoutSec = 10; + }; + }; + }; +} diff --git a/nixos/modules/services/databases/openldap.nix b/nixos/modules/services/databases/openldap.nix index cbdc676d47bd..9f22aa7c92b2 100644 --- a/nixos/modules/services/databases/openldap.nix +++ b/nixos/modules/services/databases/openldap.nix @@ -40,6 +40,13 @@ in description = "Group account under which slapd runs."; }; + urlList = mkOption { + type = types.listOf types.string; + default = [ "ldap:///" ]; + description = "URL list slapd should listen on."; + example = [ "ldaps:///" ]; + }; + dataDir = mkOption { type = types.string; default = "/var/db/openldap"; @@ -50,7 +57,7 @@ in type = types.lines; default = ""; description = " - sldapd.conf configuration + slapd.conf configuration "; example = literalExample '' ''' @@ -89,7 +96,7 @@ in mkdir -p ${cfg.dataDir} chown -R ${cfg.user}:${cfg.group} ${cfg.dataDir} ''; - serviceConfig.ExecStart = "${openldap.out}/libexec/slapd -u ${cfg.user} -g ${cfg.group} -d 0 -f ${configFile}"; + serviceConfig.ExecStart = "${openldap.out}/libexec/slapd -u ${cfg.user} -g ${cfg.group} -d 0 -h \"${concatStringsSep " " cfg.urlList}\" -f ${configFile}"; }; users.extraUsers.openldap = diff --git a/nixos/modules/services/mail/postfix.nix b/nixos/modules/services/mail/postfix.nix index bad9d527f9a1..cdde41446224 100644 --- a/nixos/modules/services/mail/postfix.nix +++ b/nixos/modules/services/mail/postfix.nix @@ -127,11 +127,11 @@ let # (yes) (yes) (no) (never) (100) # ========================================================================== smtp inet n - n - - smtpd - #submission inet n - n - - smtpd - # -o smtpd_tls_security_level=encrypt - # -o smtpd_sasl_auth_enable=yes - # -o smtpd_client_restrictions=permit_sasl_authenticated,reject - # -o milter_macro_daemon_name=ORIGINATING + '' + optionalString cfg.enableSubmission '' + submission inet n - n - - smtpd + ${concatStringsSep "\n " (mapAttrsToList (x: y: "-o " + x + "=" + y) cfg.submissionOptions)} + '' + + '' pickup unix n - n 60 1 pickup cleanup unix n - n - 0 cleanup qmgr unix n - n 300 1 qmgr @@ -201,6 +201,28 @@ in default = true; description = "Whether to enable smtp in master.cf."; }; + + enableSubmission = mkOption { + type = types.bool; + default = false; + description = "Whether to enable smtp submission"; + }; + + submissionOptions = mkOption { + type = types.attrs; + default = { "smtpd_tls_security_level" = "encrypt"; + "smtpd_sasl_auth_enable" = "yes"; + "smtpd_client_restrictions" = "permit_sasl_authenticated,reject"; + "milter_macro_daemon_name" = "ORIGINATING"; + }; + description = "Options for the submission config in master.cf"; + example = { "smtpd_tls_security_level" = "encrypt"; + "smtpd_sasl_auth_enable" = "yes"; + "smtpd_sasl_type" = "dovecot"; + "smtpd_client_restrictions" = "permit_sasl_authenticated,reject"; + "milter_macro_daemon_name" = "ORIGINATING"; + }; + }; setSendmail = mkOption { type = types.bool; diff --git a/nixos/modules/services/misc/confd.nix b/nixos/modules/services/misc/confd.nix index c0fbf06e6c4c..72ec68dee6b3 100644 --- a/nixos/modules/services/misc/confd.nix +++ b/nixos/modules/services/misc/confd.nix @@ -75,7 +75,7 @@ in { wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; serviceConfig = { - ExecStart = "${cfg.package}/bin/confd"; + ExecStart = "${cfg.package.bin}/bin/confd"; }; }; diff --git a/nixos/modules/services/misc/disnix.nix b/nixos/modules/services/misc/disnix.nix index 218802e0cf00..e5a125ad3245 100644 --- a/nixos/modules/services/misc/disnix.nix +++ b/nixos/modules/services/misc/disnix.nix @@ -36,49 +36,32 @@ in default = false; description = "Whether to enable the DisnixWebService interface running on Apache Tomcat"; }; - - publishInfrastructure = { - enable = mkOption { - default = false; - description = "Whether to publish capabilities/properties of this machine in as attributes in the infrastructure option"; - }; - - enableAuthentication = mkOption { - default = false; - description = "Whether to publish authentication credentials through the infrastructure attribute (not recommended in combination with Avahi)"; - }; - }; - - infrastructure = mkOption { - default = {}; - description = "List of name value pairs containing properties for the infrastructure model"; - }; - - publishAvahi = mkOption { - default = false; - description = "Whether to publish capabilities/properties as a Disnix service through Avahi"; + + package = mkOption { + type = types.path; + description = "The Disnix package"; + default = pkgs.disnix; }; }; }; - ###### implementation config = mkIf cfg.enable { - environment.systemPackages = [ pkgs.disnix pkgs.dysnomia ] ++ optional cfg.useWebServiceInterface pkgs.DisnixWebService; + dysnomia.enable = true; + + environment.systemPackages = [ pkgs.disnix ] ++ optional cfg.useWebServiceInterface pkgs.DisnixWebService; services.dbus.enable = true; services.dbus.packages = [ pkgs.disnix ]; - services.avahi.enable = cfg.publishAvahi; - services.tomcat.enable = cfg.useWebServiceInterface; services.tomcat.extraGroups = [ "disnix" ]; services.tomcat.javaOpts = "${optionalString cfg.useWebServiceInterface "-Djava.library.path=${pkgs.libmatthew_java}/lib/jni"} "; services.tomcat.sharedLibs = optional cfg.useWebServiceInterface "${pkgs.DisnixWebService}/share/java/DisnixConnection.jar" - ++ optional cfg.useWebServiceInterface "${pkgs.dbus_java}/share/java/dbus.jar"; + ++ optional cfg.useWebServiceInterface "${pkgs.dbus_java}/share/java/dbus.jar"; services.tomcat.webapps = optional cfg.useWebServiceInterface pkgs.DisnixWebService; users.extraGroups = singleton @@ -86,38 +69,6 @@ in gid = config.ids.gids.disnix; }; - services.disnix.infrastructure = - optionalAttrs (cfg.publishInfrastructure.enable) - ( { hostname = config.networking.hostName; - #targetHost = config.deployment.targetHost; - system = if config.nixpkgs.system == "" then builtins.currentSystem else config.nixpkgs.system; - - supportedTypes = (import "${pkgs.stdenv.mkDerivation { - name = "supportedtypes"; - buildCommand = '' - ( echo -n "[ " - cd ${dysnomia}/libexec/dysnomia - for i in * - do - echo -n "\"$i\" " - done - echo -n " ]") > $out - ''; - }}"); - } - #// optionalAttrs (cfg.useWebServiceInterface) { targetEPR = "http://${config.deployment.targetHost}:8080/DisnixWebService/services/DisnixWebService"; } - // optionalAttrs (config.services.httpd.enable) { documentRoot = config.services.httpd.documentRoot; } - // optionalAttrs (config.services.mysql.enable) { mysqlPort = config.services.mysql.port; } - // optionalAttrs (config.services.tomcat.enable) { tomcatPort = 8080; } - // optionalAttrs (config.services.svnserve.enable) { svnBaseDir = config.services.svnserve.svnBaseDir; } - // optionalAttrs (config.services.ejabberd.enable) { ejabberdUser = config.services.ejabberd.user; } - // optionalAttrs (cfg.publishInfrastructure.enableAuthentication) ( - optionalAttrs (config.services.mysql.enable) { mysqlUsername = "root"; mysqlPassword = readFile config.services.mysql.rootPassword; }) - ) - ; - - services.disnix.publishInfrastructure.enable = cfg.publishAvahi; - systemd.services = { disnix = { description = "Disnix server"; @@ -133,46 +84,17 @@ in restartIfChanged = false; - path = [ pkgs.nix pkgs.disnix dysnomia "/run/current-system/sw" ]; + path = [ config.nix.package cfg.package config.dysnomia.package "/run/current-system/sw" ]; environment = { HOME = "/root"; - }; - - preStart = '' - mkdir -p /etc/systemd-mutable/system - if [ ! -f /etc/systemd-mutable/system/dysnomia.target ] - then - ( echo "[Unit]" - echo "Description=Services that are activated and deactivated by Dysnomia" - echo "After=final.target" - ) > /etc/systemd-mutable/system/dysnomia.target - fi - ''; - - script = "disnix-service"; + } + // (if config.environment.variables ? DYSNOMIA_CONTAINERS_PATH then { inherit (config.environment.variables) DYSNOMIA_CONTAINERS_PATH; } else {}) + // (if config.environment.variables ? DYSNOMIA_MODULES_PATH then { inherit (config.environment.variables) DYSNOMIA_MODULES_PATH; } else {}); + + serviceConfig.ExecStart = "${cfg.package}/bin/disnix-service"; }; - } // optionalAttrs cfg.publishAvahi { - disnixAvahi = { - description = "Disnix Avahi publisher"; - wants = [ "avahi-daemon.service" ]; - wantedBy = [ "multi-user.target" ]; - script = '' - ${pkgs.avahi}/bin/avahi-publish-service disnix-${config.networking.hostName} _disnix._tcp 22 \ - "mem=$(grep 'MemTotal:' /proc/meminfo | sed -e 's/kB//' -e 's/MemTotal://' -e 's/ //g')" \ - ${concatMapStrings (infrastructureAttrName: - let infrastructureAttrValue = getAttr infrastructureAttrName (cfg.infrastructure); - in - if isInt infrastructureAttrValue then - ''${infrastructureAttrName}=${toString infrastructureAttrValue} \ - '' - else - ''${infrastructureAttrName}=\"${infrastructureAttrValue}\" \ - '' - ) (attrNames (cfg.infrastructure))} - ''; - }; }; }; } diff --git a/nixos/modules/services/misc/dysnomia.nix b/nixos/modules/services/misc/dysnomia.nix new file mode 100644 index 000000000000..df44d0a54866 --- /dev/null +++ b/nixos/modules/services/misc/dysnomia.nix @@ -0,0 +1,217 @@ +{pkgs, lib, config, ...}: + +with lib; + +let + cfg = config.dysnomia; + + printProperties = properties: + concatMapStrings (propertyName: + let + property = properties."${propertyName}"; + in + if isList property then "${propertyName}=(${lib.concatMapStrings (elem: "\"${toString elem}\" ") (properties."${propertyName}")})\n" + else "${propertyName}=\"${toString property}\"\n" + ) (builtins.attrNames properties); + + properties = pkgs.stdenv.mkDerivation { + name = "dysnomia-properties"; + buildCommand = '' + cat > $out << "EOF" + ${printProperties cfg.properties} + EOF + ''; + }; + + containersDir = pkgs.stdenv.mkDerivation { + name = "dysnomia-containers"; + buildCommand = '' + mkdir -p $out + cd $out + + ${concatMapStrings (containerName: + let + containerProperties = cfg.containers."${containerName}"; + in + '' + cat > ${containerName} <<EOF + ${printProperties containerProperties} + type=${containerName} + EOF + '' + ) (builtins.attrNames cfg.containers)} + ''; + }; + + linkMutableComponents = {containerName}: + '' + mkdir ${containerName} + + ${concatMapStrings (componentName: + let + component = cfg.components."${containerName}"."${componentName}"; + in + "ln -s ${component} ${containerName}/${componentName}\n" + ) (builtins.attrNames (cfg.components."${containerName}" or {}))} + ''; + + componentsDir = pkgs.stdenv.mkDerivation { + name = "dysnomia-components"; + buildCommand = '' + mkdir -p $out + cd $out + + ${concatMapStrings (containerName: + let + components = cfg.components."${containerName}"; + in + linkMutableComponents { inherit containerName; } + ) (builtins.attrNames cfg.components)} + ''; + }; +in +{ + options = { + dysnomia = { + + enable = mkOption { + type = types.bool; + default = false; + description = "Whether to enable Dysnomia"; + }; + + enableAuthentication = mkOption { + type = types.bool; + default = false; + description = "Whether to publish privacy-sensitive authentication credentials"; + }; + + package = mkOption { + type = types.path; + description = "The Dysnomia package"; + }; + + properties = mkOption { + description = "An attribute set in which each attribute represents a machine property. Optionally, these values can be shell substitutions."; + default = {}; + }; + + containers = mkOption { + description = "An attribute set in which each key represents a container and each value an attribute set providing its configuration properties"; + default = {}; + }; + + components = mkOption { + description = "An atttribute set in which each key represents a container and each value an attribute set in which each key represents a component and each value a derivation constructing its initial state"; + default = {}; + }; + + extraContainerProperties = mkOption { + description = "An attribute set providing additional container settings in addition to the default properties"; + default = {}; + }; + + extraContainerPaths = mkOption { + description = "A list of paths containing additional container configurations that are added to the search folders"; + default = []; + }; + + extraModulePaths = mkOption { + description = "A list of paths containing additional modules that are added to the search folders"; + default = []; + }; + }; + }; + + config = mkIf cfg.enable { + + environment.etc = { + "dysnomia/containers" = { + source = containersDir; + }; + "dysnomia/components" = { + source = componentsDir; + }; + "dysnomia/properties" = { + source = properties; + }; + }; + + environment.variables = { + DYSNOMIA_STATEDIR = "/var/state/dysnomia-nixos"; + DYSNOMIA_CONTAINERS_PATH = "${lib.concatMapStrings (containerPath: "${containerPath}:") cfg.extraContainerPaths}/etc/dysnomia/containers"; + DYSNOMIA_MODULES_PATH = "${lib.concatMapStrings (modulePath: "${modulePath}:") cfg.extraModulePaths}/etc/dysnomia/modules"; + }; + + environment.systemPackages = [ cfg.package ]; + + dysnomia.package = pkgs.dysnomia.override (origArgs: { + enableApacheWebApplication = config.services.httpd.enable; + enableAxis2WebService = config.services.tomcat.axis2.enable; + enableEjabberdDump = config.services.ejabberd.enable; + enableMySQLDatabase = config.services.mysql.enable; + enablePostgreSQLDatabase = config.services.postgresql.enable; + enableSubversionRepository = config.services.svnserve.enable; + enableTomcatWebApplication = config.services.tomcat.enable; + enableMongoDatabase = config.services.mongodb.enable; + }); + + dysnomia.properties = { + hostname = config.networking.hostName; + system = if config.nixpkgs.system == "" then builtins.currentSystem else config.nixpkgs.system; + + supportedTypes = (import "${pkgs.stdenv.mkDerivation { + name = "supportedtypes"; + buildCommand = '' + ( echo -n "[ " + cd ${cfg.package}/libexec/dysnomia + for i in * + do + echo -n "\"$i\" " + done + echo -n " ]") > $out + ''; + }}"); + }; + + dysnomia.containers = lib.recursiveUpdate ({ + process = {}; + wrapper = {}; + } + // lib.optionalAttrs (config.services.httpd.enable) { apache-webapplication = { + documentRoot = config.services.httpd.documentRoot; + }; } + // lib.optionalAttrs (config.services.tomcat.axis2.enable) { axis2-webservice = {}; } + // lib.optionalAttrs (config.services.ejabberd.enable) { ejabberd-dump = { + ejabberdUser = config.services.ejabberd.user; + }; } + // lib.optionalAttrs (config.services.mysql.enable) { mysql-database = { + mysqlPort = config.services.mysql.port; + } // lib.optionalAttrs cfg.enableAuthentication { + mysqlUsername = "root"; + mysqlPassword = builtins.readFile (config.services.mysql.rootPassword); + }; + } + // lib.optionalAttrs (config.services.postgresql.enable && cfg.enableAuthentication) { postgresql-database = { + postgresqlUsername = "root"; + }; } + // lib.optionalAttrs (config.services.tomcat.enable) { tomcat-webapplication = { + tomcatPort = 8080; + }; } + // lib.optionalAttrs (config.services.mongodb.enable) { mongo-database = {}; } + // lib.optionalAttrs (config.services.svnserve.enable) { subversion-repository = { + svnBaseDir = config.services.svnserve.svnBaseDir; + }; }) cfg.extraContainerProperties; + + system.activationScripts.dysnomia = '' + mkdir -p /etc/systemd-mutable/system + if [ ! -f /etc/systemd-mutable/system/dysnomia.target ] + then + ( echo "[Unit]" + echo "Description=Services that are activated and deactivated by Dysnomia" + echo "After=final.target" + ) > /etc/systemd-mutable/system/dysnomia.target + fi + ''; + }; +} diff --git a/nixos/modules/services/misc/etcd.nix b/nixos/modules/services/misc/etcd.nix index bc8064e3c879..0d6ed8eb9043 100644 --- a/nixos/modules/services/misc/etcd.nix +++ b/nixos/modules/services/misc/etcd.nix @@ -115,7 +115,7 @@ in { serviceConfig = { Type = "notify"; - ExecStart = "${pkgs.etcd}/bin/etcd"; + ExecStart = "${pkgs.etcd.bin}/bin/etcd"; User = "etcd"; PermissionsStartOnly = true; }; diff --git a/nixos/modules/services/misc/parsoid.nix b/nixos/modules/services/misc/parsoid.nix index ea97d6e30e83..0844190a5490 100644 --- a/nixos/modules/services/misc/parsoid.nix +++ b/nixos/modules/services/misc/parsoid.nix @@ -91,7 +91,7 @@ in wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; serviceConfig = { - ExecStart = "${pkgs.nodePackages_0_10.parsoid}/lib/node_modules/parsoid/api/server.js -c ${confFile} -n ${toString cfg.workers}"; + ExecStart = "${pkgs.nodePackages.parsoid}/lib/node_modules/parsoid/api/server.js -c ${confFile} -n ${toString cfg.workers}"; }; }; diff --git a/nixos/modules/services/monitoring/bosun.nix b/nixos/modules/services/monitoring/bosun.nix index 51d38e8db4de..9a1e790d3ab6 100644 --- a/nixos/modules/services/monitoring/bosun.nix +++ b/nixos/modules/services/monitoring/bosun.nix @@ -148,7 +148,7 @@ in { User = cfg.user; Group = cfg.group; ExecStart = '' - ${cfg.package}/bin/bosun -c ${configFile} + ${cfg.package.bin}/bin/bosun -c ${configFile} ''; }; }; diff --git a/nixos/modules/services/monitoring/grafana.nix b/nixos/modules/services/monitoring/grafana.nix index defbd9289dcd..0b7f3ce0a29b 100644 --- a/nixos/modules/services/monitoring/grafana.nix +++ b/nixos/modules/services/monitoring/grafana.nix @@ -228,7 +228,7 @@ in { after = ["networking.target"]; environment = mapAttrs' (n: v: nameValuePair "GF_${n}" (toString v)) envOptions; serviceConfig = { - ExecStart = "${cfg.package}/bin/grafana-server -homepath ${cfg.dataDir}"; + ExecStart = "${cfg.package.bin}/bin/grafana-server -homepath ${cfg.dataDir}"; WorkingDirectory = cfg.dataDir; User = "grafana"; }; diff --git a/nixos/modules/services/monitoring/scollector.nix b/nixos/modules/services/monitoring/scollector.nix index 1e397435e600..2684482c6184 100644 --- a/nixos/modules/services/monitoring/scollector.nix +++ b/nixos/modules/services/monitoring/scollector.nix @@ -119,7 +119,7 @@ in { PermissionsStartOnly = true; User = cfg.user; Group = cfg.group; - ExecStart = "${cfg.package}/bin/scollector -conf=${conf} ${lib.concatStringsSep " " cfg.extraOpts}"; + ExecStart = "${cfg.package.bin}/bin/scollector -conf=${conf} ${lib.concatStringsSep " " cfg.extraOpts}"; }; }; diff --git a/nixos/modules/services/networking/consul.nix b/nixos/modules/services/networking/consul.nix index 2aa101f980da..166ee7732375 100644 --- a/nixos/modules/services/networking/consul.nix +++ b/nixos/modules/services/networking/consul.nix @@ -178,14 +178,14 @@ in (filterAttrs (n: _: hasPrefix "consul.d/" n) config.environment.etc); serviceConfig = { - ExecStart = "@${cfg.package}/bin/consul consul agent -config-dir /etc/consul.d" + ExecStart = "@${cfg.package.bin}/bin/consul consul agent -config-dir /etc/consul.d" + concatMapStrings (n: " -config-file ${n}") configFiles; - ExecReload = "${cfg.package}/bin/consul reload"; + ExecReload = "${cfg.package.bin}/bin/consul reload"; PermissionsStartOnly = true; User = if cfg.dropPrivileges then "consul" else null; TimeoutStartSec = "0"; } // (optionalAttrs (cfg.leaveOnStop) { - ExecStop = "${cfg.package}/bin/consul leave"; + ExecStop = "${cfg.package.bin}/bin/consul leave"; }); path = with pkgs; [ iproute gnugrep gawk consul ]; @@ -236,7 +236,7 @@ in serviceConfig = { ExecStart = '' - ${cfg.alerts.package}/bin/consul-alerts start \ + ${cfg.alerts.package.bin}/bin/consul-alerts start \ --alert-addr=${cfg.alerts.listenAddr} \ --consul-addr=${cfg.alerts.consulAddr} \ ${optionalString cfg.alerts.watchChecks "--watch-checks"} \ diff --git a/nixos/modules/services/networking/dnscrypt-proxy.nix b/nixos/modules/services/networking/dnscrypt-proxy.nix index 2a6161ee873a..227e38acc4a6 100644 --- a/nixos/modules/services/networking/dnscrypt-proxy.nix +++ b/nixos/modules/services/networking/dnscrypt-proxy.nix @@ -89,8 +89,8 @@ in ''; example = literalExample "${pkgs.dnscrypt-proxy}/share/dnscrypt-proxy/dnscrypt-resolvers.csv"; default = pkgs.fetchurl { - url = "https://raw.githubusercontent.com/jedisct1/dnscrypt-proxy/master/dnscrypt-resolvers.csv"; - sha256 = "0lac20qhcgjxxiiz8jzcn3hkqj4ywl58hahp5n2i6vf9akfyqp7c"; + url = https://raw.githubusercontent.com/jedisct1/dnscrypt-proxy/master/dnscrypt-resolvers.csv; + sha256 = "171zvdqcqqvcw3zr7wl9h1wmdmk6m3h55xr4gq2z1j7a0x0ba2in"; }; defaultText = "pkgs.fetchurl { url = ...; sha256 = ...; }"; }; diff --git a/nixos/modules/services/networking/pptpd.nix b/nixos/modules/services/networking/pptpd.nix new file mode 100644 index 000000000000..efed604d3dda --- /dev/null +++ b/nixos/modules/services/networking/pptpd.nix @@ -0,0 +1,124 @@ +{ config, stdenv, pkgs, lib, ... }: + +with lib; + +{ + options = { + services.pptpd = { + enable = mkEnableOption "Whether pptpd should be run on startup."; + + serverIp = mkOption { + type = types.string; + description = "The server-side IP address."; + default = "10.124.124.1"; + }; + + clientIpRange = mkOption { + type = types.string; + description = "The range from which client IPs are drawn."; + default = "10.124.142.2-11"; + }; + + maxClients = mkOption { + type = types.int; + description = "The maximum number of simultaneous connections."; + default = 10; + }; + + extraPptpdOptions = mkOption { + type = types.lines; + description = "Adds extra lines to the pptpd configuration file."; + default = ""; + }; + + extraPppdOptions = mkOption { + type = types.lines; + description = "Adds extra lines to the pppd options file."; + default = ""; + example = '' + ms-dns 8.8.8.8 + ms-dns 8.8.4.4 + ''; + }; + }; + }; + + config = mkIf config.services.pptpd.enable { + systemd.services.pptpd = let + cfg = config.services.pptpd; + + pptpd-conf = pkgs.writeText "pptpd.conf" '' + # Inspired from pptpd-1.4.0/samples/pptpd.conf + ppp ${ppp-pptpd-wrapped}/bin/pppd + option ${pppd-options} + pidfile /run/pptpd.pid + localip ${cfg.serverIp} + remoteip ${cfg.clientIpRange} + connections ${toString cfg.maxClients} # (Will get harmless warning if inconsistent with IP range) + + # Extra + ${cfg.extraPptpdOptions} + ''; + + pppd-options = pkgs.writeText "ppp-options-pptpd.conf" '' + # From: cat pptpd-1.4.0/samples/options.pptpd | grep -v ^# | grep -v ^$ + name pptpd + refuse-pap + refuse-chap + refuse-mschap + require-mschap-v2 + require-mppe-128 + proxyarp + lock + nobsdcomp + novj + novjccomp + nologfd + + # Extra: + ${cfg.extraPppdOptions} + ''; + + ppp-pptpd-wrapped = pkgs.stdenv.mkDerivation { + name = "ppp-pptpd-wrapped"; + phases = [ "installPhase" ]; + buildInputs = with pkgs; [ makeWrapper ]; + installPhase = '' + mkdir -p $out/bin + makeWrapper ${pkgs.ppp}/bin/pppd $out/bin/pppd \ + --set LD_PRELOAD "${pkgs.libredirect}/lib/libredirect.so" \ + --set NIX_REDIRECTS "/etc/ppp=/etc/ppp-pptpd" + ''; + }; + in { + description = "pptpd server"; + + requires = [ "network-online.target" ]; + wantedBy = [ "multi-user.target" ]; + + preStart = '' + mkdir -p -m 700 /etc/ppp-pptpd + + secrets="/etc/ppp-pptpd/chap-secrets" + + [ -f "$secrets" ] || cat > "$secrets" << EOF + # From: pptpd-1.4.0/samples/chap-secrets + # Secrets for authentication using CHAP + # client server secret IP addresses + #username pptpd password * + EOF + + chown root.root "$secrets" + chmod 600 "$secrets" + ''; + + serviceConfig = { + ExecStart = "${pkgs.pptpd}/bin/pptpd --conf ${pptpd-conf}"; + KillMode = "process"; + Restart = "on-success"; + Type = "forking"; + PIDFile = "/run/pptpd.pid"; + }; + }; + }; +} diff --git a/nixos/modules/services/networking/skydns.nix b/nixos/modules/services/networking/skydns.nix index 39ebaa45a794..ba913482e3cb 100644 --- a/nixos/modules/services/networking/skydns.nix +++ b/nixos/modules/services/networking/skydns.nix @@ -83,7 +83,7 @@ in { SKYDNS_NAMESERVERS = concatStringsSep "," cfg.nameservers; }; serviceConfig = { - ExecStart = "${cfg.package}/bin/skydns"; + ExecStart = "${cfg.package.bin}/bin/skydns"; }; }; diff --git a/nixos/modules/services/networking/wpa_supplicant.nix b/nixos/modules/services/networking/wpa_supplicant.nix index 53648aef1e04..8d22c10d3f78 100644 --- a/nixos/modules/services/networking/wpa_supplicant.nix +++ b/nixos/modules/services/networking/wpa_supplicant.nix @@ -129,7 +129,7 @@ in { in { description = "WPA Supplicant"; - after = [ "network-interfaces.target" ]; + after = [ "network-interfaces.target" ] ++ lib.concatMap deviceUnit ifaces; requires = lib.concatMap deviceUnit ifaces; wantedBy = [ "network.target" ]; diff --git a/nixos/modules/services/security/hologram.nix b/nixos/modules/services/security/hologram.nix index 58f308df7a21..e267fed27955 100644 --- a/nixos/modules/services/security/hologram.nix +++ b/nixos/modules/services/security/hologram.nix @@ -95,7 +95,7 @@ in { wantedBy = [ "multi-user.target" ]; serviceConfig = { - ExecStart = "${pkgs.hologram}/bin/hologram-server --debug --conf ${cfgFile}"; + ExecStart = "${pkgs.hologram.bin}/bin/hologram-server --debug --conf ${cfgFile}"; }; }; }; diff --git a/nixos/modules/services/security/oauth2_proxy.nix b/nixos/modules/services/security/oauth2_proxy.nix new file mode 100644 index 000000000000..4c20392214fc --- /dev/null +++ b/nixos/modules/services/security/oauth2_proxy.nix @@ -0,0 +1,523 @@ +# NixOS module for oauth2_proxy. + +{ config, lib, pkgs, ... }: + +with lib; +let + cfg = config.services.oauth2_proxy; + + # Use like: + # repeatedArgs (arg: "--arg=${arg}") args + repeatedArgs = concatMapStringsSep " "; + + # 'toString' doesn't quite do what we want for bools. + fromBool = x: if x then "true" else "false"; + + # oauth2_proxy provides many options that are only relevant if you are using + # a certain provider. This set maps from provider name to a function that + # takes the configuration and returns a string that can be inserted into the + # command-line to launch oauth2_proxy. + providerSpecificOptions = { + azure = cfg: '' + --azure-tenant=${cfg.azure.tenant} \ + --resource=${cfg.azure.resource} \ + ''; + + github = cfg: '' + $(optionalString (!isNull cfg.github.org) "--github-org=${cfg.github.org}") \ + $(optionalString (!isNull cfg.github.team) "--github-org=${cfg.github.team}") \ + ''; + + google = cfg: '' + --google-admin-email=${cfg.google.adminEmail} \ + --google-service-account=${cfg.google.serviceAccountJSON} \ + $(repeatedArgs (group: "--google-group=${group}") cfg.google.groups) \ + ''; + }; + + authenticatedEmailsFile = pkgs.writeText "authenticated-emails" cfg.email.addresses; + + getProviderOptions = cfg: provider: + if providerSpecificOptions ? provider then providerSpecificOptions.provider cfg else ""; + + mkCommandLine = cfg: '' + --provider='${cfg.provider}' \ + ${optionalString (!isNull cfg.email.addresses) "--authenticated-emails-file='${authenticatedEmailsFile}'"} \ + --approval-prompt='${cfg.approvalPrompt}' \ + ${optionalString (cfg.passBasicAuth && !isNull cfg.basicAuthPassword) "--basic-auth-password='${cfg.basicAuthPassword}'"} \ + --client-id='${cfg.clientID}' \ + --client-secret='${cfg.clientSecret}' \ + ${optionalString (!isNull cfg.cookie.domain) "--cookie-domain='${cfg.cookie.domain}'"} \ + --cookie-expire='${cfg.cookie.expire}' \ + --cookie-httponly=${fromBool cfg.cookie.httpOnly} \ + --cookie-name='${cfg.cookie.name}' \ + --cookie-secret='${cfg.cookie.secret}' \ + --cookie-secure=${fromBool cfg.cookie.secure} \ + ${optionalString (!isNull cfg.cookie.refresh) "--cookie-refresh='${cfg.cookie.refresh}'"} \ + ${optionalString (!isNull cfg.customTemplatesDir) "--custom-templates-dir='${cfg.customTemplatesDir}'"} \ + ${repeatedArgs (x: "--email-domain='${x}'") cfg.email.domains} \ + --http-address='${cfg.httpAddress}' \ + ${optionalString (!isNull cfg.htpasswd.file) "--htpasswd-file='${cfg.htpasswd.file}' --display-htpasswd-form=${fromBool cfg.htpasswd.displayForm}"} \ + ${optionalString (!isNull cfg.loginURL) "--login-url='${cfg.loginURL}'"} \ + --pass-access-token=${fromBool cfg.passAccessToken} \ + --pass-basic-auth=${fromBool cfg.passBasicAuth} \ + --pass-host-header=${fromBool cfg.passHostHeader} \ + --proxy-prefix='${cfg.proxyPrefix}' \ + ${optionalString (!isNull cfg.profileURL) "--profile-url='${cfg.profileURL}'"} \ + ${optionalString (!isNull cfg.redeemURL) "--redeem-url='${cfg.redeemURL}'"} \ + ${optionalString (!isNull cfg.redirectURL) "--redirect-url='${cfg.redirectURL}'"} \ + --request-logging=${fromBool cfg.requestLogging} \ + ${optionalString (!isNull cfg.scope) "--scope='${cfg.scope}'"} \ + ${repeatedArgs (x: "--skip-auth-regex='${x}'") cfg.skipAuthRegexes} \ + ${optionalString (!isNull cfg.signatureKey) "--signature-key='${cfg.signatureKey}'"} \ + --upstream='${cfg.upstream}' \ + ${optionalString (!isNull cfg.validateURL) "--validate-url='${cfg.validateURL}'"} \ + ${optionalString cfg.tls.enable "--tls-cert='${cfg.tls.certificate}' --tls-key='${cfg.tls.key}' --https-address='${cfg.tls.httpsAddress}'"} \ + '' + getProviderOptions cfg cfg.provider; +in +{ + options.services.oauth2_proxy = { + enable = mkEnableOption "oauth2_proxy"; + + package = mkOption { + type = types.package; + default = pkgs.oauth2_proxy; + defaultText = "pkgs.oauth2_proxy"; + description = '' + The package that provides oauth2_proxy. + ''; + }; + + ############################################## + # PROVIDER configuration + provider = mkOption { + type = types.enum [ + "google" + "github" + "azure" + "gitlab" + "linkedin" + "myusa" + ]; + default = "google"; + description = '' + OAuth provider. + ''; + }; + + approvalPrompt = mkOption { + type = types.enum ["force" "auto"]; + default = "force"; + description = '' + OAuth approval_prompt. + ''; + }; + + clientID = mkOption { + type = types.str; + description = '' + The OAuth Client ID. + ''; + example = "123456.apps.googleusercontent.com"; + }; + + clientSecret = mkOption { + type = types.str; + description = '' + The OAuth Client Secret. + ''; + }; + + skipAuthRegexes = mkOption { + type = types.listOf types.str; + default = []; + description = '' + Skip authentication for requests matching any of these regular + expressions. + ''; + }; + + # XXX: Not clear whether these two options are mutually exclusive or not. + email = { + domains = mkOption { + type = types.listOf types.str; + default = []; + description = '' + Authenticate emails with the specified domains. Use + <literal>*</literal> to authenticate any email. + ''; + }; + + addresses = mkOption { + type = types.nullOr types.lines; + default = null; + description = '' + Line-separated email addresses that are allowed to authenticate. + ''; + }; + }; + + loginURL = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + Authentication endpoint. + + You only need to set this if you are using a self-hosted provider (e.g. + Github Enterprise). If you're using a publicly hosted provider + (e.g github.com), then the default works. + ''; + example = "https://provider.example.com/oauth/authorize"; + }; + + redeemURL = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + Token redemption endpoint. + + You only need to set this if you are using a self-hosted provider (e.g. + Github Enterprise). If you're using a publicly hosted provider + (e.g github.com), then the default works. + ''; + example = "https://provider.example.com/oauth/token"; + }; + + validateURL = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + Access token validation endpoint. + + You only need to set this if you are using a self-hosted provider (e.g. + Github Enterprise). If you're using a publicly hosted provider + (e.g github.com), then the default works. + ''; + example = "https://provider.example.com/user/emails"; + }; + + redirectURL = mkOption { + # XXX: jml suspects this is always necessary, but the command-line + # doesn't require it so making it optional. + type = types.nullOr types.str; + default = null; + description = '' + The OAuth2 redirect URL. + ''; + example = "https://internalapp.yourcompany.com/oauth2/callback"; + }; + + azure = { + tenant = mkOption { + type = types.str; + default = "common"; + description = '' + Go to a tenant-specific or common (tenant-independent) endpoint. + ''; + }; + + resource = mkOption { + type = types.str; + description = '' + The resource that is protected. + ''; + }; + }; + + google = { + adminEmail = mkOption { + type = types.str; + description = '' + The Google Admin to impersonate for API calls. + + Only users with access to the Admin APIs can access the Admin SDK + Directory API, thus the service account needs to impersonate one of + those users to access the Admin SDK Directory API. + + See <link xlink:href="https://developers.google.com/admin-sdk/directory/v1/guides/delegation#delegate_domain-wide_authority_to_your_service_account" />. + ''; + }; + + groups = mkOption { + type = types.listOf types.str; + default = []; + description = '' + Restrict logins to members of these Google groups. + ''; + }; + + serviceAccountJSON = mkOption { + type = types.path; + description = '' + The path to the service account JSON credentials. + ''; + }; + }; + + github = { + org = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + Restrict logins to members of this organisation. + ''; + }; + + team = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + Restrict logins to members of this team. + ''; + }; + }; + + + #################################################### + # UPSTREAM Configuration + upstream = mkOption { + type = types.commas; + description = '' + The http url(s) of the upstream endpoint or <literal>file://</literal> + paths for static files. Routing is based on the path. + ''; + }; + + passAccessToken = mkOption { + type = types.bool; + default = false; + description = '' + Pass OAuth access_token to upstream via X-Forwarded-Access-Token header. + ''; + }; + + passBasicAuth = mkOption { + type = types.bool; + default = true; + description = '' + Pass HTTP Basic Auth, X-Forwarded-User and X-Forwarded-Email information to upstream. + ''; + }; + + basicAuthPassword = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + The password to set when passing the HTTP Basic Auth header. + ''; + }; + + passHostHeader = mkOption { + type = types.bool; + default = true; + description = '' + Pass the request Host Header to upstream. + ''; + }; + + signatureKey = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + GAP-Signature request signature key. + ''; + example = "sha1:secret0"; + }; + + cookie = { + domain = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + An optional cookie domain to force cookies to. + ''; + example = ".yourcompany.com"; + }; + + expire = mkOption { + type = types.str; + default = "168h0m0s"; + description = '' + Expire timeframe for cookie. + ''; + }; + + httpOnly = mkOption { + type = types.bool; + default = true; + description = '' + Set HttpOnly cookie flag. + ''; + }; + + name = mkOption { + type = types.str; + default = "_oauth2_proxy"; + description = '' + The name of the cookie that the oauth_proxy creates. + ''; + }; + + refresh = mkOption { + # XXX: Unclear what the behavior is when this is not specified. + type = types.nullOr types.str; + default = null; + description = '' + Refresh the cookie after this duration; 0 to disable. + ''; + example = "168h0m0s"; + }; + + secret = mkOption { + type = types.str; + description = '' + The seed string for secure cookies. + ''; + }; + + secure = mkOption { + type = types.bool; + default = true; + description = '' + Set secure (HTTPS) cookie flag. + ''; + }; + }; + + #################################################### + # OAUTH2 PROXY configuration + + httpAddress = mkOption { + type = types.str; + default = "127.0.0.1:4180"; + description = '' + HTTPS listening address. This module does not expose the port by + default. If you want this URL to be accessible to other machines, please + add the port to <literal>networking.firewall.allowedTCPPorts</literal>. + ''; + }; + + htpasswd = { + file = mkOption { + type = types.nullOr types.path; + default = null; + description = '' + Additionally authenticate against a htpasswd file. Entries must be + created with <literal>htpasswd -s</literal> for SHA encryption. + ''; + }; + + displayForm = mkOption { + type = types.bool; + default = true; + description = '' + Display username / password login form if an htpasswd file is provided. + ''; + }; + }; + + customTemplatesDir = mkOption { + type = types.nullOr types.path; + default = null; + description = '' + Path to custom HTML templates. + ''; + }; + + proxyPrefix = mkOption { + type = types.str; + default = "/oauth2"; + description = '' + The url root path that this proxy should be nested under. + ''; + }; + + tls = { + enable = mkOption { + type = types.bool; + default = false; + description = '' + Whether to serve over TLS. + ''; + }; + + certificate = mkOption { + type = types.path; + description = '' + Path to certificate file. + ''; + }; + + key = mkOption { + type = types.path; + description = '' + Path to private key file. + ''; + }; + + httpsAddress = mkOption { + type = types.str; + default = ":443"; + description = '' + <literal>addr:port</literal> to listen on for HTTPS clients. + + Remember to add <literal>port</literal> to + <literal>allowedTCPPorts</literal> if you want other machines to be + able to connect to it. + ''; + }; + }; + + requestLogging = mkOption { + type = types.bool; + default = true; + description = '' + Log requests to stdout. + ''; + }; + + #################################################### + # UNKNOWN + + # XXX: Is this mandatory? Is it part of another group? Is it part of the provider specification? + scope = mkOption { + # XXX: jml suspects this is always necessary, but the command-line + # doesn't require it so making it optional. + type = types.nullOr types.str; + default = null; + description = '' + OAuth scope specification. + ''; + }; + + profileURL = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + Profile access endpoint. + ''; + }; + + }; + + config = mkIf cfg.enable { + + users.extraUsers.oauth2_proxy = { + description = "OAuth2 Proxy"; + }; + + systemd.services.oauth2_proxy = { + description = "OAuth2 Proxy"; + path = [ cfg.package ]; + wantedBy = [ "multi-user.target" ]; + after = [ "network-interfaces.target" ]; + + serviceConfig = { + User = "oauth2_proxy"; + Restart = "always"; + ExecStart = "${cfg.package.bin}/bin/oauth2_proxy ${mkCommandLine cfg}"; + }; + }; + + }; +} diff --git a/nixos/modules/services/web-servers/apache-httpd/default.nix b/nixos/modules/services/web-servers/apache-httpd/default.nix index c23897192b4c..9844e3c435d1 100644 --- a/nixos/modules/services/web-servers/apache-httpd/default.nix +++ b/nixos/modules/services/web-servers/apache-httpd/default.nix @@ -337,6 +337,7 @@ let allModules = concatMap (svc: svc.extraModulesPre) allSubservices ++ map (name: {inherit name; path = "${httpd}/modules/mod_${name}.so";}) apacheModules + ++ optional mainCfg.enableMellon { name = "auth_mellon"; path = "${pkgs.apacheHttpdPackages.mod_auth_mellon}/modules/mod_auth_mellon.so"; } ++ optional enablePHP { name = "php5"; path = "${php}/modules/libphp5.so"; } ++ concatMap (svc: svc.extraModules) allSubservices ++ extraForeignModules; @@ -541,6 +542,12 @@ in ''; }; + enableMellon = mkOption { + type = types.bool; + default = false; + description = "Whether to enable the mod_auth_mellon module."; + }; + enablePHP = mkOption { type = types.bool; default = false; @@ -650,6 +657,7 @@ in environment = optionalAttrs enablePHP { PHPRC = phpIni; } + // optionalAttrs mainCfg.enableMellon { LD_LIBRARY_PATH = "${pkgs.xmlsec}/lib"; } // (listToAttrs (concatMap (svc: svc.globalEnvVars) allSubservices)); preStart = diff --git a/nixos/modules/services/x11/desktop-managers/gnome3.nix b/nixos/modules/services/x11/desktop-managers/gnome3.nix index 91601f387cbe..700faad0c695 100644 --- a/nixos/modules/services/x11/desktop-managers/gnome3.nix +++ b/nixos/modules/services/x11/desktop-managers/gnome3.nix @@ -78,6 +78,8 @@ in { type = types.listOf types.path; description = "List of packages for which gsettings are overridden."; }; + + debug = mkEnableOption "gnome-session debug messages"; }; environment.gnome3.packageSet = mkOption { @@ -159,7 +161,7 @@ in { # Update user dirs as described in http://freedesktop.org/wiki/Software/xdg-user-dirs/ ${pkgs.xdg-user-dirs}/bin/xdg-user-dirs-update - ${gnome3.gnome_session}/bin/gnome-session& + ${gnome3.gnome_session}/bin/gnome-session ${optionalString cfg.debug "--debug"} & waitPID=$! ''; }; diff --git a/nixos/modules/services/x11/desktop-managers/kde5.nix b/nixos/modules/services/x11/desktop-managers/kde5.nix index 538300f5793a..060dda1a70a8 100644 --- a/nixos/modules/services/x11/desktop-managers/kde5.nix +++ b/nixos/modules/services/x11/desktop-managers/kde5.nix @@ -170,7 +170,9 @@ in services.xserver.displayManager.sddm = { theme = "breeze"; themes = [ + kde5.extra-cmake-modules # for the setup-hook kde5.plasma-workspace + kde5.breeze-icons (kde5.oxygen-icons or kde5.oxygen-icons5) ]; }; diff --git a/nixos/modules/services/x11/window-managers/i3.nix b/nixos/modules/services/x11/window-managers/i3.nix index 2e2e10cc33b0..aea0a8986786 100644 --- a/nixos/modules/services/x11/window-managers/i3.nix +++ b/nixos/modules/services/x11/window-managers/i3.nix @@ -3,37 +3,43 @@ with lib; let - cfg = config.services.xserver.windowManager.i3; -in - -{ - options = { - services.xserver.windowManager.i3 = { - enable = mkEnableOption "i3"; + wmCfg = config.services.xserver.windowManager; - configFile = mkOption { - default = null; - type = types.nullOr types.path; - description = '' - Path to the i3 configuration file. - If left at the default value, $HOME/.i3/config will be used. - ''; - }; + i3option = name: { + enable = mkEnableOption name; + configFile = mkOption { + default = null; + type = types.nullOr types.path; + description = '' + Path to the i3 configuration file. + If left at the default value, $HOME/.i3/config will be used. + ''; }; }; - config = mkIf cfg.enable { - services.xserver.windowManager = { - session = [{ - name = "i3"; - start = '' - ${pkgs.i3}/bin/i3 ${optionalString (cfg.configFile != null) - "-c \"${cfg.configFile}\"" - } & - waitPID=$! - ''; - }]; - }; - environment.systemPackages = with pkgs; [ i3 ]; + i3config = name: pkg: cfg: { + services.xserver.windowManager.session = [{ + inherit name; + start = '' + ${pkg}/bin/i3 ${optionalString (cfg.configFile != null) + "-c \"${cfg.configFile}\"" + } & + waitPID=$! + ''; + }]; + environment.systemPackages = [ pkg ]; + }; + +in + +{ + options.services.xserver.windowManager = { + i3 = i3option "i3"; + i3-gaps = i3option "i3-gaps"; }; + + config = mkMerge [ + (mkIf wmCfg.i3.enable (i3config "i3" pkgs.i3 wmCfg.i3)) + (mkIf wmCfg.i3-gaps.enable (i3config "i3-gaps" pkgs.i3-gaps wmCfg.i3-gaps)) + ]; } diff --git a/nixos/modules/services/x11/xbanish.nix b/nixos/modules/services/x11/xbanish.nix new file mode 100644 index 000000000000..e1e3cbc8e441 --- /dev/null +++ b/nixos/modules/services/x11/xbanish.nix @@ -0,0 +1,30 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let cfg = config.services.xbanish; + +in { + options.services.xbanish = { + + enable = mkEnableOption "xbanish"; + + arguments = mkOption { + description = "Arguments to pass to xbanish command"; + default = ""; + example = "-d -i shift"; + type = types.str; + }; + }; + + config = mkIf cfg.enable { + systemd.user.services.xbanish = { + description = "xbanish hides the mouse pointer"; + wantedBy = [ "default.target" ]; + serviceConfig.ExecStart = '' + ${pkgs.xbanish}/bin/xbanish ${cfg.arguments} + ''; + serviceConfig.Restart = "always"; + }; + }; +} diff --git a/nixos/modules/virtualisation/docker.nix b/nixos/modules/virtualisation/docker.nix index 97b2927cf1bd..c99fc78d49e7 100644 --- a/nixos/modules/virtualisation/docker.nix +++ b/nixos/modules/virtualisation/docker.nix @@ -95,7 +95,7 @@ in LimitNPROC = 1048576; } // proxy_env; - path = [ pkgs.kmod ] ++ (optional (cfg.storageDriver == "zfs") pkgs.zfs); + path = [ config.system.sbin.modprobe ] ++ (optional (cfg.storageDriver == "zfs") pkgs.zfs); environment.MODULE_DIR = "/run/current-system/kernel-modules/lib/modules"; postStart = if cfg.socketActivation then "" else cfg.postStart; diff --git a/nixos/tests/grsecurity.nix b/nixos/tests/grsecurity.nix index 14f1aa9ff885..aadbfd8371ff 100644 --- a/nixos/tests/grsecurity.nix +++ b/nixos/tests/grsecurity.nix @@ -3,17 +3,39 @@ import ./make-test.nix ({ pkgs, ...} : { name = "grsecurity"; meta = with pkgs.stdenv.lib.maintainers; { - maintainers = [ copumpkin ]; + maintainers = [ copumpkin joachifm ]; }; machine = { config, pkgs, ... }: - { boot.kernelPackages = pkgs.linuxPackages_grsec_testing_server; }; + { security.grsecurity.enable = true; + boot.kernel.sysctl."kernel.grsecurity.deter_bruteforce" = 0; + security.apparmor.enable = true; + }; - testScript = - '' - $machine->succeed("uname -a") =~ /grsec/; - # FIXME: this seems to hang the whole test. Unclear why, but let's fix it - # $machine->succeed("${pkgs.paxtest}/bin/paxtest blackhat"); - ''; -}) + testScript = '' + subtest "grsec-lock", sub { + $machine->succeed("systemctl is-active grsec-lock"); + $machine->succeed("grep -Fq 1 /proc/sys/kernel/grsecurity/grsec_lock"); + $machine->fail("echo -n 0 >/proc/sys/kernel/grsecurity/grsec_lock"); + }; + + subtest "paxtest", sub { + # TODO: running paxtest blackhat hangs the vm + $machine->succeed("${pkgs.paxtest}/lib/paxtest/anonmap") =~ /Killed/ or die; + $machine->succeed("${pkgs.paxtest}/lib/paxtest/execbss") =~ /Killed/ or die; + $machine->succeed("${pkgs.paxtest}/lib/paxtest/execdata") =~ /Killed/ or die; + $machine->succeed("${pkgs.paxtest}/lib/paxtest/execheap") =~ /Killed/ or die; + $machine->succeed("${pkgs.paxtest}/lib/paxtest/execstack") =~ /Killed/ or die; + $machine->succeed("${pkgs.paxtest}/lib/paxtest/mprotanon") =~ /Killed/ or die; + $machine->succeed("${pkgs.paxtest}/lib/paxtest/mprotbss") =~ /Killed/ or die; + $machine->succeed("${pkgs.paxtest}/lib/paxtest/mprotdata") =~ /Killed/ or die; + $machine->succeed("${pkgs.paxtest}/lib/paxtest/mprotheap") =~ /Killed/ or die; + $machine->succeed("${pkgs.paxtest}/lib/paxtest/mprotstack") =~ /Killed/ or die; + }; + subtest "tcc", sub { + $machine->execute("echo -e '#include <stdio.h>\nint main(void) { puts(\"hello\"); return 0; }' >main.c"); + $machine->succeed("${pkgs.tinycc.bin}/bin/tcc -run main.c"); + }; + ''; +}) |