244

I need to run something as sudo without a password, so I used visudo and added this to my sudoers file:

MYUSERNAME ALL = NOPASSWD: /path/to/my/program

Then I tried it out:

$ sudo /path/to/my/program
[sudo] password for MYUSERNAME: 

Why does it ask for a password? How can I run/use commands as root with a non-root user, without asking for a password?

LanceBaynes
  • 40,135
  • 97
  • 255
  • 351

15 Answers15

194

If there are multiple matching entries in /etc/sudoers, sudo uses the last one. Therefore, if you can execute any command with a password prompt, and you want to be able to execute a particular command without a password prompt, you need the exception last.

myusername ALL = (ALL) ALL
myusername ALL = (root) NOPASSWD: /path/to/my/program

Note the use of (root), to allow the program to be run as root but not as other users. (Don't give more permissions than the minimum required unless you've thought out the implications.)

Note for readers who aren't running Ubuntu or who have changed the default sudo configuration (Ubuntu's sudo is ok by default): Running shell scripts with elevated privileges is risky, you need to start from a clean environment (once the shell has started, it's too late (see Allow setuid on shell scripts), so you need sudo to take care of that). Make sure that you have Defaults env_reset in /etc/sudoers or that this option is the compile-time default (sudo sudo -V | grep env should include Reset the environment to a default set of variables).

  • 3
    ex to go root from jhon with sudo su an no pass ----->

    john ALL=(ALL) NOPASSWD: /bin/su

    – bortunac Jul 13 '14 at 14:05
  • 7
    @adrian If you want to allow arbitrary commands as root, make that john ALL=(ALL) NOPASSWD: all. There's no point in going via su. – Gilles 'SO- stop being evil' Jul 13 '14 at 14:08
  • Question: should I alter the permissions of my shell script so that it can get modified and read by root user only, for security? I'm thinking about an attacker modifying the script, which has all the permissions granted without the need of a password, so that it does what he/she wants. Obviously, the attacker can't even read sudoers file to know which scripts have this privilege, but can still try with all my custom scripts once he/she finds the folder in which they are stored in hope some are allowed, or something like that. – Jeffrey Lebowski Oct 10 '17 at 18:13
  • 1
    @JeffreyLebowski If you have a sudo rule that runs the script (directly or indirectly) then it's vital that only root (or people who have root privileges anyway) can write to the script file, and to the directory containing the script file, and to its parent directory and so on. It doesn't matter that anyone can read the script file (unless it contains a password or something, but that's a bad idea, if there's a password it should be in its own file, otherwise there's too much risk of accidentally leaking it e.g. by copy-pasting that section of the code in a question on this site). – Gilles 'SO- stop being evil' Oct 10 '17 at 18:51
  • Much better than accepted answer – hmedia1 Mar 01 '19 at 05:23
  • Do we have to reboot after making changes into the /etc/sudoers file? @Gilles – alper Mar 18 '19 at 08:45
  • 2
    @alper No. Very few things require rebooting. After changing sudoers, you don't need to do anything special: sudo checks it each time. – Gilles 'SO- stop being evil' Mar 18 '19 at 19:02
122

You have another entry in the sudoers file, typically located at /etc/sudoers, which also matches your user. The NOPASSWD rule needs to be after that one in order for it to take precedence.

Having done that, sudo will prompt for a password normally for all commands except /path/to/my/program, which it will always let you run without asking for your password.

Thomas
  • 105
Warren Young
  • 72,032
28

WARNING: This answer has been deemed insecure. See comments below

Complete Solution: The following steps will help you achieve the desired output:

  1. Create a new script file (replace create_dir.sh with your desired script name):

    vim ~/create_dir.sh
    

    The script will be created in the user’s home directory

  2. Add some commands that only a root or sudo user can execute like creating a folder at the root directory level:

    mkdir /abc
    

    Note: Don’t add sudo to these commands. Save and exit (using :wq!)

  3. Assign execute permissions to it using:

    sudo chmod u+x create_dir.sh
    
  4. Make changes so that this script doesn’t require a password.

    1. Open the sudoers file:

      sudo visudo -f /etc/sudoers
      
    2. Add the following line at the end:

      ahmad ALL=(root) NOPASSWD: /home/ahmad/create_dir.sh
      

      Replace ahmad with whatever your username is. Also make sure this is the last line. Save and exit.

  5. Now when running the command add sudo before it like:

    sudo ./create_dir.sh
    

    This will run the commands inside the script file without asking for a password.

Follow the easy steps mentioned here http://step4wd.com/2013/09/14/run-root-commands-in-linux-ubuntu-without-password/

Eldamir
  • 131
  • It would be better if you provided the relevant steps here and used the link as a backup for more detailed information. That way your answer retains possible value even if that link would not be valid anymore. – Anthon Sep 14 '13 at 05:37
  • 24
    This advice is insecure. The sudo part of sudo chmod u+x create_dir.sh is unnecessary as the user has (presumably) ownership over his/her home dir. Since the user can write to create_dir.sh, you have effectively given a free root shell to that user. – Lekensteyn Jul 19 '14 at 08:36
  • 1
    @Lekensteyn Which means also to any program running as the user. Might as well just allow the user to run anything with sudo without a password. – pydsigner May 23 '16 at 01:41
  • 2
    Am I missing something? I believe that the entire chmod is unnecessary, since you’re relying on sudo to elevate your privileges. – G-Man Says 'Reinstate Monica' Jun 13 '18 at 14:57
14

If you want to avoid having to use sudo nor have to change the sudoers config file, you can use:

sudo chown root:root path/to/command/COMMAND_NAME
sudo chmod 4775 path/to/command/COMMAND_NAME

This will make the command run as root without the need of sudo.

Thomas
  • 6,362
  • Wow, I never heard of this solution before, mind boggling – somethingSomething Nov 10 '18 at 14:18
  • 3
    @RyanNerd: This is not a secure solution. Not only can the OP now run the command as root without a password, buy anybody can now run the command as the root user. – Ethan Furman Feb 07 '20 at 16:36
  • 2
    "chmod 4775 filename" is one way. Second, maybe better way to SETUID, without re-defining whole file permissions is "chmod u+s filename" – 16851556 Feb 09 '20 at 11:12
  • sudo chmod 005 is safe. You don't wanna give writing permissions to the current user. Otherwise anyone in your session could do anything with your script. – Adrian Lopez Sep 09 '20 at 13:01
13

I think your syntax is wrong. At least I use the following which works for me:

myusername ALL=(ALL) NOPASSWD: /path/to/executable
musiKk
  • 583
8

If you have an distro like Manjaro, you must deal first with a file that overrides the definition of /etc/sudoers; you may delete it or work directly with that file to add your new configurations.

This file is:

sudo cat /etc/sudoers.d/10-installer

The ONLY way to see it is under root privileges; you cannot list this directory without it. This file is Manjaro specific: you may find this configuration with a different name, but in same directory.

In your file of choice, you can add the following line(s) to get your desired configuration(s):

Ignore authentication for a group:

%group ALL=(ALL) NOPASSWD: ALL

or Ignore authentication for a user:

youruser ALL=(ALL) NOPASSWD: ALL

or Ignore authentication on a specific executable for a user:

youruser ALL=(ALL) NOPASSWD: /path/to/executable

QUICK NOTE: You are opening a door to use sudo without authentication, which means you can run everything modifying everything on your system; use it with responsibility.

Toby Speight
  • 8,678
Lyoneel
  • 180
4

Verify that sudo is not aliased. Run like this

/usr/bin/sudo /path/to/my/program

For example a shell alias like this one:

alias sudo="sudo env PATH=$PATH"

may cause this behaviour.

peterph
  • 30,838
Sepero
  • 1,599
  • You are right, my comment was out of order here, sorry for that. Nevertheless I'm intrigued - how do you expect aliasing to change the processing of sudoers by sudo. Or are you talking about redirecting sudo to something that always prints this error message to scoop passwords? That is unlikely the case here... – peterph Jul 19 '14 at 08:18
  • 3
    I was having the same problem as the OP. It turned out to be caused by having alias sudo="sudo env PATH=$PATH" in my ~/.bashrc. Rather than just solving it for myself and blindly just going about my business, I submitted my answer as a possible solution for anyone else that comes along this thread. – Sepero Jul 19 '14 at 22:50
  • 1
    That's fine, but when it is not obvious (which in this case isn't at least to some people) it is good to put an explanation into the answer to provide some context and prevent people from blindly using magic incantations. +2 (-(-1) + +1). :) – peterph Jul 24 '14 at 22:45
