182 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			Nix
		
	
	
	
	
	
			
		
		
	
	
			182 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			Nix
		
	
	
	
	
	
{ 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 <filename>/etc/gale/conf</filename>.
 | 
						|
        '';
 | 
						|
      };
 | 
						|
    };
 | 
						|
  };
 | 
						|
 | 
						|
  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 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 ${cfg.user}:${cfg.group} ${home} ${home}/auth ${home}/auth/*
 | 
						|
           chown ${cfg.user}:${cfg.group} ${home}/.gale ${home}/.gale/auth ${home}/.gale/auth/private
 | 
						|
         ''
 | 
						|
       );
 | 
						|
 | 
						|
       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.users.${cfg.user} = {
 | 
						|
         description = "Gale daemon";
 | 
						|
         uid = config.ids.uids.gale;
 | 
						|
         group = cfg.group;
 | 
						|
         home = home;
 | 
						|
         createHome = true;
 | 
						|
       };
 | 
						|
 | 
						|
       users.groups = [{
 | 
						|
         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.wrappers.gksign = 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 -o ${cfg.user} -g ${cfg.group} ${keyPath}/${cfg.domain}.gpri "${home}/.gale/auth/private/"
 | 
						|
           install -m 0644 -o ${cfg.user} -g ${cfg.group} ${gpubFile} "${home}/.gale/auth/private/${cfg.domain}.gpub"
 | 
						|
           install -m 0644 -o ${cfg.user} -g ${cfg.group} ${gpubFile} "${home}/auth/local/${cfg.domain}.gpub"
 | 
						|
         '';
 | 
						|
 | 
						|
         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;
 | 
						|
         };
 | 
						|
       };
 | 
						|
    })
 | 
						|
  ];
 | 
						|
}
 |