about summary refs log tree commit diff
path: root/nixos/modules
diff options
context:
space:
mode:
Diffstat (limited to 'nixos/modules')
-rw-r--r--nixos/modules/config/shells-environment.nix2
-rw-r--r--nixos/modules/installer/tools/nixos-generate-config.pl2
-rw-r--r--nixos/modules/installer/tools/nixos-install.sh4
-rw-r--r--nixos/modules/misc/locate.nix19
-rw-r--r--nixos/modules/module-list.nix2
-rw-r--r--nixos/modules/programs/kbdlight.nix2
-rw-r--r--nixos/modules/programs/light.nix2
-rw-r--r--nixos/modules/programs/shadow.nix16
-rw-r--r--nixos/modules/rename.nix1
-rw-r--r--nixos/modules/security/apparmor-suid.nix3
-rw-r--r--nixos/modules/security/chromium-suid-sandbox.nix2
-rw-r--r--nixos/modules/security/duosec.nix3
-rw-r--r--nixos/modules/security/pam.nix19
-rw-r--r--nixos/modules/security/pam_usb.nix8
-rw-r--r--nixos/modules/security/polkit.nix14
-rw-r--r--nixos/modules/security/setuid-wrapper.c81
-rw-r--r--nixos/modules/security/setuid-wrappers.nix146
-rw-r--r--nixos/modules/security/sudo.nix5
-rw-r--r--nixos/modules/security/wrappers/default.nix228
-rw-r--r--nixos/modules/security/wrappers/wrapper.c229
-rw-r--r--nixos/modules/services/logging/logcheck.nix4
-rw-r--r--nixos/modules/services/mail/dovecot.nix2
-rw-r--r--nixos/modules/services/mail/exim.nix4
-rw-r--r--nixos/modules/services/mail/mail.nix2
-rw-r--r--nixos/modules/services/monitoring/munin.nix4
-rw-r--r--nixos/modules/services/monitoring/smartd.nix2
-rw-r--r--nixos/modules/services/network-filesystems/samba.nix2
-rw-r--r--nixos/modules/services/networking/gale.nix2
-rw-r--r--nixos/modules/services/networking/prayer.nix2
-rw-r--r--nixos/modules/services/networking/smokeping.nix7
-rw-r--r--nixos/modules/services/scheduling/atd.nix6
-rw-r--r--nixos/modules/services/scheduling/cron.nix10
-rw-r--r--nixos/modules/services/scheduling/fcron.nix5
-rw-r--r--nixos/modules/services/system/dbus.nix17
-rw-r--r--nixos/modules/services/x11/desktop-managers/enlightenment.nix2
-rw-r--r--nixos/modules/services/x11/desktop-managers/kde5.nix19
-rw-r--r--nixos/modules/tasks/network-interfaces.nix19
-rw-r--r--nixos/modules/virtualisation/virtualbox-host.nix9
38 files changed, 570 insertions, 336 deletions
diff --git a/nixos/modules/config/shells-environment.nix b/nixos/modules/config/shells-environment.nix
index 8147fed39d09..8a7b3ea0bfd2 100644
--- a/nixos/modules/config/shells-environment.nix
+++ b/nixos/modules/config/shells-environment.nix
@@ -168,7 +168,7 @@ in
 
          ${cfg.extraInit}
 
-         # The setuid wrappers override other bin directories.
+         # The setuid/setcap wrappers override other bin directories.
          export PATH="${config.security.wrapperDir}:$PATH"
 
          # ~/bin if it exists overrides other bin directories.
diff --git a/nixos/modules/installer/tools/nixos-generate-config.pl b/nixos/modules/installer/tools/nixos-generate-config.pl
index 48f6cc76e4aa..a1b6cf535971 100644
--- a/nixos/modules/installer/tools/nixos-generate-config.pl
+++ b/nixos/modules/installer/tools/nixos-generate-config.pl
@@ -347,7 +347,7 @@ foreach my $fs (read_file("/proc/self/mountinfo")) {
 
     # Skip special filesystems.
     next if in($mountPoint, "/proc") || in($mountPoint, "/dev") || in($mountPoint, "/sys") || in($mountPoint, "/run") || $mountPoint eq "/var/lib/nfs/rpc_pipefs";
-    next if $mountPoint eq "/var/setuid-wrappers";
+    next if $mountPoint eq "/run/wrappers";
 
     # Skip the optional fields.
     my $n = 6; $n++ while $fields[$n] ne "-"; $n++;
diff --git a/nixos/modules/installer/tools/nixos-install.sh b/nixos/modules/installer/tools/nixos-install.sh
index da28c027c563..57bc249360e7 100644
--- a/nixos/modules/installer/tools/nixos-install.sh
+++ b/nixos/modules/installer/tools/nixos-install.sh
@@ -259,9 +259,9 @@ chroot $mountPoint /nix/var/nix/profiles/system/activate
 
 
 # Ask the user to set a root password.
-if [ -z "$noRootPasswd" ] && chroot $mountPoint [ -x /var/setuid-wrappers/passwd ] && [ -t 0 ]; then
+if [ -z "$noRootPasswd" ] && chroot $mountPoint [ -x /run/wrappers/bin/passwd ] && [ -t 0 ]; then
     echo "setting root password..."
-    chroot $mountPoint /var/setuid-wrappers/passwd
+    chroot $mountPoint /run/wrappers/bin/passwd
 fi
 
 
diff --git a/nixos/modules/misc/locate.nix b/nixos/modules/misc/locate.nix
index a9c84f6db243..089f354f6119 100644
--- a/nixos/modules/misc/locate.nix
+++ b/nixos/modules/misc/locate.nix
@@ -103,15 +103,16 @@ in {
   config = mkIf cfg.enable {
     users.extraGroups = mkIf isMLocate { mlocate = {}; };
 
-    security.setuidOwners = mkIf isMLocate
-      [ { group = "mlocate";
-          owner = "root";
-          permissions = "u+rx,g+x,o+x";
-          setgid = true;
-          setuid = false;
-          program = "locate";
-        }
-      ];
+    security.wrappers = mkIf isMLocate {
+      mlocate = {
+        group = "mlocate";
+        owner = "root";
+        permissions = "u+rx,g+x,o+x";
+        setgid = true;
+        setuid = false;
+        program = "locate";
+      };
+    };
 
     nixpkgs.config = { locate.dbfile = cfg.output; };
 
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index cf791a67f53f..9dbc009a6e44 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -113,7 +113,7 @@
   ./security/prey.nix
   ./security/rngd.nix
   ./security/rtkit.nix
-  ./security/setuid-wrappers.nix
+  ./security/wrappers
   ./security/sudo.nix
   ./services/amqp/activemq/default.nix
   ./services/amqp/rabbitmq.nix
diff --git a/nixos/modules/programs/kbdlight.nix b/nixos/modules/programs/kbdlight.nix
index 0172368e968f..58e45872fac8 100644
--- a/nixos/modules/programs/kbdlight.nix
+++ b/nixos/modules/programs/kbdlight.nix
@@ -11,6 +11,6 @@ in
 
   config = mkIf cfg.enable {
     environment.systemPackages = [ pkgs.kbdlight ];
-    security.setuidPrograms = [ "kbdlight" ];
+    security.wrappers.kbdlight.source = "${pkgs.kbdlight.out}/bin/kbdlight";
   };
 }
diff --git a/nixos/modules/programs/light.nix b/nixos/modules/programs/light.nix
index 09cd1113d9c7..6f8c389acc97 100644
--- a/nixos/modules/programs/light.nix
+++ b/nixos/modules/programs/light.nix
@@ -21,6 +21,6 @@ in
 
   config = mkIf cfg.enable {
     environment.systemPackages = [ pkgs.light ];
-    security.setuidPrograms = [ "light" ];
+    security.wrappers.light.source = "${pkgs.light.out}/bin/light";
   };
 }
diff --git a/nixos/modules/programs/shadow.nix b/nixos/modules/programs/shadow.nix
index ce4d46e19bf9..0f3f42901bab 100644
--- a/nixos/modules/programs/shadow.nix
+++ b/nixos/modules/programs/shadow.nix
@@ -101,11 +101,15 @@ in
         chpasswd = { rootOK = true; };
       };
 