3

In the script sudoers which is inside /etc/ uncomment the line given below:

#includedir /etc/sudoers.d

Create one file with any name inside /etc/sudoers.d/ directory and add the content as given in the maximum answers. Like for all users as root

#!/bin/bash
ALL    ALL = NOPASSWD: /path/of/the/script/which/you/want/to/run/as/root

This is the safest way to run the script with root permission.

Cherry
  • 51
2

When you execute your script you need to run it as sudo /path/to/my/script.

Edit: Based on your comment to another answer, you want to run this from an icon. You will need to create a .desktop file that executes your program with sudo, just like on the terminal.

You could also consider using gtk-sudo for a visual password prompt.

You should probably consider the idea that you shouldn't be running things as root and that changing the system farther down the road so that you don't need root permissions at all would be a better way to go.

Michael Mrozek
  • 93,103
  • 40
  • 240
  • 233
Caleb
  • 70,105
2

Another possibility might be to install, configure, then use the super command to run your script as

super /path/to/your/script

If you want to run some binary executable (e.g. that you have compiled into ELF binary from some C source code) -which is not a script- as root, you might consider making it setuid (and actually /bin/login, /usr/bin/sudo and /bin/su and super are all using that technique). However, be very careful, you could open a huge security hole.

Concretely, your program should be paranoically coded (so check all arguments and the environment and outside conditions before "acting", assuming a potentially hostile user), then you could use seteuid(2) and friends (see also setreuid(2)) carefully (see also capabilities(7) & credentials(7) & execve(2)...)

