14

Background

I'm trying to restart some programs (mail-notification and stalonetray) regularly, as they appear to die frequently. I want to set restart them whenever NetworkManager reconnects. Hence, I have them triggered by a script in /etc/NetworkManager/dispatcher.d/.

Scripting

I can create a script as follows.

#!/bin/bash
sudo -u foo_user pkill mail-notificati -x
sudo -u foo_user DISPLAY=:0 mail-notification &

This works fine if I run it directly as a user. However, if I call it from root's script, it fails. I am prompted to enter the passwords for mail-notification; it cannot read Gnome Keyring.

How can I run this program as foo_user in every way?

14
  • What does "in every way" mean? Every program that a user runs can have different environment, so saying that (for example) DISPLAY should be set for it to be "in every way" doesn't make much sense. You'd need to define this question more for it to make sense.
    – Chris Down
    Commented Sep 29, 2015 at 5:14
  • @ChrisDown I mean I want it to work when running the script as root as it does when running the script as foo_user. I appreciate that DISPLAY isn't necessarily relevant here, but included it as an example of what I was doing.
    – Sparhawk
    Commented Sep 29, 2015 at 5:16
  • That still doesn't clarify, because "doing the same thing when run as root as when run as a user" doesn't make sense -- an environment is per-process, not per-user.
    – Chris Down
    Commented Sep 29, 2015 at 5:17
  • @ChrisDown Sorry, I'm afraid I don't understand the distinction in this case. Here, I'm asking to run the mail-notification process as in foo_user's environment.
    – Sparhawk
    Commented Sep 29, 2015 at 5:18
  • How do you know foo_user is logged in, and on which display? On a single-user system it's perhaps reasonable to assume that it's always :0.0 but it is not reasonable to assume that the user is logged in at all times. Anyway, this makes more sense to run within the X session script of foo_user, which will remove both your original problem and the complications it caused you to want to try to solve.
    – tripleee
    Commented Sep 29, 2015 at 6:48

4 Answers 4

15

In 2021

In short:

To run a command as another user you can use this commands:

runuser -u user -- command
can be used only by root to run commands as another user.
do not require authentication.
do not create log messages.
has permission limitations and issues.

su - user -c command
can be used by any user.
require authentication as target user.
create message in /var/log/auth.log or /var/log/secure.

sudo -u user command
can be used by the user with root privileges or the user from the sudoers file.
require authentication as current user (you).
create message in /var/log/auth.log or /var/log/secure.

pkexec --user user command
can be used by any user.
require authentication as target user.
create message in /var/log/auth.log or /var/log/secure.
replacement for GUI tools such as gksu or gksudo.

More info:

Linux Run Command As Another User

Run a GUI application as another user:

If you want to run a GUI application as another user, you need first allow to the target user connecting to your display:
xhost +si:localuser:user
then use runuser/su/sudo/pkexec to run the application,
and then use xhost to prevent the subsequent connections:
xhost -si:localuser:user

2
  • 2
    Excellent answer! I tried to use this to run spotify as a non-privileged system user. Your answers, especially for running a GUI app, worked for me. However, I did neet to pass in my DISPLAY var through sudo using the -E flag. Also, I was ignorant and didn't realize localuser is that literal string. Finally, a gui app may fail to various other issues with expecting a normal user's profile. HTH
    – labyrinth
    Commented Mar 3, 2022 at 3:13
  • Regarding GUI: Is this safe though? Can user send arbitrary input after having been given access to the display?
    – php_nub_qq
    Commented May 23, 2023 at 13:51
4

You can always use good old su :

man 1 su

This command opens a sub-shell as the user you want to impersonate. As root you can use it without being prompted for a password.

su foo_user -c whatevercommandyouwant

Works from scripts too.

4
  • I'm not sure what -x is (I get su: invalid option -- 'x'), but after removing that, it still fails as per the question.
    – Sparhawk
    Commented Oct 2, 2015 at 6:03
  • Hi, sorry for the confusion, but my aim is not to provide a one shot solution but to tell you how the command su works. If you did a direct cut and paste you may have got an error. But, that's exactly why I added a link to the su man page as the first thing. Please cut and paste this into the shell and see what it says ;)
    – runlevel0
    Commented Oct 5, 2015 at 14:20
  • Sorry, I still don't understand. Are you suggesting that su will provide a different env to sudo that should fix my problem? If so, then that doesn't seem to be the case.
    – Sparhawk
    Commented Oct 5, 2015 at 21:57
  • Yes. Again: man7.org/linux/man-pages/man1/su.1.html " su allows to run commands with a substitute user and group ID. When called without arguments, su defaults to running an interactive shell as root. For backward compatibility, su defaults to not change the current directory and to only set the environment variables HOME and SHELL (plus USER and LOGNAME if the target user is not root). " anyway sudo has nothing to do with that, sudo su does. sudo grants permissions to run commands that require specific privileges to your user.
    – runlevel0
    Commented Oct 7, 2015 at 8:19
1

If you want to interact with a GUI from a process that isn't started from that GUI, you need to set a few environment variables: at least DISPLAY, possibly also XAUTHORITY if it isn't in the default location, and for many modern programs you need to set DBUS_SESSION_BUS_ADDRESS.

But a more reliable approach for your problem would be to not restart those programs from NetworkManager. In addition to the difficulty of successfully launching them, you also need to worry about whether you're logged in at all, and if there might be other users and other displays to consider, and so on. Instead, kill those programs, but don't restart them. In your normal session, instead of starting them directly, start them from a supervisor that restarts them if they die. I think systemd includes this functionality (but I don't know how to use it); or you can use dedicated supervisor programs such as monit, supervise, …

0

Read, copy and install run-as, a Bash and a Python script which wrap up usage of machinectl, xhost and of managing running dbus and setting variables to run a graphical application for you:

run-as <user> <command>

To run a graphical application do

run-as -X <user> <command>

References

You must log in to answer this question.

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