7

I need root to be able to manage systemctl --user units.

Right now I have user1 set up with systemd user units. If the user logs in directly via terminal, GUI, or SSH, they are able to to run all systemctl --user commands.

While the user is still logged in, I can run the following as root and perform all systemctl --user commands at that user with no problem:

su - user1 -c "systemctl --user status myunit.service"

However if the user logs off, then no one can run systemctl --user commands as that user, not even root. I will continue to get

Failed to connect to bus: No such file or directory

Even if I sudo - user1 as root, that is not good enough, will get the same error. The user literally needs to login to manage that user's units.

Apparently this is a known "issue" (quotes as the system is running as designed).

Note: I tried setting the XDG_RUNTIME_DIR environment varialbe in user1's bashrc, but that does not help.

Another user seems to have found a workaround, but it does not work. Looks like the developers did not approve of his idea.

The only work around I found is literally ssh into the user account to run commands like this after auth with public keys:

ssh user1@localhost -f 'systemctl --user status myunit.service'

I am looking for a workaround that does not require a SSH connection. I need root to be able to manage a systemd user unit while that user is not logged in. How can I accomplish this?

7
  • 2
    I don't know whether that helps you, but your problem seems... unusual. Are you sure you don't just want to run a service as a user? Running a user service as root rings all my security problem alarm bells, and sounds like an architectural backwards approach ;) Commented Oct 4, 2021 at 19:17
  • @MarcusMüller I am curious what security issues you see in root being able to run a user service. Can you elaborate more? Unrelated, its a requirement of the project. The project uses a scripted installer to deploy all packages for a user and systemctl --service. The script needs to run as root.
    – Dave
    Commented Oct 5, 2021 at 13:55
  • if it installs all things as a user, why would it need to run as root? Commented Oct 5, 2021 at 14:01
  • Good question, the installer does other actions that require root permissions, so the installer needs to run as root.
    – Dave
    Commented Oct 5, 2021 at 14:05
  • hm, so why not a root-installed systemd .service that specifies that the service is to be run as user1? Commented Oct 5, 2021 at 14:07

3 Answers 3

9

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

$ sudo systemctl --user -M user1@ status myunit.service

Reference: The new feature listed in the file NEWS

(There is no need to run loginctl enable-linger user1 for this solution to work)

1

Don't use su or sudo, but use machinectl instead which will give you a proper user-session and context.

You can either just drop in a shell, just as you're used to from su/sudo:

machinectl shell [email protected]

…and execute whatever you want to in the given user's context, or you can pass the cmd to be executed as an additional argument, e.g.:

machinectl shell [email protected] $(which bash) -c "systemctl --user status myunit.service"

Make sure not to nest $(which bash) -c in quotes.

4
  • This does not work when trying to pass a command via bash. Tried the following as a simple test: machinectl shell [email protected] "/bin/bash -c 'whoami'". I get no output and the session terminates. Output in /var/log/messages is "[email protected]: Executable /bin/bash -c 'whoami' missing, skipping: No such file or directory" Is there some special way to send commands I am unaware of?
    – Dave
    Commented Oct 6, 2021 at 13:59
  • Got it working! syntax should actually be machinectl shell [email protected] /bin/bash -c "whoami" Dont next /bin/bash in quotes.
    – Dave
    Commented Oct 8, 2021 at 16:52
  • I should add this command will hang if systemctl --user daemon-reload is run.
    – Dave
    Commented Oct 8, 2021 at 17:04
  • 1
    @Dave $(which bash) should be wrapped in double quotes to prevent word splitting and globbing, though it's really unlikely to be an issue. Your example, machinectl shell [email protected] /bin/bash -c whoami, would be fine even with no quotes at all, because the command string (what follows -c) is a single word. In general, you'd want the command string wrapped in double quotes if expansions are meant to happen in the current shell (where machinectl runs) and in single quotes if expansions are meant to happen in the shell invoked by machinectl.
    – fra-san
    Commented Oct 8, 2021 at 22:03
0

I actually figured out a very clean way of doing this that does not involve having the user actually logged in. Needed to enable linger with loginctl for the user as root.

loginctl enable-linger user1

Then you can check status with

loginctl user-status user1

This should list all processes the user is running from their systemd process. Now I can run, as root without the user actually being logged in:

runuser -l user1 -c 'systemctl --user status myunit.service'

2
  • 1
    Support for running systemctl --user commands as root was added to systemd 248. See -M option. Commented Mar 29, 2023 at 17:16
  • 1
    The systemctl -M switch is only available starting with RHEL9. RHEL8 is still at version 239. You should have specified it. Commented Sep 15, 2023 at 12:16

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .