diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix index f24afccb405a..39ed914994c1 100644 --- a/nixos/modules/misc/ids.nix +++ b/nixos/modules/misc/ids.nix @@ -244,6 +244,7 @@ postsrsd = 220; opendkim = 221; dspam = 222; + gale = 223; # When adding a uid, make sure it doesn't match an existing gid. And don't use uids above 399! @@ -465,6 +466,7 @@ postsrsd = 220; opendkim = 221; dspam = 222; + gale = 223; # When adding a gid, make sure it doesn't match an existing # uid. Users and groups with the same name should have equal diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index b2f08feb1082..d9e8c2da5b32 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -301,6 +301,7 @@ ./services/networking/firewall.nix ./services/networking/flashpolicyd.nix ./services/networking/freenet.nix + ./services/networking/gale.nix ./services/networking/gateone.nix ./services/networking/git-daemon.nix ./services/networking/gnunet.nix diff --git a/nixos/modules/services/networking/gale.nix b/nixos/modules/services/networking/gale.nix new file mode 100644 index 000000000000..3a5d9bd63c7b --- /dev/null +++ b/nixos/modules/services/networking/gale.nix @@ -0,0 +1,182 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.gale; + # we convert the path to a string to avoid it being copied to the nix store, + # otherwise users could read the private key as all files in the store are + # world-readable + keyPath = toString cfg.keyPath; + # ...but we refer to the pubkey file using a path so that we can ensure the + # config gets rebuilt if the public key changes (we can assume the private key + # will never change without the public key having changed) + gpubFile = cfg.keyPath + "/${cfg.domain}.gpub"; + home = "/var/lib/gale"; + keysPrepared = cfg.keyPath != null && lib.pathExists cfg.keyPath; +in +{ + options = { + services.gale = { + enable = mkEnableOption "the Gale messaging daemon"; + + user = mkOption { + default = "gale"; + type = types.str; + description = "Username for the Gale daemon."; + }; + + group = mkOption { + default = "gale"; + type = types.str; + description = "Group name for the Gale daemon."; + }; + + setuidWrapper = mkOption { + default = null; + description = "Configuration for the Gale gksign setuid wrapper."; + }; + + domain = mkOption { + default = ""; + type = types.str; + description = "Domain name for the Gale system."; + }; + + keyPath = mkOption { + default = null; + type = types.nullOr types.path; + description = '' + Directory containing the key pair for this Gale domain. The expected + filename will be taken from the domain option with ".gpri" and ".gpub" + appended. + ''; + }; + + extraConfig = mkOption { + type = types.lines; + default = ""; + description = '' + Additional text to be added to /etc/gale/conf. + ''; + }; + }; + }; + + config = mkMerge [ + (mkIf cfg.enable { + assertions = [{ + assertion = cfg.domain != ""; + message = "A domain must be set for Gale."; + }]; + + warnings = mkIf (!keysPrepared) [ + "You must run gale-install in order to generate a domain key." + ]; + + system.activationScripts.gale = mkIf cfg.enable ( + stringAfter [ "users" "groups" ] '' + chmod -R 755 ${home} + mkdir -m 0777 -p ${home}/auth/cache + mkdir -m 1777 -p ${home}/auth/local # GALE_DOMAIN.gpub + mkdir -m 0700 -p ${home}/auth/private # ROOT.gpub + mkdir -m 0755 -p ${home}/auth/trusted # ROOT + mkdir -m 0700 -p ${home}/.gale + mkdir -m 0700 -p ${home}/.gale/auth + mkdir -m 0700 -p ${home}/.gale/auth/private # GALE_DOMAIN.gpri + + ln -sf ${pkgs.gale}/etc/gale/auth/trusted/ROOT "${home}/auth/trusted/ROOT" + chown -R ${cfg.user}:${cfg.group} ${home} + '' + ); + + environment = { + etc = { + "gale/auth".source = home + "/auth"; # symlink /var/lib/gale/auth + "gale/conf".text = '' + GALE_USER ${cfg.user} + GALE_DOMAIN ${cfg.domain} + ${cfg.extraConfig} + ''; + }; + + systemPackages = [ pkgs.gale ]; + }; + + users.extraUsers = [{ + name = cfg.user; + description = "Gale daemon"; + uid = config.ids.uids.gale; + group = cfg.group; + home = home; + createHome = true; + }]; + + users.extraGroups = [{ + name = cfg.group; + gid = config.ids.gids.gale; + }]; + }) + (mkIf (cfg.enable && keysPrepared) { + assertions = [ + { + assertion = cfg.keyPath != null + && lib.pathExists (cfg.keyPath + "/${cfg.domain}.gpub"); + message = "Couldn't find a Gale public key for ${cfg.domain}."; + } + { + assertion = cfg.keyPath != null + && lib.pathExists (cfg.keyPath + "/${cfg.domain}.gpri"); + message = "Couldn't find a Gale private key for ${cfg.domain}."; + } + ]; + + services.gale.setuidWrapper = { + program = "gksign"; + source = "${pkgs.gale}/bin/gksign"; + owner = cfg.user; + group = cfg.group; + setuid = true; + setgid = false; + }; + + security.setuidOwners = [ cfg.setuidWrapper ]; + + systemd.services.gale-galed = { + description = "Gale messaging daemon"; + wantedBy = [ "multi-user.target" ]; + wants = [ "gale-gdomain.service" ]; + after = [ "network.target" ]; + + preStart = '' + install -m 0640 ${keyPath}/${cfg.domain}.gpri "${home}/.gale/auth/private/" + install -m 0644 ${gpubFile} "${home}/.gale/auth/private/${cfg.domain}.gpub" + install -m 0644 ${gpubFile} "${home}/auth/local/${cfg.domain}.gpub" + chown -R ${cfg.user}:${cfg.group} ${home} + ''; + + serviceConfig = { + Type = "forking"; + ExecStart = "@${pkgs.gale}/bin/galed galed"; + User = cfg.user; + Group = cfg.group; + PermissionsStartOnly = true; + }; + }; + + systemd.services.gale-gdomain = { + description = "Gale AKD daemon"; + wantedBy = [ "multi-user.target" ]; + requires = [ "gale-galed.service" ]; + after = [ "gale-galed.service" ]; + + serviceConfig = { + Type = "forking"; + ExecStart = "@${pkgs.gale}/bin/gdomain gdomain"; + User = cfg.user; + Group = cfg.group; + }; + }; + }) + ]; +} diff --git a/pkgs/applications/networking/instant-messengers/gale/default.nix b/pkgs/applications/networking/instant-messengers/gale/default.nix new file mode 100644 index 000000000000..65f6cab6e81c --- /dev/null +++ b/pkgs/applications/networking/instant-messengers/gale/default.nix @@ -0,0 +1,31 @@ +{ stdenv, fetchFromGitHub, adns, boehmgc, openssl, automake, m4, autoconf +, libtool, pkgconfig }: + +stdenv.mkDerivation { + name = "gale-1.1happy"; + + src = fetchFromGitHub { + owner = "grawity"; + repo = "gale"; + rev = "b34a67288e8bd6f0b51b60abb704858172a3665c"; + sha256 = "19mcisxxqx70m059rqwv7wpmp94fgyckzjwywpmdqd7iwvppnsqf"; + }; + + nativeBuildInputs = [ m4 libtool automake autoconf ]; + buildInputs = [ boehmgc openssl adns pkgconfig ]; + + patches = [ ./gale-install.in.patch ]; + + preConfigure = '' + substituteInPlace configure.ac --replace \$\{sysconfdir\} /etc + ./bootstrap + ''; + configureArgs = [ "--sysconfdir=/etc" ]; + + meta = with stdenv.lib; { + homepage = "http://gale.org/"; + description = "chat/messaging system (server and client)"; + platforms = platforms.all; + license = licenses.gpl2Plus; + }; +} diff --git a/pkgs/applications/networking/instant-messengers/gale/gale-install.in.patch b/pkgs/applications/networking/instant-messengers/gale/gale-install.in.patch new file mode 100644 index 000000000000..f9c3e3c55922 --- /dev/null +++ b/pkgs/applications/networking/instant-messengers/gale/gale-install.in.patch @@ -0,0 +1,339 @@ +diff --git a/gale-install.in b/gale-install.in +index 50e8ad8..eec0ed2 100644 +--- a/gale-install.in ++++ b/gale-install.in +@@ -29,22 +29,78 @@ testkey_stdin() { + gkinfo -x 2>/dev/null | qgrep "^Public key: <$1>" + } + +-if [ -n "$GALE_SYS_DIR" ]; then +- SYS_DIR="$GALE_SYS_DIR" +-elif [ -n "$sysconfdir" ]; then +- SYS_DIR="$sysconfdir/gale" ++INST_SYS_DIR="$sysconfdir/gale" ++ ++if [ `id -u` -eq 0 ]; then ++ is_root=yes ++ SYS_DIR=/etc/gale ++else ++ is_root=no ++ SYS_DIR="$HOME/.gale" ++fi ++ ++if [ -f /etc/NIXOS ]; then ++ is_nixos=yes ++else ++ is_nixos=no ++fi ++ ++if [ -u /var/setuid-wrappers/gksign ]; then ++ cat < "$CONF" <> "$CONF" <> "$CONF" << EOM ++ cat > "$CONF" </dev/null`" +-[ -f "$gksignlink" ] && gksign="$gksignlink" +- +-echo "" +-if copy chown "$GALE_USER" "$gksign" ; then +- : +-else +- echo "*** We need to chown $GALE_USER '$gksign'." +- echo " Please run this script as a user that can do so," +- echo " or do so yourself and re-run this script." +- exit 1 ++ fi + fi +-run chmod 4755 "$gksign" + +-# ----------------------------------------------------------------------------- +-# create a domain, if necessary ++if [ $is_root = no ]; then ++ GALE_SYS_DIR="$SYS_DIR" ++ export GALE_SYS_DIR + +-echo "" +-if test -u "$gksign" || copy chmod u+s "$gksign" ; then +- : ++ testkey "$GALE_DOMAIN" && exit 0 ++ echo "*** You lack a signed key for your domain, \"$GALE_DOMAIN\"." ++ GALE="$SYS_DIR" + else +- echo "*** We need to chmod u+s '$gksign'." +- echo " Please run this script as a user that can do so," +- echo " or do so yourself and re-run this script." +- exit 1 +-fi +- +-testkey "$GALE_DOMAIN" && exit 0 +-echo "*** You lack a signed key for your domain, \"$GALE_DOMAIN\"." +- +-if [ "x$GALE_USER" != "x$USER" ]; then +-cat <