1

I am running a LEMP stack and wish to write a simple control panel for it.

So, I want to be able to restart php-fpm from a php script. To achieve this, this is what I did.

Created a binary wrapper in c like this php-shell.c:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_CMN_LEN 100

int main(int argc, char *argv[])
{
    char cmd[MAX_CMN_LEN] = "", **p;

    if (argc < 2)
    {
        fprintf(stderr, "Usage: ./php_shell terminal_command ...");
        exit(EXIT_FAILURE);
    }
    else
    {
        strcat(cmd, argv[1]);
        for (p = &argv[2]; *p; p++)
        {
            strcat(cmd, " ");
            strcat(cmd, *p);
        }
        system(cmd);
    }

    return 0;
}

This program was compiled like this:

gcc php_shell.c -o php_shell

I have then added nginx user to sudo visudo like this:

Defaults:nginx        !requiretty
nginx    ALL=(ALL)    NOPASSWD:/path/to/php_shell

Then I executed the command in a php script like this:

var_dump(shell_exec('sudo /path/to/php_shell "service nginx restart" 2>&1'));

As soon as I run this script php script, I get 502 Gateway Error and it appears all php-fpm processes has been killed off and it does not start back up.

Any ideas? Am I doing this wrong? I want to be able to restart nginx server from php script by executing service nginx restart. How can I achieve this?

1 Answer 1

1

Congratulations! You are on the path to giving unrestricted root access to anyone who can make your nginx server run arbitrary code. You had better be sure that every single CGI script and php page and anything else that might be used to execute arbitrary code is secure.

Your C wrapper is equivalent to configuring sudo to allow nginx to run any command at all as root.

DON'T do it like that.

Write individual shell script (or whatever) wrappers for specific commands and then grant sudo access only to those wrapper scripts. For example, /usr/local/sbin/restart-nginx.sh which does nothing but service nginx restart and give nginx sudo access to that script.

Then write another, completely separate script to run, say, dmidecode -s system-uuid as in your previous question. And give nginx sudo access to that script too.

The simpler and less complicated each individual script, the better. Safest of all is to take no user input at all, not from the command-line and not from environment variables.

If some of your wrapper scripts must take user input, sanity check and sanitise all user-supplied input before using it. And quote your variables - e.g. always use "$variable" and never just $variable without quotes.

If your wrapper scripts are getting excessively long and complicated then try to identify just the minimum command or set of commands that need to be run as root and write them as a separate script (or scripts), which are called by sudo from the main script. i.e. run as little as possible as root.

You must log in to answer this question.

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