29

I have a service that I want to start with system startup. I have built a ap@.service definition for it as a template, because there could be many instances.

Defined in the root systemd, this works well, and starts and stops the service with the system. The service instance is installed with systemctl enable ap@inst1 as would be expected. Root is also able to start and stop the service without problems. The service runs in its own account (myuser), not root, controlled by User=myuser in the ap@.service template.

But I want user 'myuser' to be able to start and stop their own service, without compromising system security.

I switched to using a user systemd, and enabled lingering with loginctl enable-linger myuser. I then enable the service defined in the ~myuser/.config/systemd/user directory. The service now starts and stops cleanly with the system, as designed. If I log in to a terminal as 'myuser', systemctl --user start ap@inst1, and systemctl --user stop ap@inst1 both work perfectly.

However, if I log in as a different user (user2) and perform sudo su - myuser in a terminal, then systemctl --user commands now fail with error message "Failed to get D-Bus connection: no such file or directory".

How do I enable systemctl --user to work after a sudo su - myuser command to switch the user?

NeilCasey
  • 621
  • 6
  • 8
  • Is your CWD still the home directory of the other user? Some utilities have problems if the invoking user doesn't have permission to see the current directory. – Dave Dec 08 '15 at 22:49
  • Hi Dave... the home directory has switched, forced by the - in the sudo command. The CWD has changed to the home directory of the new user. – NeilCasey Dec 08 '15 at 22:53
  • Ah OK. Ignore me then. – Dave Dec 08 '15 at 23:15

2 Answers2

33

I found the answer on another site with further searches using different terms.

The solutions needed was to provide the shell with information to reach the correct DBUS for the user.

By adding the following environment variables to the shell before running systemctl --user, the DBUS problem is eliminated, and systemctl operates correctly.

export XDG_RUNTIME_DIR="/run/user/$UID"
export DBUS_SESSION_BUS_ADDRESS="unix:path=${XDG_RUNTIME_DIR}/bus"

To ensure that the DBUS_SESSION_BUS_ADDRESS is available in the sudo shell, I added the environment variables to ~/.bash_profile of the target userid. This requires that a login shell ( sudo su - myuser or sudo -l myuser) is created in order to create the correct environment.

Alternatively, add the creation of the environment variables to ~/.bashrc (or equivalent for other shells). The environment will then be established anew for all shell creations.

NeilCasey
  • 621
  • 6
  • 8
  • That might work, but there must be a better way to achieve it. Possibly in the su and PAM configuration files. – Bachsau Jul 17 '20 at 12:36
  • 1
    This only worked for me if I enabled lingering beforehand (as the OP stated). With lingering disabled the `/run/user/$UID` directory doesn't exist and `systemctl --user` commands will fail regardless. Also for me it sufficed setting the `XDG_RUNTIME_DIR` env variable. – morrow Nov 10 '21 at 19:03
3

systemd 248 (released March 2021) introduced support for the syntax -M myuser@ for specifying another user.

$ sudo systemctl --user -M myuser@ start ap@inst1

A side-note: If you want to get an interactive login shell for the user myuser

$ sudo machinectl shell myuser@
Erik Sjölund
  • 10,690
  • 7
  • 46
  • 74