Sudoers NOPASSWD option not working

Hi,
I would like to stop a service as user martin without having to enter the password each time.

For this I have entered the following line in the file /etc/sudoers:
martin ALL=(ALL) NOPASSWD: /usr/bin/systemctl stop vdr.service

## Allow root to run any commands anywhere 
root    ALL=(ALL)       ALL
vdr     ALL=(ALL)       NOPASSWD: /usr/bin/markad
martin  ALL=(ALL)       NOPASSWD: /usr/bin/systemctl stop vdr.service

## Allows members of the 'sys' group to run networking, software, 
## service management apps and more.
# %sys ALL = NETWORKING, SOFTWARE, SERVICES, STORAGE, DELEGATING, PROCESSES, LOCATE, DRIVERS

## Allows people in group wheel to run all commands
%wheel  ALL=(ALL)       ALL

## Same thing without a password
# %wheel        ALL=(ALL)       NOPASSWD: ALL

## Allows members of the users group to mount and unmount the 
## cdrom as root
# %users  ALL=/sbin/mount /mnt/cdrom, /sbin/umount /mnt/cdrom

## Allows members of the users group to shutdown this system
# %users  localhost=/sbin/shutdown -h now

## Read drop-in files from /etc/sudoers.d (the # here does not mean a comment)
#includedir /etc/sudoers.d

the user martin may run the following commands:

[martin@fc36 vdr]$ sudo -l -U martin
Matching Defaults entries for martin on fc36:
    !visiblepw, always_set_home, match_group_by_gid, always_query_group_plugin, env_reset, env_keep="COLORS DISPLAY HOSTNAME HISTSIZE KDEDIR LS_COLORS", env_keep+="MAIL QTDIR USERNAME LANG LC_ADDRESS LC_CTYPE", env_keep+="LC_COLLATE LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES", env_keep+="LC_MONETARY LC_NAME
    LC_NUMERIC LC_PAPER LC_TELEPHONE", env_keep+="LC_TIME LC_ALL LANGUAGE LINGUAS _XKB_CHARSET XAUTHORITY", secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/var/lib/snapd/snap/bin

User martin may run the following commands on fc36:
    (ALL) NOPASSWD: /usr/bin/systemctl stop vdr.service
    (ALL) ALL

but when I want to stop the service I am asked to enter the password.

[martin@fc36 vdr]$ systemctl stop vdr
Failed to stop vdr.service: Access denied
See system logs and 'systemctl status vdr.service' for details.

How can i solve this ?
Regards
Martin

Just asking,
Did you edit the file with visudo ?

Does sudo systemctl stop vdr work?

and …sudo systemctl disable vdr

yes, it works with sudo …

At the beginning I had edited the file /etc/sudoers with the editor vim directly, then with the command sudo visudo, but that made no difference.

The command in your sudoers file is:

/usr/bin/systemctl stop vdr.service

but, at the command line, you are attempting to execute:

/usr/bin/systemctl stop vdr

A solution: Add both variations to your sudoers file:

martin  ALL=(ALL)       NOPASSWD: /usr/bin/systemctl stop vdr
martin  ALL=(ALL)       NOPASSWD: /usr/bin/systemctl stop vdr.service

BTW, a good practice it to place custom sudoders rules into files created in /etc/sudoers.d directory. Such a file can be created with one of the following commands:

sudo visudo -f /etc/sudoers.d/martin-vdr-service
sudo visudo /etc/sudoers.d/martin-vdr-service # [1]

[1] “As of version 1.8.27, the sudoers path can be specified without using the -f option.” – man page for visudo

That means it works fine. If you execute it without sudo, you are getting prompted by polkit to elevate privileges and i am nut sure but apparently, it doesn’t read /etc/sudoers file.

created the custom sudoers rule as mentioned in /etc/sudoers.d directory, but it still asks for the password.

the following sudoers rules are read from the /etc/sudoers file:

[martin@fc36 ~]$ sudo -l -U martin
Matching Defaults entries for martin on fc36:
    !visiblepw, always_set_home, match_group_by_gid, always_query_group_plugin, env_reset, env_keep="COLORS DISPLAY HOSTNAME HISTSIZE KDEDIR LS_COLORS", env_keep+="MAIL QTDIR USERNAME LANG LC_ADDRESS LC_CTYPE",
    env_keep+="LC_COLLATE LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES", env_keep+="LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE", env_keep+="LC_TIME LC_ALL LANGUAGE LINGUAS _XKB_CHARSET XAUTHORITY",
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/var/lib/snapd/snap/bin

User martin may run the following commands on fc36:
    (ALL) ALL
    (ALL) NOPASSWD: /usr/bin/systemctl stop vdr
    (ALL) NOPASSWD: /usr/bin/systemctl stop vdr.service

password request as user martin:

[martin@fc36 ~]$ /usr/bin/systemctl stop vdr
Failed to stop vdr.service: Access denied
See system logs and 'systemctl status vdr.service' for details.

In any case, nopasswd or not, you have to use sudo. Isn’t it?
sudo systemctl stop vdr

1 Like

yes, it works now as user martin, i have to use this command and the password is no longer requested.

[martin@fc36 ~]$ sudo systemctl stop vdr.service

2 Likes

If you don’t want to prepend sudo to the command, you should consider to use polkit instead of the old style sudo.

I’m not an expert, but it seems to work.
Create a file like /etc/polkit-1/rules.d/10-vdr.rules containing this stuff:

polkit.addRule(function(action, subject) {
    if (action.id == "org.freedesktop.systemd1.manage-units") {
        polkit.log("action=" + action)
        polkit.log("subject=" + subject)
        polkit.log("unit="+action.lookup("unit"))
        if (action.lookup("unit") == "vdr.service") {
            polkit.log("verb="+action.lookup("verb"))
            var verb = action.lookup("verb");
            if (verb == "start" || verb == "stop" || verb == "restart") {
                return polkit.Result.YES;
            }
        }
    }
});

Now, systemctl {start|stop|restart} vdr (even without sudo) shouldn’t ask for a password anymore.

Yes, polkit is way more complicated than sudo, but it is where the world is going today. However, as you could imagine, it allows to assign more fine grained authorizations in the modern world.

1 Like

You could also add a check if the user is in the wheel group

...
            if (verb == "start" || verb == "stop" || verb == "restart") {
                if (subject.isInGroup("wheel")) {
                    return polkit.Result.YES;
                }
            }
...

or limit the policy to a specific user

            if (subject.user == "martin") {
                if (verb == "start" || verb == "stop" || verb == "restart") {
                    return polkit.Result.YES;
                }
            }
...
2 Likes

the polkit rules sounds reasonable.
The reason for my request is that I want to wake up my Video Disk Recorder (VDR) from sleep (suspend mode) via a desktop script.
For this I made the desktop icons visible again under Fedora 36 and created 2 desktop scripts (Start\ VDR.desktop + Stop\ VDR.desktop) and another script (vdr_start_stop). If I now want to control the call via polkit then it will probably be very long or what do you think ?

[martin@fc36 ~]$ cat -v /home/martin/Desktop/Start\ VDR.desktop 
[desktop entry]
Version=1.0
Encoding=UTF-8
Name=vdr_attach
Exec=/home/martin/scripts/vdr/vdr_start_stop start + deta
Exec=/home/martin/scripts/vdr/vdr_start_stop start + atta
Icon=/home/martin/scripts/vdr/softhddevice.png
Type=Application
Name[en]=VDR on
Name[en_DE]=VDR on
Comment[en_DE]=attach vdr
[martin@fc36 ~]$ cat -v /home/martin/desktop/stop\ VDR.desktop 
[Desktop Entry]
Version=1.0
Encoding=UTF-8
Name=vdr_dettach
Exec=/home/martin/scripts/vdr/vdr_start_stop stop + deta
Icon=/home/martin/scripts/vdr/softhddevice.png
Type=Application
Name[en]=VDR off
Name[en_DE]=VDR off
Comment[en_DE]=vdr dettachen
StartupNotify=true
[martin@fc36 ~]$ cat -v /home/martin/scripts/vdr/vdr_start_stop 
#!/bin/sh
sudo systemctl $1 vdr.service
xhost $2
svdrpsend plug softhddevice $3