-    security.setuidPrograms = [ "su" "chfn" ]
-      ++ [ "newuidmap" "newgidmap" ] # new in shadow 4.2.x
-      ++ lib.optionals config.users.mutableUsers
-      [ "passwd" "sg" "newgrp" ];
-
+    security.wrappers = {
+      su.source        = "${pkgs.shadow.su}/bin/su";
+      chfn.source      = "${pkgs.shadow.out}/bin/chfn";
+      newuidmap.source = "${pkgs.shadow.out}/bin/newuidmap";
+      newgidmap.source = "${pkgs.shadow.out}/bin/newgidmap";
+    } // (if config.users.mutableUsers then {
+      passwd.source    = "${pkgs.shadow.out}/bin/passwd";
+      sg.source        = "${pkgs.shadow.out}/bin/sg";
+      newgrp.source    = "${pkgs.shadow.out}/bin/newgrp";
+    } else {});
   };
-
 }
diff --git a/nixos/modules/rename.nix b/nixos/modules/rename.nix
index 5ae3f4bd6e63..e419474b3e32 100644
--- a/nixos/modules/rename.nix
+++ b/nixos/modules/rename.nix
@@ -10,7 +10,6 @@ with lib;
     (mkRenamedOptionModule [ "fonts" "enableFontConfig" ] [ "fonts" "fontconfig" "enable" ])
     (mkRenamedOptionModule [ "fonts" "extraFonts" ] [ "fonts" "fonts" ])
 
-    (mkRenamedOptionModule [ "security" "extraSetuidPrograms" ] [ "security" "setuidPrograms" ])
     (mkRenamedOptionModule [ "networking" "enableWLAN" ] [ "networking" "wireless" "enable" ])
     (mkRenamedOptionModule [ "networking" "enableRT73Firmware" ] [ "networking" "enableRalinkFirmware" ])
 
