Is XDG_DATA_HOME modified by Snap's adapters?

Context: I’m trying to figure out what’s necessary for the Snap distribution of Barrier to work with Systemd (275 on my Ubuntu 18.04.3 machine, but that can be changed if necessary). One of the problems I’ve run into is that the Systemd service config sets up some environment variables to point to persistent data. Here’s an excerpt of the [Service] section (I’ve hard coded the snap paths in for now, don’t worry about that):

Environment=XDG_DATA_HOME=/var/lib/barrier/barrier@%i                                                                
# TrustedServers.txt Directory                                                                                       
Environment=FP_DIR=/var/lib/barrier/barrier@%i/barrier/SSL/Fingerprints                                              
# Ensure the Fingerprints directory exists                                                                           
ExecStartPre=/bin/mkdir -p "${FP_DIR}"                                                                               
                                                                                                                     
# This uses openssl commands and grep to get the server's key and                                                    
# store it in the TrustedServers.txt file. OpenSSL is a requirement                                                  
# for barrier on Linux so these commands should exist. This will only                                                
# work if using the default 24800 port (since the port number must be                                                
# specified for openssl)                                                                                             
ExecStartPre=/bin/sh -c "[ -f "${FP_DIR}/TrustedServers.txt" ] ||\                                                   
openssl s_client -connect %i:24800 2>/dev/null |\                                                                    
openssl x509 -noout -sha1 -fingerprint |\                                                                            
grep -oE '([A-Z0-9]{2}:?){20}' > ${FP_DIR}/TrustedServers.txt"                                                       
                                                                                                                     
# Main executable                                                                                                    
ExecStart=/snap/bin/barrier.barrierc --enable-crypto --display ${DISPLAY} --debug ${LOG_LEVEL} --no-daemon %i

What this does is set up a persistent log of acceptable fingerprints under /var/lib/barrier/barrier@<hostname>/... and then set XDG_DATA_HOME to point to that directory.

In theory, Barrier will then look up XGD_DATA_HOME, construct the full path to the fingerprint file, and find it there.

What I’m actually seeing in the logs is:

May 29 13:33:59 fox barrier.barrierc[2595]: [2020-05-29T13:33:59] NOTE: trustedServersFilename: /root/snap/barrier/83/.local/share/barrier/SSL/Fingerprints/TrustedServers.txt                                                                  
May 29 13:33:59 fox barrier.barrierc[2595]: [2020-05-29T13:33:59] NOTE: Unable to open trustedServersFile: /root/snap/barrier/83/.local/share/barrier/SSL/Fingerprints/TrustedServers.txt

Barrier is looking for /root/snap/barrier/83/.local/share/barrier/SSL/Fingerprints/TrustedServers.txt. The directory doesn’t exist, so it fails. I haven’t tried, but I suspect that even if I created it, Apparmor would deny access.

It looks for all the world like XDG_DATA_HOME is being overriden to be ${HOME}/snap/barrier/83/.local/share. I kind of see this hinted at in some forum posts, but I can’t find any mention of it in the “Environment variables” section of the docs. (Sorry, I had some direct links to the posts, but I’m not allowed to post them :upside_down_face: )

Snap info from snap --version:

snap    2.44.3
snapd   2.44.3
series  16
ubuntu  18.04
kernel  4.15.0-101-generic

Is XDG_DATA_HOME getting overridden by Snap here? And can I stop it?

I’m not sure it’s clear what you are trying to do. Are you trying to run barrier as a system service?

Yes. The aim is for Barrier to be useful on headless machines, which means it needs to be running when the login screen for the display manager is up.

barrier is packaged as a desktop snap, as such it sets up environment variables from a desktop-launcher script … this script in turn has some expectations that a running desktop exposes some variables you do not have when trying to start it as a service …

if you do not want to re-pack the snap as a service you could try to manually create an autostart file for the desktop and auto-log in a user where you add this autostart file to the desktop session …

I guess it will not work either without more tweaking. For instance, gdm runs as a separte user gdm, so barrier client running for would still be unable to write in locations accessible only to root.

Regarding the desktop packaging, the snap package also contains the command line clients barrier.barrierc and barrier.barriers. These can be run as non-desktop commands. Auto login is not an option for many users, which is why I’m trying to get it running at the login screen. It actually works when not using the snap package, I’m really just trying to figure out if snap is resetting certain environment variables, and if so, which ones.

all executable binaries in this snap use the desktop launcher:

particulary:

while you could dig through the different bits and pieces in the source, the assembled launcher usually lives in /snap/<snapname>/current/bin … its a shell script and you should be able to quickly see what variables it sets …

my recommendation would be to ask the devs for an additional barriers.cli command that simply omits the launcher though …

Thanks for this, it’s very useful! I will dig into these.

I had thought that the barrier.barriers and barrier.barrierc binaries were the non-launcher versions but I could be wrong.

So, I think I’m getting closer to what’s going on. Firstly, the not-wrapped-in-a-script binaries exist in the snap already eg.:

$ file /snap/barrier/current/usr/bin/barrierc 
/snap/barrier/current/usr/bin/barrierc: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=bcc94c53fec6505125b1a681b69ba95b2d88f3c6, not stripped

But the commands I was using weren’t that, they were these ones:

file /snap/bin/barrier.barrierc
/snap/bin/barrier.barrierc: symbolic link to /usr/bin/snap

They’re not scripts, they’re symbolic links to snap itself. I assume snap figures out how to deal with them by looking at the name of the program it was invoked as (equivalent to $0 in a Bash script)? What does it do from there, is that documented somewhere? (I tried to Google this but I could only think of very generic, unhelpful terms.)

Anyway, going back to what you flagged: the desktop-launch script does indeed contain:

  export XDG_CONFIG_HOME=$SNAP_USER_DATA/.config

So I’ll work on invoking the real binaries in the snap package to see if that gets me somewhere.

Thanks for the info!

Doing that will run the executables unconfined, and potentially linking with incorrect libraries from your host. Running executables from a snap without using the /usr/bin/snap wrapper is not the right way. You need to get the snap to not use the desktop-launch script when you want to run it as a service. That will require changing the snap, preferably by rebuilding it from the snapcraft.yaml with snapcraft.

@lucyllewy Okay thanks for the advice. I’ll relay that on the pull request. At least it helped us get proof of concept going, and we can continue with doing it the snap-appropriate way for daemon services.