With the main polkit rule you mentioned the commands are working on console, but not with
the desktop icons.

running the commands on console, all is working

/home/martin/scripts/vdr/vdr_start_stop start + deta
/home/martin/scripts/vdr/vdr_start_stop start + atta

but when selecting the desktop icons the plugin is not dettached and no X-Window opens.
see journalctl -b

Jun 18 16:29:27 fc36 polkitd[715]: <no filename>:3: action=[Action id='org.freedesktop.systemd1.manage-units' verb='start' unit='vdr.service' polkit.message='Authentication is required to start '$(unit)'.' polkit.gettext_domain='systemd']
Jun 18 16:29:27 fc36 polkitd[715]: <no filename>:4: subject=[Subject pid=8087 user='martin' groups=martin,root,wheel,video,audio seat=null session=null local=true active=true]
Jun 18 16:29:27 fc36 polkitd[715]: <no filename>:5: unit=vdr.service
Jun 18 16:29:27 fc36 polkitd[715]: <no filename>:7: verb=start
Jun 18 16:29:27 fc36 nemo-autostart-with-gnome.desktop[8088]: access control disabled, clients can connect from any host
Jun 18 16:29:27 fc36 vdr[5302]: [5322] SVDRP fc36 < 127.0.0.1:51010 client connection accepted
Jun 18 16:29:27 fc36 vdr[5302]: [5322] SVDRP fc36 > 127.0.0.1:51010 server created
Jun 18 16:29:27 fc36 nemo-autostart-with-gnome.desktop[8089]: 220 fc36 SVDRP VideoDiskRecorder 2.6.1; Sat Jun 18 16:29:27 2022; UTF-8
Jun 18 16:29:27 fc36 nemo-autostart-with-gnome.desktop[8089]:900 can't attach SoftHdDevice not detached
Jun 18 16:29:27 fc36 nemo-autostart-with-gnome.desktop[8089]: 221 fc36 closing connection
Jun 18 16:29:27 fc36 vdr[5302]: [5322] SVDRP fc36 < 127.0.0.1:51010 connection closed
Jun 18 16:29:27 fc36 vdr[5302]: [5322] SVDRP fc36 < 127.0.0.1:51010 server destroyed

@alciregi Thanks for your great Solution with the polkit rules. :+1:

2 Likes

I found an even simpler way, this example is for making virt-manager work without password prompt:

printf """polkit.addRule(function(action, subject) {
  if (action.id == "org.libvirt.unix.manage" && subject.local && subject.active && subject.isInGroup("wheel")) {
      return polkit.Result.YES;
  }
});""" | sudo tee /etc/polkit-1/rules.d/80-libvirt-manage.rules

This should do a good and secure policy change, only wheel is allowed. I think this should be standard behavior, as well as with other things like mounting LUKS drives. It is very annoying how it currently is.

There is a built-in policy that only requires relevant group membership:

sudo usermod -a -G libvirt ${USER}
1 Like

Is martin a member of the wheel group? That line above seems to indicate the possibility.

If so then any command that does not ‘exactly’ match the specialized command for that user will fall over to the next available option and since a wheel member is required to enter the password now the password is required.

This one shows what I suspect to be the ‘wheel’ entry before the custom entries, so it would always require the password. The permission is granted at the first entry to match.

I always allow wheel members to use the entry in the sudoers file and put specialized entries for other users in /etc/sudoers.d/ This avoids conflicts between the config for the wheel group and for individual users. The individual users should not be a member of the wheel group. As you can see, privileges may conflict.