diff --git a/nixos/modules/security/apparmor-suid.nix b/nixos/modules/security/apparmor-suid.nix
index 4a6d61d26766..dfbf5d859ba9 100644
--- a/nixos/modules/security/apparmor-suid.nix
+++ b/nixos/modules/security/apparmor-suid.nix
@@ -19,7 +19,7 @@ with lib;
   config = mkIf (cfg.confineSUIDApplications) {
     security.apparmor.profiles = [ (pkgs.writeText "ping" ''
       #include <tunables/global>
-      /var/setuid-wrappers/ping {
+      /run/wrappers/bin/ping {
         #include <abstractions/base>
         #include <abstractions/consoles>
         #include <abstractions/nameservice>
@@ -33,7 +33,6 @@ with lib;
         ${pkgs.attr.out}/lib/libattr.so* mr,
 
         ${pkgs.iputils}/bin/ping mixr,
-        /var/setuid-wrappers/ping.real r,
 
         #/etc/modules.conf r,
 
diff --git a/nixos/modules/security/chromium-suid-sandbox.nix b/nixos/modules/security/chromium-suid-sandbox.nix
index 88fbe518c2de..0458ffb6c46c 100644
--- a/nixos/modules/security/chromium-suid-sandbox.nix
+++ b/nixos/modules/security/chromium-suid-sandbox.nix
@@ -27,6 +27,6 @@ in
 
   config = mkIf cfg.enable {
     environment.systemPackages = [ sandbox ];
-    security.setuidPrograms    = [ sandbox.passthru.sandboxExecutableName ];
+    security.wrappers."${sandbox.passthru.sandboxExecutableName}".source = "${sandbox}/bin/${sandbox.passthru.sandboxExecutableName}";
   };
 }
diff --git a/nixos/modules/security/duosec.nix b/nixos/modules/security/duosec.nix
index 97e2d39dc076..9ca818e86ffa 100644
--- a/nixos/modules/security/duosec.nix
+++ b/nixos/modules/security/duosec.nix
@@ -187,7 +187,8 @@ in
       ];
 
      environment.systemPackages = [ pkgs.duo-unix ];
-     security.setuidPrograms    = [ "login_duo" ];
+
+     security.wrappers.login_duo.source = "${pkgs.duo-unix.out}/bin/login_duo";
      environment.etc = loginCfgFile ++ pamCfgFile;
 
      /* If PAM *and* SSH are enabled, then don't do anything special.
diff --git a/nixos/modules/security/pam.nix b/nixos/modules/security/pam.nix
index 67652fbd1e70..e37c55aa1ac9 100644
--- a/nixos/modules/security/pam.nix
+++ b/nixos/modules/security/pam.nix
@@ -472,19 +472,20 @@ in
       ++ optionals config.security.pam.enableU2F [ pkgs.pam_u2f ]
       ++ optionals config.security.pam.enableEcryptfs [ pkgs.ecryptfs ];
 
-    security.setuidPrograms =
-        optionals config.security.pam.enableEcryptfs [ "mount.ecryptfs_private" "umount.ecryptfs_private" ];
+    security.wrappers = {
+      unix_chkpwd = {
+        source = "${pkgs.pam}/sbin/unix_chkpwd.orig";
+        owner = "root";
+        setuid = true;
+      };
+    } // (if config.security.pam.enableEcryptfs then {
+      "mount.ecryptfs_private".source = "${pkgs.ecryptfs.out}/bin/mount.ecryptfs_private";
+       "umount.ecryptfs_private".source = "${pkgs.ecryptfs.out}/bin/umount.ecryptfs_private";
+    } else {});
 
     environment.etc =
       mapAttrsToList (n: v: makePAMService v) config.security.pam.services;
 
-    security.setuidOwners = [ {
-      program = "unix_chkpwd";
-      source = "${pkgs.pam}/sbin/unix_chkpwd.orig";
-      owner = "root";
-      setuid = true;
-    } ];
-
     security.pam.services =
       { other.text =
           ''
diff --git a/nixos/modules/security/pam_usb.nix b/nixos/modules/security/pam_usb.nix
index 11708a1f0167..6f811dab8d76 100644
--- a/nixos/modules/security/pam_usb.nix
+++ b/nixos/modules/security/pam_usb.nix
@@ -32,10 +32,12 @@ in
 
   config = mkIf (cfg.enable || anyUsbAuth) {
 
-    # pmount need to have a set-uid bit to make pam_usb works in user
-    # environment. (like su, sudo)
+    # Make sure pmount and pumount are setuid wrapped.
+    security.wrappers = {
+      pmount.source = "${pkgs.pmount.out}/bin/pmount";
+      pumount.source = "${pkgs.pmount.out}/bin/pumount";
+    };
 
-    security.setuidPrograms = [ "pmount" "pumount" ];
     environment.systemPackages = [ pkgs.pmount ];
 
   };
diff --git a/nixos/modules/security/polkit.nix b/nixos/modules/security/polkit.nix
index 507f81bbf073..419abb8b086d 100644
--- a/nixos/modules/security/polkit.nix
+++ b/nixos/modules/security/polkit.nix
@@ -83,16 +83,10 @@ in
 
     security.pam.services.polkit-1 = {};
 
-    security.setuidPrograms = [ "pkexec" ];
-
-    security.setuidOwners = [
-      { program = "polkit-agent-helper-1";
-        owner = "root";
-        group = "root";
-        setuid = true;
-        source = "${pkgs.polkit.out}/lib/polkit-1/polkit-agent-helper-1";
-      }
-    ];
+    security.wrappers = {
+      pkexec.source = "${pkgs.polkit.out}/bin/pkexec";
+      "polkit-agent-helper-1".source = "${pkgs.polkit.out}/lib/polkit-1/polkit-agent-helper-1";
+    };
 
     system.activationScripts.polkit =
       ''
diff --git a/nixos/modules/security/setuid-wrapper.c b/nixos/modules/security/setuid-wrapper.c
deleted file mode 100644
index ffd0b65b7629..000000000000
--- a/nixos/modules/security/setuid-wrapper.c
+++ /dev/null
@@ -1,81 +0,0 @@
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <dirent.h>
-#include <assert.h>
-#include <string.h>
-#include <errno.h>
-
-/* Make sure assertions are not compiled out.  */
-#undef NDEBUG
-
-extern char **environ;
-
-static char * wrapperDir = WRAPPER_DIR;
-
-int main(int argc, char * * argv)
-{
-    char self[PATH_MAX];
-
-    int len = readlink("/proc/self/exe", self, sizeof(self) - 1);
-    assert (len > 0);
-    self[len] = 0;
-
-    /* Make sure that we are being executed from the right location,
-       i.e., `wrapperDir'.  This is to prevent someone from
-       creating hard link `X' from some other location, along with a
-       false `X.real' file, to allow arbitrary programs from being
-       executed setuid.  */
-    assert ((strncmp(self, wrapperDir, strlen(wrapperDir)) == 0) &&
-            (self[strlen(wrapperDir)] == '/'));
-
-    /* Make *really* *really* sure that we were executed as `self',
-       and not, say, as some other setuid program.  That is, our
-       effective uid/gid should match the uid/gid of `self'. */
-    //printf("%d %d\n", geteuid(), getegid());
-
-    struct stat st;
-    assert (lstat(self, &st) != -1);
-
-    //printf("%d %d\n", st.st_uid, st.st_gid);
-
-    assert ((st.st_mode & S_ISUID) == 0 ||
-            (st.st_uid == geteuid()));
-
-    assert ((st.st_mode & S_ISGID) == 0 ||
-            st.st_gid == getegid());
-
-    /* And, of course, we shouldn't be writable. */
-    assert (!(st.st_mode & (S_IWGRP | S_IWOTH)));
-
-
-    /* Read the path of the real (wrapped) program from <self>.real. */
-    char realFN[PATH_MAX + 10];
-    int realFNSize = snprintf (realFN, sizeof(realFN), "%s.real", self);
-    assert (realFNSize < sizeof(realFN));
-
-    int fdSelf = open(realFN, O_RDONLY);
-    assert (fdSelf != -1);
-
-    char real[PATH_MAX];
-    len = read(fdSelf, real, PATH_MAX);
-    assert (len != -1);
-    assert (len < sizeof (real));
-    assert (len > 0);
-    real[len] = 0;
-
-    close(fdSelf);
-
-    //printf("real = %s, len = %d\n", real, len);
-
-    execve(real, argv, environ);
-
-    fprintf(stderr, "%s: cannot run `%s': %s\n",
-        argv[0], real, strerror(errno));
-
-    exit(1);
-}
diff --git a/nixos/modules/security/setuid-wrappers.nix b/nixos/modules/security/setuid-wrappers.nix
deleted file mode 100644
index fe220c94313f..000000000000
--- a/nixos/modules/security/setuid-wrappers.nix
+++ /dev/null
@@ -1,146 +0,0 @@
-{ config, lib, pkgs, ... }:
-
-with lib;
-
-let
-
-  inherit (config.security) wrapperDir;
-
-  setuidWrapper = pkgs.stdenv.mkDerivation {
-    name = "setuid-wrapper";
-    unpackPhase = "true";
-    installPhase = ''
-      mkdir -p $out/bin
-      cp ${./setuid-wrapper.c} setuid-wrapper.c
-      gcc -Wall -O2 -DWRAPPER_DIR=\"/run/setuid-wrapper-dirs\" \
-          setuid-wrapper.c -o $out/bin/setuid-wrapper
-    '';
-  };
-
-in
-
-{
-
-  ###### interface
-
-  options = {
-
-    security.setuidPrograms = mkOption {
-      type = types.listOf types.str;
-      default = [];
-      example = ["passwd"];
-      description = ''
-        The Nix store cannot contain setuid/setgid programs directly.
-        For this reason, NixOS can automatically generate wrapper
-        programs that have the necessary privileges.  This option
-        lists the names of programs in the system environment for
-        which setuid root wrappers should be created.
-      '';
-    };
-
-    security.setuidOwners = mkOption {
-      type = types.listOf types.attrs;
-      default = [];
-      example =
-        [ { program = "sendmail";
-            owner = "nobody";
-            group = "postdrop";
-            setuid = false;
-            setgid = true;
-            permissions = "u+rx,g+x,o+x";
-          }
-        ];
-      description = ''
-        This option allows the ownership and permissions on the setuid
-        wrappers for specific programs to be overridden from the
-        default (setuid root, but not setgid root).
-      '';
-    };
-
-    security.wrapperDir = mkOption {
-      internal = true;
-      type = types.path;
-      default = "/var/setuid-wrappers";
-      description = ''
-        This option defines the path to the setuid wrappers.  It
-        should generally not be overriden. Some packages in Nixpkgs
-        expect that <option>wrapperDir</option> is
-        <filename>/var/setuid-wrappers</filename>.
-      '';
-    };
-
-  };
-
-
-  ###### implementation
-
-  config = {
-
-    security.setuidPrograms = [ "fusermount" ];
-
-    system.activationScripts.setuid =
-      let
-        setuidPrograms =
-          (map (x: { program = x; owner = "root"; group = "root"; setuid = true; })
-            config.security.setuidPrograms)
-          ++ config.security.setuidOwners;
-
-        makeSetuidWrapper =
-          { program
-          , source ? ""
-          , owner ? "nobody"
-          , group ? "nogroup"
-          , setuid ? false
-          , setgid ? false
-          , permissions ? "u+rx,g+x,o+x"
-          }:
-
-          ''
-            if ! source=${if source != "" then source else "$(readlink -f $(PATH=$SETUID_PATH type -tP ${program}))"}; then
-                # If we can't find the program, fall back to the
-                # system profile.
-                source=/nix/var/nix/profiles/default/bin/${program}
-            fi
-
-            cp ${setuidWrapper}/bin/setuid-wrapper $wrapperDir/${program}
-            echo -n "$source" > $wrapperDir/${program}.real
-            chmod 0000 $wrapperDir/${program} # to prevent races
-            chown ${owner}.${group} $wrapperDir/${program}
-            chmod "u${if setuid then "+" else "-"}s,g${if setgid then "+" else "-"}s,${permissions}" $wrapperDir/${program}
-          '';
-
-      in stringAfter [ "users" ]
-        ''
-          # Look in the system path and in the default profile for
-          # programs to be wrapped.
-          SETUID_PATH=${config.system.path}/bin:${config.system.path}/sbin
-
-          mkdir -p /run/setuid-wrapper-dirs
-          wrapperDir=$(mktemp --directory --tmpdir=/run/setuid-wrapper-dirs setuid-wrappers.XXXXXXXXXX)
-          chmod a+rx $wrapperDir
-
-          ${concatMapStrings makeSetuidWrapper setuidPrograms}
-
-          if [ -L ${wrapperDir} ]; then
-            # Atomically replace the symlink
-            # See https://axialcorps.com/2013/07/03/atomically-replacing-files-and-directories/
-            old=$(readlink ${wrapperDir})
-            ln --symbolic --force --no-dereference $wrapperDir ${wrapperDir}-tmp
-            mv --no-target-directory ${wrapperDir}-tmp ${wrapperDir}
-            rm --force --recursive $old
-          elif [ -d ${wrapperDir} ]; then
-            # Compatibility with old state, just remove the folder and symlink
-            rm -f ${wrapperDir}/*
-            # if it happens to be a tmpfs
-            ${pkgs.utillinux}/bin/umount ${wrapperDir} || true
-            rm -d ${wrapperDir}
-            ln -d --symbolic $wrapperDir ${wrapperDir}
-          else
-            # For initial setup
-            ln --symbolic $wrapperDir ${wrapperDir}
-          fi
-        '';
-
-  };
-
-}
diff --git a/nixos/modules/security/sudo.nix b/nixos/modules/security/sudo.nix
index f5612e1b0c5d..67a9b9a45ee3 100644
--- a/nixos/modules/security/sudo.nix
+++ b/nixos/modules/security/sudo.nix
@@ -81,7 +81,10 @@ in
         ${cfg.extraConfig}
       '';
 
-    security.setuidPrograms = [ "sudo" "sudoedit" ];
+    security.wrappers = {
+      sudo.source = "${pkgs.sudo.out}/bin/sudo";
+      sudoedit.source = "${pkgs.sudo.out}/bin/sudoedit";
+    };
 
     environment.systemPackages = [ sudo ];
 
diff --git a/nixos/modules/security/wrappers/default.nix b/nixos/modules/security/wrappers/default.nix
new file mode 100644
index 000000000000..757765ed08c4
--- /dev/null
+++ b/nixos/modules/security/wrappers/default.nix
@@ -0,0 +1,228 @@
+{ config, lib, pkgs, ... }:
+let
+
+  inherit (config.security) wrapperDir wrappers setuidPrograms;
+
+  programs =
+    (lib.mapAttrsToList
+      (n: v: (if v ? "program" then v else v // {program=n;}))
+      wrappers);
+
+  mkWrapper = { program, source ? null, ...}:
+    let buildWrapper = ''
+          parentWrapperDir=$(dirname ${wrapperDir})
+          gcc -Wall -O2 -DSOURCE_PROG=\"${source}\" -DWRAPPER_DIR=\"$parentWrapperDir\" \
+              -Wformat -Wformat-security -Werror=format-security \
+              -fstack-protector-strong --param ssp-buffer-size=4 \
+              -D_FORTIFY_SOURCE=2 -fPIC \
+              -lcap-ng -lcap ${./wrapper.c} -o $out/bin/${program}.wrapper -L ${pkgs.libcap.lib}/lib -L ${pkgs.libcap_ng}/lib \
+              -I ${pkgs.libcap.dev}/include -I ${pkgs.libcap_ng}/include -I ${pkgs.linuxHeaders}/include
+        '';
+    in pkgs.stdenv.mkDerivation {
+      name         = "${program}-wrapper";
+      unpackPhase  = "true";
+      installPhase = ''
+        mkdir -p $out/bin
+        ${buildWrapper}
+      '';
+    };
+
+  ###### Activation script for the setcap wrappers
+  mkSetcapProgram =
+    { program
+    , capabilities
+    , source ? null
+    , owner  ? "nobody"
+    , group  ? "nogroup"
+    , ...
+    }:
+    assert (lib.versionAtLeast (lib.getVersion config.boot.kernelPackages.kernel) "4.3");
+    let wrapperDrv = mkWrapper { inherit program source; };
+    in ''
+      cp ${wrapperDrv}/bin/${program}.wrapper $wrapperDir/${program}
+
+      # Prevent races
+      chmod 0000 $wrapperDir/${program}
+      chown ${owner}.${group} $wrapperDir/${program}
+
+      # Set desired capabilities on the file plus cap_setpcap so
+      # the wrapper program can elevate the capabilities set on
+      # its file into the Ambient set.
+      ${pkgs.libcap.out}/bin/setcap "cap_setpcap,${capabilities}" $wrapperDir/${program}
+
+      # Set the executable bit
+      chmod u+rx,g+x,o+x $wrapperDir/${program}
+    '';
+
+  ###### Activation script for the setuid wrappers
+  mkSetuidProgram =
+    { program
+    , source ? null
+    , owner  ? "nobody"
+    , group  ? "nogroup"
+    , setuid ? false
+    , setgid ? false
+    , permissions ? "u+rx,g+x,o+x"
+    , ...
+    }:
+    let wrapperDrv = mkWrapper { inherit program source; };
+    in ''
+      cp ${wrapperDrv}/bin/${program}.wrapper $wrapperDir/${program}
+
+      # Prevent races
+      chmod 0000 $wrapperDir/${program}
+      chown ${owner}.${group} $wrapperDir/${program}
+
+      chmod "u${if setuid then "+" else "-"}s,g${if setgid then "+" else "-"}s,${permissions}" $wrapperDir/${program}
+    '';
+
+  mkWrappedPrograms =
+    builtins.map
+      (s: if (s ? "capabilities")
+          then mkSetcapProgram s
+          else if 
+             (s ? "setuid"  && s.setuid  == true) ||
+             (s ? "setguid" && s.setguid == true) ||
+             (s ? "permissions")
+          then mkSetuidProgram s
+          else mkSetuidProgram
+                 ({ owner  = "root";
+                    group  = "root";
+                    setuid = true;
+                    setgid = false;
+                    permissions = "u+rx,g+x,o+x";
+                  } // s)
+      ) programs;
+in
+{
+
+  ###### interface
+
+  options = {
+    security.wrappers = lib.mkOption {
+      type = lib.types.attrs;
+      default = {};
+      example = {
+        sendmail.source = "/nix/store/.../bin/sendmail";
+        ping = {
+          source  = "${pkgs.iputils.out}/bin/ping";
+          owner   = "nobody";
+          group   = "nogroup";
+          capabilities = "cap_net_raw+ep";
+        };
+      };
+      description = ''
+        This option allows the ownership and permissions on the setuid
+        wrappers for specific programs to be overridden from the
+        default (setuid root, but not setgid root).
+
+        Additionally, this option can set capabilities on a wrapper
+        program that propagates those capabilities down to the
+        wrapped, real program.
+
+        The <literal>program</literal> attribute is the name of the
+        program to be wrapped. If no <literal>source</literal>
+        attribute is provided, specifying the absolute path to the
+        program, then the program will be searched for in the path
+        environment variable.
+
+        NOTE: cap_setpcap, which is required for the wrapper program
+        to be able to raise caps into the Ambient set is NOT raised to
+        the Ambient set so that the real program cannot modify its own
+        capabilities!! This may be too restrictive for cases in which
+        the real program needs cap_setpcap but it at least leans on
+        the side security paranoid vs. too relaxed.
+      '';
+    };
+
+    security.old-wrapperDir = lib.mkOption {
+      type        = lib.types.path;
+      default     = "/var/setuid-wrappers";
+      internal    = true;
+      description = ''
+        This option defines the path to the wrapper programs. It
+        should not be overriden.
+      '';
+    };
+
+    security.wrapperDir = lib.mkOption {
+      type        = lib.types.path;
+      default     = "/run/wrappers/bin";
+      internal    = true;
+      description = ''
+        This option defines the path to the wrapper programs. It
+        should not be overriden.
+      '';
+    };
+  };
+
+  ###### implementation
+  config = {
+
+    security.wrappers.fusermount.source = "${pkgs.fuse}/bin/fusermount";
+
+    # Make sure our wrapperDir exports to the PATH env variable when
+    # initializing the shell
+    environment.extraInit = ''
+      # Wrappers override other bin directories.
+      export PATH="${wrapperDir}:$PATH"
+    '';
+
+    ###### setcap activation script
+    system.activationScripts.wrappers =
+      lib.stringAfter [ "users" ]
+        ''
+          # Look in the system path and in the default profile for
+          # programs to be wrapped.
+          WRAPPER_PATH=${config.system.path}/bin:${config.system.path}/sbin
+
+          # Remove the old /var/setuid-wrappers path from the system...
+          #
+          # TDOO: this is only necessary for ugprades 16.09 => 17.x;
+          # this conditional removal block needs to be removed after
+          # the release.
+          if [ -d ${config.security.old-wrapperDir} ]; then
+            rm -rf ${config.security.old-wrapperDir}
+          fi
+
+          # Remove the old /run/setuid-wrappers-dir path from the
+          # system as well...
+          #
+          # TDOO: this is only necessary for ugprades 16.09 => 17.x;
+          # this conditional removal block needs to be removed after
+          # the release.
+          if [ -d /run/setuid-wrapper-dirs ]; then
+            rm -rf /run/setuid-wrapper-dirs
+          fi
+
+          # Get the "/run/wrappers" path, we want to place the tmpdirs
+          # for the wrappers there
+          parentWrapperDir="$(dirname ${wrapperDir})"
+
+          mkdir -p "$parentWrapperDir"
+          wrapperDir=$(mktemp --directory --tmpdir="$parentWrapperDir" wrappers.XXXXXXXXXX)
+          chmod a+rx $wrapperDir
+
+          ${lib.concatStringsSep "\n" mkWrappedPrograms}
+
+          if [ -L ${wrapperDir} ]; then
+            # Atomically replace the symlink
+            # See https://axialcorps.com/2013/07/03/atomically-replacing-files-and-directories/
+            old=$(readlink -f ${wrapperDir})
+            ln --symbolic --force --no-dereference $wrapperDir ${wrapperDir}-tmp
+            mv --no-target-directory ${wrapperDir}-tmp ${wrapperDir}
+            rm --force --recursive $old
+          elif [ -d ${wrapperDir} ]; then
+            # Compatibility with old state, just remove the folder and symlink
+            rm -f ${wrapperDir}/*
+            # if it happens to be a tmpfs
+            ${pkgs.utillinux}/bin/umount ${wrapperDir} || true
+            rm -d ${wrapperDir}
+            ln -d --symbolic $wrapperDir ${wrapperDir}
+          else
+            # For initial setup
+            ln --symbolic $wrapperDir ${wrapperDir}
+          fi
+        '';
+  };
+}
diff --git a/nixos/modules/security/wrappers/wrapper.c b/nixos/modules/security/wrappers/wrapper.c
new file mode 100644
index 000000000000..e6f2605143fe
--- /dev/null
+++ b/nixos/modules/security/wrappers/wrapper.c
@@ -0,0 +1,229 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <assert.h>
+#include <errno.h>
+#include <linux/capability.h>
+#include <sys/capability.h>
+#include <linux/prctl.h>
+#include <sys/prctl.h>
+#include <cap-ng.h>
+
+// Make sure assertions are not compiled out, we use them to codify
+// invariants about this program and we want it to fail fast and
+// loudly if they are violated.
+#undef NDEBUG
+
+extern char **environ;
+
+// The SOURCE_PROG and WRAPPER_DIR macros are supplied at compile time
+// for a security reason: So they cannot be changed at runtime.
+static char * sourceProg = SOURCE_PROG;
+static char * wrapperDir = WRAPPER_DIR;
+
+// Wrapper debug variable name
+static char * wrapperDebug = "WRAPPER_DEBUG";
+
+// Update the capabilities of the running process to include the given
+// capability in the Ambient set.
+static void set_ambient_cap(cap_value_t cap)
+{
+    capng_get_caps_process();
+
+    if (capng_update(CAPNG_ADD, CAPNG_INHERITABLE, (unsigned long) cap))
+    {
+        perror("cannot raise the capability into the Inheritable set\n");
+        exit(1);
+    }
+
+    capng_apply(CAPNG_SELECT_CAPS);
+    
+    if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, (unsigned long) cap, 0, 0))
+    {
+        perror("cannot raise the capability into the Ambient set\n");
+        exit(1);
+    }
+}
+
+// Given the path to this program, fetch its configured capability set
+// (as set by `setcap ... /path/to/file`) and raise those capabilities
+// into the Ambient set.
+static int make_caps_ambient(const char *selfPath)
+{
+    cap_t caps = cap_get_file(selfPath);
+
+    if(!caps)
+    {
+        if(getenv(wrapperDebug))
+            fprintf(stderr, "no caps set or could not retrieve the caps for this file, not doing anything...");
+
+        return 1;
+    }
+
+    // We use `cap_to_text` and iteration over the tokenized result
+    // string because, as of libcap's current release, there is no
+    // facility for retrieving an array of `cap_value_t`'s that can be
+    // given to `prctl` in order to lift that capability into the
+    // Ambient set.
+    //
+    // Some discussion was had around shot-gunning all of the
+    // capabilities we know about into the Ambient set but that has a
+    // security smell and I deemed the risk of the current
+    // implementation crashing the program to be lower than the risk
+    // of a privilege escalation security hole being introduced by
+    // raising all capabilities, even ones we didn't intend for the
+    // program, into the Ambient set.
+    //
+    // `cap_t` which is returned by `cap_get_*` is an opaque type and
+    // even if we could retrieve the bitmasks (which, as far as I can
+    // tell we cannot) in order to get the `cap_value_t`
+    // representation for each capability we would have to take the
+    // total number of capabilities supported and iterate over the
+    // sequence of integers up-to that maximum total, testing each one
+    // against the bitmask ((bitmask >> n) & 1) to see if it's set and
+    // aggregating each "capability integer n" that is set in the
+    // bitmask.
+    //
+    // That, combined with the fact that we can't easily get the
+    // bitmask anyway seemed much more brittle than fetching the
+    // `cap_t`, transforming it into a textual representation,
+    // tokenizing the string, and using `cap_from_name` on the token
+    // to get the `cap_value_t` that we need for `prctl`. There is
+    // indeed risk involved if the output string format of
+    // `cap_to_text` ever changes but at this time the combination of
+    // factors involving the below list have led me to the conclusion
+    // that the best implementation at this time is reading then
+    // parsing with *lots of documentation* about why we're doing it
+    // this way.
+    //
+    // 1. No explicit API for fetching an array of `cap_value_t`'s or
+    //    for transforming a `cap_t` into such a representation
+    // 2. The risk of a crash is lower than lifting all capabilities
+    //    into the Ambient set
+    // 3. libcap is depended on heavily in the Linux ecosystem so
+    //    there is a high chance that the output representation of
+    //    `cap_to_text` will not change which reduces our risk that
+    //    this parsing step will cause a crash
+    //
+    // The preferred method, should it ever be available in the
+    // future, would be to use libcap API's to transform the result
+    // from a `cap_get_*` into an array of `cap_value_t`'s that can
+    // then be given to prctl.
+    //
+    // - Parnell
+    ssize_t capLen;
+    char* capstr = cap_to_text(caps, &capLen);
+    cap_free(caps);
+    
+    // TODO: For now, we assume that cap_to_text always starts its
+    // result string with " =" and that the first capability is listed
+    // immediately after that. We should verify this.
+    assert(capLen >= 2);
+    capstr += 2;
+
+    char* saveptr = NULL;
+    for(char* tok = strtok_r(capstr, ",", &saveptr); tok; tok = strtok_r(NULL, ",", &saveptr))
+    {
+      cap_value_t capnum;
+      if (cap_from_name(tok, &capnum))
+      {
+          if(getenv(wrapperDebug))
+              fprintf(stderr, "cap_from_name failed, skipping: %s", tok);
+      }
+      else if (capnum == CAP_SETPCAP)
+      {
+          // Check for the cap_setpcap capability, we set this on the
+          // wrapper so it can elevate the capabilities to the Ambient
+          // set but we do not want to propagate it down into the
+          // wrapped program.
+          //
+          // TODO: what happens if that's the behavior you want
+          // though???? I'm preferring a strict vs. loose policy here.
+          if(getenv(wrapperDebug))
+              fprintf(stderr, "cap_setpcap in set, skipping it\n");
+      }
+      else
+      {
+          set_ambient_cap(capnum);
+
+          if(getenv(wrapperDebug))
+              fprintf(stderr, "raised %s into the Ambient capability set\n", tok);
+      }
+    }
+    cap_free(capstr);
+
+    return 0;
+}
+
+int main(int argc, char * * argv)
+{
+    // I *think* it's safe to assume that a path from a symbolic link
+    // should safely fit within the PATH_MAX system limit. Though I'm
+    // not positive it's safe...
+    char selfPath[PATH_MAX];
+    int selfPathSize = readlink("/proc/self/exe", selfPath, sizeof(selfPath) - 1);
+
+    assert(selfPathSize > 0);
+
+    // Assert we have room for the zero byte, this ensures the path
+    // isn't being truncated because it's too big for the buffer.
+    //
+    // A better way to handle this might be to use something like the
+    // whereami library (https://github.com/gpakosz/whereami) or a
+    // loop that resizes the buffer and re-reads the link if the
+    // contents are being truncated.
+    assert(selfPathSize < sizeof(selfPath));
+
+    // Set the zero byte since readlink doesn't do that for us.
+    selfPath[selfPathSize] = '\0';
+
+    // Make sure that we are being executed from the right location,
+    // i.e., `safeWrapperDir'.  This is to prevent someone from creating
+    // hard link `X' from some other location, along with a false
+    // `X.real' file, to allow arbitrary programs from being executed
+    // with elevated capabilities.
+    int len = strlen(wrapperDir);
+    if (len > 0 && '/' == wrapperDir[len - 1])
+      --len;
+    assert(!strncmp(selfPath, wrapperDir, len));
+    assert('/' == wrapperDir[0]);
+    assert('/' == selfPath[len]);
+
+    // Make *really* *really* sure that we were executed as
+    // `selfPath', and not, say, as some other setuid program. That
+    // is, our effective uid/gid should match the uid/gid of
+    // `selfPath'.
+    struct stat st;
+    assert(lstat(selfPath, &st) != -1);
+
+    assert(!(st.st_mode & S_ISUID) || (st.st_uid == geteuid()));
+    assert(!(st.st_mode & S_ISGID) || (st.st_gid == getegid()));
+
+    // And, of course, we shouldn't be writable.
+    assert(!(st.st_mode & (S_IWGRP | S_IWOTH)));
+
+    struct stat stR;
+    stat(sourceProg, &stR);
+
+    // Make sure the program we're wrapping is non-zero
+    assert(stR.st_size > 0);
+
+    // Read the capabilities set on the file and raise them in to the
+    // Ambient set so the program we're wrapping receives the
+    // capabilities too!
+    make_caps_ambient(selfPath);
+
+    execve(sourceProg, argv, environ);
+    
+    fprintf(stderr, "%s: cannot run `%s': %s\n",
+        argv[0], sourceProg, strerror(errno));
+
+    exit(1);
+}
+
+
diff --git a/nixos/modules/services/logging/logcheck.nix b/nixos/modules/services/logging/logcheck.nix
index 27ed5374f561..72925b95cae4 100644
--- a/nixos/modules/services/logging/logcheck.nix
+++ b/nixos/modules/services/logging/logcheck.nix
@@ -29,8 +29,8 @@ let
     };
 
   cronJob = ''
-    @reboot   logcheck env PATH=/var/setuid-wrappers:$PATH nice -n10 ${pkgs.logcheck}/sbin/logcheck -R ${flags}
-    2 ${cfg.timeOfDay} * * * logcheck env PATH=/var/setuid-wrappers:$PATH nice -n10 ${pkgs.logcheck}/sbin/logcheck ${flags}
+    @reboot   logcheck env PATH=/run/wrappers/bin:$PATH nice -n10 ${pkgs.logcheck}/sbin/logcheck -R ${flags}
+    2 ${cfg.timeOfDay} * * * logcheck env PATH=/run/wrappers/bin:$PATH nice -n10 ${pkgs.logcheck}/sbin/logcheck ${flags}
   '';
 
   writeIgnoreRule = name: {level, regex, ...}:
diff --git a/nixos/modules/services/mail/dovecot.nix b/nixos/modules/services/mail/dovecot.nix
index f2097638c637..3b25e41edb19 100644
--- a/nixos/modules/services/mail/dovecot.nix
+++ b/nixos/modules/services/mail/dovecot.nix
@@ -13,7 +13,7 @@ let
     ''
       base_dir = ${baseDir}
       protocols = ${concatStringsSep " " cfg.protocols}
-      sendmail_path = /var/setuid-wrappers/sendmail
+      sendmail_path = /run/wrappers/bin/sendmail
     ''
 
     (if isNull cfg.sslServerCert then ''
diff --git a/nixos/modules/services/mail/exim.nix b/nixos/modules/services/mail/exim.nix
index e0890d96a88b..440eae281f40 100644
--- a/nixos/modules/services/mail/exim.nix
+++ b/nixos/modules/services/mail/exim.nix
@@ -70,7 +70,7 @@ in
       etc."exim.conf".text = ''
         exim_user = ${cfg.user}
         exim_group = ${cfg.group}
-        exim_path = /var/setuid-wrappers/exim
+        exim_path = /run/wrappers/bin/exim
         spool_directory = ${cfg.spoolDir}
         ${cfg.config}
       '';
@@ -89,7 +89,7 @@ in
       gid = config.ids.gids.exim;
     };
 
-    security.setuidPrograms = [ "exim" ];
+    security.wrappers.exim.source = "${exim}/bin/exim";
 
     systemd.services.exim = {
       description = "Exim Mail Daemon";
diff --git a/nixos/modules/services/mail/mail.nix b/nixos/modules/services/mail/mail.nix
index 63e8d78b5b02..cfe1b5496a45 100644
--- a/nixos/modules/services/mail/mail.nix
+++ b/nixos/modules/services/mail/mail.nix
@@ -26,7 +26,7 @@ with lib;
 
   config = mkIf (config.services.mail.sendmailSetuidWrapper != null) {
 
-    security.setuidOwners = [ config.services.mail.sendmailSetuidWrapper ];
+    security.wrappers.sendmail = config.services.mail.sendmailSetuidWrapper;
 
   };
 
diff --git a/nixos/modules/services/monitoring/munin.nix b/nixos/modules/services/monitoring/munin.nix
index 57df16b58d9c..6d2ce5383687 100644
--- a/nixos/modules/services/monitoring/munin.nix
+++ b/nixos/modules/services/monitoring/munin.nix
@@ -34,7 +34,7 @@ let
         cap=$(sed -nr 's/.*#%#\s+capabilities\s*=\s*(.+)/\1/p' $file)
 
         wrapProgram $file \
-          --set PATH "/var/setuid-wrappers:/run/current-system/sw/bin:/run/current-system/sw/bin" \
+          --set PATH "/run/wrappers/bin:/run/current-system/sw/bin:/run/current-system/sw/bin" \
           --set MUNIN_LIBDIR "${pkgs.munin}/lib" \
           --set MUNIN_PLUGSTATE "/var/run/munin"
 
@@ -183,7 +183,7 @@ in
 
         mkdir -p /etc/munin/plugins
         rm -rf /etc/munin/plugins/*
-        PATH="/var/setuid-wrappers:/run/current-system/sw/bin:/run/current-system/sw/bin" ${pkgs.munin}/sbin/munin-node-configure --shell --families contrib,auto,manual --config ${nodeConf} --libdir=${muninPlugins} --servicedir=/etc/munin/plugins 2>/dev/null | ${pkgs.bash}/bin/bash
+        PATH="/run/wrappers/bin:/run/current-system/sw/bin:/run/current-system/sw/bin" ${pkgs.munin}/sbin/munin-node-configure --shell --families contrib,auto,manual --config ${nodeConf} --libdir=${muninPlugins} --servicedir=/etc/munin/plugins 2>/dev/null | ${pkgs.bash}/bin/bash
       '';
       serviceConfig = {
         ExecStart = "${pkgs.munin}/sbin/munin-node --config ${nodeConf} --servicedir /etc/munin/plugins/";
diff --git a/nixos/modules/services/monitoring/smartd.nix b/nixos/modules/services/monitoring/smartd.nix
index f2834f288f90..4d10299a9879 100644
--- a/nixos/modules/services/monitoring/smartd.nix
+++ b/nixos/modules/services/monitoring/smartd.nix
@@ -124,7 +124,7 @@ in
           };
 
           mailer = mkOption {
-            default = "/var/setuid-wrappers/sendmail";
+            default = "/run/wrappers/bin/sendmail";
             type = types.path;
             description = ''
               Sendmail-compatible binary to be used to send the messages.
diff --git a/nixos/modules/services/network-filesystems/samba.nix b/nixos/modules/services/network-filesystems/samba.nix
index 7de85b59e2af..09a11585bc92 100644
--- a/nixos/modules/services/network-filesystems/samba.nix
+++ b/nixos/modules/services/network-filesystems/samba.nix
@@ -30,7 +30,7 @@ let
     ''
       [ global ]
       security = ${cfg.securityType}
-      passwd program = /var/setuid-wrappers/passwd %u
+      passwd program = /run/wrappers/bin/passwd %u
       pam password change = ${smbToString cfg.syncPasswordsByPam}
       invalid users = ${smbToString cfg.invalidUsers}
 
diff --git a/nixos/modules/services/networking/gale.nix b/nixos/modules/services/networking/gale.nix
index bc975159cdfd..fd83f9e3c1b7 100644
--- a/nixos/modules/services/networking/gale.nix
+++ b/nixos/modules/services/networking/gale.nix
@@ -141,7 +141,7 @@ in
          setgid = false;
        };
 
-       security.setuidOwners = [ cfg.setuidWrapper ];
+       security.wrappers.gksign = cfg.setuidWrapper;
 
        systemd.services.gale-galed = {
          description = "Gale messaging daemon";
diff --git a/nixos/modules/services/networking/prayer.nix b/nixos/modules/services/networking/prayer.nix
index 9d63f549b23a..8cd4a0823534 100644
--- a/nixos/modules/services/networking/prayer.nix
+++ b/nixos/modules/services/networking/prayer.nix
@@ -18,7 +18,7 @@ let
     var_prefix = "${stateDir}"
     prayer_user = "${prayerUser}"
     prayer_group = "${prayerGroup}"
-    sendmail_path = "/var/setuid-wrappers/sendmail"
+    sendmail_path = "/run/wrappers/bin/sendmail"
 
     use_http_port ${cfg.port}
 
diff --git a/nixos/modules/services/networking/smokeping.nix b/nixos/modules/services/networking/smokeping.nix
index 6648ada0c0de..bac794745277 100644
--- a/nixos/modules/services/networking/smokeping.nix
+++ b/nixos/modules/services/networking/smokeping.nix
@@ -226,7 +226,7 @@ in
       sendmail = mkOption {
         type = types.nullOr types.path;
         default = null;
-        example = "/var/setuid-wrappers/sendmail";
+        example = "/run/wrappers/bin/sendmail";
         description = "Use this sendmail compatible script to deliver alerts";
       };
       smokeMailTemplate = mkOption {
@@ -273,7 +273,10 @@ in
         message = "services.smokeping: sendmail and Mailhost cannot both be enabled.";
       }
     ];
-    security.setuidPrograms = [ "fping" "fping6" ];
+    security.wrappers = {
+      fping.source = "${pkgs.fping}/bin/fping";
+      "fping6".source = "${pkgs.fping}/bin/fping6";
+    };
     environment.systemPackages = [ pkgs.fping ];
     users.extraUsers = singleton {
       name = cfg.user;
diff --git a/nixos/modules/services/scheduling/atd.nix b/nixos/modules/services/scheduling/atd.nix
index 2070b2ffa018..f3ada6b7496a 100644
--- a/nixos/modules/services/scheduling/atd.nix
+++ b/nixos/modules/services/scheduling/atd.nix
@@ -42,13 +42,13 @@ in
 
   config = mkIf cfg.enable {
 
-    security.setuidOwners = map (program: {
-      inherit program;
+    security.wrappers = map (program: {"${program}" = {
+      source = "${pkgs.atd}/bin/${program}";
       owner = "atd";
       group = "atd";
       setuid = true;
       setgid = true;
-    }) [ "at" "atq" "atrm" "batch" ];
+    };}) [ "at" "atq" "atrm" "batch" ];
 
     environment.systemPackages = [ at ];
 
diff --git a/nixos/modules/services/scheduling/cron.nix b/nixos/modules/services/scheduling/cron.nix
index f5e132fd77d8..cc6eb96bf5da 100644
--- a/nixos/modules/services/scheduling/cron.nix
+++ b/nixos/modules/services/scheduling/cron.nix
@@ -20,7 +20,7 @@ let
   cronNixosPkg = pkgs.cron.override {
     # The mail.nix nixos module, if there is any local mail system enabled,
     # should have sendmail in this path.
-    sendmailPath = "/var/setuid-wrappers/sendmail";
+    sendmailPath = "/run/wrappers/bin/sendmail";
   };
 
   allFiles =
@@ -61,7 +61,7 @@ in
           A list of Cron jobs to be appended to the system-wide
           crontab.  See the manual page for crontab for the expected
           format. If you want to get the results mailed you must setuid
-          sendmail. See <option>security.setuidOwners</option>
+          sendmail. See <option>security.wrappers</option>
 
           If neither /var/cron/cron.deny nor /var/cron/cron.allow exist only root
           will is allowed to have its own crontab file. The /var/cron/cron.deny file
@@ -92,13 +92,9 @@ in
   config = mkMerge [
 
     { services.cron.enable = mkDefault (allFiles != []); }
-
     (mkIf (config.services.cron.enable) {
-
-      security.setuidPrograms = [ "crontab" ];
-
+      security.wrappers.crontab.source = "${pkgs.cronNixosPkg.out}/bin/crontab";
       environment.systemPackages = [ cronNixosPkg ];
-
       environment.etc.crontab =
         { source = pkgs.runCommand "crontabs" { inherit allFiles; preferLocalBuild = true; }
             ''
diff --git a/nixos/modules/services/scheduling/fcron.nix b/nixos/modules/services/scheduling/fcron.nix
index 7b4665a82046..e4ada2768715 100644
--- a/nixos/modules/services/scheduling/fcron.nix
+++ b/nixos/modules/services/scheduling/fcron.nix
@@ -96,7 +96,7 @@ in
             fcronallow  =       /etc/fcron.allow
             fcrondeny   =       /etc/fcron.deny
             shell       =       /bin/sh
-            sendmail    =       /var/setuid-wrappers/sendmail
+            sendmail    =       /run/wrappers/bin/sendmail
             editor      =       /run/current-system/sw/bin/vi
           '';
           target = "fcron.conf";
@@ -106,8 +106,7 @@ in
 
     environment.systemPackages = [ pkgs.fcron ];
 
-    security.setuidPrograms = [ "fcrontab" ];
-
+    security.wrappers.fcrontab.source = "${pkgs.fcron.out}/bin/fcrontab";
     systemd.services.fcron = {
       description = "fcron daemon";
       after = [ "local-fs.target" ];
diff --git a/nixos/modules/services/system/dbus.nix b/nixos/modules/services/system/dbus.nix
index aeb5bf9c7a36..33bc890a78c8 100644
--- a/nixos/modules/services/system/dbus.nix
+++ b/nixos/modules/services/system/dbus.nix
@@ -104,15 +104,14 @@ in
 
     systemd.packages = [ pkgs.dbus.daemon ];
 
-    security.setuidOwners = singleton
-      { program = "dbus-daemon-launch-helper";
-        source = "${pkgs.dbus.daemon}/libexec/dbus-daemon-launch-helper";
-        owner = "root";
-        group = "messagebus";
-        setuid = true;
-        setgid = false;
-        permissions = "u+rx,g+rx,o-rx";
-      };
+    security.wrappers.dbus-daemon-launch-helper = {
+      source = "${pkgs.dbus.daemon}/libexec/dbus-daemon-launch-helper";
+      owner = "root";
+      group = "messagebus";
+      setuid = true;
+      setgid = false;
+      permissions = "u+rx,g+rx,o-rx";
+    };
 
     services.dbus.packages = [
       pkgs.dbus.out
diff --git a/nixos/modules/services/x11/desktop-managers/enlightenment.nix b/nixos/modules/services/x11/desktop-managers/enlightenment.nix
index 7ea8b30d23d1..d908553ccdf8 100644
--- a/nixos/modules/services/x11/desktop-managers/enlightenment.nix
+++ b/nixos/modules/services/x11/desktop-managers/enlightenment.nix
@@ -62,7 +62,7 @@ in
       '';
     }];
 
-    security.setuidPrograms = [ "e_freqset" ];
+    security.wrappers.e_freqset.source = "${e.enlightenment.out}/bin/e_freqset";
 
     environment.etc = singleton
       { source = "${pkgs.xkeyboard_config}/etc/X11/xkb";
diff --git a/nixos/modules/services/x11/desktop-managers/kde5.nix b/nixos/modules/services/x11/desktop-managers/kde5.nix
index 644fd8d77527..06f9f0a62ef8 100644
--- a/nixos/modules/services/x11/desktop-managers/kde5.nix
+++ b/nixos/modules/services/x11/desktop-managers/kde5.nix
@@ -61,24 +61,13 @@ in
           ''}
 
           exec "${kde5.startkde}"
-
         '';
       };
 
-      security.setuidOwners = [
-        {
-          program = "kcheckpass";
-          source = "${kde5.plasma-workspace.out}/lib/libexec/kcheckpass";
-          owner = "root";
-          setuid = true;
-        }
-        {
-          program = "start_kdeinit";
-          source = "${kde5.kinit.out}/lib/libexec/kf5/start_kdeinit";
-          owner = "root";
-          setuid = true;
-        }
-      ];
+      security.wrappers = {
+        kcheckpass.source = "${kde5.plasma-workspace.out}/lib/libexec/kcheckpass";
+        "start_kdeinit".source = "${kde5.kinit.out}/lib/libexec/kf5/start_kdeinit";
+      };
 
       environment.systemPackages =
         [
diff --git a/nixos/modules/tasks/network-interfaces.nix b/nixos/modules/tasks/network-interfaces.nix
index d8ebe0af0886..28c7b358093d 100644
--- a/nixos/modules/tasks/network-interfaces.nix
+++ b/nixos/modules/tasks/network-interfaces.nix
@@ -1,4 +1,4 @@
-{ config, lib, pkgs, utils, ... }:
+{ config, lib, pkgs, utils, stdenv, ... }:
 
 with lib;
 with utils;
@@ -933,7 +933,22 @@ in
         (i: flip map [ "4" "6" ] (v: nameValuePair "net.ipv${v}.conf.${i.name}.proxy_arp" true))
       ));
 
-    security.setuidPrograms = [ "ping" "ping6" ];
+    # Capabilities won't work unless we have at-least a 4.3 Linux
+    # kernel because we need the ambient capability
+    security.wrappers = if (versionAtLeast (getVersion config.boot.kernelPackages.kernel) "4.3") then {
+      ping = {
+        source  = "${pkgs.iputils.out}/bin/ping";
+        capabilities = "cap_net_raw+p";
+      };
+
+      ping6 = {
+        source  = "${pkgs.iputils.out}/bin/ping6";
+        capabilities = "cap_net_raw+p";
+      };
+    } else {
+      ping.source = "${pkgs.iputils.out}/bin/ping";
+      "ping6".source = "${pkgs.iputils.out}/bin/ping6";
+    };
 
     # Set the host and domain names in the activation script.  Don't
     # clear it if it's not configured in the NixOS configuration,
diff --git a/nixos/modules/virtualisation/virtualbox-host.nix b/nixos/modules/virtualisation/virtualbox-host.nix
index 7214543871d6..501ed9bc6839 100644
--- a/nixos/modules/virtualisation/virtualbox-host.nix
+++ b/nixos/modules/virtualisation/virtualbox-host.nix
@@ -68,14 +68,13 @@ in
     boot.extraModulePackages = [ kernelModules ];
     environment.systemPackages = [ virtualbox ];
 
-    security.setuidOwners = let
-      mkSuid = program: {
-        inherit program;
+    security.wrappers = let
+      mkSuid = program: {"${program}" = {
         source = "${virtualbox}/libexec/virtualbox/${program}";
         owner = "root";
         group = "vboxusers";
         setuid = true;
-      };
+      };};
     in mkIf cfg.enableHardening (map mkSuid [
       "VBoxHeadless"
       "VBoxNetAdpCtl"
@@ -99,7 +98,7 @@ in
         SUBSYSTEM=="usb", ACTION=="remove", ENV{DEVTYPE}=="usb_device", RUN+="${virtualbox}/libexec/virtualbox/VBoxCreateUSBNode.sh --remove $major $minor"
       '';
 
-    # Since we lack the right setuid binaries, set up a host-only network by default.
+    # Since we lack the right setuid/setcap binaries, set up a host-only network by default.
   } (mkIf cfg.addNetworkInterface {
     systemd.services."vboxnet0" =
       { description = "VirtualBox vboxnet0 Interface";