Since I am doing a lot of remote systems administration tasks due to the nature
of my IT consulting work and since I am also running Linux on all my computers
I was looking for a native way how to get a remote console to VMware VMs from
linux.

After some searching I found that VMware Player (which has native binaries for
Linux) can be used as a VNC client to get to VMs consoles. However, once I have
downloaded VMware Player’s bundle and was faced with its requirement to run the
installation script as root I became quite unhappy with an idea of running some
proprietary software on my machine as root, especially after looking into the
bundle and the way the installation script was written. Moreover, there was no
need for other parts of VMware Player – I just wanted to have a small tool to
be able to hook the remote consoles up under my lovely Linux environment.
Therefore, I decided to take a challenge and to tweak the installation so it
will be possible to install the whole thing as a non-privileged user. Another
sub-goal was to strip the installation further down and prepare a small package
with only components needed for remote console sessions.

If you are not concerned about security (and integrity) of your system, e.g.
you are fine with the re-installation of the whole system, then it will be
cheaper to just install the VMware Player under the root account. In this case
you don’t need to read any further since what I am describing below is for
those brave hearts who value their systems and who do not want to give a chance
to mess their systems up by running low-quality custom installation scripts as
root.

Well, if you are still reading, then I hope that my research on this topic and
the how-to I have spent considerable time to come up with is worth something
and will be of some help to you.

Our starting point is a Linux-based system (it does not matter what
distribution you are running, but I did everything on a customised ALT Linux‘s
RPM-based distribution) running on an x86 compatible hardware (mine was 32-bit,
but I see no issues with 64-bit ones).

The first step is to download VMware Player for your architecture, set proper
permissions on the downloaded file, and then extract the payload as follows
(you need to ensure that you have at least 40MB of free space on /tmp, BTW):

So far so good. We now have the whole bundle unacked into the specified
directory and we are interested in just two subdirectories: vmware-player and
vmware-player-app, the rest is not related to the functionality we are
looking for.

Now, let’s pick up all parts from which we will build our future “VMware remote
console” tool. To make it easier create a dedicated subdirectory, e.g.
vmrconsole, with the following structure:

$ mkdir -m700 ~/vmrconsole

$ mkdir -m700 ~/vmrconsole/{bin,etc,lib,share}

$ ls -l ~/vmrconsole

total 12

drwx------ 2 vmware vmware 4096 Nov 24 01:21 bin

drwx------ 2 vmware vmware 4096 Nov 24 01:21 etc

drwx------ 2 vmware vmware 4096 Nov 24 01:21 lib

drwx------ 2 vmware vmware 4096 Nov 24 01:21 share

From now on we are going to populate these directories with files from the
unpacked bundle.

The first file we are interested in is appLoader – this is the primary
executable by the way, we need to copy it to our bin directory and then try to
run it:

$ cp ~/vmplayer/vmware-player-app/lib/bin/appLoader ~/vmrconsole/bin/

$ chmod 0700 ~/vmrconsole/bin/appLoader

$ ln -s appLoader ~/vmrconsole/bin/vmplayer

$ ~/vmrconsole/bin/vmplayer

$ echo $?

255

$

Huh, this is not very informative, is it? The binary silently exits with error
code of 255. Well, you may get other errors at this stage if you don’t have all
the required shared libraries installed on you system – however I doubt it
since the requirements of this binary are pretty reasonable: glibc and zlib.

OK, let’s take a peek inside and figure out what is going on (originally I used
strace with logging to a file, but to keep this article reasonable short I am
highlighting important things only):

It looks that vmplayer wants to access a global config file and does not try to
look for an alternative, home directory based one. Well, this is understandable
since VMware folks did not expect it to be run as a non-privileged process, but
we need to deal with this somehow. What are our options here? The simpliest
option I could think of at the moment is to substitute the hardcoded absolute
path inside the binary with something relative:

$ strings ~/vmrconsole/bin/appLoader | fgrep /etc/vmware | uniq -c

1 /etc/vmware/config

1 /etc/vmware/icu

1 /etc/vmware/ssl/rui.crt

1 /etc/vmware/ssl/rui.key

1 /etc/vmware/ssl/dh512.pem

1 /etc/vmware/ssl/dh1024.pem

$ sed -i 's,/etc/vmware,..//////etc,g' ~/vmrconsole/bin/appLoader

The trick here is to substitute one string with another of the same length (we
are modifying a binary so we do not want to mess offsets up) and luckily enough
we can use whatever number of slashes we want – they all are considered as a
single separator nevertheless. OK, we could have used a hex editor and could
have terminated strings with a NULL byte, but the point is that the approach I
took is the quickest and is working well. Let’s run the modified binary through
strace again, but this time we need to be prepared for the changed behaviour:

I do not know much about VMware Players config file but according to the log
message it wants some variable called libdir and this variable should point
to the library directory, so let’s introduce such a variable and try to execute
the binary again:

