Archive for December, 2015

Running scripts as root from PHP

| December 12th, 2015

I needed to integrate a Linux server with our existing web application, which involved dynamically changing iptables rules by a bash script. For obvious reasons, the script needed root privileges to execute successfully.

On CentOS (and a handful of other distros), Apache processes run as the apache user by default. To call a script with root privileges and dump out the output from PHP, we can use the shell_exec command with sudo:

    echo shell_exec("sudo /usr/sbin/");

Unsurprisingly, The apache user doesn’t have sudo privileges by default, so we need to add a line to the /etc/sudoers file using the visudo command. Visudo makes sure that the file’s syntax is correct before applying the new rules, which is especially important if you have the root user disabled in your system.

The following line will allow the apache user to run the above dummy example script (and nothing else) with sudo without asking for a password:

apache ALL=NOPASSWD: /usr/sbin/

If you need to run more than one command, just add them separated by commas.

There might be one more thing to change in /etc/sudoers: at this point if the output is empty and the command silently fails, it’s because sudo is set to only be used directly from the terminal. To lift this requirement for a certain command or user, use the following:

# This line is probably in sudoers somewhere,
# disallowing script usage
Defaults    requiretty
# To allow our script to be run from anywhere,
# add the following line:
Defaults!/usr/sbin/ !requiretty
# Alternatively you can enable apache user
# to run all allowed commands from anywhere.
# (Not recommended, be as specific as you can be!)
Defaults:apache !requiretty
Security warning

Please make sure you think about security and be especially careful when accepting user input as command parameters to avoid injection attacks. It’s also good idea to implement some sort of authentication before executing the code path with the script.

I only needed it for communication between servers, so I put it in an Apache VirtualHost on a custom port and made sure it’s only accessible from the other server’s internal IP address.