Running my own desktop environment on someone else's system

Yet another tale of other, even more, ridiculous hacks.


I'm doing some work on something, and I'm using other people's workstations as a means to getting this work done. All of these workstations are running pretty stock Fedora 27 with Gnome. User files are on an NFS share and mounted on demand as users log in, so custom configuration and software is available across all machines. Authentication is performed against a centrally managed LDAP server. The sysadmins have got a really nice setup here.

Problem statement

I want to run Openbox (masquerading as evilwm) instead of Gnome. I'd also like LXTerminal as well, instead of gnome-terminal.

"Unsuspecting Unix user, meet rabbit hole."


Turns out it's really, really, really hard to make gdm launch a window manager other than the Gnome default (I believe it's called mutter, but I forget) without having root access. The default Xsession script that comes with Fedora explicitly checks for the display manager requesting a Gnome session before falling back to looking for files like ~/.xsession. I spent a good hour or so probing the interwebs and reading the X server startup scripts to try and figure out some place I could slot in some custom logic (including ~/.xprofile -- yes, that's a thing!), but nothing actually useful came out of it.

I can't remember how I found out about this exactly, but it turns out that Openbox (and several other window managers) has a --replace option which makes it forcefully override the current active window manager. So as a compromise, I wound up writing a script which does some setup (with setxkbmap and xsetroot etc) and then invokes openbox --replace and bound that script to a keybinding in Gnome -- I would have to log into Gnome and then press the magic buttons to launch Openbox (this is a saga of compromises, by the way, so don't hold your breath).

Breaking out the compiler

I downloaded the Openbox sources, and compiled it (surprisingly, without issues). Then I realised that Openbox comes with a few shared libaries, so to reduce breakage potentional and LD_LIBRARY_PATH hacking, I reconfigured it with the --disable-shared option. I copied the binary to the appropriate path, and then manually ran openbox --reconfigure. This failed to run, as Openbox couldn't find a config file, a menu file nor its default theme (leaving me with no window manager active!). So, building on recent work, I copied the configuration and menu files (rc.xml and menu.xml) from one of my own machines to the user configuration directory, and then did a make install of Openbox to a temporary directory and copied the default "Clearlooks" theme directory to ~/.themes. So Openbox now works.

LXTerminal was harder. Firstly, the LXTerminal build requires this suite of shell scripts called Intltool -- this was easy to install locally in my home directory. LXTerminal also requires this library called VTE, which the system I was on had the shared libraries but not the header files for. So I downloaded the source tarball for VTE and tried to compile it. This is where it starts getting messy. After a number of false starts (at least five), the series of steps I came up with comprised:

I then returned to building and installing LXTerminal, which was thereafter thankfully uneventful.

Rather pleased with my handiwork, I started using the desktop environment I had hacked in, only to realise I now had no screen locking facility, which is necessary in the shared environment in which I'm working.

Back to the compiler. I use slock on my personal machines; it's really nice and simple. It compiled and installed easily, however I then realised that the authentication on these systems goes through PAM (because LDAP, remember?), and slock simply looks at crypt()ed passwords. (Yes, I realised this after locking myself out.) So I did some ninja-googling and decided to take a shot on i3lock instead.

i3lock requires some XCB libraries, which these systems have shared libraries for, but no headers (again). So I got xcb-util and xcb-util-image installed in my home directory, and then when returning to the i3lock build realised that the host systems have no PAM headers installed either. At this point, I drew the line -- I haven't a clue what I'm doing with PAM, nor was I going to try wrestling with configuring and compiling it correctly.

At this point I downloaded the Fedora 27 RPM file for i3lock, extracted the binary, and tried running it. It ran (no loader errors!), but didn't let me back in. After remotely killing the i3lock process from another machine, I then went and did some more investigation. When i3lock starts chatting to the PAM system, it calls this library function pam_start(3), which takes a service name as a string argument. In i3lock this is set to "i3lock", however the systems have no service file in /etc/pam.d called "i3lock", so this falls flat on its face. Taking a look at the i3lock distribution, it includes an appropriate file, whose contents simply include /etc/pam.d/login.

So I copied the i3lock binary, opened it in a hex editor, and changed the appropriate "i3lock" string to "login" with an extra null byte for padding. This worked.

I wired LXTerminal, Firefox and i3lock into keybindings in my Openbox configuration, and then got on with actual work.