Control Debian X Sessions with Xsession.options

Xsession.options is the file that decides whether your desktop trusts your own startup script, and most people never look at it until a login breaks. This guide switches user startup files, X resources, failsafe sessions, D-Bus activation and SSH-agent wrapping on or off, without touching the Xsession shell script itself.

It follows the Xsession.options(5) shipped by x11-common version 1:7.7+23ubuntu4 on this machine. The file format is shared across Debian-derived systems, but the available options and package version can differ on yours. Allow about ten minutes, plus one X session restart to test the result.

You need a shell and access to the machine's X session configuration. Reading and checking files is unprivileged. Changing /etc/X11 needs an account permitted to use sudo. A configuration change affects the next X session, so save your current state first and make the change when you have a way back in.

1. Check the package and current configuration

Start with read-only checks. They show which package supplied the behaviour and which options are currently enabled:

$ dpkg-query -W -f='${Package} ${Version}\n' x11-common
x11-common 1:7.7+23ubuntu4
$ sed -n '1,120p' /etc/X11/Xsession.options
# configuration options for /etc/X11/Xsession
allow-failsafe
allow-user-resources
allow-user-xsession
use-ssh-agent
use-session-dbus

Your version and file may not match this output. The shipped defaults enable all five documented options on this host. Do not assume a line present means the feature is actually in use: use-ssh-agent, for example, only wraps the startup command when no agent process already appears to be running.

Checkpoint: Keep a copy of the output, or record the file's checksum, before you edit anything.

$ sha256sum /etc/X11/Xsession.options
HASH  /etc/X11/Xsession.options

2. Understand the option format

Each non-comment line contains one hyphen-separated option. A plain name enables it; prefixing it with no- disables it. Blank lines and comments beginning with # are fine to use.

Options are read from /etc/X11/Xsession.options, then from files matching *.conf in /etc/X11/Xsession.options.d/, in sorted order. The last occurrence wins, enable or disable. That ordering is exactly what makes the drop-in directory useful: a local file can override a vendor setting without changing the main one.

For a quick, read-only view of the effective text, show both sources in the order that Xsession reads them:

$ { cat /etc/X11/Xsession.options 2>/dev/null; \
    run-parts --list --regex '\\.conf$' /etc/X11/Xsession.options.d 2>/dev/null | \
    xargs -r -d '\n' cat; } \
  | nl -ba

This shows lines, not a parsed summary. If two lines mention the same option, the later one is authoritative. Keep filenames simple, such as 90-local.conf; a file without the expected .conf suffix is ignored on this path entirely.

3. Add a narrowly scoped policy

Say this machine must never run a user's executable ~/.xsession as the session startup program. The relevant option is allow-user-xsession. Disabling it also blocks an explicitly requested session program from being accepted through the paths described by Xsession(5).

Warning: This changes how every user's graphical session starts. Test it on a machine where you have a second access path, and do not combine it with unrelated session changes.

Create a drop-in with elevated privileges:

$ printf '%s\n' '# Local session policy' 'no-allow-user-xsession' | \
    sudo tee /etc/X11/Xsession.options.d/90-local.conf
# Local session policy
no-allow-user-xsession

The tee command writes the new file as root without touching the vendor file. Check the result and the file mode:

$ sudo cat /etc/X11/Xsession.options.d/90-local.conf
# Local session policy
no-allow-user-xsession
$ sudo test -f /etc/X11/Xsession.options.d/90-local.conf && echo 'drop-in exists'
drop-in exists

Do not stack several experiments in one drop-in while diagnosing a failed login. One change per file makes the cause easy to spot.

4. Choose the other controls deliberately

The documented options have different effects:

For example, a host policy that keeps user resources but disables both user startup scripts and automatic agent wrapping would use:

# /etc/X11/Xsession.options.d/90-local.conf
no-allow-user-xsession
no-use-ssh-agent

Use the exact option names from the installed manual. An administrator may support additional local options, but an unfamiliar name is not proof that a feature actually exists.

5. Verify precedence before restarting X

Check for every occurrence of the option you changed:

$ { cat /etc/X11/Xsession.options 2>/dev/null; \
    run-parts --list --regex '\\.conf$' /etc/X11/Xsession.options.d 2>/dev/null | \
    xargs -r -d '\n' cat; } | grep -nE '(^|^no-)allow-user-xsession$'
3:allow-user-xsession
1:no-allow-user-xsession

The line numbers above are illustrative because the combined input depends on your own files. In the real output, the final matching line must read no-allow-user-xsession. If a later drop-in re-enables it, rename or edit that later file rather than guessing which one wins.

Start a new X session through your normal display manager or startx path. Do not invoke /etc/X11/Xsession directly as a substitute: the manual says it needs the environment set up by an X server startup mechanism. If the session fails, inspect the user's X session log, commonly $HOME/.xsession-errors, from another login.

6. Undo the change cleanly

Because the example added one isolated file, recovery is simple. This removes the local policy and leaves the vendor file untouched:

$ sudo rm /etc/X11/Xsession.options.d/90-local.conf
$ sudo test ! -e /etc/X11/Xsession.options.d/90-local.conf && echo 'drop-in removed'
drop-in removed

Removal is irreversible for that file. If it holds local work you might need later, move it to a clearly named backup instead of deleting it. After undoing the setting, start a fresh X session and confirm the original configuration is effective again: a running session does not retroactively re-read these options.

Done means