dragnpkgs/modules/ghidra-server/default.nix

93 lines
3.6 KiB
Nix

{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.ghidra-server;
adminCli = pkgs.callPackage ./cli.nix {
inherit (cfg) package jdkPackage directory;
};
in {
options.services.ghidra-server = {
enable = mkEnableOption "ghidra-server";
enableAdminCli = mkEnableOption "ghidra-svrAdmin" // { default = true; };
package = mkPackageOption pkgs "ghidra_headless" { };
jdkPackage = mkPackageOption pkgs "openjdk21_headless" { };
host = mkOption {
default = null;
defaultText = literalExpression "null";
example = literalExpression "\"myserver.lol\"";
description = "Ghidra server hostname or IP.";
type = types.str;
};
basePort = mkOption {
default = 13100;
description = "Ghidra server base port - the server will use 3 consecutive TCP ports starting from the provided port number.";
type = types.port;
};
directory = mkOption {
default = "ghidra-server";
description = ''
Directory for Ghidra server data, under `/var/lib` (for systemd `StateDirectory`)
'';
type = types.str;
};
user = mkOption {
type = types.str;
default = "ghidra";
description = "User account under which ghidra server runs.";
};
group = mkOption {
type = types.str;
default = "ghidra";
description = "Group account under which ghidra server runs.";
};
};
config = mkIf cfg.enable {
users.users."${cfg.user}" = {
isSystemUser = true;
home = "/var/lib/${cfg.directory}";
inherit (cfg) group;
packages = [ cfg.package cfg.jdkPackage ];
};
users.groups."${cfg.group}" = {};
systemd.services."ghidra-server" =
let
ghidra_log4j_config = ./custom.log4j.xml;
ghidra_java_opt = "-Dlog4j.configurationFile=${ghidra_log4j_config} -Djava.net.preferIPv4Stack=true -Djava.io.tmpdir=/tmp -Djna.tmpdir=/tmp -Dghidra.tls.server.protocols=TLSv1.2;TLSv1.3 -Ddb.buffers.DataBuffer.compressedOutput=true -Xms396m -Xmx768m";
ghidra_home = "${cfg.package}/lib/ghidra";
ghidra_classpath = with builtins; let
input = lib.readFile "${ghidra_home}/Ghidra/Features/GhidraServer/data/classpath.frag";
inputSplit = split "[^\n]*ghidra_home.([^\n]*)\n" input;
paths = map head (filter isList inputSplit);
in ghidra_home + (concatStringsSep (":" + ghidra_home) paths);
ghidra_mainclass = "ghidra.server.remote.GhidraServer";
ghidra_args = "-a0 -u -p${toString cfg.basePort} -ip ${cfg.host} /var/lib/${cfg.directory}/repositories";
in {
description = "Ghidra server";
after = ["network.target"];
serviceConfig = {
ExecStart = "${cfg.jdkPackage}/bin/java ${ghidra_java_opt} -classpath ${ghidra_classpath} ${ghidra_mainclass} ${ghidra_args}";
WorkingDirectory = "/var/lib/${cfg.directory}";
Environment = "GHIDRA_HOME=${ghidra_home}";
User = cfg.user;
Group = cfg.group;
SuccessExitStatus = 143;
# use StateDirectory to create home dir and additional needed dirs with overridden
# permissions when the unit starts
# this is needed because we'd like the group (ghidra) to have write access to the
# directories here, particularly ~admin
StateDirectory = "${cfg.directory} ${cfg.directory}/repositories ${cfg.directory}/repositories/~admin";
StateDirectoryMode = "0770";
PrivateTmp = true;
NoNewPrivileges = true;
};
wantedBy = ["multi-user.target"];
};
environment.systemPackages = optionals cfg.enableAdminCli [ adminCli ];
};
}