From 78925e4a90f838c0a977fe22b2c39a004b931fd3 Mon Sep 17 00:00:00 2001 From: aszlig Date: Tue, 5 Apr 2016 18:07:21 +0200 Subject: [PATCH] nixos/taskserver: Factor out nixos-taskdctl With a cluttered up module source it's really a pain to navigate through it, so it's a good idea to put it into another file. No changes in functionality here, just splitting up the files and fixing references. Signed-off-by: aszlig --- nixos/modules/module-list.nix | 2 +- .../default.nix} | 321 +---------------- .../services/misc/taskserver/helper-tool.nix | 323 ++++++++++++++++++ 3 files changed, 327 insertions(+), 319 deletions(-) rename nixos/modules/services/misc/{taskserver.nix => taskserver/default.nix} (57%) create mode 100644 nixos/modules/services/misc/taskserver/helper-tool.nix diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index d5922057ad4..2e1b2be403e 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -249,7 +249,7 @@ ./services/misc/sundtek.nix ./services/misc/svnserve.nix ./services/misc/synergy.nix - ./services/misc/taskserver.nix + ./services/misc/taskserver ./services/misc/uhub.nix ./services/misc/zookeeper.nix ./services/monitoring/apcupsd.nix diff --git a/nixos/modules/services/misc/taskserver.nix b/nixos/modules/services/misc/taskserver/default.nix similarity index 57% rename from nixos/modules/services/misc/taskserver.nix rename to nixos/modules/services/misc/taskserver/default.nix index 992c13401e5..4a33ddd9d24 100644 --- a/nixos/modules/services/misc/taskserver.nix +++ b/nixos/modules/services/misc/taskserver/default.nix @@ -59,43 +59,6 @@ let ''} ''; - genClientKey = '' - umask 0077 - if tmpdir="$(${pkgs.coreutils}/bin/mktemp -d)"; then - trap "rm -rf '$tmpdir'" EXIT - ${pkgs.gnutls}/bin/certtool -p --bits 2048 --outfile "$tmpdir/key" - - cat > "$tmpdir/template" <<-\ \ EOF - organization = $organisation - cn = ${cfg.server.fqdn} - tls_www_client - encryption_key - signing_key - EOF - - ${pkgs.gnutls}/bin/certtool -c \ - --load-privkey "$tmpdir/key" \ - --load-ca-privkey "${cfg.dataDir}/keys/ca.key" \ - --load-ca-certificate "${cfg.dataDir}/keys/ca.cert" \ - --template "$tmpdir/template" \ - --outfile "$tmpdir/cert" - - mkdir -m 0700 -p "${cfg.dataDir}/keys/user/$organisation/$user" - chown root:root "${cfg.dataDir}/keys/user/$organisation/$user" - cat "$tmpdir/key" \ - > "${cfg.dataDir}/keys/user/$organisation/$user/private.key" - cat "$tmpdir/cert" \ - > "${cfg.dataDir}/keys/user/$organisation/$user/public.cert" - - rm -rf "$tmpdir" - trap - EXIT - else - echo "Unable to create temporary directory for client" \ - "certificate creation." >&2 - exit 1 - fi - ''; - orgOptions = { name, ... }: { options.users = mkOption { type = types.uniq (types.listOf types.str); @@ -117,290 +80,12 @@ let }; mkShellStr = val: "'${replaceStrings ["'"] ["'\\''"] val}'"; - mkShellName = replaceStrings ["-"] ["_"]; - mkSubCommand = name: { args, description, script }: let - mkArg = pos: arg: "local ${arg}=\"\$${toString pos}\""; - mkDesc = line: "echo ${mkShellStr " ${line}"} >&2"; - usagePosArgs = concatMapStringsSep " " (a: "<${a}>") args; - in '' - subcmd_${mkShellName name}() { - ${concatImapStringsSep "\n " mkArg args} - ${script} - } - - usage_${mkShellName name}() { - echo " nixos-taskdctl ${name} ${usagePosArgs}" >&2 - ${concatMapStringsSep "\n " mkDesc description} - } - ''; - - mkCStr = val: "\"${escape ["\\" "\""] val}\""; - - taskdUser = let - runUser = pkgs.writeText "runuser.c" '' - #include - #include - #include - #include - #include - #include - #include - - int main(int argc, char **argv) { - struct passwd *userinfo; - struct group *groupinfo; - errno = 0; - if ((userinfo = getpwnam(${mkCStr cfg.user})) == NULL) { - if (errno == 0) - fputs(${mkCStr "User name `${cfg.user}' not found."}, stderr); - else - perror("getpwnam"); - return EXIT_FAILURE; - } - errno = 0; - if ((groupinfo = getgrnam(${mkCStr cfg.group})) == NULL) { - if (errno == 0) - fputs(${mkCStr "Group name `${cfg.group}' not found."}, stderr); - else - perror("getgrnam"); - return EXIT_FAILURE; - } - if (setgid(groupinfo->gr_gid) == -1) { - perror("setgid"); - return EXIT_FAILURE; - } - if (setuid(userinfo->pw_uid) == -1) { - perror("setgid"); - return EXIT_FAILURE; - } - argv[0] = "taskd"; - if (execv(${mkCStr taskd}, argv) == -1) { - perror("execv"); - return EXIT_FAILURE; - } - /* never reached */ - return EXIT_SUCCESS; - } - ''; - in pkgs.runCommand "taskd-user" {} '' - cc -Wall -std=c11 "${runUser}" -o "$out" - ''; - - subcommands = { - list-users = { - args = [ "organisation" ]; - - description = [ - "List all users belonging to the specified organisation." - ]; - - script = '' - legend "The following users exist for $organisation:" - ${pkgs.findutils}/bin/find \ - "${cfg.dataDir}/orgs/$organisation/users" \ - -mindepth 2 -maxdepth 2 -name config \ - -exec ${pkgs.gnused}/bin/sed -ne 's/^user *= *//p' {} + - ''; - }; - - list-orgs = { - args = []; - - description = [ - "List available organisations" - ]; - - script = '' - legend "The following organisations exist:" - ${pkgs.findutils}/bin/find \ - "${cfg.dataDir}/orgs" -mindepth 1 -maxdepth 1 \ - -type d - ''; - }; - - get-uuid = { - args = [ "organisation" "user" ]; - - description = [ - "Get the UUID of the specified user belonging to the specified" - "organisation." - ]; - - script = '' - for uuid in "${cfg.dataDir}/orgs/$organisation/users"/*; do - usr="$(${pkgs.gnused}/bin/sed -ne 's/^user *= *//p' "$uuid/config")" - if [ "$usr" = "$user" ]; then - legend "User $user has the following UUID:" - echo "$(${pkgs.coreutils}/bin/basename "$uuid")" - exit 0 - fi - done - echo "No UUID found for user $user." >&2 - exit 1 - ''; - }; - - export-user = { - args = [ "organisation" "user" ]; - - description = [ - "Export user of the specified organisation as a series of shell" - "commands that can be used on the client side to easily import" - "the certificates." - "" - "Note that the private key will be exported as well, so use this" - "with care!" - ]; - - script = '' - if ! subcmd_quiet list-users "$organisation" | grep -qxF "$user"; then - exists "User $user doesn't exist in organisation $organisation." - fi - - uuid="$(subcmd_quiet get-uuid "$organisation" "$user")" || exit 1 - - cat < "\$taskdatadir/keys/public.cert" < "\$taskdatadir/keys/private.key" < "\$taskdatadir/keys/ca.cert" <&2 - echo >&2 - usage_${mkShellName name} - exit 1 - fi - subcmd "${name}" ${cmdArgs};; - ''; - - nixos-taskdctl = pkgs.writeScriptBin "nixos-taskdctl" '' - #!${pkgs.stdenv.shell} - export TASKDDATA=${mkShellStr cfg.dataDir} - - quiet=0 - # Deliberately undocumented, because we don't want people to use this as - # it's only used in and specific to the preStart script of the Taskserver - # service. - if [ "$1" = "--service-helper" ]; then - quiet=1 - exists() { - exit 0 - } - shift - else - exists() { - echo "$@" >&2 - exit 1 - } - fi - - legend() { - if [ $quiet -eq 0 ]; then - echo "$@" >&2 - fi - } - - subcmd() { - local cmdname="''${1//-/_}" - shift - "subcmd_$cmdname" "$@" - } - - subcmd_quiet() { - local prev_quiet=$quiet - quiet=1 - subcmd "$@" - local ret=$? - quiet=$prev_quiet - return $ret - } - - ${concatStrings (mapAttrsToList mkSubCommand subcommands)} - - case "$1" in - ${concatStrings (mapAttrsToList mkCase subcommands)} - *) echo "Usage: nixos-taskdctl []" >&2 - echo >&2 - echo "A tool to manage taskserver users on NixOS" >&2 - echo >&2 - echo "The following subcommands are available:" >&2 - ${concatMapStringsSep "\n " (c: "usage_${mkShellName c}") - (attrNames subcommands)} - exit 1 - esac - ''; - ctlcmd = "${nixos-taskdctl}/bin/nixos-taskdctl --service-helper"; in { diff --git a/nixos/modules/services/misc/taskserver/helper-tool.nix b/nixos/modules/services/misc/taskserver/helper-tool.nix new file mode 100644 index 00000000000..90ac8594816 --- /dev/null +++ b/nixos/modules/services/misc/taskserver/helper-tool.nix @@ -0,0 +1,323 @@ +{ config, pkgs, lib, mkShellStr, taskd }: + +let + mkShellName = lib.replaceStrings ["-"] ["_"]; + + genClientKey = '' + umask 0077 + if tmpdir="$(${pkgs.coreutils}/bin/mktemp -d)"; then + trap "rm -rf '$tmpdir'" EXIT + ${pkgs.gnutls}/bin/certtool -p --bits 2048 --outfile "$tmpdir/key" + + cat > "$tmpdir/template" <<-\ \ EOF + organization = $organisation + cn = ${config.server.fqdn} + tls_www_client + encryption_key + signing_key + EOF + + ${pkgs.gnutls}/bin/certtool -c \ + --load-privkey "$tmpdir/key" \ + --load-ca-privkey "${config.dataDir}/keys/ca.key" \ + --load-ca-certificate "${config.dataDir}/keys/ca.cert" \ + --template "$tmpdir/template" \ + --outfile "$tmpdir/cert" + + mkdir -m 0700 -p "${config.dataDir}/keys/user/$organisation/$user" + chown root:root "${config.dataDir}/keys/user/$organisation/$user" + cat "$tmpdir/key" \ + > "${config.dataDir}/keys/user/$organisation/$user/private.key" + cat "$tmpdir/cert" \ + > "${config.dataDir}/keys/user/$organisation/$user/public.cert" + + rm -rf "$tmpdir" + trap - EXIT + else + echo "Unable to create temporary directory for client" \ + "certificate creation." >&2 + exit 1 + fi + ''; + + mkSubCommand = name: { args, description, script }: let + mkArg = pos: arg: "local ${arg}=\"\$${toString pos}\""; + mkDesc = line: "echo ${mkShellStr " ${line}"} >&2"; + usagePosArgs = lib.concatMapStringsSep " " (a: "<${a}>") args; + in '' + subcmd_${mkShellName name}() { + ${lib.concatImapStringsSep "\n " mkArg args} + ${script} + } + + usage_${mkShellName name}() { + echo " nixos-taskdctl ${name} ${usagePosArgs}" >&2 + ${lib.concatMapStringsSep "\n " mkDesc description} + } + ''; + + mkCStr = val: "\"${lib.escape ["\\" "\""] val}\""; + + taskdUser = let + runUser = pkgs.writeText "runuser.c" '' + #include + #include + #include + #include + #include + #include + #include + + int main(int argc, char **argv) { + struct passwd *userinfo; + struct group *groupinfo; + errno = 0; + if ((userinfo = getpwnam(${mkCStr config.user})) == NULL) { + if (errno == 0) + fputs(${mkCStr "User name `${config.user}' not found."}, stderr); + else + perror("getpwnam"); + return EXIT_FAILURE; + } + errno = 0; + if ((groupinfo = getgrnam(${mkCStr config.group})) == NULL) { + if (errno == 0) + fputs(${mkCStr "Group name `${config.group}' not found."}, stderr); + else + perror("getgrnam"); + return EXIT_FAILURE; + } + if (setgid(groupinfo->gr_gid) == -1) { + perror("setgid"); + return EXIT_FAILURE; + } + if (setuid(userinfo->pw_uid) == -1) { + perror("setgid"); + return EXIT_FAILURE; + } + argv[0] = "taskd"; + if (execv(${mkCStr taskd}, argv) == -1) { + perror("execv"); + return EXIT_FAILURE; + } + /* never reached */ + return EXIT_SUCCESS; + } + ''; + in pkgs.runCommand "taskd-user" {} '' + cc -Wall -std=c11 "${runUser}" -o "$out" + ''; + + subcommands = { + list-users = { + args = [ "organisation" ]; + + description = [ + "List all users belonging to the specified organisation." + ]; + + script = '' + legend "The following users exist for $organisation:" + ${pkgs.findutils}/bin/find \ + "${config.dataDir}/orgs/$organisation/users" \ + -mindepth 2 -maxdepth 2 -name config \ + -exec ${pkgs.gnused}/bin/sed -ne 's/^user *= *//p' {} + + ''; + }; + + list-orgs = { + args = []; + + description = [ + "List available organisations" + ]; + + script = '' + legend "The following organisations exist:" + ${pkgs.findutils}/bin/find \ + "${config.dataDir}/orgs" -mindepth 1 -maxdepth 1 \ + -type d + ''; + }; + + get-uuid = { + args = [ "organisation" "user" ]; + + description = [ + "Get the UUID of the specified user belonging to the specified" + "organisation." + ]; + + script = '' + for uuid in "${config.dataDir}/orgs/$organisation/users"/*; do + usr="$(${pkgs.gnused}/bin/sed -ne 's/^user *= *//p' "$uuid/config")" + if [ "$usr" = "$user" ]; then + legend "User $user has the following UUID:" + echo "$(${pkgs.coreutils}/bin/basename "$uuid")" + exit 0 + fi + done + echo "No UUID found for user $user." >&2 + exit 1 + ''; + }; + + export-user = { + args = [ "organisation" "user" ]; + + description = [ + "Export user of the specified organisation as a series of shell" + "commands that can be used on the client side to easily import" + "the certificates." + "" + "Note that the private key will be exported as well, so use this" + "with care!" + ]; + + script = '' + if ! subcmd_quiet list-users "$organisation" | grep -qxF "$user"; then + exists "User $user doesn't exist in organisation $organisation." + fi + + uuid="$(subcmd_quiet get-uuid "$organisation" "$user")" || exit 1 + + cat < "\$taskdatadir/keys/public.cert" < "\$taskdatadir/keys/private.key" < "\$taskdatadir/keys/ca.cert" <&2 + echo >&2 + usage_${mkShellName name} + exit 1 + fi + subcmd "${name}" ${cmdArgs};; + ''; + +in pkgs.writeScriptBin "nixos-taskdctl" '' + #!${pkgs.stdenv.shell} + export TASKDDATA=${mkShellStr config.dataDir} + + quiet=0 + # Deliberately undocumented, because we don't want people to use this as + # it's only used in and specific to the preStart script of the Taskserver + # service. + if [ "$1" = "--service-helper" ]; then + quiet=1 + exists() { + exit 0 + } + shift + else + exists() { + echo "$@" >&2 + exit 1 + } + fi + + legend() { + if [ $quiet -eq 0 ]; then + echo "$@" >&2 + fi + } + + subcmd() { + local cmdname="''${1//-/_}" + shift + "subcmd_$cmdname" "$@" + } + + subcmd_quiet() { + local prev_quiet=$quiet + quiet=1 + subcmd "$@" + local ret=$? + quiet=$prev_quiet + return $ret + } + + ${lib.concatStrings (lib.mapAttrsToList mkSubCommand subcommands)} + + case "$1" in + ${lib.concatStrings (lib.mapAttrsToList mkCase subcommands)} + *) echo "Usage: nixos-taskdctl []" >&2 + echo >&2 + echo "A tool to manage taskserver users on NixOS" >&2 + echo >&2 + echo "The following subcommands are available:" >&2 + ${lib.concatMapStringsSep "\n " (c: "usage_${mkShellName c}") + (lib.attrNames subcommands)} + exit 1 + esac +''