I have a PHP script which contains a shell_exec() and the command it executes normally requires sudo. I've edited the sudoers with visudo to contain the following:

www-data ALL = NOPASSWD: /var/root/node/npm/node_modules/less/
%users ALL = NOPASSWD: /var/root/node/npm/node_modules/less/

I suspect either should work, but I went with the belt-and-suspenders approach to be sure.

I'm editing etc/sudoers with vim, so after adding these lines, I do :x and everything works. My PHP script does what it's supposed to... for about 10-15 minutes. Then the script stops working. Specifically, the shell_exec() stops working.

If I do sudo visudo again, my new lines are still there. But only when I save it again does the script start working again.

Can anyone tell me why this might be happening? I have two guesses that aren't very good:

  1. There is some sort of grace period that starts when I sudo visudo and this is what's allowing my script to work (but only until it expires).
  2. The new data in etc/sudoers is staying in sudoers.tmp (the "Lock file")... Neither of these add up to me.


I think I'm using the wrong username... It looks like for MAMP, the apache user is actually my user (not www-data). I know this because I added this to my PHP script: echo = shell_exec("whoami"); My username appears: Emerson. So does this mean I should add Emerson ALL = NOPASSWD: /var/root/note/npm/node_modules/less/bin/lessc to my sudoers file?


I've got it working with this in my sudoers file. Emerson ALL=(ALL) NOPASSWD: ALL It works, but I don't think it's the way it should be. Aside from a bunch of redundancy, it's also too permissive. I've left all the nonsense in so you can see what I've currently got.


# Host alias specification

# User alias specification

# Cmnd alias specification

# Defaults specification
Defaults        env_reset
Defaults        env_keep += "BLOCKSIZE"
Defaults        env_keep += "COLORFGBG COLORTERM"
Defaults        env_keep += "__CF_USER_TEXT_ENCODING"
Defaults        env_keep += "LC_MESSAGES LC_MONETARY LC_NUMERIC LC_TIME"
Defaults        env_keep += "LINES COLUMNS"
Defaults        env_keep += "LSCOLORS"
Defaults        env_keep += "SSH_AUTH_SOCK"
Defaults        env_keep += "TZ"
Defaults        env_keep += "EDITOR VISUAL"
Defaults        !requiretty

# Runas alias specification

# User privilege specification
root    ALL=(ALL) ALL
%admin  ALL=(ALL) ALL

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

# Same thing without a password

# Samples
# %users  ALL=/sbin/mount /cdrom,/sbin/umount /cdrom
# %users  localhost=/sbin/shutdown -h now

#Allow PHP to compile .less files
www-data ALL = NOPASSWD: /var/root/node/npm/node_modules/less/bin/lessc
%users ALL = NOPASSWD: /var/root/node/npm/node_modules/less/bin/lessc
Emerson ALL =(ALL) NOPASSWD: /var/root/node/npm/node_modules/less/bin/lessc
apache ALL =(ALL) NOPASSWD: /var/root/node/npm/node_modules/less/bin/lessc
  • Are there any relevant messages in the file that sudo logs to when it fails? The log file could be /var/log/secure or /var/log/auth.log (or elsewhere) – user9517 Dec 11 '11 at 21:16
  • I don't have a /var/log/auth.log but I do have a /var/log/secure.log. I took a look at the entries from the past 36 hours. Nothing seems to be relevant, but I'm also not sure what I should be looking for? Would it be appropriate to add the contents to my post? – emersonthis Dec 12 '11 at 2:32

Neither of the things you suggested are the issue here.

Do you have a requiretty line in your sudoers file? This would explain why it works for you, but not your PHP script. Removing that would fix the issue.

Sudo may have been configured to cache your password for 15 minutes, check for a line like 'Defaults timestamp_timeout = XXXX' in your sudoers file.

One word of advice, consider limiting sudo to only the files it needs. What if an attacker manages to drop a malicious file into your node_modules/less/ directory?

| improve this answer | |
  • I added the contents of my sudoers file above (I don't think that's unsafe). There does not appear to be a requiretty line. I agree, I should make the permission more specific by adding /bin/lessc to the end of the path. – emersonthis Dec 11 '11 at 22:06

You should disable requiretty for the web user

Here is the syntax for /etc/sudoers

Defaults:username !requiretty

Don't edit /etc/sudo with vim use the visudo command

| improve this answer | |
  • I just want to make sure I understand your code. Is the colon at the end of "Defaults:" correct? Your syntax is a bit different than the other defaults in my current file. Also, is "username" a placeholder for an actual username? Like www-data? Sorry if these are dumb questions. My understanding of this syntax is poor. – emersonthis Dec 12 '11 at 2:25
  • Update. It didn't work with username. I'm testing it as follows: Defaults:www-data !requiretty – emersonthis Dec 12 '11 at 2:34
  • Update. It still didn't work. I still have to open/re-save etc/sudoer to keep my script working. It sounds like the requiretty flag should be off by default anyway. – emersonthis Dec 12 '11 at 2:44

You have to authorize the user that you want to allow elevated privileges within the sudoers file. If your webserver is running as Emerson then

Emerson ALL = NOPASSWD: /var/root/note/npm/node_modules/less/bin/lessc

should fix your problem.

| improve this answer | |
  • I actually tried this, and for some reason it didn't work with the full path. I've got it working currently, but with this: Emerson ALL=(ALL) NOPASSWD: ALL I'm not happy about it because it seems too permissive to be safe. Am I wrong about that? – emersonthis Dec 12 '11 at 21:33
  • with what ? <filler> – user9517 Dec 12 '11 at 21:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.