I hope you have noticed that I have used a relative path for the library
directory in the config file and this means that we always should run the
binary with its directory being the current working directory. This is a bit
inconvenient, but we will solve this with a wrapper script later. Right now, we
need to get it working and we see that it tried to dynamically load some
library from the library directory. OK, let’s search for this library in the
unpacked bundle directory and copy the library file over to our tree:

The last command showed that libvmplayer.so depends on some libraries and
that their locations are currently unknown to the system. In order to solve
this there are two things we need to do:

We need to tell the system where it should search for the libraries;

We need to locate these libraries and put them into a directory where the
system will find them.

To accomplish the first thing we need to create a wrapper script around
vmplayer and use this script for fine-tuning later. Here is the very basic
script for this purpose (created as ~/vmrconsole/bin/loader.sh:

echo "ERROR: could not return to the original '$OLD_PWD' directory!" >&2

exit 1

fi

# we don't need the following variable anymore

unset OLD_PWD

# change the current directory to $VMW_BINDIR

if ! cd "$VMW_BINDIR" >/dev/null 2>&1 ; then

echo "ERROR: failed to change directory to '$VMW_BINDIR'!" >&2

exit 1

fi

# set the library search path so the dynamic linker will be able

# to locate locally installed libraries.

LD_LIBRARY_PATH="$VMW_LIBDIR${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"

export LD_LIBRARY_PATH

# execute the real binary and pass the supplied arguments to it

exec -a "$ORIG_NAME" ./appLoader "$@"

This wrapper script should not be called directly, instead we need to create a
symbolic link to this wrapper, e.g. for vmplayer the following should be
performed:

$ ln -sf loader.sh ~/vmrconsole/bin/vmplayer

Since our vmplayer is not a full scale VMware Player I suggest to create
another small wrapper script and name it vmrconsole:

$ cat ~/vmrconsole/bin/vmrconsole

#!/bin/bash

ABS_NAME=$(readlink -e $BASH_SOURCE) || exit 1

BINDIR="${ABS_NAME%/*}"

exec "$BINDIR/vmplayer" -h "$@"

$ chmod 0700 ~/vmrconsole/bin/vmrconsole

Now we need to populate our library directory with the needed libraries. It is
a bit tricky to describe since on different systems you will likely end up with
different sets of libraries inside our local directory. For example, on my
system I have quite a few of the libraries installed from the distribution
repositories and these versions of libraries are fresher and with many bug
fixes in comparison to the VMWare provided ones.

Anyway, the general approach to install missing libraries is the following –
we start with the libraries we determined as missing during our ldd
~/vmrconsole/lib/libvmplayer.so/libvmplayer.so | fgrep 'not found' step (we
need to locate and copy them over to our library directory):

Once this is done we need to follow the following loop until there is no output
from the command listed below (in fact, on my system this step was not needed
since I had all dependencies in place already, but it is harmless to execute
this command anyway):

Ufff, we did a lot of binary patching – luckily, VMware binaries and libraries
are not calculating their checksums. Now, we need to put all this stuff we have
seen in the strings output and during the execution of the program in place (in
accordance to our new relative paths):

At this stage we should be able to launch the vmplayer program via our wrapper
script (I am launching it on a remote machine through SSH, but here I am
describing how it should look on the local console):

$ ~/vmrconsole/bin/vmplayer

So far so good, but we need to resolve the issue with the OpenSSL library
dependency. To resolve the issue we need to create symbolic links from our
local library directory to the system-wide version of the OpenSSL library:

Well, this error message does not say much except that we are not getting our
console :). If we check the log file directory we would see there is a file
called player-XXXXX.log (where XXXXX is the PID of the VMware Player that
produced this log file). Inside the log file we may see some interesting parts
like the following (I have included only those messages which are related to our
task):

From the messages quoted above it is quite clear that the program is trying to
launch some helper binaries/daemons in the background and to delegate the
actual remote console task to them. You can strace/ltrace the whole thing,
review the resulting logs and you will find that it tries to execute two helper
binaries: vmware-authd and vmware-remotemks, the latter is the remote
console engine, while the former is some kind of an authentication daemon and I
do not think it is needed for our purposes. I am not going to describe in
details how I arrived at the following (it is all clear once you have studied
the strace/ltrace log files):

Ouch, we are presented by a bunch of hints (your mileage may vary since it
depends on the environment), but you surely will see the hint/error message
presented on the above screenshot.

This is not a showstopper if you are an English-only user - just click on the
OK button and you should be able to work with the console, however I think it
is just a right thing to do to fix this little bugger:

P.S. Oh, boy, it takes 2 hours to investigate and to come up with a solution,
then 8 hours to write an article to describe steps to reproduce! I hope that
somebody has found this article useful and I would appreciate any comments.