Create a Linux kiosk at your library
As a frequent client of my local library, I’m very invested in the health, sustainability, and privacy of library systems all over the world. When my friend and fellow Both.org author, Don Watkins, mentioned a project he was working on to deliver his library with computers so people could do research on them, he also mentioned that he needed the computers to erase all user data after the user has logged out of their session. I’m interested in “kiosk mode” for Linux computers, and I’ve used distributions like Porteus as a Kiosk at computer conferences, but recently I’ve just been using GNOME Display Manager (GDM) on any distribution that makes GDM available. Here’s how to use Linux and GDM to create a Guest mode for your Linux computer.
Start without a guest account
The first few steps of this process don’t actually require a guest user directory to exist, so do NOT create your guest user account yet. However, you do need to choose what your guest user account is going to be called. A reasonable account name for Don’s purposes is libraryguest. On my personal computer I call my guest account guestaccount, and I’ve used kioskguest on some installations. I avoid just the name “guest” because in modern computing the term “guest” gets used in a few other ways (such as a “guest operating system” in a virtual environment), and it’s just easier to find something unique in logs.
Choose a unique name for you guest account, but don’t create it yet. For this article, I’m using libraryguest.
Create the PostSession script
By default, GDM recognises several states: Init, PostLogin, PreSession, and PostSession. Each state has a directory located in /etc/gdm. When you place a shell script called Default in one of those directories, GDM runs the script when it reaches that state.
To trigger actions to clean up a user’s environment upon logout, create the file /etc/gdm/PostSession/Default. You can add whatever actions you want to run upon logout to the Default script. In the case of Don’s library, we wanted to clear everything from the guest’s home directory, including browser history, any LibreOffice files or GIMP files they may have created, and so on. It was important that we limited the very drastic action of removing all user data to just the guest user. We didn’t want the admin’s data to be erased upon logout, so whatever rule we added to /etc/gdm/PostSession/Default had to be limited to the guest user.
Here’s what we came up with:
#!/usr/bin/sh
echo "$USER logged out at `date`" >> /tmp/PostSession.log
if [ "X$USER" = "Xlibraryguest" ]; then
rm -rf "$HOME"
fi
exit 0
The first line is for logging purposes. The /tmp directory gets cleared out on most distributions automatically, so we weren’t worried about creating a file that’ll grow forever and eventually crash the computer. If your distribution of choice doesn’t clean out /tmp automatically, create a cron job to do that for you.
GDM knows what user triggered the logout process, so the if statement verifies that the user logging out is definitely the libraryguest user (that’s the literal name of the user we created for library patrons).
Note that the whitespace around the square brackets is important, so be precise when typing!
As long as it is libraryguest, then the script removes the entire user directory ($HOME). That can be extremely dangerous if you make a mistake, so do thorough testing on a dummy system before implementing a script like this! If you get a condition wrong, you could erase your entire home directory upon logout.
In this example, I’ve successfully limited the rm command to a logout action performed by user libraryguest. The entire /home/libraryguest directory is erased, and the computer returns to the GDM login screen. When a new user logs in, a fresh directory is created for the user.
You can put any number of commands in your script, of course. You don’t have to erase an entire directory. If all you really want to do is clear browser history and any stray data, then you can do that instead. If you need to copy specific configuration files into the environment, you can do that during the PreSession state.
Just be sure to test thoroughly before committing your creation to your users!
What happens when the guest doesn’t log out
At this point, the computer erases all of the user’s data when the user logs out, but a reboot or a shutdown is different to a logout. GDM doesn’t enter a PostSession state after a reboot signal has been received, even if the reboot occurs during an active GDM session.
The easiest and safest way to erase an entire home directory when there’s a cut to system power is to use a temporary RAM filesystem (tmpfs) to house the data in the first place. If the systems you’re configuring have 8 GB or more, and the system is exclusively used as a guest computer, you can probably afford to use RAM as the guest’s home directory. If your system doesn’t have a lot of RAM, then you can use the systemd work-around in the next section.
Assuming you have the RAM to spare, and that your systems are supported by a backup power supply, you can add a tmpfs entry in /etc/fstab. In this example, my tmpfs is mounted to /home/libraryguest and is just 2 GB:
tmpfs /home/libraryguest tmpfs rw,nosuid,nodev,size=2G 0 0
That’s plenty of space for some Internet browsing and even a few LibreOffice documents to be saved while a user works.
Mount the new volume:
$ sudo mount /home/libraryguest
Next, you must create the libraryguest user manually in a terminal.
The useradd command creates user profiles:
$ sudo useradd --home-dir /home/libraryguest libraryguest
useradd: warning: the home directory /home/libraryguest/ already exists.
useradd: Not copying any file from skel directory into it.
Because you’ve already created a location for the home directory, you do get a warning after creating the user. It’s only a warning, not a fatal error, and the guest account is automatically populated later.
Create a password for the new user:
$ sudo passwd libraryguest
That’s it! You’ve created a guest account that refreshes with every logout and every reboot. You can skip over the next section of this article.
Using systemd targets instead of a ramdisk
Assuming you can’t create a ramdisk for temporary user data, you can instead create a systemd service that runs a script when the reboot, poweroff, and multi-user targets are triggered:
[Unit]
Description=Kiosk cleanup
[Service]
Type=oneshot
ExecStart=/usr/local/bin/kiosk-cleanup.sh
[Install]
WantedBy=poweroff.target reboot.target multi-user.target
Save the file to /etc/systemd/system/kioskmode.service and then enable it:
$ sudo systemctl enable --now kioskmode
The script, like the GDM script, removes the libraryguest directory. Unlike GDM script, this one must also recreate an empty home directory and grant it user permissions:
#!/usr/bin/bash
rm -rf /home/libraryguest
mkdir /home/libraryguest
chown -R libraryguest:libraryguest /home/libraryguest
Grant the script itself permission to run:
$ sudo chmod +x /usr/local/bin/kiosk-cleanup.sh
Now the libraryguest user data is erased after:
- Logout
- Reboot
- Shutdown
- Startup
Essentially, no matter how the computer loses its session or its power, the libraryguest account starts fresh when a new session is started.
Security and privacy
Using systemd to erase data at shutdown and startup isn’t strictly as secure as using a temporary ramdisk for all user data. Should the computer lose power suddenly, all saved user data in the libraryguest account is present during the next boot. Of course, it’s erased as soon as multi-user.target is called by systemd, but it is technically possible to interrupt the boot process and mine for data. You must use full drive encryption to protect data from being discovered by an interrupted boot sequence.
Why not just use xguest
On many Linux distributions, the xguest package is designed to provide the Guest account, which resets after each logout. It was an extremely useful package that I installed on every machine I owned, because it’s handy to be able to let friends use my computer without risking them making a mess of my home directory. Lately, it seems that xguest is failing to launch a desktop, however, presumably because it relies on X11.
If xguest works for you in your tests, then you may want to use it instead of the solution I’ve presented here. My solution offers a lot of flexibility, thanks to GDM’s autodetection of session states.
Kiosks in libraries
Privacy and personal information is more important than ever. Regardless of how you setup a kiosk for your library, you have an obligation to your users to keep them informed of how their data is being stored. This goes both ways. Users need to know that their data is destined to be erased as soon as they log out, and also they deserve to be assured that their data is not retained.
However, it’s also your responsibility to admit that glitches and exceptions could occur. Users need to understand that the computer they’re using are public computers on a public network. Encryption is being used for traffic and for data storage, but you cannot guarantee absolute privacy.
As long as everyone understands the arrangement, everyone can compute with confidence. Linux, GDM, and systemd are great tools to help libraries create a sustainable, robust, honest, and communal computing platform.