I’ve always been looking for a way in NX/FreeNX to be able to authenticate using mechanisms other than username and password, like SSH private/public keys or Kerberos. Turns out that it is possible :)

Someone pointed me to the FreeNX 0.7.3 announcement that contains the following excerpt:


Usermode and SUID Wrapper
==================

We are now very close to login directly with users and I also heard of a C program, which can be seamlessly put between nxclient and nxssh. So with client support we now have three alternatives:

1. Login as user via ssh and connect to server with ssh command on server again.
2. Login as user and use usermode to save all sessions locally for each user.
3. Use a SUID nx (not root!) wrapper to startup a new "trusted" session.

One is error prone, two is good, but looses the central structure, three is best of both worlds and with being suid nx also has the most advantages, however not the dreaded public key problems.

_Yes_, this means if you use the suid wrapper, you still need the nx user, but you can remove the public keys and it'll still work.

The SUID wrapper is a part from the work of the redesign and thanks goes to Alistair Riddoch from Google here.

By default, NoMachine’s NX nxserver requires nxclient to login via SSH into the remote machine as user nx. As nxserver is defined as the login shell, it is run by the sshd daemon. From there on, there is a dialogue between nxclient and nxserver where nxclient supplies the user credentials (username and password that were specified in the nxclient configuration). There is, in fact, a second authentication that is performed via another SSH session to 127.0.0.1 using nxclient’s supplied credentials. If this second authentication succeeds, the NX session is activated and accessible from the NX client.

This works well for remote servers that are shared by multiple users, as the nx user and its centralized approach makes it very easy to see how many sessions are currently running (or suspended), terminate them, etc. However, for machines that are not shared by multiple users, or in those cases where authentication mechanisms other than username and password are required, this model does not work very well.

This is where FreeNX’s usermode enters the scene. Basically, what it means, is that authentication to nxserver does no longer happen as the nx user but as the end-user himself. Now, the number of SSH sessions is reduced to one that authenticates the user directly by means of SSH’s built-in authentication capabilities, and where nxserver is run under the end-user credentials instead of the nx user. This, obviously, kills the centralized approach originally envisioned by NoMachine, since now all the control and session files can’t be stored easily and securely in a central location but are now stored in the user’s home directory. But I think the upsides of the usermode support outdo the lack of centralized management. At least in my case, I don’t need centralized management since it’s me who manages all my boxes and logs into them.

How to install and configure FreeNX to support usermode

Next I describe what I had to do, both on the remote machine and also on the client, to get a working FreeNX environment that supports usermode. Other modes are also supported, like legacy nx-based, SUID and others.

Download NX4U tarball from BerliOS and extract it

$ wget http://download.berlios.de/freenx/NX4U.tar.gz
$ sudo tar -C /opt -zxf NX4U.tar.gz

NOTE: The NX4U tarball that I used can also be downloaded from this Web site here.

NOTE: The NX4U set and the nxssh wrapper are smart enough so that you can also extract the NX4U tarball in other locations. Looking at the source code for the nxssh wrapper — nxssh-4US.c — nxssh wrapper uses the following PATH to locate the nxserver binary:

#define NXSERVER_PATH \
"~/bin:
~/NX4U/:
/usr/NX/bin:
/opt/NX/bin:
/opt/NX4U/bin:
/usr/NX4U/bin:
/usr/local/NX4U/bin:
/usr/lib/nx/bin"

Compile the nxssh wrapper

First, download the source code from the SVN repository:

$ svn checkout https://developername@svn.berlios.de/svnroot/repos/freenx/trunk

NOTE: I saved a copy of the SVN repository that I used. The tarball is available in this Web site here.
Build the nxssh wrapper for Mac OS X. nxssh is a simple C program that currently compiles for me with no problems on Linux and Mac OS X:

$ cd trunk/freenx-utils/nxpublickey/
$ make nxssh

NOTE: The Makefile also has a target named nxssh.exe to compile the wrapper for Windows.

