1

My situation is this: I'm trying to give the www-data user the ability to sudo-execute some shell scripts, so that I can have a page on my web server display system information (in PHP using shell_exec() ). To this end, I edited my sudoers file with the following line

www-data ALL=(ALL:ALL) NOPASSWD: /home/evermind/scripts/*

to give Apache the ability to run scripts in that directory without needing a password for suoo. Unfortunately, this doesn't work, nor does (as a sanity check) specifying a specific script within that directory. shell_exec fails to execute the command, and gives the following error:

sudo: no tty present and no askpass program specified

This is where things get...strange. If I replace the path specification with "ALL" then everything works perfectly. Why is this? Is there a reason I can't specify NOPASSWD for individual files or directories?

For security reasons, I am extremely hesitant to allow www-data free reign over everything, even though the web application is extremely secure and there isn't an obvious way anyone could execute arbitrary commands.

2
  • even though the web application is extremely secure and there isn't an obvious way anyone could execute arbitrary commands. Famous last words :D
    – crasic
    Jun 26, 2014 at 19:45
  • Yep, which is exactly why going with "NOPASSWD: ALL" wasn't something I considered a viable option in spite of any apparent security.
    – jrp3
    Jun 26, 2014 at 21:50

3 Answers 3

2

How about adding just using the directory path without the wildcard?

www-data ALL=(ALL:ALL) NOPASSWD: /home/evermind/scripts/

According to the sudoers man page:

A Cmnd_List is a list of one or more
commandnames, directories, and 
other aliases. ... A directory is a fully 
qualified path name ending in a '/'. 
When you specify a directory in a 
Cmnd_List, the user will be able to 
run any file within that directory (but 
not in any subdirectories therein).
4
  • That doesn't work either, unfortunately. My goal was to be able to have nested directories there, eventually, which is why I went the wildcard route. But when that didn't work, I tried taking it out.
    – jrp3
    Jun 25, 2014 at 1:57
  • @user297607 if that's your intention, then you're out of luck. The * explicitly does not match /, by intention. This is to prevent people doing stuff like /home/evermind/scripts/../../../../bin/rm -rf /. If you want it have access to nested directories, you'll have to list each subdirectory.
    – muru
    Jun 25, 2014 at 2:01
  • @jrp3 ah. I just noticed you said that even s specific script couldn't run. This is interesting. I'll test this out and get back.
    – muru
    Jun 25, 2014 at 2:12
  • Just came across this question doing cleanup... any further insight?
    – Zanna
    Nov 12, 2016 at 19:12
2

Okay, after stepping away from the problem for a day and coming back to it, I seem to have more or less solved my own problem.

Previously, the terminal command I was executing via shell_exec() was

sudo sh <path to my script>

Today, more or less for the sake of just trying something, I chmod'd my script to make it executable directly. Then, I changed the shell_exec() string to be

sudo <path to my script>

And voilà, it started working. Logic would seem to suggest that the culprit was actually the sh utility declaration, since that was the key distinction in the commands. If anyone knows what the deal with this was, though, I'd be really interested to know.

1
  • 1
    The deal here is simply that the command being executed as sudo is not the script in question, but sh, with the script an argument for sh. sudo uses execve to run the command according to the man page, and according to stackoverflow.com/a/3027353, execve processes the shebang line to run script. Since the check for permission presumably occurs before execve gets to its job, using sh will block it.
    – muru
    Jul 5, 2014 at 1:08
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/myWebScript

Insert your line granting permission: www-data ALL= NOPASSWD: /home/evermind/scripts/

The way you were calling it if you wanted to restrict is specifically to a directory for sh you would use: www-data ALL= NOPASSWD: /bin/sh /home/evermind/scripts/

I'm not sure why these scripts would require sudo access, typically you could just chmod o+x scriptname.sh and make sure that they were in a directory owned by the www-data user.

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.

You must log in to answer this question.

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