You'll use chmod u+s (read chmod(1)) when installing such a binary.

But be very careful.

Read many things about setuid, including Advanced Linux Programming, before coding such a thing.

Notice that a script, or any shebang-ed thing, cannot be setuid. But you could code (in C) a small setuid-binary wrapping it.

Be aware that on Linux, application code interact with the Linux kernel using syscalls(2). Most of them could fail, see errno(3). A lot of Linux applications (e.g. GNU bash, GNU make, GNU gdb, GNOME) are open source : you are allowed to download then study and contribute to their source code.

2

This solved the issue for me (also tried some of the other answers, that might have helped):

The script I was calling was in /usr/bin, a directory that I don't have write permissions to (though I can usually read any files there). The script was chmodded +x (executable permisison), but it still didn't work. Moving this file to a path in my home directory, instead of /usr/bin, I was finally able to call it with sudo without entering a password.

Also something I doubted about (clarifying for future readers): You need to run your script as sudo. Type sudo when calling the script. Don't use sudo for the command inside your script that actually needs root (changing keyboard backlight in my case). Perhaps that also works, but you don't need to, and it seems like a better solution not to.

peterph
  • 30,838
Luc
  • 3,610
  • The second paragraph had the answer to my problem – M. Ahmad Zafar Sep 13 '13 at 08:02
  • @MuhammadAhmadZafar Glad it helped! – Luc Sep 13 '13 at 10:53
  • 4
    Actually using sudo inside of a script is perfectly fine provided you have the appropriate rights (set in sudoers) to run the command in question without a password. It makes things a bit more secure. – peterph Jul 19 '14 at 08:21
  • could really use this answer re-written as a step-by-step 'this is how you do it' rather than as a dialogue with the other answers – Walrus the Cat Nov 28 '17 at 22:31
  • @WalrustheCat Good point. Re-reading my answer, I think I might have been confused a little myself. Right now though, I don't remember what the exact situation was so I can't really do a better writeup. If you figure it out, perhaps a combination of several answers, by all means submit a new answer! – Luc Nov 29 '17 at 07:24
1

To allow any user to execute program as sudo without asking password you can add following line

%sudo ALL=(root) NOPASSWD: /path/to/your/program

in /etc/sudoers

Note that %sudo make it.

  • While that's one way to accomplish a sudo rule, it doesn't answer the question about why setting the NOPASSWD flag on this rule still resulted in a password prompt. See the accepted answer for an idea why it happened. – Jeff Schaller Mar 02 '19 at 17:19
1

