From 6e157a481a7bd03ac6bbeb86847f4d593ed0a854 Mon Sep 17 00:00:00 2001 From: Yarny0 <41838844+Yarny0@users.noreply.github.com> Date: Wed, 15 Sep 2021 15:31:49 +0200 Subject: [PATCH 01/15] tsm-client: fix lvm2 support lvm2 support was broken when lvm2 got converted to a multiple-output derivation: https://github.com/NixOS/nixpkgs/pull/93024 https://github.com/NixOS/nixpkgs/commit/d3a991d41028c5d2a5af2796c0bb542836457822 The `runtimeDependencies` attribute doesn't specifically look for a `lib` output, so it uses the main `out` output which no longer contains the library object files. Since TSM loads the `libdevmapper.so` library dynamically (likely with `dlfcn.h` functions), the breakage couldn't be detected at build time. The commit at hand simply uses `getLib` to pick the correct output. --- pkgs/tools/backup/tsm-client/default.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/tools/backup/tsm-client/default.nix b/pkgs/tools/backup/tsm-client/default.nix index e298751facab..9e0e5e3a606c 100644 --- a/pkgs/tools/backup/tsm-client/default.nix +++ b/pkgs/tools/backup/tsm-client/default.nix @@ -91,7 +91,7 @@ let zlib ]; runtimeDependencies = [ - lvm2 + (lib.attrsets.getLib lvm2) ]; sourceRoot = "."; From ce6eea6002704b5a2285fb7800e247e3e0946f6c Mon Sep 17 00:00:00 2001 From: Yarny0 <41838844+Yarny0@users.noreply.github.com> Date: Sat, 18 Sep 2021 10:08:29 +0200 Subject: [PATCH 02/15] tsm-client: add gnugrep to PATH While testing the new version, I observed that `dsmc` prints an error "sh: grep: command not found" when executed with empty PATH. Apparently, `dsmc` needs `grep` in its PATH. --- pkgs/tools/backup/tsm-client/default.nix | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkgs/tools/backup/tsm-client/default.nix b/pkgs/tools/backup/tsm-client/default.nix index 9e0e5e3a606c..e1f5055b2218 100644 --- a/pkgs/tools/backup/tsm-client/default.nix +++ b/pkgs/tools/backup/tsm-client/default.nix @@ -3,6 +3,7 @@ , autoPatchelfHook , buildEnv , fetchurl +, gnugrep , makeWrapper , procps , zlib @@ -158,7 +159,7 @@ buildEnv { target=$(readlink "$bin") rm "$bin" makeWrapper "$target" "$bin" \ - --prefix PATH : "$out/dsm_dir:${lib.strings.makeBinPath [ procps acl jdk8 ]}" \ + --prefix PATH : "$out/dsm_dir:${lib.makeBinPath [ procps gnugrep acl jdk8 ]}" \ --set DSM_DIR $out/dsm_dir done ''; From 6d134acc4a18897eb248e7ce7daeecc06e68d517 Mon Sep 17 00:00:00 2001 From: Yarny0 <41838844+Yarny0@users.noreply.github.com> Date: Sun, 28 Nov 2021 21:52:04 +0100 Subject: [PATCH 03/15] tsm-client: use explicit package option for Java GUI The tsm-client package comes in two flavours: command line only (`tsm-client`) and with a Java-backed GUI (`tsm-client-withGui`). To control which package is built, the build recipe simply used to check if the `jdk8` package was provided as package input. This commit changes this mechanism: The build recipe now accepts the explicit option `enableGui`, which is set to `false` by default. As the commit at hand touches the build recipe arguments, it also changes argument sorting following https://nixos.org/manual/nixpkgs/stable/#sec-syntax --- pkgs/tools/backup/tsm-client/default.nix | 27 +++++++++++++----------- pkgs/top-level/all-packages.nix | 4 ++-- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/pkgs/tools/backup/tsm-client/default.nix b/pkgs/tools/backup/tsm-client/default.nix index e1f5055b2218..bd7b21be7645 100644 --- a/pkgs/tools/backup/tsm-client/default.nix +++ b/pkgs/tools/backup/tsm-client/default.nix @@ -1,16 +1,16 @@ { lib , stdenv -, autoPatchelfHook -, buildEnv , fetchurl -, gnugrep -, makeWrapper -, procps +, autoPatchelfHook , zlib -# optional packages that enable certain features -, acl ? null # EXT2/EXT3/XFS ACL support -, jdk8 ? null # Java GUI -, lvm2 ? null # LVM image backup and restore functions +, lvm2 # LVM image backup and restore functions (optional) +, acl # EXT2/EXT3/XFS ACL support (optional) +, gnugrep +, procps +, jdk8 # Java GUI (needed for `enableGui`) +, buildEnv +, makeWrapper +, enableGui ? false # enables Java GUI `dsmj` # path to `dsm.sys` configuration files , dsmSysCli ? "/etc/tsm-client/cli.dsm.sys" , dsmSysApi ? "/etc/tsm-client/api.dsm.sys" @@ -127,6 +127,9 @@ let ''; }; + binPath = lib.makeBinPath ([ acl gnugrep procps ] + ++ lib.optional enableGui jdk8); + in buildEnv { @@ -145,7 +148,7 @@ buildEnv { # to the so-called "installation directories" # * Add symlinks to the "installation directories" # that point to the `dsm.sys` configuration files - # * Drop the Java GUI executable unless `jdk` is present + # * Drop the Java GUI executable unless `enableGui` is set # * Create wrappers for the command-line interface to # prepare `PATH` and `DSM_DIR` environment variables postBuild = '' @@ -153,13 +156,13 @@ buildEnv { ln --symbolic --no-target-directory opt/tivoli/tsm/client/api/bin64 $out/dsmi_dir ln --symbolic --no-target-directory "${dsmSysCli}" $out/dsm_dir/dsm.sys ln --symbolic --no-target-directory "${dsmSysApi}" $out/dsmi_dir/dsm.sys - ${lib.optionalString (jdk8==null) "rm $out/bin/dsmj"} + ${lib.optionalString (!enableGui) "rm $out/bin/dsmj"} for bin in $out/bin/* do target=$(readlink "$bin") rm "$bin" makeWrapper "$target" "$bin" \ - --prefix PATH : "$out/dsm_dir:${lib.makeBinPath [ procps gnugrep acl jdk8 ]}" \ + --prefix PATH : "$out/dsm_dir:${binPath}" \ --set DSM_DIR $out/dsm_dir done ''; diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index ff2ae2087025..b5e787375e2e 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -4923,8 +4923,8 @@ with pkgs; timeline = callPackage ../applications/office/timeline { }; - tsm-client = callPackage ../tools/backup/tsm-client { jdk8 = null; }; - tsm-client-withGui = callPackage ../tools/backup/tsm-client { }; + tsm-client = callPackage ../tools/backup/tsm-client { }; + tsm-client-withGui = callPackage ../tools/backup/tsm-client { enableGui = true; }; tracker = callPackage ../development/libraries/tracker { }; From 517ae2a288d11366de4f6867f74e04215e916b85 Mon Sep 17 00:00:00 2001 From: Yarny0 <41838844+Yarny0@users.noreply.github.com> Date: Tue, 30 Nov 2021 21:59:57 +0100 Subject: [PATCH 04/15] tsm-client: update URL structure IBM has changed the URL structures of their support web pages. The commit at hand updates most URLs and in particular the package update instructions so they follow the new structure. It also calculates the source download URL from the version number, so package updates no longer have to update the URL in addition to the version string. --- pkgs/tools/backup/tsm-client/default.nix | 32 ++++++++++++++++-------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/pkgs/tools/backup/tsm-client/default.nix b/pkgs/tools/backup/tsm-client/default.nix index bd7b21be7645..0e2c99c485e1 100644 --- a/pkgs/tools/backup/tsm-client/default.nix +++ b/pkgs/tools/backup/tsm-client/default.nix @@ -19,7 +19,7 @@ # For an explanation of optional packages # (features provided by them, version limits), see -# https://www-01.ibm.com/support/docview.wss?uid=swg21052223#Version%208.1 +# https://www.ibm.com/support/pages/node/660813#Version%208.1 # IBM Tivoli Storage Manager Client uses a system-wide @@ -41,21 +41,25 @@ # point to this derivations `/dsmi_dir` directory symlink. # Other environment variables might be necessary, # depending on local configuration or usage; see: -# https://www.ibm.com/support/knowledgecenter/en/SSEQVQ_8.1.8/client/c_cfg_sapiunix.html +# https://www.ibm.com/docs/en/spectrum-protect/8.1.8?topic=solaris-set-api-environment-variables -# The newest version of TSM client should be discoverable -# by going the the `downloadPage` (see `meta` below), -# there to "Client Latest Downloads", -# "IBM Spectrum Protect Client Downloads and READMEs", -# then to "Linux x86_64 Ubuntu client" (as of 2019-07-15). +# The newest version of TSM client should be discoverable by +# going to the `downloadPage` (see `meta` below), then +# * find section "Client Service Release", +# * pick the latest version and follow the link +# "IBM Spectrum Protect Client .. Downloads and READMEs" +# * in the table at the page's bottom, follow the +# "HTTPS" link of the "Linux x86_64 Ubuntu client" +# * in the directory listing, pick the big `.tar` file +# (as of 2021-12-13) let meta = { - homepage = "https://www.ibm.com/us-en/marketplace/data-protection-and-recovery"; - downloadPage = "https://www-01.ibm.com/support/docview.wss?uid=swg21239415"; + homepage = "https://www.ibm.com/products/data-protection-and-recovery"; + downloadPage = "https://www.ibm.com/support/pages/ibm-spectrum-protect-downloads-latest-fix-packs-and-interim-fixes"; platforms = [ "x86_64-linux" ]; license = lib.licenses.unfree; maintainers = [ lib.maintainers.yarny ]; @@ -75,11 +79,19 @@ let ''; }; + mkSrcUrl = version: + let + major = lib.versions.major version; + minor = lib.versions.minor version; + patch = lib.versions.patch version; + in + "https://public.dhe.ibm.com/storage/tivoli-storage-management/maintenance/client/v${major}r${minor}/Linux/LinuxX86_DEB/BA/v${major}${minor}${patch}/${version}-TIV-TSMBAC-LinuxX86_DEB.tar"; + unwrapped = stdenv.mkDerivation rec { name = "tsm-client-${version}-unwrapped"; version = "8.1.8.0"; src = fetchurl { - url = "ftp://public.dhe.ibm.com/storage/tivoli-storage-management/maintenance/client/v8r1/Linux/LinuxX86_DEB/BA/v818/${version}-TIV-TSMBAC-LinuxX86_DEB.tar"; + url = mkSrcUrl version; sha256 = "0c1d0jm0i7qjd314nhj2vj8fs7sncm1x2n4d6dg4049jniyvjhpk"; }; inherit meta; From 5ad0ecb9019e964d2abfe034e184f8b846e42dfa Mon Sep 17 00:00:00 2001 From: Yarny0 <41838844+Yarny0@users.noreply.github.com> Date: Tue, 30 Nov 2021 22:07:04 +0100 Subject: [PATCH 05/15] tsm-client: 8.1.8.0 -> 8.1.13.0 tsm-client now links against openssl; patchelf complains without it. Links to IBM's "Authorized Program Analysis Report"s (something like release notes), to READMEs, and to Security Bulletins, for all updates between 8.1.8.0 and 8.1.13.0: * 8.1.9.x * APARs: https://www.ibm.com/support/pages/node/1077159 * READMEs: https://www.ibm.com/support/pages/node/1108473 * https://www.ibm.com/support/pages/node/1107261 (CVE-2018-2025) * https://www.ibm.com/support/pages/node/1107777 (CVE-2019-4406) * 8.1.10.x * APARs: https://www.ibm.com/support/pages/node/6223098 * READMEs: https://www.ibm.com/support/pages/node/6223388 * https://www.ibm.com/support/pages/node/6221448 (CVE-2020-4494, CVE-2020-4406) * https://www.ibm.com/support/pages/node/6245356 (CVE-2020-2654) * https://www.ibm.com/support/pages/node/6245366 (CVE-2015-4000) * 8.1.11.x * APARs: https://www.ibm.com/support/pages/node/6367203 * READMEs: https://www.ibm.com/support/pages/node/6367205 * https://www.ibm.com/support/pages/node/6371646 * https://www.ibm.com/support/pages/node/6371650 * https://www.ibm.com/support/pages/node/6371652 * 8.1.12.x * APARs: https://www.ibm.com/support/pages/node/6429561 * READMEs: https://www.ibm.com/support/pages/node/6443671 * https://www.ibm.com/support/pages/node/6445503 (CVE-2021-20532) * https://www.ibm.com/support/pages/node/6445497 (CVE-2021-29672, CVE-2021-20546) * https://www.ibm.com/support/pages/node/6445489 (CVE-2020-1971, CVE-2021-23840, CVE-2021-23841) * https://www.ibm.com/support/pages/node/6445483 (CVE-2020-27221, CVE-2020-14782) * 8.1.13.x * APARs: https://www.ibm.com/support/pages/node/6524936 * READMEs: https://www.ibm.com/support/pages/node/6524938 * https://www.ibm.com/support/pages/node/6524706 (CVE-2021-39048) * https://www.ibm.com/support/pages/node/6524712 (CVE-2021-3712, CVE-2021-3711) --- pkgs/tools/backup/tsm-client/default.nix | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/pkgs/tools/backup/tsm-client/default.nix b/pkgs/tools/backup/tsm-client/default.nix index 0e2c99c485e1..e29efa3c0019 100644 --- a/pkgs/tools/backup/tsm-client/default.nix +++ b/pkgs/tools/backup/tsm-client/default.nix @@ -2,6 +2,7 @@ , stdenv , fetchurl , autoPatchelfHook +, openssl , zlib , lvm2 # LVM image backup and restore functions (optional) , acl # EXT2/EXT3/XFS ACL support (optional) @@ -41,7 +42,7 @@ # point to this derivations `/dsmi_dir` directory symlink. # Other environment variables might be necessary, # depending on local configuration or usage; see: -# https://www.ibm.com/docs/en/spectrum-protect/8.1.8?topic=solaris-set-api-environment-variables +# https://www.ibm.com/docs/en/spectrum-protect/8.1.13?topic=solaris-set-api-environment-variables # The newest version of TSM client should be discoverable by @@ -89,10 +90,10 @@ let unwrapped = stdenv.mkDerivation rec { name = "tsm-client-${version}-unwrapped"; - version = "8.1.8.0"; + version = "8.1.13.0"; src = fetchurl { url = mkSrcUrl version; - sha256 = "0c1d0jm0i7qjd314nhj2vj8fs7sncm1x2n4d6dg4049jniyvjhpk"; + sha256 = "0fy9c224g6rkrgd6ls01vs30bk9j9mlhf2x6akd11r7h8bib19zn"; }; inherit meta; @@ -100,6 +101,7 @@ let autoPatchelfHook ]; buildInputs = [ + openssl stdenv.cc.cc zlib ]; From 7934926b2e9761fe38ef567efaa0791d7d96388d Mon Sep 17 00:00:00 2001 From: Yarny0 <41838844+Yarny0@users.noreply.github.com> Date: Sun, 24 Oct 2021 08:59:16 +0200 Subject: [PATCH 06/15] tsm-client: makeWrapper buildInputs to nativeBuildInputs Although I'm not sure if `tsm-client` will ever be subject to cross-compiling, referencing makeWrapper from native BuildInputs is The Right Thing. This is a kind of follow-up of https://github.com/NixOS/nixpkgs/pull/112276 --- pkgs/tools/backup/tsm-client/default.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/tools/backup/tsm-client/default.nix b/pkgs/tools/backup/tsm-client/default.nix index e29efa3c0019..cb7ec933e8e4 100644 --- a/pkgs/tools/backup/tsm-client/default.nix +++ b/pkgs/tools/backup/tsm-client/default.nix @@ -151,7 +151,7 @@ buildEnv { inherit meta; passthru = { inherit unwrapped; }; paths = [ unwrapped ]; - buildInputs = [ makeWrapper ]; + nativeBuildInputs = [ makeWrapper ]; pathsToLink = [ "/" "/bin" From 8fa6f90ad6d03a8eb9b7a069f78f7f10a1fa2b51 Mon Sep 17 00:00:00 2001 From: Yarny0 <41838844+Yarny0@users.noreply.github.com> Date: Sat, 4 Dec 2021 09:00:58 +0100 Subject: [PATCH 07/15] tsm-client: set mainProgram The TSM command line client `dsmc` should be the program that is usually invoked from this package. However, if a user explicitely asks for the package with GUI support (with `enableGui`, available in the package `tsm-client-withGui`), we set the mainProgram to the graphical application `dsmj` as that's likely what the user is looking for. --- pkgs/tools/backup/tsm-client/default.nix | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pkgs/tools/backup/tsm-client/default.nix b/pkgs/tools/backup/tsm-client/default.nix index cb7ec933e8e4..ad9b8315aedc 100644 --- a/pkgs/tools/backup/tsm-client/default.nix +++ b/pkgs/tools/backup/tsm-client/default.nix @@ -62,6 +62,7 @@ let homepage = "https://www.ibm.com/products/data-protection-and-recovery"; downloadPage = "https://www.ibm.com/support/pages/ibm-spectrum-protect-downloads-latest-fix-packs-and-interim-fixes"; platforms = [ "x86_64-linux" ]; + mainProgram = "dsmc"; license = lib.licenses.unfree; maintainers = [ lib.maintainers.yarny ]; description = "IBM Spectrum Protect (Tivoli Storage Manager) CLI and API"; @@ -148,7 +149,9 @@ in buildEnv { name = "tsm-client-${unwrapped.version}"; - inherit meta; + meta = meta // lib.attrsets.optionalAttrs enableGui { + mainProgram = "dsmj"; + }; passthru = { inherit unwrapped; }; paths = [ unwrapped ]; nativeBuildInputs = [ makeWrapper ]; From 3f6d1f5f60461dc60992bf200e8c13535e2727a7 Mon Sep 17 00:00:00 2001 From: Yarny0 <41838844+Yarny0@users.noreply.github.com> Date: Sun, 24 Oct 2021 10:17:59 +0200 Subject: [PATCH 08/15] nixos/tsm-{client,backup}: update links in module comments IBM has changed the URL structures of their support web pages. The commit at hand updates URLs in two comments so they follow the new structure. --- nixos/modules/programs/tsm-client.nix | 2 +- nixos/modules/services/backup/tsm.nix | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/nixos/modules/programs/tsm-client.nix b/nixos/modules/programs/tsm-client.nix index 65d4db7834ff..421beec86e50 100644 --- a/nixos/modules/programs/tsm-client.nix +++ b/nixos/modules/programs/tsm-client.nix @@ -144,7 +144,7 @@ let }; config.name = mkDefault name; # Client system-options file directives are explained here: - # https://www.ibm.com/support/knowledgecenter/SSEQVQ_8.1.8/client/c_opt_usingopts.html + # https://www.ibm.com/docs/en/spectrum-protect/8.1.13?topic=commands-processing-options config.extraConfig = mapAttrs (lib.trivial.const mkDefault) ( { diff --git a/nixos/modules/services/backup/tsm.nix b/nixos/modules/services/backup/tsm.nix index 6c238745797e..d138e163e34f 100644 --- a/nixos/modules/services/backup/tsm.nix +++ b/nixos/modules/services/backup/tsm.nix @@ -88,7 +88,7 @@ in # TSM needs a HOME dir to store certificates. environment.HOME = "/var/lib/tsm-backup"; # for exit status description see - # https://www.ibm.com/support/knowledgecenter/en/SSEQVQ_8.1.8/client/c_sched_rtncode.html + # https://www.ibm.com/docs/en/spectrum-protect/8.1.13?topic=clients-client-return-codes serviceConfig.SuccessExitStatus = "4 8"; # The `-se` option must come after the command. # The `-optfile` option suppresses a `dsm.opt`-not-found warning. From c5effcaaeac42e3d54dd04985645ab2600641ad8 Mon Sep 17 00:00:00 2001 From: Yarny0 <41838844+Yarny0@users.noreply.github.com> Date: Sun, 24 Oct 2021 10:56:40 +0200 Subject: [PATCH 09/15] nixos/tsm-backup: enable most systemd sandboxing options This enables some systemd sandboxing options for the `tsm-backup.service`. Those settings have been determined by expermentation. This commit tries hard to protect the filesystem from write access, but not to hide anything from read access, so users can backup all files they choose to backup. An exception are API filesystems (`/dev`, `/proc`, `/sys`): As their "files" are not stored on persistent storage, they are sandboxed away as much as possible. Note that the service still has to run with root privileges to reach files with limited access permissions. The obvious alternative to use a dedicated user account and the `CAP_DAC_READ_SEARCH` capability to permit system-wide read access while blocking write access does not work. Experiments have shown that `dsmc` verifies access permissions for each file before attempting to open it for reading. Hence `dsmc` refuses to copy files where the file permission mode blocks read access -- even if process capabilities would allow it to proceed irrespective of permissions. --- nixos/modules/services/backup/tsm.nix | 39 ++++++++++++++++++++------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/nixos/modules/services/backup/tsm.nix b/nixos/modules/services/backup/tsm.nix index d138e163e34f..0017a6f69c16 100644 --- a/nixos/modules/services/backup/tsm.nix +++ b/nixos/modules/services/backup/tsm.nix @@ -87,16 +87,35 @@ in environment.DSM_LOG = "/var/log/tsm-backup/"; # TSM needs a HOME dir to store certificates. environment.HOME = "/var/lib/tsm-backup"; - # for exit status description see - # https://www.ibm.com/docs/en/spectrum-protect/8.1.13?topic=clients-client-return-codes - serviceConfig.SuccessExitStatus = "4 8"; - # The `-se` option must come after the command. - # The `-optfile` option suppresses a `dsm.opt`-not-found warning. - serviceConfig.ExecStart = - "${cfgPrg.wrappedPackage}/bin/dsmc ${cfg.command} -se='${cfg.servername}' -optfile=/dev/null"; - serviceConfig.LogsDirectory = "tsm-backup"; - serviceConfig.StateDirectory = "tsm-backup"; - serviceConfig.StateDirectoryMode = "0750"; + serviceConfig = { + # for exit status description see + # https://www.ibm.com/docs/en/spectrum-protect/8.1.13?topic=clients-client-return-codes + SuccessExitStatus = "4 8"; + # The `-se` option must come after the command. + # The `-optfile` option suppresses a `dsm.opt`-not-found warning. + ExecStart = + "${cfgPrg.wrappedPackage}/bin/dsmc ${cfg.command} -se='${cfg.servername}' -optfile=/dev/null"; + LogsDirectory = "tsm-backup"; + StateDirectory = "tsm-backup"; + StateDirectoryMode = "0750"; + # systemd sandboxing + LockPersonality = true; + NoNewPrivileges = true; + PrivateDevices = true; + #PrivateTmp = true; # would break backup of {/var,}/tmp + #PrivateUsers = true; # would block backup of /home/* + ProtectClock = true; + ProtectControlGroups = true; + ProtectHome = "read-only"; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectProc = "noaccess"; + ProtectSystem = "strict"; + RestrictNamespaces = true; + RestrictSUIDSGID = true; + }; startAt = mkIf (cfg.autoTime!=null) cfg.autoTime; }; }; From c2192ed77ae517094a235dfb0ef33d7b88d81212 Mon Sep 17 00:00:00 2001 From: Yarny0 <41838844+Yarny0@users.noreply.github.com> Date: Sun, 5 Dec 2021 13:52:06 +0100 Subject: [PATCH 10/15] nixos/tsm-{client,backup}: use new type `nonEmptyStr` The module option type `nonEmptyStr` was introduced in commit https://github.com/NixOS/nixpkgs/commit/a3c5f0cba8fa9c4d9782ef83757be6e4028f54b7 The tsm modules previously simply used `strMatching ".+"` to prevent empty option strings, but the new type is more thorough as it also catches space-only strings. --- nixos/modules/programs/tsm-client.nix | 6 +++--- nixos/modules/services/backup/tsm.nix | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/nixos/modules/programs/tsm-client.nix b/nixos/modules/programs/tsm-client.nix index 421beec86e50..28db96253875 100644 --- a/nixos/modules/programs/tsm-client.nix +++ b/nixos/modules/programs/tsm-client.nix @@ -7,7 +7,7 @@ let inherit (lib.modules) mkDefault mkIf; inherit (lib.options) literalExpression mkEnableOption mkOption; inherit (lib.strings) concatStringsSep optionalString toLower; - inherit (lib.types) addCheck attrsOf lines nullOr package path port str strMatching submodule; + inherit (lib.types) addCheck attrsOf lines nonEmptyStr nullOr package path port str strMatching submodule; # Checks if given list of strings contains unique # elements when compared without considering case. @@ -35,7 +35,7 @@ let ''; }; options.server = mkOption { - type = strMatching ".+"; + type = nonEmptyStr; example = "tsmserver.company.com"; description = '' Host/domain name or IP address of the IBM TSM server. @@ -56,7 +56,7 @@ let ''; }; options.node = mkOption { - type = strMatching ".+"; + type = nonEmptyStr; example = "MY-TSM-NODE"; description = '' Target node name on the IBM TSM server. diff --git a/nixos/modules/services/backup/tsm.nix b/nixos/modules/services/backup/tsm.nix index 0017a6f69c16..4e690ac6ecda 100644 --- a/nixos/modules/services/backup/tsm.nix +++ b/nixos/modules/services/backup/tsm.nix @@ -5,7 +5,7 @@ let inherit (lib.attrsets) hasAttr; inherit (lib.modules) mkDefault mkIf; inherit (lib.options) mkEnableOption mkOption; - inherit (lib.types) nullOr strMatching; + inherit (lib.types) nonEmptyStr nullOr; options.services.tsmBackup = { enable = mkEnableOption '' @@ -15,7 +15,7 @@ let ''; command = mkOption { - type = strMatching ".+"; + type = nonEmptyStr; default = "backup"; example = "incr"; description = '' @@ -24,7 +24,7 @@ let ''; }; servername = mkOption { - type = strMatching ".+"; + type = nonEmptyStr; example = "mainTsmServer"; description = '' Create a systemd system service @@ -41,7 +41,7 @@ let ''; }; autoTime = mkOption { - type = nullOr (strMatching ".+"); + type = nullOr nonEmptyStr; default = null; example = "12:00"; description = '' From f6dca95c5dc8ab63322e439ae33a148877838ba9 Mon Sep 17 00:00:00 2001 From: Yarny0 <41838844+Yarny0@users.noreply.github.com> Date: Sat, 18 Dec 2021 09:21:57 +0100 Subject: [PATCH 11/15] tsm-client: add test derivation and a module test The tsm-client needs a tsm-server to do anything useful. Without a server, automated tests can just check diagnostic outputs for plausibility. The commit at hand adds two tests: 1. The command line interface `dsmc` is called, then it is verified that the program does * report the correct client version, * find its configuration file, * report a connection error. 2. To check the GUI (and the tsm-client nixos module), we add a vm test which uses the module to install `tsm-client-withGui`. To verify that the GUI's basic functionality is present, we skip over all connection failure related error messages and open the "Connection Information" dialog from the main application window. This dialog presents the node name and the client version; both are verified by the test. Note: Our `tsm-client` build recipe consists of two packages: The "unwrapped" package and the final package. This commit puts the unwrapped one into the final package's `passthru` so that tests can access the original version string that is needed to check the client version reported by the application. --- nixos/tests/all-tests.nix | 1 + nixos/tests/tsm-client-gui.nix | 57 ++++++++++++++++++++++ pkgs/tools/backup/tsm-client/default.nix | 11 ++++- pkgs/tools/backup/tsm-client/test-cli.nix | 58 +++++++++++++++++++++++ 4 files changed, 125 insertions(+), 2 deletions(-) create mode 100644 nixos/tests/tsm-client-gui.nix create mode 100644 pkgs/tools/backup/tsm-client/test-cli.nix diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 95ce2cc5ccf2..ef98567a006f 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -487,6 +487,7 @@ in trezord = handleTest ./trezord.nix {}; trickster = handleTest ./trickster.nix {}; trilium-server = handleTestOn ["x86_64-linux"] ./trilium-server.nix {}; + tsm-client-gui = handleTest ./tsm-client-gui.nix {}; txredisapi = handleTest ./txredisapi.nix {}; tuptime = handleTest ./tuptime.nix {}; turbovnc-headless-server = handleTest ./turbovnc-headless-server.nix {}; diff --git a/nixos/tests/tsm-client-gui.nix b/nixos/tests/tsm-client-gui.nix new file mode 100644 index 000000000000..e4bcd344a895 --- /dev/null +++ b/nixos/tests/tsm-client-gui.nix @@ -0,0 +1,57 @@ +# The tsm-client GUI first tries to connect to a server. +# We can't simulate a server, so we just check if +# it reports the correct connection failure error. +# After that the test persuades the GUI +# to show its main application window +# and verifies some configuration information. + +import ./make-test-python.nix ({ lib, pkgs, ... }: { + name = "tsm-client"; + + enableOCR = true; + + machine = { pkgs, ... }: { + imports = [ ./common/x11.nix ]; + programs.tsmClient = { + enable = true; + package = pkgs.tsm-client-withGui; + defaultServername = "testserver"; + servers.testserver = { + # 192.0.0.8 is a "dummy address" according to RFC 7600 + server = "192.0.0.8"; + node = "SOME-NODE"; + passwdDir = "/tmp"; + }; + }; + }; + + testScript = '' + machine.succeed("which dsmj") # fail early if this is missing + machine.wait_for_x() + machine.execute("DSM_LOG=/tmp dsmj -optfile=/dev/null >&2 &") + + # does it report the "TCP/IP connection failure" error code? + machine.wait_for_window("IBM Spectrum Protect") + machine.wait_for_text("ANS2610S") + machine.send_key("esc") + + # it asks to continue to restore a local backupset now; + # "yes" (return) leads to the main application window + machine.wait_for_text("backupset") + machine.send_key("ret") + + # main window: navigate to "Connection Information" + machine.wait_for_text("Welcome") + machine.send_key("alt-f") # "File" menu + machine.send_key("c") # "Connection Information" + + # "Connection Information" dialog box + machine.wait_for_window("Connection Information") + machine.wait_for_text("SOME-NODE") + machine.wait_for_text("${pkgs.tsm-client.passthru.unwrapped.version}") + + machine.shutdown() + ''; + + meta.maintainers = [ lib.maintainers.yarny ]; +}) diff --git a/pkgs/tools/backup/tsm-client/default.nix b/pkgs/tools/backup/tsm-client/default.nix index ad9b8315aedc..6303d76a1dad 100644 --- a/pkgs/tools/backup/tsm-client/default.nix +++ b/pkgs/tools/backup/tsm-client/default.nix @@ -1,4 +1,6 @@ { lib +, callPackage +, nixosTests , stdenv , fetchurl , autoPatchelfHook @@ -81,6 +83,11 @@ let ''; }; + passthru.tests = { + test-cli = callPackage ./test-cli.nix {}; + test-gui = nixosTests.tsm-client-gui; + }; + mkSrcUrl = version: let major = lib.versions.major version; @@ -96,7 +103,7 @@ let url = mkSrcUrl version; sha256 = "0fy9c224g6rkrgd6ls01vs30bk9j9mlhf2x6akd11r7h8bib19zn"; }; - inherit meta; + inherit meta passthru; nativeBuildInputs = [ autoPatchelfHook @@ -152,7 +159,7 @@ buildEnv { meta = meta // lib.attrsets.optionalAttrs enableGui { mainProgram = "dsmj"; }; - passthru = { inherit unwrapped; }; + passthru = passthru // { inherit unwrapped; }; paths = [ unwrapped ]; nativeBuildInputs = [ makeWrapper ]; pathsToLink = [ diff --git a/pkgs/tools/backup/tsm-client/test-cli.nix b/pkgs/tools/backup/tsm-client/test-cli.nix new file mode 100644 index 000000000000..0858083c9f90 --- /dev/null +++ b/pkgs/tools/backup/tsm-client/test-cli.nix @@ -0,0 +1,58 @@ +{ lib +, writeText +, runCommand +, tsm-client +}: + +# Let the client try to connect to a server. +# We can't simulate a server, so there's no more to test. + +let + + # 192.0.0.8 is a "dummy address" according to RFC 7600 + dsmSysCli = writeText "cli.dsm.sys" '' + defaultserver testserver + server testserver + commmethod v6tcpip + tcpserveraddress 192.0.0.8 + nodename ARBITRARYNODENAME + ''; + + tsm-client_ = tsm-client.override { inherit dsmSysCli; }; + + env.nativeBuildInputs = [ tsm-client_ ]; + + versionString = + let + inherit (tsm-client_.passthru.unwrapped) version; + major = lib.versions.major version; + minor = lib.versions.minor version; + patch = lib.versions.patch version; + fixup = lib.lists.elemAt (lib.versions.splitVersion version) 3; + in + "Client Version ${major}, Release ${minor}, Level ${patch}.${fixup}"; + +in + +runCommand "${tsm-client.name}-test-cli" env '' + set -o nounset + set -o pipefail + + export DSM_LOG=$(mktemp -d ./dsm_log.XXXXXXXXXXX) + + { dsmc -optfile=/dev/null || true; } | tee dsmc-stdout + + # does it report the correct version? + grep --fixed-strings '${versionString}' dsmc-stdout + + # does it use the provided dsm.sys config file? + # if it does, it states the node's name + grep ARBITRARYNODENAME dsmc-stdout + + # does it try (and fail) to connect to the server? + # if it does, it reports the "TCP/IP connection failure" error code + grep ANS1017E dsmc-stdout + grep ANS1017E $DSM_LOG/dsmerror.log + + touch $out +'' From 66d068bf66f8e5f55c589ff4c6114c0773c4ee70 Mon Sep 17 00:00:00 2001 From: Yarny0 <41838844+Yarny0@users.noreply.github.com> Date: Sat, 18 Dec 2021 13:49:54 +0100 Subject: [PATCH 12/15] tsm-client: use rpm source instead of deb/Ubuntu IBM publishes their IBM Spectrum Protect client for Linux in two flavors: * "Linux x86_64 client" * "Linux x86_64 Ubuntu client" Up to this commit, nixpkgs used the Ubuntu flavor to build its `tsm-client` derivation. However, the history of published archive files in * https://public.dhe.ibm.com/storage/tivoli-storage-management/maintenance/client/v8r1/Linux/ * https://public.dhe.ibm.com/storage/tivoli-storage-management/patches/client/v8r1/Linux/ suggests that updates in the fourth level of the version numbers (e.g. 8.1.13.0 -> 8.1.13.1) do not get published as Ubuntu flavor. It order to be able to always use the latest release, this commit switches to the non-Ubuntu flavor. The non-Ubuntu archive contains rpm files, so this commit switches from `ar` to `rpmextract`. Instead of unpacking all deb files, the build recipe now unpacks all _but one_ rpm file: The file `TIVsm-WEBGUI.x86_64.rpm` apparently contains a plugin that is not included in the Ubuntu version (see note below). Comparing the old and the new derivation's output indicates that this choice minimizes the difference between the results: The output of the old (Ubuntu flavor) derivation contains: * `commons-codec-1.6.jar` * `share/` with changelog and copyright information for the packages `gskssl64` and `gskcrypt64` The output of the new (non-Ubuntu flavor) derivation contains: * `lib64`, symlink to `lib` * `commons-codec-1.14.jar` * `opt/tivoli/tsm/license/{api,baclient}/sm/` with license agreement files in many languages Besides these differences, the outputs' file names are equal. Note: I don't know what functionality `TIVsm-WEBGUI.x86_64.rpm` actually provides. Unpacking it with the other rpm files makes patchelf complain about missing X11 libraries, so in order to include it here, one would likely need to add those to `buildInputs`. However, as the old (Ubuntu flavor) `tsm-client` package did not contain this functionality and as I cannot test or use it in any way, I opted to not include it now. If we want to include this with a later commit, we should add another package build option (like `enableGui`) so that the default `tsm-client` package does not pull in X11 libraries and its closure size therefore stays small. --- pkgs/tools/backup/tsm-client/default.nix | 46 +++++++++++++++--------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/pkgs/tools/backup/tsm-client/default.nix b/pkgs/tools/backup/tsm-client/default.nix index 6303d76a1dad..2cb29106c989 100644 --- a/pkgs/tools/backup/tsm-client/default.nix +++ b/pkgs/tools/backup/tsm-client/default.nix @@ -4,6 +4,7 @@ , stdenv , fetchurl , autoPatchelfHook +, rpmextract , openssl , zlib , lvm2 # LVM image backup and restore functions (optional) @@ -48,14 +49,20 @@ # The newest version of TSM client should be discoverable by -# going to the `downloadPage` (see `meta` below), then -# * find section "Client Service Release", -# * pick the latest version and follow the link -# "IBM Spectrum Protect Client .. Downloads and READMEs" -# * in the table at the page's bottom, follow the -# "HTTPS" link of the "Linux x86_64 Ubuntu client" -# * in the directory listing, pick the big `.tar` file -# (as of 2021-12-13) +# going to the `downloadPage` (see `meta` below). +# Find the "Backup-archive client" table on that page. +# Look for "Download Documents" of the latest release. +# Here, two links must be checked: +# * "IBM Spectrum Protect Client ... Downloads and READMEs": +# In the table at the page's bottom, +# check the date of the "Linux x86_64 client" +# * "IBM Spectrum Protect BA client ... interim fix downloads" +# Look for the "Linux x86_64 client" rows +# in the table # at the bottom of each page. +# Follow the "HTTPS" link of the row with the latest date stamp. +# In the directory listing to show up, pick the big `.tar` file. +# +# (as of 2021-12-18) let @@ -93,20 +100,22 @@ let major = lib.versions.major version; minor = lib.versions.minor version; patch = lib.versions.patch version; + fixup = lib.lists.elemAt (lib.versions.splitVersion version) 3; in - "https://public.dhe.ibm.com/storage/tivoli-storage-management/maintenance/client/v${major}r${minor}/Linux/LinuxX86_DEB/BA/v${major}${minor}${patch}/${version}-TIV-TSMBAC-LinuxX86_DEB.tar"; + "https://public.dhe.ibm.com/storage/tivoli-storage-management/${if fixup=="0" then "maintenance" else "patches"}/client/v${major}r${minor}/Linux/LinuxX86/BA/v${major}${minor}${patch}/${version}-TIV-TSMBAC-LinuxX86.tar"; unwrapped = stdenv.mkDerivation rec { name = "tsm-client-${version}-unwrapped"; version = "8.1.13.0"; src = fetchurl { url = mkSrcUrl version; - sha256 = "0fy9c224g6rkrgd6ls01vs30bk9j9mlhf2x6akd11r7h8bib19zn"; + sha256 = "1p6bw1szsb6kl7nfalsnz0kxcs8dvggh8ad8irj677ljhhryqbm4"; }; inherit meta passthru; nativeBuildInputs = [ autoPatchelfHook + rpmextract ]; buildInputs = [ openssl @@ -119,12 +128,15 @@ let sourceRoot = "."; postUnpack = '' - for debfile in *.deb - do - ar -x "$debfile" - tar --xz --extract --file=data.tar.xz - rm data.tar.xz - done + rpmextract TIVsm-API64.x86_64.rpm + rpmextract TIVsm-APIcit.x86_64.rpm + rpmextract TIVsm-BA.x86_64.rpm + rpmextract TIVsm-BAcit.x86_64.rpm + rpmextract TIVsm-BAhdw.x86_64.rpm + rpmextract TIVsm-JBB.x86_64.rpm + # use globbing so that version updates don't break the build: + rpmextract gskcrypt64-*.linux.x86_64.rpm + rpmextract gskssl64-*.linux.x86_64.rpm ''; installPhase = '' @@ -136,7 +148,7 @@ let # Fix relative symlinks after `/usr` was moved up one level preFixup = '' - for link in $out/lib/* $out/bin/* + for link in $out/lib{,64}/* $out/bin/* do target=$(readlink "$link") if [ "$(cut -b -6 <<< "$target")" != "../../" ] From 4a42ca06c10fc049a63cc12201ab1b93125230fe Mon Sep 17 00:00:00 2001 From: Yarny0 <41838844+Yarny0@users.noreply.github.com> Date: Sat, 18 Dec 2021 16:25:03 +0100 Subject: [PATCH 13/15] tsm-client: 8.1.13.0 -> 8.1.13.1 Link to Security Bulletin: https://www.ibm.com/support/pages/node/6527080 (CVE-2021-44228) --- pkgs/tools/backup/tsm-client/default.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/tools/backup/tsm-client/default.nix b/pkgs/tools/backup/tsm-client/default.nix index 2cb29106c989..2f5c50e2b294 100644 --- a/pkgs/tools/backup/tsm-client/default.nix +++ b/pkgs/tools/backup/tsm-client/default.nix @@ -106,10 +106,10 @@ let unwrapped = stdenv.mkDerivation rec { name = "tsm-client-${version}-unwrapped"; - version = "8.1.13.0"; + version = "8.1.13.1"; src = fetchurl { url = mkSrcUrl version; - sha256 = "1p6bw1szsb6kl7nfalsnz0kxcs8dvggh8ad8irj677ljhhryqbm4"; + sha256 = "00kgfn00b4gmmpxgw7n5kyfh94a9fkmi8bm9pqy9gz8qrp1v9d2r"; }; inherit meta passthru; From be904af99c0a9a26f2beb4cab2da45ff0c139bc7 Mon Sep 17 00:00:00 2001 From: Yarny0 <41838844+Yarny0@users.noreply.github.com> Date: Thu, 6 Jan 2022 10:02:11 +0100 Subject: [PATCH 14/15] tsm-client: 8.1.13.1 -> 8.1.13.2 Link to Security Bulletin: https://www.ibm.com/support/pages/node/6537640 (CVE-2021-45105, CVE-2021-45046) --- pkgs/tools/backup/tsm-client/default.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/tools/backup/tsm-client/default.nix b/pkgs/tools/backup/tsm-client/default.nix index 2f5c50e2b294..7c29d34d2046 100644 --- a/pkgs/tools/backup/tsm-client/default.nix +++ b/pkgs/tools/backup/tsm-client/default.nix @@ -106,10 +106,10 @@ let unwrapped = stdenv.mkDerivation rec { name = "tsm-client-${version}-unwrapped"; - version = "8.1.13.1"; + version = "8.1.13.2"; src = fetchurl { url = mkSrcUrl version; - sha256 = "00kgfn00b4gmmpxgw7n5kyfh94a9fkmi8bm9pqy9gz8qrp1v9d2r"; + sha256 = "0cspxr96g93kb8vy6m86ks16sfw1zghkd2fmxk95mwphs762d5xm"; }; inherit meta passthru; From 756f45306b69ac4fe0a4cd4e2d42bb3d29162f43 Mon Sep 17 00:00:00 2001 From: Yarny0 <41838844+Yarny0@users.noreply.github.com> Date: Sat, 15 Jan 2022 10:53:06 +0100 Subject: [PATCH 15/15] tsm-client: 8.1.13.2 -> 8.1.13.3 Link to Security Bulletin: https://www.ibm.com/support/pages/node/6540692 (CVE-2021-44832) --- pkgs/tools/backup/tsm-client/default.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/tools/backup/tsm-client/default.nix b/pkgs/tools/backup/tsm-client/default.nix index 7c29d34d2046..c684b34ec4e5 100644 --- a/pkgs/tools/backup/tsm-client/default.nix +++ b/pkgs/tools/backup/tsm-client/default.nix @@ -106,10 +106,10 @@ let unwrapped = stdenv.mkDerivation rec { name = "tsm-client-${version}-unwrapped"; - version = "8.1.13.2"; + version = "8.1.13.3"; src = fetchurl { url = mkSrcUrl version; - sha256 = "0cspxr96g93kb8vy6m86ks16sfw1zghkd2fmxk95mwphs762d5xm"; + sha256 = "1dwczf236drdaf4jcfzz5154vdwvxf5zraxhrhiddl6n80hnvbcd"; }; inherit meta passthru;