4

I have a collection of bash and Perl scripts to

  1. develop a directory structure desired for deployment on linux box
  2. (optionally) export code from svn
  3. build a package from this source

This is working well from terminal. Now my client requests a web interface to this process.

e.g "Create New Package" button on certain page will invoke above steps one by one and return the output to user as script echos, not when the whole scripts executes.

Is it possible to send instantaneous output from bash script to webpage or php script which has invoked it through program execution functions (system, exec, passthru ... or any thing else that suite this process flow) ?

What is elegant why to do this ?

What security precautions I should take while doing such thing (if possible)?

Edit After some search I have found part of the solution but still not working :

$cmd = 'cat ./password.txt|sudo  -S  ./setup.sh ';

$descriptorspec = array(
        0 => array("pipe", "r"),  // stdin is a pipe that the child will read from
        1 => array("pipe", "w"),  // stdout is a pipe that the child will write to
        2 => array("pipe", "w") // stderr is a pipe that the child will read from
);

flush();

$process = proc_open($cmd, $descriptorspec, $pipes, './', array());
echo "<pre>";
if (is_resource($process)) {    

    while ($s = fgets($pipes[1])) {
        print "Message:".$s;
        flush();
    }
    while ($s = fgets($pipes[2])) {
        print "Error:".$s;
        flush();
    }
}
echo "</pre>";

output: (webpage)

Error:WARNING: Improper use of the sudo command could lead to data loss
Error:or the deletion of important system files. Please double-check your
Error:typing when using sudo. Type "man sudo" for more information.
Error:
Error:To proceed, enter your password, or type Ctrl-C to abort.
Error:
Error:Password:
Error:Sorry, try again.
Error:Password:
Error:Sorry, try again.
Error:Password:
Error:Sorry, try again.
Error:sudo: 3 incorrect password attempts**

First issue I am having now is to pass sudo passoword

help please !

fedorqui
  • 275,237
  • 103
  • 548
  • 598
sakhunzai
  • 13,900
  • 23
  • 98
  • 159
  • related: http://stackoverflow.com/questions/1281140/run-process-with-realtime-output-in-php http://stackoverflow.com/questions/133935/is-there-a-way-to-have-php-print-the-data-to-a-web-browser-in-real-time – clt60 Jun 17 '12 at 01:05

6 Answers6

5

I would use a kind of master / slave design. The slave would be your perl / bash script, just doing a job (packaging, compiling, exporting code or so), and feed a log entry.

The master would be your php process. So the principle is the following: the master and the slave share a communication channel, and communicate asynchronously from that channel.

You could imagine a database like:

create table tasks ( id INT primary key, status INT, argument VARCHAR(100));

You php page should switch user choice, and filter input:

switch ($_GET['action']) {
   case 'export':
       $argument = sanitize($_GET['arg']);
       add_task('export', $argument);
       break;
   case '...': 
     // ...
}

and the add_task function could be something like:

function add_task($action, $arg)
{
   return $db->add('tasks', array($action, NEW_TASK, $arg);
}

The slaves could be run via a cron job, and query the database, feeding the progression of the task.

The pro are:

  • independant systems, ease the evolution.
  • if a client gets disconnected, the job is never lost
  • easier to secure

The cons are:

  • a little more complicated at the beginning.
  • less reactive, because of the polling time of the slaves running (for instance if they run every 5 minutes)
  • less output than the direct output of the command

Notice that you can then implement xml-rpc like triggers to run the slaves, rather than using a message passing system.

Aif
  • 11,015
  • 1
  • 30
  • 44
  • You answer provides some interesting options to handle the system. I ll appreciate if you have some working code ,or similar script/system designed this way. Thanks – sakhunzai Jun 14 '12 at 12:39
  • Sorry, I've only been using them in a java project for distributed computation, and in perl in vhffs (vhffs.org, see bots/ folder). – Aif Jun 14 '12 at 12:59
  • +1 on Alf's suggested approach. This is a pretty standard pattern to meet this type of requirement. It facilitates addressing most security and control concerns as it separates the "request and monitoring" domain from the execution on. You can use separate identification and authentication for these front-end and back-end services, and formalise their interaction through the data and process models for the interface. – TerryE Jun 15 '12 at 10:48
1

The simplest approach is to use shell_exec for your purpose. It executes a command via shell and returns the complete output as a string, hence you can display it on your website.

If this doesn't suit your purpose, because maybe you want some responses while waiting for the command to finish, check out the other program execution functions available in php (hint: there are a few good comments on the manual pages).

Keep in mind, when evoking commandline scripts this way, generated output will have the file owner, group and permissions of your webserver (p.e. wwwrun or whatever). If parts of your deployment need a separate owner, group and/or file permissions, you have to manually set them either in your scripts or after invoking shell_exec (chmod, chown and chgrp can deal with this in php).

About security: Alot of web-based applications put that kind of function into a separate installation directory, and kindly ask you to remove this directory after installing. I even remember some of them shouting at admins quite persistent unless it is removed. This is an easy way preventing this script being invoked by wrong hands at a wrong time. If your application might need it after installing, then you have to put it into an area where only authorized users have access to (p.e. admin area or something similar).

Bjoern
  • 15,934
  • 4
  • 43
  • 48
1

You can use the Comet web application model to do real time updating of the results page.

For the sudo problem, as a quick and dirty solution I'd use restricted set of commands that the web server can execute without password. Example (add in /etc/sudoers):

apache ALL=(ALL) NOPASSWD: /sbin/service myproject *

which would allow apache to run /sbin/service myproject stop, /sbin/service myproject start and so on.

Take a look at Jenkins, it does the web part nicely, you'll only have to add your scripts in the build.

A better solution would be, as suggested by Aif, to separate the logic. One daemon process waiting for tasks and a web application visualizing the results.

Community
  • 1
  • 1
Doncho Gunchev
  • 2,159
  • 15
  • 21
0

Always use escapeshellarg and escapeshellcmd when executing system commands via PHP for security. It would also be suggested to have the user within a chroot'd directory as limited as possible.

Mike Mackintosh
  • 13,917
  • 6
  • 60
  • 87
0

You seem to have solved the issue of getting stdout and stdin to be outputted to your webpage by using proc_open. Now the problem looks to be executing the script via sudo.

From a security perspective, having a PHP app run a script as root (via sudo) makes me cringe. Having the root password in password.txt is a pretty huge security hole.

What I would do (if possible) is to make whatever changes necessary so that setup.sh can be run by the unix user that is running Apache. (I'm assuming you're running PHP with Apache.) If setup.sh is going to be executed by the webserver, it should be able to run it without resorting to sudo.

If you really need to execute the script as a different user, you may check into suPHP, which is designed to run PHP scripts as a non-standard user.

JonM
  • 450
  • 1
  • 5
  • 8
0

Provide automated sudo rights to a specific user using the NOPASSWD option of /etc/sudoers then run the command with the prefix sudo -u THE_SUDO_USER to have the command execute as that user. This prevents the security hole of giving the entire apache user sudo rights, but also allows sudo to be executed on the script from within apache.

Abandoned Cart
  • 4,512
  • 1
  • 34
  • 41