Alternately you can use python pudo package.

Installation:

user$ sudo -H pip3 install pudo # you can install using pip2 also

Below is the code snippet for using in python automation for running commands under root privilege:

user$ python3 # or python2
>>> import pudo
>>> (ret, out) = pudo.run(('ls', '/root')) # or pudo.run('ls /root')
>>> print(ret)
>>> 0
>>> print(out)
>>> b'Desktop\nDownloads\nPictures\nMusic\n'

Below is the cmd example for running commands under root privilege:

user$ pudo ls /root
Desktop  Downloads  Pictures  Music
Paulo Tomé
  • 3,782
0

Ideally if you are customizing what commands can be run via sudo you should be making these changes in a separate file under /etc/sudoers.d/ instead of editing the sudoers file directly. You should also always use visudo to edit the file(s). You should NEVER grant NOPASSWD on ALL commands.

Example: sudo visudo -f /etc/sudoers.d/mynotriskycommand

Insert your line granting permission: myuser ALL= NOPASSWD: /path/to/your/program

Then save and exit and visudo will warn you if you have any syntax errors.

You can run sudo -l to see the permissions that your user has been granted, if any of the user specific NOPASSWD commands appear BEFORE any %groupyouarein ALL=(ALL) ALL command in the output you will be prompted for your password.

If you find yourself creating lots of these sudoers.d files then perhaps you will want to create them named per user so they are easier to visualize. Keep in mind that the ordering of the FILE NAMES and of the RULES within the file is very important, the LAST one loaded wins, whether it is MORE or LESS permissive than the previous entries.

You can control the file name ordering by using a prefix of 00-99 or aa/bb/cc, though also keep in mind that if you have ANY files that don't have numeric prefix, they will load after the numbered files, overriding the settings. This is because depending on your language settings the "lexical sorting" the shell uses sorts numbers first and then may interleave upper and lowercase when sorting in "ascending" order.

Try running printf '%s\n' {{0..99},{A-Z},{a-z}} | sort and printf '%s\n' {{0..99},{A-Z},{a-z}} | LANG=C sort to see whether your current language prints AaBbCc etc or ABC then abc to determine what the best "last" letter prefix to use would be.

dragon788
  • 852
0

The following is for the case where you want to run a command without password only if it has a specific set of options, where a part of the options is variable. AFAIK it is not possible to use variables or value ranges in sudoers declarations, i.e. you can allow access explicitly to command option1 but not command option2 using:

user_name ALL=(root) /usr/bin/command option1

but if the structure is command option1 value1, where value1 can vary, you would need to have explicit sudoers lines for each possible value of value1. Shell script provides a way around it.

This answer was inspired by M. Ahmad Zafar's answer and fixes the security issue there.

  1. Create a shell script where you call the command without sudo.
  2. Save the script in a root-privileged folder (e.g. /usr/local/bin/), make the file root-owned (e.g. chown root:wheel /usr/local/bin/script_name) with no write access for others (e.g. chmod 755 /usr/local/bin/script_name).
  3. Add the exception to sudoers using visudo:

    user_name ALL=(root) NOPASSWD: /usr/local/bin/script_name.

  4. Run your script sudo script_name.

For example, I want to change display sleep timeout on macOS. This is done using:

sudo pmset displaysleep time_in_minutes

I consider changing the sleep timeout an innocent action that doesn't justify the hassle of password typing, but pmset can do many things and I'd like to keep these other things behind the sudo password.

So I have the following script at /usr/local/bin/ds:

#!/bin/bash
if [ $# -eq 0 ]; then
        echo 'To set displaysleep time, run "sudo ds [sleep_time_in_minutes]"'
else
        if [[ $1 =~ ^([0-9]|[1-9][0-9]|1[0-7][0-9]|180)$ ]]; then
                pmset displaysleep $1 
        else
                echo 'Time must be 0..180, where 0 = never, 1..180 = number of minutes'
        fi
fi

At the end of sudoers file I have the following line:

user_name ALL=(root) NOPASSWD: /usr/local/bin/ds

To set the timeout at 3 minutes, I run my script from the ordinary user account user_name:

sudo ds 3

PS Most of my script is input validation, which is not mandatory, so the following would also work:

#!/bin/bash
pmset displaysleep $1