Now, let’s rename NoMachine’s nxssh binary to mxssh (the nxssh wrapper expects NoMachine’s nxssh binary to be renamed to mxssh), then install the nxssh wrapper:

$ sudo bash
# mv /usr/NX/bin/nxssh /usr/NX/bin/mxssh
# install -m755 nxssh /usr/NX/bin/nxssh
# ^D

Configure .ssh/config

What looks like a bug in NoMachine’s nxssh, will cause authentication requests using public key to fail with a "percent_expand: NULL replacement" error unless .ssh/config is modified to explicitly state the location of the public key. For example:

Host my.host.org
        IdentityFile ~/.ssh/id_dsa

Configure nxclient

In order to use usermode authentication, make sure to prepend the hostname with the @ (at) sign:

Hostname: @my.host.org

Also, make sure the username has the @ (at) sign prepended plus @U (at U) appended. These non-standard forms are parsed by the nxssh wrapper and enable usermode authentication (or other authentications like SUID):

Username: @myself@U

For more information about possible syntaxes, take a look at freenx-utils/nxpublickey/nxssh-wrapper (the shell script implementation of the nxssh wrapper).

Stateless autoconfiguration of IPv6 addresses in Windows 7 (and also Windows Vista) uses, by default, randomization. This is against section 4 of RFC 2464 that mandates that the network identifier part of the IPv6 address is derived from the 48-bit MAC address for Ethernet (and Wireless) interfaces:

4. Stateless Autoconfiguration

The Interface Identifier [AARCH] for an Ethernet interface is based on the EUI-64 identifier [EUI64] derived from the interface’s built-in 48-bit IEEE 802 address. The EUI-64 is formed as follows. (Canonical bit order is assumed throughout.)

The OUI of the Ethernet address (the first three octets) becomes the company_id of the EUI-64 (the first three octets). The fourth and fifth octets of the EUI are set to the fixed value FFFE hexadecimal. The last three octets of the Ethernet address become the last three octets of the EUI-64.

The Interface Identifier is then formed from the EUI-64 by complementing the “Universal/Local” (U/L) bit, which is the next-to-lowest order bit of the first octet of the EUI-64. Complementing this bit will generally change a 0 value to a 1, since an interface’s built-in address is expected to be from a universally administered address space and hence have a globally unique value. A universally administered IEEE 802 address or an EUI-64 is signified by a 0 in the U/L bit position, while a globally unique IPv6 Interface Identifier is signified by a 1 in the corresponding position. For further discussion on this point, see [AARCH].

For example, the Interface Identifier for an Ethernet interface whose built-in address is, in hexadecimal,

34-56-78-9A-BC-DE

would be

36-56-78-FF-FE-9A-BC-DE.

A different MAC address set manually or by software should not be used to derive the Interface Identifier. If such a MAC address must be used, its global uniqueness property should be reflected in the value of the U/L bit.

An IPv6 address prefix used for stateless autoconfiguration [ACONF] of an Ethernet interface must have a length of 64 bits.

The fact that Windows 7 doesn’t seem to adhere to this by default might create interoperability problems in networks where section 4 of RFC 2464 is assumed to be true. Linux, *BSD and Solaris map adhere to RFC 2464 by default, and hence many administrators statically create DNS AAAA RRs for such hosts. However, randomization in Windows makes this unfeasible.

A workaround consists of running the following command, with administrator privileges:

netsh interface ipv6 set global randomizeidentifiers=disabled

I’ve sent feedback to Microsoft asking if this is deliberate and why this decision was made in the first place. (Not sure if they will ever reply, though).

Do any of you have any insight on this?

While testing Windows 7 on an Apple MacBook Pro system, I noticed that sound didn’t work at all. Of course, this was after I installed BootCamp drivers and everything was working (more or less as expected) except the sound.

What’s the solution? I found it here. In essence, the solution consists of running the RealTekSetup.exe binary from the Leopard DVD using “Troubleshoot Compatibility“, telling it that “The program worked in earlier versions of Windows” and that it worked fine in “Windows Vista“. After it has been installed no reboot it’s even needed!