diff options
author | Igor Pashev <pashev.igor@gmail.com> | 2016-09-29 13:51:44 +0300 |
---|---|---|
committer | Igor Pashev <pashev.igor@gmail.com> | 2016-09-29 13:51:44 +0300 |
commit | 62f28d30a069135f9c48678507203958adfc334f (patch) | |
tree | 7f38af0c8d3f445ee8cc50906a639baec7011127 /modules/apps/cli.nix | |
parent | 1af9e6589bdd18e6ba7eeabf073aa7d710020cdd (diff) | |
download | nixsap-62f28d30a069135f9c48678507203958adfc334f.tar.gz |
Moved everything into ./modules
Diffstat (limited to 'modules/apps/cli.nix')
-rw-r--r-- | modules/apps/cli.nix | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/modules/apps/cli.nix b/modules/apps/cli.nix new file mode 100644 index 0000000..00365d8 --- /dev/null +++ b/modules/apps/cli.nix @@ -0,0 +1,140 @@ +{ config, pkgs, lib, ...}: + +let + + inherit (builtins) + toString ; + inherit (lib) + concatMapStrings filterAttrs mapAttrsToList mkOption + types unique ; + inherit (types) + attrsOf path str submodule ; + + explicit = filterAttrs (n: v: n != "_module" && v != null); + apps = explicit config.nixsap.apps.cli; + + exec = name: { user, command, ... }: + let + uid = toString config.users.users.${user}.uid; + gid = uid; + src = pkgs.writeText "${name}.c" '' + #include <unistd.h> + #include <grp.h> + #include <pwd.h> + #include <stdio.h> + #include <stdlib.h> + #include <sys/types.h> + + int main (int __attribute__((unused)) argc, char *argv[]) + { + int rc; + + if (getuid() != ${uid}) { + if (geteuid() != 0) { + fprintf(stderr, "Forbidden.\n"); + return EXIT_FAILURE; + } + + rc = initgroups("${user}", ${gid}); + if (0 != rc) { + perror("initgroups()"); + return EXIT_FAILURE; + } + + rc = setgid(${gid}); + if (0 != rc) { + perror("setgid()"); + return EXIT_FAILURE; + } + + rc = setuid(${uid}); + if (0 != rc) { + perror("setuid()"); + return EXIT_FAILURE; + } + + if ((getuid() != ${uid}) || (geteuid() != ${uid})) { + fprintf(stderr, "Something went wrong.\n"); + return EXIT_FAILURE; + } + + struct passwd * pw = getpwuid(${uid}); + if (NULL == pw) { + perror("getpwuid()"); + return EXIT_FAILURE; + } + + if (NULL != pw->pw_dir) { + rc = chdir(pw->pw_dir); + if (0 != rc) { + rc = chdir("/"); + } + } else { + rc = chdir("/"); + } + if (0 != rc) { + perror("chdir()"); + return EXIT_FAILURE; + } + } + + argv[0] = "${command}"; + execv(argv[0], argv); + + perror("execv()"); + return EXIT_FAILURE; + } + ''; + in pkgs.runCommand name {} "gcc -Wall -Wextra -Werror -std=gnu99 -O2 ${src} -o $out"; + + cliapp = submodule({name, ...}: + { + options = { + user = mkOption { + description = '' + User (and group) to run as. Only users in this group can execute + this application. + ''; + type = str; + default = name; + }; + command = mkOption { + description = "Path to executable"; + type = path; + }; + }; + }); + +in { + options.nixsap = { + apps.cli = mkOption { + description = '' + Command line applications that should run as other users and likely + have special privileges, e. g. to access secret keys. This is + implemented with setuid-wrappers. Each wrapper is launched as root, + immediately switches to specified user, then executes something + useful. This is like sudo, but access is controlled via wrapper's + group: only users in wrapper's group can execute the wrapper. + + Starting as set-uid-non-root is not sufficient, because we might + need supplementary groups, like "keys". + ''; + type = attrsOf cliapp; + default = {}; + }; + }; + + config = { + nixsap.system.users.daemons = unique (mapAttrsToList (_: a: a.user) apps); + security.setuidOwners = mapAttrsToList (n: a: + { program = n; + owner = "root"; + group = a.user; + setuid = true; + setgid = false; + permissions = "u+rx,g+x,o="; + source = exec n a; + }) apps; + }; +} + |