Bash script containing clogin not working when executed via php - php

I created a simple PHP site we would like to use to disable/enable ports on a cisco switch.
I am passing over two arguments (port and action) to a bash script via the php function exec(). For debugging I set those arguments at the end inside the bash script.
The important part of the php function I am calling looks like this:
function PortAction($port, $action){
echo "<hr /> Port:".$port."<br />Action:".$action;
chdir('/usr/local/icinga-1.7.0/videowand/');
echo exec('sh /usr/local/icinga-1.7.0/videowand/action2.sh 2>&1',$output, $return);
echo "Return / Output: ".$return;
print_r($output);
}
The bash script "action2.sh":
#!/bin/bash
/usr/libexec/rancid/clogin -c "conf t; int Fa0/1; shutdown" 192.168.6.6
If i execute the bash script manually (or even the directly the clogin command) as apache user, it all works as expected, the port gets disabled.
But as soon as I call it over the PHP function, I get the output:
Array ( [0] => no such variable [1] => (read trace on "env(HOME)") [2] => invoked from within [3] => "set password_file $env(HOME)/.cloginrc" [4] => (file "/usr/libexec/rancid/clogin" line 66)
And nothing gets done.
Which indicates some problem with the password entry (as far as I can see).
Permissions on this file(s) are correct, I guess they have to otherwise it wouldn't work directly inside the shell.
Even tried to change the .cloginrc path using the -f switch, no success.
PHP Safe-mode: Off
Display errors: On
The script takes a while because a telnet connection needs to be opened. This is why I put this into a separate bash script.

Provide the full path to the sh binary, like this:
echo exec('/bin/sh /usr/local/icinga-1.7.0/videowand/action2.sh 2>&1',$output, $return);
I'm assuming /bin/sh above, as that is commonly the standard path for sh, but make sure with which sh command.
/bin/sh is a soft link to your shell, which usually is /bin/bash, I'm not sure exec() can work with soft links of binaries, so if above doesn't works then just use /bin/bash instead of /bin/sh

Related

Redirecting the output of a shell command using PHP's exec() function

I am trying to redirect the output of a shell command, like so:
# echo here > /tmp/output
I need to do this from inside a PHP script being executed by apache using the exec() function:
var_dump(exec('echo here > /tmp/output')); // string (0) "", no file created
The above command does not create the file and returns with an exit code of 0.
I can verify PHP is able to execute commands using exec, like this:
var_dump(exec('echo here')); // string(4) "here"
I have tried executing this code from inside a php shell running as the apache user, and it works:
# su -s /bin/bash -c 'php -a' apache
php > var_dump(exec('echo here > /tmp/output')); // file is created
I have tried redirecting stderr as well as stdout:
var_dump(exec('echo here 2>&1 /tmp/output')); // string(0) "", no file created
And finally, I have tried redirecting the stderr from the entire command back to exec():
var_dump(exec('echo here > /tmp/output 2>&1')); // string(0) "", no file created
Based on the steps above it seems to me that the issue must be related to apache calling php, since it works fine running from a php shell as the apache user.
Any help is much appreciated!
I figured out my issue. The problem was apache was configured to use private temp directories:
PrivateTmp= Takes a boolean argument. If true, sets up a new file
system namespace for the executed processes and mounts private /tmp
and /var/tmp directories inside it, that are not shared by processes
outside of the namespace. This is useful to secure access to
temporary files of the process, but makes sharing between processes
via /tmp or /var/tmp impossible. All temporary data created by service
will be removed after service is stopped. Defaults to false.
As a result I was looking in the wrong place for the output of my script.

sudo command inside shell script and called by PHP

Background
I have made a PHP web application to execute a Linux Shell Script to change the data in network-scripts of CentOS 7. In other words, this is a PHP web application that can change the IP in CentOS 7.
The script itself is good to change, I can run the script using SSH with proper arguments, the usage like the following:
sh ./ipchanger.sh <fileName> <oldIpAddress> <newIpAddress> <oldSubnetMask> <newSubnetMask> <oldGateway> <newGateway>
Sample usage:
sh ./ipchanger.sh /etc/sysconfig/network-scripts/ifcfg-ens32 192.168.1.5 192.168.1.205 PREFIX0=32 PREFIX0=24 192.168.1.1 192.168.1.1
That will change the IP from 192.168.1.5 to 192.168.1.205 and the subnet mask will be changed from 255.255.255.255 to 255.255.255.0. The gateway will remain unchanged.
PHP Application
The data will be posted from a form processed with PHP. The code will check if the IP addresses are correct or not. If the arguments are collected and correct, my PHP code will call the shell script to make changes to the network-scripts.
Like this:
$retval = exec('sh /var/www/html/ipchanger/ipchanger.sh {$fileName} {$currentIpAddress} {$newIpAddress} {$currentSubnetMask} {$newSubnetMask} {$currentGateway} {$newGateway}');
That means:
$retval = exec('sh /var/www/html/ipchanger/ipchanger.sh /etc/sysconfig/network-scripts/ifcfg-ens32 192.168.1.5 192.168.1.205 PREFIX0=32 PREFIX0=24 192.168.1.1 192.168.1.1');
Shell Scripts
#!/bin/sh
#
# My IP Changer
fileName="$1"
currentIpAddress="$2"
newIpAddress="$3"
currentSubnetMask="$4"
newSubnetMask="$5"
currentGateway="$6"
newGateway="$7"
`sudo sed -i -e "s/$currentIpAddress/$newIpAddress/g" ${fileName}`
`sudo sed -i -e "s/$currentSubnetMask}/$newSubnetMask/g" ${fileName}`
`sudo sed -i -e "s/$currentGateway/$newGateway/g" ${fileName}`
Problem
The file /etc/sysconfig/network-scripts/ifcfg-ens32 doesn't changed at all. If I run the shell script in SSH (refer to sample usage in background chapter), it works! So my shell script should be fine.
Other Trials
1. Put echo in shell script to see if the arguments are in the correct position
Result: Yes.
The arguments showed just like expected.
2. Put 2>&1 behind the exec()
Result: Message showed.
sudo: sorry, you must have a tty to run sudo. I don't know if sed needs root permission or not. So I put it in the shell script anyway to make the shell script execute smoother.
3. Remove sudo in shell script
Result: In SSH, good; In PHP, message showed.
sed: couldn't open temporary file /etc/sysconfig/network-scripts/sedJfDtCD: Permission denied. I googled this message. When using sed -i, it will create a temporary file to store the original file in case the script messed up.
4. Remove -i in sed command in shell script
Result: Failed.
The script cannot perform its task.
Other Information
OS: CentOS
Web server type: LAMP
whoami: apache
Script usage: Internal use. So I don't care about security issues
Please help! Thanks.
not directly for you right problem but i advice to add some security on such file change
and optimize the three last lines with:
`sudo sed -i -e "s/$currentIpAddress/$newIpAddress/g;s/$currentSubnetMask}/$newSubnetMask/g;s/$currentGateway/$newGateway/g" ${fileName}`
the last g of each of your s/// is normaly not necessary (only 1 change by line)
I recently published a project that allows PHP to obtain and interact with a real Bash shell (as user: apache/www-data or root if needed). Get it here: https://github.com/merlinthemagic/MTS
After downloading you would simply use the following code.
//You could maintain your ipchanger.sh script and simply trigger that script
//through the shell, but the point of the shell project is that it lets you
//trigger commands directly. in your case you could do this:
$ifFilePath = '/etc/sysconfig/network-scripts/ifcfg-ens32';
$ifCfg= "DEVICE=ens32";
$ifCfg.= "\nIPADDR=192.168.1.205";
$ifCfg.= "\nPREFIX0=24";
$ifCfg.= "\n192.168.1.1";
$strCmd = "echo \'".$ifCfg."\' > \'".$ifFilePath."\'";
//But if you wanna stick with your script then:
$strCmd = "sh ./ipchanger.sh /etc/sysconfig/network-scripts/ifcfg-ens32 192.168.1.5 192.168.1.205 PREFIX0=32 PREFIX0=24 192.168.1.1 192.168.1.1";
//in either case the $strCmd is triggered like this:
$shell = \MTS\Factories::getDevices()->getLocalHost()->getShell('bash', true);
$return1 = $shell->exeCmd($strCmd);
After the config file change you can then reload the interface config using the same shell:
$return2 = $shell->exeCmd('service network restart');

pushd not changing directory in php on ubuntu 14.04

sorry i posted the wrong code before but this is the question again.
i'm trying to use pushd in an exec from php but the working directory doesn't change. I have got the sample code to a few lines:
<?php
exec('pwd; pushd abc/def/; pwd; popd; pwd; 2>&1', $output);
echo('<pre>');
print_r($output);
the output is
Array
(
[0] => /var/www/html
[1] => /var/www/html
[2] => /var/www/html
)
i would all like to thank you all in advance in an attempt to answer this question
vinaka
Concerning your question:
exec() creates a new process, which has its own working directory, so it doesn't affect the working copy of the process that started it. Just type "change working directory php" into the starting page of your browser and do some research, that shouldn't be too difficult to find out.
Concerning your code:
Not every shell has a pushd builtin. For example, the default /bin/sh on Debian doesn't, but you don't see that because you only capture stdout, not stderr, in spite of your attempts. I'd suggest writing your code in PHP though instead of parsing shell output.
If you would like to change the directory for the currently running PHP process, use
chdir ( $directory )
This returns true/false based on success/failure.
http://php.net/manual/en/function.chdir.php

Running a python script from php with system( ) or even passthru( ) produces no output. Why?

I need to run a python script (a log parser) on hundreds of log files, but I'm a PHP guy so I figured I'd write a little PHP script to grab the list of files from a directory and call the python script dynamically in a foreach loop.
I've set variables in my PHP script using the full system paths to the python binary, the full path to the python script and checked that everything seems correct. I echo the output of the script I'm trying to run to check it over:
<?php
// batch.php (modified for SO post)
$python = '/usr/bin/python';
$script = '/mnt/data/scripts/the/python/script.py';
// $folder contains the full system path to the dir containing
// the files I need to pass as args to script.py
$files = scandir($folder);
foreach($files as $file){
if($file=='..'||$file=='.')
{
continue;
}
$system = $python.' '.$script.' '.$folder.$file.' 2>&1';
echo "Running ". $system ."\n";
// I also tried passthru( )
system($system);
}
Next I do
php batch.php
All I get is the first line from PHP:
Running /usr/bin/python /mnt/data/scripts/the/python/script.py /path/to/data/file/one.log
I can copy, paste and run the output echoed in shell (after 'Running ') directly with python and there's my output, no problem, so I know the PHP script has no syntax problems.
But when running the php script wrapping it, it produces no output other than my echo( ) statement from PHP. It just hangs there (I am thinking that my long-running Python script is actually working, but I'm not sure how to tell.) There's nothing in the error log, and the script never exits until I Ctrl-C.
I've seen a lot of discussions about exec( ), system( ) and passthru( ) and from what I can tell I should be seeing output using system( ) but for some reason I'm not.
I even tried to
root:~# ps aux | grep php
and then
root:~# strace -p <process_id>
of the PHP script, but all I get is
root:~# strace -p 14232
Process 14232 attached - interrupt to quit
read(4,
Note: I added the 2>&1 bit from this question but it didn't help; that references Apache however I'm running PHP on the CLI.
Note:
root:~# echo $PYTHONPATH
in shell produces no output.
What am I missing?
python buffers output by default. If your script terminates prematurely (possibly thanks to a PHP script timeout), the buffer is not flushed.
Call set_time_limit() to extend the timeout, and set environment variable PYTHONUNBUFFERED to a nonempty string, or run python with -u.

PHP + Run bash script to create file

In addition to my previous question, another problem appeared and I decided to make a new question for it:
I am currently calling a php script that than runs a bash script. The php script looks like:
chdir('/home/');
$output = shell_exec('./do.sh');
echo "<pre>$output</pre>";
The do.sh contains:
#! /bin/bash
echo 12;
dd if=/dev/urandom of=test.test bs=1048576 count=2
The problem is following:
When I call ./do.sh from the terminal everything works fine: test.test is created and the ouput is 12
However, when I call it from my php file, the output is 12 aswell, but no file is being created. Since I know almost nothing about bash scripting, I have no idea why this is happening...
Check if PHP safe_mode is enabled. You have to turn it off in your /etc/php.ini file, and obviously check filesystem permissions.

Resources