Integrating Citrix ICA Client into LTSP
Paul Whittaker (Paul.Whittaker@iname.com)
Director, Cloud Network Technologies Pty Ltd, Australia
Last Update: 11 February 2002
Index
This HowTo and the files provided with it will enable you to modify LTSP 3.0
to allow thin clients to connect to a Windows NT4 or Windows 2000 terminal
server using the ICA protocol. It has been tested with ICA Client for Linux
6.20.973 against servers running Windows NT4 Terminal Server Edition (SP6) with
Metaframe 1.8 (SP2, FR1) and Windows 2000 Server (hotfixes but no SPs) with
Metaframe XP 1.0 (SP1, FR1).
Out of the box, Windows NT4 Terminal Server Edition and Windows 2000 Server
provide an RDP (Remote Desktop Protocol) service; client workstations must
connect to the terminal server using this protocol. RDP is somewhat like X11
combined with XDMCP, but features built-in encryption and compression and has
some inherent limitations such as a maximum of 256 colors. Windows NT4TSE
implements RDP version 4, and Windows 2000 Server implements RDP version 5.
RDP 5 has some minor improvements such as rudimentary load balancing.
Citrix have developed a product known as MetaFrame (formerly known as WinFrame)
which integrates smoothly with Windows NT4TSE/2000 Server and implements an
alternative protocol called ICA (Independent Computing Architecture), which is
essentially a value-added vendor derivative of RDP. ICA is a much more complex
protocol than RDP; its principal aim is to increase the granularity of remote
access such that individual applications can be "exported" from a terminal
server and "imported" seamlessly into the desktop of a remote client, in
addition to the traditional "desktop-in-a-window" approach. It also provides
many additional features such as client resource sharing, 16 and 24-bit
color depth, rudimentary sound support and automatic load balancing, although
some of these features cannot be used until additional licenses are purchased.
(Side note: A now-defunct Citrix Metaframe companion product called UNIX
Integration Services can be used as an X11-ICA and NAS-ICA bridge. Using this
product, you can query your Metaframe server using the X11/XDMCP protocol
and get full sound support via the LTSP sound server with absolutely no
modification to standard LTSP whatsoever!)
Citrix have adopted the cruel-but-effective marketing strategy of charging
like a wounded bull for the Citrix Metaframe server product but making the
client product freely available for multiple platforms in order to promote
widespread use of the ICA protocol. Hence we can make use of the freely
available ICA client for Linux on diskless LTSP clients. However, the
licensing agreement for the Citrix ICA Client expressly forbids redistribution
of the client, so I cannot provide a "shrink-wrapped" LTSP bolt-on - you must
fetch the ICA client yourself (for use at your own site only), and integrate it
using these intructions. If you want to bundle ICA Client as part of any kind
of distribution you must pay Citrix $$$ for the privilege.
I have antipicated the need for two modes of operation for the ICA Client:
- ICA at Boot-Up
In this mode of operation the thin client workstation boots directly into a
full-screen Windows desktop or full-screen standalone Windows application. The
X11 protocol is only used locally on the workstation and is all but invisible
to the end-user; all graphical data exchanges with the server are made using
the ICA protocol. The thin client looks and feels like a Windows box.
A possible variation of this is a "dual mode" whereby the LTSP workstation
starts up a second X11 display, or second X11 server instance on another virtual
terminal, and runs ICA full-screen in this. You then have X11 and ICA displays
side-by-side or switchable using VT hot keys. This is not covered in this
HowTo.
- ICA on Demand
In this mode of operation the end-user invokes specific ICA services via
rsh, which are displayed on the desktop (whether X11, RDP or ICA) in
subwindows, just like Local Apps under X11. ICA Client can do this is two
different ways; the "Windows-in-a-Box" approach, using a fixed-size window
with independent internal subwindow management, or using a "seamless" window
(in practice not quite seamless on an X11 desktop, due to irreconcilable
differences between X11 and Windows window management) whereby the window
appears to be under the control of the local window manager (ie. can be
resized, iconified etc).
My solution caters to either or both access methods. It consists of a shell
wrapper for the main ICA Client binary (wfica) which dynamically
generates throwaway ICA config files based on command-line arguments,
lts.conf defaults and internal defaults (in order of decreasing
priority), and launches wfica against them. The wrapper can be
invoked from xinit for ICA at Boot-Up mode, or via rsh (either
directly or as a user's shell) for ICA on Demand mode.
Citrix ICA Client is highly configurable, and I cannot hope to cater to every
possible permutation of its use in this HowTo. I have made a best effort to
cater to most common client- and server-specific configurables. For some
options I use deductive logic or autodetection rather than user-defined
settings in order to reduce option complexity.
I have not attempted to cache or preset anything to do with authentication
(ie. username, password, and domain) because it's too difficult to do this in a
sufficiently flexible and secure manner. I want to allow for anonymous access
to a stateless thin client as well as the Local Apps scenario. In any case,
ICA Client has a connection re-use feature that will prevent the need for an
explicit logon under some circumstances.
The wrapper explicitly sets only a bare minimum of client options. Where
possible, rather than modify the wrapper to set more options, you should edit
the global config files in /opt/ltsp/i386/usr/lib/ICAClient/config to
meet any site-specific needs. Unfortunately due to some strange quirks in
wfica's config file parsing, certain options (eg. keyboard settings)
must be set in the wfclient.ini file created by the wrapper.
LSTP lacks the client-side facilities needed to make effective use of ICA
Client's drive and printer mapping capabilities, so I have disabled them and do
not recommend their use. The desired effect can be achieved through use of the
Removable Media contrib for LTSP 3.0 and lp_server respectively, using
standard FTP and JetDirect/AppSocket protocols that are supported by native
Windows drivers. This is perhaps not as elegant as the ICA Client methods,
but it's a lot more thin-client friendly.
If serial ports are detected (ie. if the serial.o kernel module is
preloaded), my script will automatically map up to two of them onto COM1: and
COM2: on the server using the ICA com port mapping feature. If you want to
use serial expansion cards, you're on your own.
To enable audio in ICA you must preload the relevant sound modules using
MODULE_nn options, and then either set ICA_AUDIO to
Y or invoke the wrapper using the +a switch. Note that ICA
audio does not require the LTSP Sound package and does not require that
you set SOUND to Y in lts.conf. The LTSP Sound
package provides a network audio protocol abstraction (NAS) that duplicates a
built-in capability of the ICA protocol in an incompatible fashion. It's safer
not to install it, to avoid possible audio device contention.
Unfortunately ICA Client doesn't implement a software mixer (or synthesizer)
under Windows, even if your hardware is capable of it, so you'll have to resort
to hardware volume controls. If your default software mixer setting is too
quiet, you may need to install aumix on your LTSP workstation so that
you can increase the volume at boot-time.
ICA audio has three bandwidth-greediness settings, with worsening sound quality
at lower bandwidth usage. My wrapper uses the maximum and minimum settings
only, based upon a user-defined high or low available bandwidth setting.
Note, however, that a client request for high audio bandwidth doesn't guarantee
that it will get it. There is also a server-side setting (medium by default),
and the lower of the two values is used. If you are getting poor sound quality
even on a high-bandwidth network, check your server setting.
Don't expect miracles from ICA audio. The best you can hope for is laggy WAV
file playback without too much white noise. No network audio protocol can
ever hope to match local audio playback for quality, and the ICA implentation
isn't very good as network audio protocols go. Unless you really need it, it's
better to leave it off to reduce server load and bandwidth consumption.
- In accordance with the /etc/lts.conf RCFILE_nn
setting, /etc/rc.local invokes /etc/rc.d/rc.ica.
rc.ica rewrites the /tmp/start_ws file created by
rc.local such that it launches the X server via
/usr/X11R6/bin/xinit rather than directly, and omits the XDMCP query
argument. rc.ica then creates a /tmp/xinitrc script that
repeatedly launches the ICA Client wrapper /usr/bin/ica against the
ICA_SERVICE specified in lts.conf, in a never-ending loop.
- rc.local exits and init enters runlevel 5, executing
/tmp/start_ws.
- xinit starts and spawns the X server as specified by its command
line parameters, and then executes /.xinitrc, which is a symbolic link
to /tmp/xinitrc.
- .xinitrc runs the wrapper script ica with the -F
(fullscreen) and -quiet options and an ICA service name. ica
constructs files in /tmp according to command line arguments,
lts.conf defaults and internal defaults, and then launches
/usr/lib/ICAClient/wfica against these files using command-line
arguments.
- wfica runs fullscreen and initiates an ICA connection to the
specified service.
- When the ICA session terminates, .xinitrc restarts it as per
step 3 above. This is somewhat tidier and more efficient than exiting and
allowing init to respawn xinit and thereby restart the X
server.
- The user, or a program initiated by the user, runs an rsh command
on the server to invoke the ICA Client wrapper with the required options. For
example, using Local Apps from a Linux server, you might use something like
"rsh -n ws1 ica Word +a &" to invoke a published application called
Word, with audio enabled, from your workstation ws1. Without
Local Apps from a Windows server, you might use "rsh ws1 -l ica -n Word
+a" to achieve the same result by means of a dummy account ica
whose shell is the ICA wrapper.
- xinetd on the LTSP workstation spawns /usr/sbin/in.rshd
to handle the request.
- in.rshd uses PAM libraries to check whether the command is allowed,
according to rules in /etc/pam.d/rsh (which in turn consult
/etc/hosts.equiv and ~/.rhosts as required). If allowed,
in.rshd invokes the command with the arguments provided as the calling
user or the user specified with -l. The actual command issued is
"user-shell -c program 'arguments'", so using the
above examples you would have something like "/bin/bash -c ica
'Word +a'" and "/usr/bin/ica -c Word '+a'" respectively.
- ica constructs files in /tmp according to arguments
(ignoring a leading "-c" if present), lts.conf defaults and
internal defaults, and then launches /usr/lib/ICAClient/wfica against
these files using command-line arguments. The display used is implictly
":0" unless overridden via the command line; if not using Local Apps the
display must allow access from any user on the workstation (either by
DISABLE_ACCESS_CONTROL=Y in lts.conf or by creation of an
/etc/X0.hosts file, which is a bit more secure).
Requirements: ltsp_core, ltsp_kernel, and ltsp_x_core LTSP 3.0.x packages.
If using ICA on Demand mode and not using ICA at Boot-Up mode you will need
ltsp_x_fonts also. For ICA on Demand mode you will normally need
ltsp_local_apps installed and enabled, but it is possible to set up anonymous
access without enabling Local Apps (see below).
- Install ica and checkhostname in /opt/ltsp/i386/usr/bin.
checkhostname is a trivial C helper program for the ica wrapper
script; source code is available here. Both
files require rwxr-xr-x (0755) permissions.
- Download the latest version of the Citrix ICA Client for Linux from
http://www.citrix.com/download.
Get the compressed tar version, not the RPM version. Extract the file in a
temporary directory and run setupwfc. Follow the prompts to install
the ICA Client to /opt/ltsp/i386/usr/lib/ICAClient instead of the
default installation directory.
- Add appropriate entries to /opt/ltsp/i386/etc/lts.conf - see the
lts.conf Options section. If using ICA at
Boot-Up mode you will need to specify an ICA_SERVICE option and set
one of the RCFILE_nn slots to "rc.ica". If you
want to enable audio or use serial ports, you must load the necessary kernel
modules via MODULE_nn options also.
- Review and edit the files in
/opt/ltsp/i386/usr/lib/ICAClient/config to meet any requirements of
your system that are not catered to by my wrapper script. The best way to
do this is to set options via the GUI by running
"/opt/ltsp/i386/usr/lib/ICAClient/wfcmgr -icaroot
/opt/ltsp/i386/usr/lib/ICAClient", and then copy relevant entries from
the files it creates in the .ICAClient subdirectory of your home
directory into the corresponding files in
/opt/ltsp/i386/usr/lib/ICAClient/config.
- If you are unable or choose not to use the X11 font server, it is not
necessary to install the full ltsp_x_fonts set. The ICA protocol does not
require client-side fonts as X11 does, so we need only supply the mandatory
fonts required by the X server and those needed by the wfica binary
itself. I have prepared a minimal font set for
this purpose - extract it into /opt/ltsp/i386.
- Install rc.ica in
/opt/ltsp/i386/etc/rc.d and copy /usr/X11R6/bin/xinit from
your Linux server to /opt/ltsp/i386/usr/X11R6/bin/xinit. Set
rwxr-xr-x (0755) permissions on the files.
- Create a symbolic link /opt/ltsp/i386/.xinitrc pointing to
/tmp/xinitrc using the command "ln -s /tmp/xinitrc
/opt/ltsp/i386/.xinitrc".
- Append the following lines to /opt/ltsp/i386/etc/devfsd.conf:
# Loosen permissions on audio device for ICA Client
REGISTER sound/dsp PERMISSIONS -1.-1 622
This is needed because the default permissions do not allow unprivileged users
to write to /dev/dsp, which is what wfica tries to do.
- Edit /opt/ltsp/i386/etc/rc.local and add the line "chmod 1777
/tmp" after the line "/bin/mount -n /dev/ram1 /tmp". This will
allow unprivileged users to create files in /tmp.
- Install but do not activate (ie. do not set LOCAL_APPS to
Y in lts.conf) the ltsp_local_apps package. We actually only
need the parts of this package related to xinetd, in.rshd and PAM, but it's
simpler just to install the whole package.
- Edit /opt/ltsp/i386/etc/pam.d/rsh and substitute
pam_securetty.so for pam_rhosts_auth.so. This will
disable traditional rsh security measures and allow any remote user to do any
rsh operation as any local user other than root. Normally this would be a
severe security hazard, but it's actually quite safe provided that no local
user has an interactive shell.
- Set disable=yes in all files in
/opt/ltsp/i386/etc/xinetd.d except the one named rsh. This
will turn off unneeded inet services - we only need rsh.
- Edit /opt/ltsp/i386/etc/passwd. Change bin's shell to
/bin/false by appending /bin/false to the bin entry,
remove the line starting with "+" (it's harmless as long as NIS is
not in use, but we'll remove it anyway just to be on the safe side), and add
an entry for a dummy user with /usr/bin/ica as its shell, eg.:
ica:x:99:99:ICA Client:/tmp:/usr/bin/ica
If you want to make use of the xcapture utility (provided with ICA
Client to assist with graphics cut-and-paste operations between X11 and ICA),
you could add a second dummy user which has as its shell a trivial wrapper
script as follows:
DISPLAY=:0
export DISPLAY
exec /usr/lib/ICAClient/util/xcapture
- Create a symbolic link /opt/ltsp/i386/etc/X0.hosts to
/proc/sys/kernel/hostname using the command "ln -s
/proc/sys/kernel/hostname /opt/ltsp/i386/etc/X0.hosts". This will allow
any process running on the LTSP workstation to access the local X display.
Alternatively, you could set DISABLE_ACCESS_CONTROL to Y in
lts.conf, but this is excessively permissive and insecure.
- Create a symbolic link /opt/ltsp/i386/etc/rc.d/xinetd to
/usr/sbin/xinetd using the command "ln -s /usr/sbin/xinetd
/opt/ltsp/i386/etc/rc.d/xinetd", and then set the first available
RCFILE_nn option in /opt/ltsp/i386/etc/lts.conf to
"xinetd".
The ICA wrapper script makes use of several new lts.conf options:
- ICA_AUDIO
- One of: Y or N (default N). Y enables
ICA audio (if an audio device is available), N disables.
- ICA_BANDWIDTH
- One of: high or low (default high). high
tells the wrapper to optimize for LAN bandwidths, and low for
WAN/modem bandwidths, through use or disuse of compression and an audio
bandwidth cap (if applicable).
- ICA_BROWSER_ADDR
- An IP address or hostname, optionally appending :port where
port is the port number for the HTTP/HTTPS service, at which the ICA
browser service can be found. The default is the local broadcast address if
the protocol is UDP, ica:80 if HTTP and ica:443 if HTTPS.
- ICA_BROWSER_PROTO
- One of: udp, http or https (default
http). This is the protocol that ICA Client will use to discover
addresses for published applications.
- ICA_COLOR
- One of: max or min (default max). max
makes the wrapper try to match the color depth of the X11 display in the ICA
window. min tells the wrapper to set a pessimistic safe value, to
avoid colormap conflicts in an 8-bit display or unlicensed feature warnings at
greater depths (specifically 16 or 256 colors respectively). The wrapper
always tells wfica to use private colormaps where necessary for 8-bit
displays, because the "approximate colors" setting doesn't work in an unmanaged
display (ie. ICA at Boot-up mode).
- ICA_ENCRYPTION
- One of: basic, 40, 56, 128 and
128login (default: basic).
- ICA_WINSIZE
- A string of the form NxN specifying the X and Y dimensions,
in pixels, of the ICA window (default 800x600). This value is only meaningful
for ICA on Demand connections to hosts - not published applications - and
when not using fullscreen mode. The wrapper will use "seamless" mode for
published applications in preference to a fixed geometry.
The wrapper will also use the RAMDISK_SIZE to determine the maximum
amount of space the ICA Client bitmap cache should be allowed to use (one
quarter of RAMDISK_SIZE). The cache is shared by all users of the
LTSP thin client and persists for the run-time of the client, so it is probably
in your interest to increase this value if you can spare the RAM.
There is one additional option that is not used by the wrapper itself, but
rather by the rc.d script that invokes it (via xinit) at boot-time,
when using the ICA at Boot-up mode of operation:
- ICA_SERVICE
- A hostname, IP address or published application name (default is the value
of SERVER or 192.168.0.254 if unset). If you have two or more ICA
servers and you wish to load balance, you should publish the desktop (ie.
explorer.exe) and specify it by name here rather than use hostnames.
The wrapper requires a mandatory service name, which may be either a hostname,
IP address or published application name. The wrapper will invoke a custom C
binary to distinguish between the two by using a gethostbyname(2) system
call to attempt to resolve the identifier into an IP address - if it can't, it
will assume it is an application. It is therefore vital that no application
has the same name as a known host or host alias. It is also important for
parsing reasons that applications do not contain shell metacharacters or words
beginning with minus (-) or plus (+). Applications may contain spaces, and
need not be double- or single-quoted.
Counter-conventionally, the mandatory service argument must appear
before any option switches. This is deliberate, to avoid parsing
problems that might otherwise occur with some implementations of rsh
(eg. Windows rsh) if you use the wrapper as the shell of a dummy user. The
sense of the audio options is also somewhat counter-conventional, for
consistency with bandwidth and color options; think of "-" as "down" and "+"
as "up".
All wrapper options have a long (human-readable) form and a short form; you may
use either. After the wrapper options you may append one or more options for
the wfica binary itself. One such useful option is the -param
switch, supported by ICA Client 6.20 and above. If you have the necessary
server-side feature release and license installed, this allows you to pass
parameters (such as a filename) through to a published application. This means
that you can potentially set up an rsh command as a file-type
association, and have your LTSP thin client automagically fire up a Windows
application and load the document as a browser or mailer detach action - how
cool is that!
Wrapper syntax is briefly as follows:
Usage: ica service [options] [wfica arguments...]
Options:
--browseraddr,-A hostname[:port] ICA browser address
--noaudio,-a Disable audio
--audio,+a Enable audio
--lowbandwidth,-b Optimize for low bandwidth
--highbandwidth,+b Optimize for high bandwidth
--mincolor,-c Limit color usage to avoid
colormap conflicts or
unsupported feature warnings
--maxcolor,+c Maximize available colors
--encryption,-e basic|40|56|128[login] Encryption level
--fullscreen,-F Display using the entire screen
--browserproto,-p http|https|udp ICA browser protocol
--winsize,-s widthxheight Window dimensions
--help,-? Display this message
Defaults are derived from the relevant lts.conf variables where
applicable, and internal defaults otherwise (see lts.conf section above). --fullscreen is not
the default, and if specified overrides any --winsize or
ICA_WINSIZE option.