{ lib, stdenv, fetchurl, dpkg, makeWrapper, patchelf , coreutils, systemd, glib, zlib, xz, curl, libxml2 }: let version = "5.1.17.3394"; # libxml2's "out" output has lib/libxml2.so.16 libxml2_out = libxml2.out; # System library RPATH for all bundled ELF binaries (cisco's own lib dir is # appended during fixupPhase via $out) sysRpath = lib.makeLibraryPath [ systemd glib zlib xz stdenv.cc.cc.lib curl libxml2_out ]; in stdenv.mkDerivation { pname = "cisco-secure-client"; inherit version; src = fetchurl { url = "https://archive.org/download/cisco-secure-client-linux64-${version}/cisco-secure-client-linux64-${version}-predeploy-deb-k9.tgz"; sha256 = "5c4cafb4694e64cbf041481f5df3d70389399926f8aa2a469d480c0555b58c2c"; }; nativeBuildInputs = [ dpkg makeWrapper patchelf ]; buildInputs = [ systemd glib zlib xz stdenv.cc.cc.lib curl libxml2_out ]; dontStrip = true; dontAutoPatchelf = true; unpackPhase = '' tar xzf "$src" DEB_FILE=$(ls cisco-secure-client-vpn-cli_*_amd64.deb 2>/dev/null || true) if [ -z "$DEB_FILE" ]; then DEB_FILE=$(ls cisco-secure-client-vpn_*_amd64.deb 2>/dev/null || true) fi if [ -z "$DEB_FILE" ]; then echo "ERROR: No .deb file found" exit 1 fi dpkg-deb -x "$DEB_FILE" . ''; installPhase = '' runHook preInstall mkdir -p "$out" cp -r opt/* "$out/" runHook postInstall ''; # fixupPhase: patchelf corrupts Cisco's embedded code signatures on ALL # shipped ELF binaries and .so plugins. We skip patchelf entirely and # instead rely on LD_LIBRARY_PATH wrappers for system library resolution. # The binaries' original RPATH of /opt/cisco/secureclient/lib resolves # correctly at runtime via the /opt/cisco/secureclient -> store symlink. fixupPhase = '' runHook preFixup # Fix absolute symlinks — the deb assumes install under /opt/cisco/secureclient/ # but nix puts it in the store. Convert to relative symlinks. for link in $(find "$out" -type l); do target=$(readlink "$link") if echo "$target" | grep -q "^/opt/"; then rel=$(basename "$target") ln -sf "$rel" "$link" fi done for f in "$out"/cisco/secureclient/bin/* "$out"/cisco/secureclient/lib/*.so*; do chmod +x "$f" 2>/dev/null || true done # Create libxml2.so.2 symlink (SONAME mismatch: Cisco wants .2, nixpkgs provides .16) libxml2_so=$(find ${libxml2_out}/lib -name "libxml2.so.16*" 2>/dev/null | head -1) if [ -n "$libxml2_so" ]; then ln -sf "$libxml2_so" "$out/cisco/secureclient/lib/libxml2.so.2" fi # NO patchelf on Cisco ELFs — their embedded code signatures are # verified at runtime (especially plugins loaded by vpnagentd). # All ELFs keep their original RPATH /opt/cisco/secureclient/lib # which resolves via the tmpfiles symlink. # System libs are provided via LD_LIBRARY_PATH in wrappers below. ldPath="$out/cisco/secureclient/lib:${sysRpath}" # Wrap vpn CLI — wrapProgram renames the original to .vpn-wrapped wrapProgram "$out/cisco/secureclient/bin/vpn" \ --prefix LD_LIBRARY_PATH : "$ldPath" \ --prefix PATH : ${lib.makeBinPath [ coreutils ]} # Create $out/bin/ wrappers for all user-facing executables mkdir -p "$out/bin" makeWrapper "$out/cisco/secureclient/bin/vpn" "$out/bin/vpn" \ --prefix LD_LIBRARY_PATH : "$ldPath" \ --prefix PATH : ${lib.makeBinPath [ coreutils ]} makeWrapper "$out/cisco/secureclient/bin/vpnagentd" "$out/bin/vpnagentd" \ --prefix LD_LIBRARY_PATH : "$ldPath" \ --prefix PATH : ${lib.makeBinPath [ coreutils ]} for cli in acinstallhelper manifesttool_vpn vpndownloader-cli; do if [ -f "$out/cisco/secureclient/bin/$cli" ]; then makeWrapper "$out/cisco/secureclient/bin/$cli" "$out/bin/$cli" \ --prefix LD_LIBRARY_PATH : "$ldPath" fi done runHook postFixup ''; meta = with lib; { description = "Cisco Secure Client (AnyConnect successor) VPN client"; homepage = "https://www.cisco.com/site/us/en/products/security/secure-client/index.html"; sourceProvenance = with sourceTypes; [ binaryNativeCode ]; license = { name = "Cisco Secure Client EULA — proprietary, not redistributable"; url = "https://www.cisco.com/c/en/us/products/security/secure-client/eula.html"; }; platforms = [ "x86_64-linux" ]; maintainers = [ ]; }; }