1{
2 lib,
3 stdenv,
4 requireFile,
5 makeWrapper,
6 autoPatchelfHook,
7 wrapGAppsHook3,
8 alsa-lib,
9 atk,
10 cacert,
11 cairo,
12 dconf,
13 fetchurl,
14 file,
15 fontconfig,
16 freetype,
17 gdk-pixbuf,
18 glib,
19 glib-networking,
20 gnome2,
21 gtk2,
22 gtk2-x11,
23 gtk3,
24 gtk_engines,
25 heimdal,
26 krb5,
27 libGL,
28 libappindicator-gtk3,
29 libcanberra-gtk3,
30 libcap,
31 libcxx,
32 libfaketime,
33 libgbm,
34 libinput,
35 libjpeg,
36 libjson,
37 libpng12,
38 libpulseaudio,
39 libredirect,
40 libsecret,
41 libsoup_2_4,
42 libvorbis,
43 libxml2,
44 llvmPackages,
45 more,
46 nspr,
47 nss,
48 opencv4,
49 openssl,
50 pango,
51 pcsclite,
52 sane-backends,
53 speex,
54 symlinkJoin,
55 systemd,
56 tzdata,
57 webkitgtk_4_0,
58 which,
59 xorg,
60 zlib,
61
62 homepage,
63 version,
64 prefix,
65 hash,
66
67 extraCerts ? [ ],
68}:
69
70let
71 openssl' = symlinkJoin {
72 name = "openssl-backwards-compat";
73 nativeBuildInputs = [ makeWrapper ];
74 paths = [ (lib.getLib openssl) ];
75 postBuild = ''
76 ln -sf $out/lib/libcrypto.so $out/lib/libcrypto.so.1.0.0
77 ln -sf $out/lib/libssl.so $out/lib/libssl.so.1.0.0
78 '';
79 };
80
81 opencv4' = symlinkJoin {
82 name = "opencv4-compat";
83 nativeBuildInputs = [ makeWrapper ];
84 paths = [ opencv4 ];
85 postBuild = ''
86 for so in ${opencv4}/lib/*.so; do
87 ln -s "$so" $out/lib/$(basename "$so").407 || true
88 ln -s "$so" $out/lib/$(basename "$so").410 || true
89 done
90 '';
91 };
92
93 libxml2' = libxml2.overrideAttrs (oldAttrs: rec {
94 version = "2.13.8";
95 src = fetchurl {
96 url = "mirror://gnome/sources/libxml2/${lib.versions.majorMinor version}/libxml2-${version}.tar.xz";
97 hash = "sha256-J3KUyzMRmrcbK8gfL0Rem8lDW4k60VuyzSsOhZoO6Eo=";
98 };
99 meta = oldAttrs.meta // {
100 knownVulnerabilities = oldAttrs.meta.knownVulnerabilities or [ ] ++ [
101 "CVE-2025-6021"
102 ];
103 };
104 });
105
106in
107
108stdenv.mkDerivation rec {
109 pname = "citrix-workspace";
110 inherit version;
111
112 src = requireFile rec {
113 name = "${prefix}-${version}.tar.gz";
114 sha256 = hash;
115
116 message = ''
117 In order to use Citrix Workspace, you need to comply with the Citrix EULA and download
118 the ${if stdenv.hostPlatform.is64bit then "64-bit" else "32-bit"} binaries, .tar.gz from:
119
120 ${homepage}
121
122 (if you do not find version ${version} there, try at
123 https://www.citrix.com/downloads/workspace-app/)
124
125 Once you have downloaded the file, please use the following command and re-run the
126 installation:
127
128 nix-prefetch-url file://\$PWD/${name}
129 '';
130 };
131
132 dontBuild = true;
133 dontConfigure = true;
134 sourceRoot = ".";
135 preferLocalBuild = true;
136 passthru.icaroot = "${placeholder "out"}/opt/citrix-icaclient";
137
138 nativeBuildInputs = [
139 autoPatchelfHook
140 file
141 libfaketime
142 makeWrapper
143 more
144 which
145 wrapGAppsHook3
146 ];
147
148 buildInputs = [
149 alsa-lib
150 atk
151 cairo
152 dconf
153 fontconfig
154 freetype
155 gdk-pixbuf
156 glib-networking
157 gnome2.gtkglext
158 gtk2
159 gtk2-x11
160 gtk3
161 gtk_engines
162 heimdal
163 krb5
164 libGL
165 libcanberra-gtk3
166 libcap
167 libcxx
168 libgbm
169 libinput
170 libjpeg
171 libjson
172 libpng12
173 libpulseaudio
174 libsecret
175 libsoup_2_4
176 libvorbis
177 libxml2'
178 llvmPackages.libunwind
179 nspr
180 nss
181 opencv4'
182 openssl'
183 pango
184 pcsclite
185 sane-backends
186 speex
187 stdenv.cc.cc
188 (lib.getLib systemd)
189 webkitgtk_4_0
190 xorg.libXScrnSaver
191 xorg.libXaw
192 xorg.libXmu
193 xorg.libXtst
194 zlib
195 ];
196
197 runtimeDependencies = [
198 glib
199 glib-networking
200 libappindicator-gtk3
201 libGL
202 pcsclite
203
204 xorg.libX11
205 xorg.libXScrnSaver
206 xorg.libXext
207 xorg.libXfixes
208 xorg.libXinerama
209 xorg.libXmu
210 xorg.libXrender
211 xorg.libXtst
212 xorg.libxcb
213 xorg.xdpyinfo
214 xorg.xprop
215 ];
216
217 installPhase =
218 let
219 icaFlag =
220 program:
221 if (builtins.match "selfservice(.*)" program) != null then
222 "--icaroot"
223 else if (builtins.match "wfica(.*)" program != null) then
224 null
225 else
226 "-icaroot";
227 wrap = program: ''
228 wrapProgram $out/opt/citrix-icaclient/${program} \
229 ${lib.optionalString (icaFlag program != null) ''--add-flags "${icaFlag program} $ICAInstDir"''} \
230 --set ICAROOT "$ICAInstDir" \
231 --prefix GIO_EXTRA_MODULES : "${glib-networking}/lib/gio/modules" \
232 --prefix LD_LIBRARY_PATH : "$ICAInstDir:$ICAInstDir/lib" \
233 --set LD_PRELOAD "${libredirect}/lib/libredirect.so ${lib.getLib pcsclite}/lib/libpcsclite.so" \
234 --set NIX_REDIRECTS "/usr/share/zoneinfo=${tzdata}/share/zoneinfo:/etc/zoneinfo=${tzdata}/share/zoneinfo:/etc/timezone=$ICAInstDir/timezone"
235 '';
236 wrapLink = program: ''
237 ${wrap program}
238 ln -sf $out/opt/citrix-icaclient/${program} $out/bin/${baseNameOf program}
239 '';
240
241 copyCert = path: ''
242 cp -v ${path} $out/opt/citrix-icaclient/keystore/cacerts/${baseNameOf path}
243 '';
244
245 mkWrappers = lib.concatMapStringsSep "\n";
246
247 toWrap = [
248 "wfica"
249 "selfservice"
250 "util/configmgr"
251 "util/conncenter"
252 "util/ctx_rehash"
253 ];
254 in
255 ''
256 runHook preInstall
257
258 mkdir -p $out/{bin,share/applications}
259 export ICAInstDir="$out/opt/citrix-icaclient"
260 export HOME=$(mktemp -d)
261
262 # Run upstream installer in the store-path.
263 sed -i -e 's,^ANSWER="",ANSWER="$INSTALLER_YES",g' -e 's,/bin/true,true,g' ./${prefix}/hinst
264 source_date=$(date --utc --date=@$SOURCE_DATE_EPOCH "+%F %T")
265 faketime -f "$source_date" ${stdenv.shell} ${prefix}/hinst CDROM "$(pwd)"
266
267 if [ -f "$ICAInstDir/util/setlog" ]; then
268 chmod +x "$ICAInstDir/util/setlog"
269 ln -sf "$ICAInstDir/util/setlog" "$out/bin/citrix-setlog"
270 fi
271 ${mkWrappers wrapLink toWrap}
272 ${mkWrappers wrap [
273 "PrimaryAuthManager"
274 "ServiceRecord"
275 "AuthManagerDaemon"
276 "util/ctxwebhelper"
277 ]}
278
279 ln -sf $ICAInstDir/util/storebrowse $out/bin/storebrowse
280
281 # As explained in https://wiki.archlinux.org/index.php/Citrix#Security_Certificates
282 echo "Expanding certificates..."
283 pushd "$ICAInstDir/keystore/cacerts"
284 awk 'BEGIN {c=0;} /BEGIN CERT/{c++} { print > "cert." c ".pem"}' \
285 < ${cacert}/etc/ssl/certs/ca-bundle.crt
286 popd
287
288 ${mkWrappers copyCert extraCerts}
289
290 # See https://developer-docs.citrix.com/en-us/citrix-workspace-app-for-linux/citrix-workspace-app-for-linux-oem-reference-guide/reference-information/#library-files
291 # Those files are fallbacks to support older libwekit.so and libjpeg.so
292 rm $out/opt/citrix-icaclient/lib/ctxjpeg_fb_8.so || true
293 rm $out/opt/citrix-icaclient/lib/UIDialogLibWebKit.so || true
294
295 # We support only Gstreamer 1.0
296 rm $ICAInstDir/util/{gst_aud_{play,read},gst_*0.10,libgstflatstm0.10.so} || true
297 ln -sf $ICAInstDir/util/gst_play1.0 $ICAInstDir/util/gst_play
298 ln -sf $ICAInstDir/util/gst_read1.0 $ICAInstDir/util/gst_read
299
300 echo "We arbitrarily set the timezone to UTC. No known consequences at this point."
301 echo UTC > "$ICAInstDir/timezone"
302
303 echo "Copy .desktop files."
304 cp $out/opt/citrix-icaclient/desktop/* $out/share/applications/
305
306 # We introduce a dependency on the source file so that it need not be redownloaded everytime
307 echo $src >> "$out/share/workspace_dependencies.pin"
308
309 runHook postInstall
310 '';
311
312 # Make sure that `autoPatchelfHook` is executed before
313 # running `ctx_rehash`.
314 dontAutoPatchelf = true;
315 preFixup = ''
316 find $out/opt/citrix-icaclient/lib -name "libopencv_imgcodecs.so.*" | while read -r fname; do
317 # lib needs libtiff.so.5, but nixpkgs provides libtiff.so.6
318 patchelf --replace-needed libtiff.so.5 libtiff.so $fname
319 # lib needs libjpeg.so.8, but nixpkgs provides libjpeg.so.9
320 patchelf --replace-needed libjpeg.so.8 libjpeg.so $fname
321 done
322 '';
323 postFixup = ''
324 autoPatchelf -- "$out"
325 $out/opt/citrix-icaclient/util/ctx_rehash
326 '';
327
328 meta = with lib; {
329 license = licenses.unfree;
330 description = "Citrix Workspace";
331 sourceProvenance = with sourceTypes; [ binaryNativeCode ];
332 platforms = [ "x86_64-linux" ] ++ optional (versionOlder version "24") "i686-linux";
333 maintainers = with maintainers; [ flacks ];
334 inherit homepage;
335 };
336}