executing an ssh command in php via exec -ssh key issue - php

I have a bit of code that runs on the remote server fine but will not run on my local php instance.
private function serverCmd($server, $cmd, $exec = false) {
$line = system("whoami");
print($line."\n");
$localCmd = 'ssh -o StrictHostKeyChecking=no myuser#uk-staging.internal.myhost.com "mkdir -p /home/deploy/backups/etl; rm -f /home/deploy/backups/etl/*.gz; rm -f /home/deploy/backups/etl/*.csv; sudo chown myhost:mysql /home/deploy/backups/etl"';
for ($retry = 0; $retry < 10; $retry++) {
if ($exec) {
$output = array();
exec($localCmd, $output, $retval);
if ($retval === 0) return $output;
}
else {
system($localCmd, $retval)
if ($retval === 0) return true;
}
sleep(1);
}
return false;
}
The issue is with the this line : system($localCmd, $retval).
if i run the ssh command directly on my ubuntu shell it works but if php trys to run it via that line it just hangs and I get the following error on the server its trying to ssh into :
sshd[10203]: Postponed keyboard-interactive for my user sshd[10202]: error: PAM: Authentication failure for myuser.
My dev machine has ssh keys setup to that I can just ssh in without entering a password. I assumed that php would use the same as its using my user.
How do I make sure php is using the same keys and authentication methods to ssh in as my shell? This is a cli script
Anybody got any ideas?

Related

How to run Fast lane in terminal using php? exec() or shell_exec()

i was trying run fast lane commands in terminal using php, the commands like cd, pwd, ls and chmod working fine in php using exec or shell exec functions but when i try to run fast lane command it throws error 127, how can i run fast lane using php?
function terminal($command)
{
$output = [];
$return_var = '';
//exec
if (function_exists('exec')) {
exec($command, $output, $return_var);
} else {
$output = 'Command execution not possible on this system';
$return_var = 1;
}
return array('output' => $output, 'status' => $return_var);
}
// $path = "cd /Applications/XAMPP/xamppfiles/htdocs/mystudiomobile/cordova7/platforms/ios/fastlane";
// $path_c = "fastlane init"; path and path_c present in test.sh
$command = "/Applications/XAMPP/xamppfiles/htdocs/php1/test.sh";
$path_change = terminal("$command");
if($path_change['status'] == 0)
{
echo json_encode($path_change['output']);
echo $path_change['status'];
}
else
{
echo "some problem";
echo $path_change['status'];
}
I found out that there are limitations in php to perform http and https protocols using system functions like exec. which could not run fast lane, the best practise is to go with bash script which access php instead of vice versa .

Running Google Chrome headless with PHP exec doesn’t return output till IIS restarted

My environment is Windows Server 2016 and IIS 10. In my PHP script I’m trying to run Google Chrome in a headless mode to get html code of an external web page:
<?php
$chromeApp = "C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe";
$command = "\"$chromeApp\" --headless --disable-gpu \
--dump-dom $urladdress > page.html";
exec ($command);
?>
That code works if I run
>C:\php script.php
from the Command line. It also works if I run the actual command:
>"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" \
--headless --disable-gpu --dump-dom https://google.com > page.html
But if I run that script from a browser it creates empty page.html file and hungs till timeout. However if I restart IIS during its execution I get the page.html file filled with the needed data.
What could be a problem here?
this is not an answer, but too much to put in a comment, exec() doesn't really give much feedback,
first don't do this:
$command = "\"$chromeApp\" ";
because different shells can't agree on how stuff should be quoted, so you should use the escapeshellarg() function instead, also don't do this
--dump-dom $urladdress > page.html
because $urladdress may need to be escaped (and if hackers are able to control your $urladdress, then this is actually an arbitrary code execution vulnerability), do this instead:
$command = escapeshellarg($chromeApp)." --headless --disable-gpu \
--dump-dom ".escapeshellarg($urladdress)." > page.html";
(and if your page.html may have names with special characters too, you should run that name through escapeshellarg() as well.)
but replace exec() with proc_open, tell me what you get from running this:
<?php
declare(strict_types=1);
$urladdress="http://google.com";
$chromeApp = _cygwinify_filepath("C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe");
$command = escapeshellarg($chromeApp)." --headless --disable-gpu --dump-dom ".escapeshellarg($urladdress);
$descriptorspec = array(
0 => array("pipe", "rb"), // by default stdin is inherited, we don't want that so we create a stdin pipe just so we can fclose() it.
1 => array("pipe", "wb"), // stdout
2 => array("pipe", "wb"), // stderr
);
$proc=proc_open($command,$descriptorspec,$pipes);
if(!$proc){
throw new \RuntimeException("failed to create process! \"{$command}\"");
}
$stdout="";
$stderr="";
$fetch=function()use(&$stdout,&$stderr,&$pipes){
$tmp=stream_get_contents($pipes[1]);
if(is_string($tmp) && strlen($tmp) > 0){
$stdout.=$tmp;
}
$tmp=stream_get_contents($pipes[2]);
if(is_string($tmp) && strlen($tmp) > 0){
$stderr.=$tmp;
}
};
fclose($pipes[0]);
$status=array();
while(($status=proc_get_status($proc))['running']){
$fetch();
}
$fetch();
fclose($pipes[1]);
fclose($pipes[2]);
proc_close($proc);
var_dump($stdout,$stderr,$status);
function _uncygwinify_filepath(string $path) : string
{
static $is_cygwin_cache = null;
if ($is_cygwin_cache === null) {
$is_cygwin_cache = (false !== stripos(PHP_OS, "cygwin"));
}
if ($is_cygwin_cache) {
return trim(shell_exec("cygpath -aw " . escapeshellarg($path)));
} else {
return $path;
}
}
function _cygwinify_filepath(string $path) : string
{
static $is_cygwin_cache = null;
if ($is_cygwin_cache === null) {
$is_cygwin_cache = (false !== stripos(PHP_OS, "cygwin"));
}
if ($is_cygwin_cache) {
return trim(shell_exec("cygpath -a " . escapeshellarg($path)));
//return "/cygdrive/" . strtr($path, array(':' => '', '\\' => '/'));
} else {
return $path;
}
}
edit: i wrote use(&$stdout,$stderr,&$pipes) instead of use(&$stdout,&$stderr,&$pipes), sorry, fixed. re-run it if you just ran it without this fix.
You have 4 processes in play here.
W3WP.exe
PHP.exe
CMD.exe
Chrome.exe
CMD.exe is taking the output of Chrome.exe and piping it to your file. It will do that upon completion of Chrome.exe or may do it partially intermittently. When I run similar code to yours above, my Chrome.exe does not finish. I can see Chrome.exe still running in TaskManager consuming 25% CPU (100% on one of my cores).
I'm guessing restarting IIS somehow forces the flush in progress of the commands. In most of my cases, there was data inside the page.html file prior to doing IISReset, thought not all of it. (Windows Explorer showed 0KBs, but opening the file showed data in the file nonetheless).
As for things to try, try at --no-sandbox as an argument as that may be interfering since the process is running under a non-interactive session.

How is the main process running after return in PHP and Shell

I am new to daemons and shell script.
I have followed a tutorial to run a PHP file as a service.
Here is the code. I did chmod a+x on both the /etc/init.d/daemon and the /home/user/Work/Daemon.php files.
Here is the code of the bash file daemon. The problem that I am facing is that, when I do a sudo service daemon start, it just prints Starting Program Name: and does not close it(i.e. I have to do a ctrl+c to close it). When I check the log that the PHP file it printing, it does show that the PHP file was running when the command was given.
#!/bin/bash
#
# /etc/init.d/Daemon
#
# Starts the at daemon
#
# chkconfig: 345 95 5
# description: Runs the demonstration daemon.
# processname: Daemon
# Source function library.
. /etc/init.d/functions
#startup values
log=/var/log/Daemon.log
#verify that the executable exists
test -x /home/user/Work/Daemon.php || exit 0RETVAL=0
#
# Set prog, proc and bin variables.
#
prog="Program Name"
proc=/var/lock/subsys/Daemon
bin=/home/user/Work/Daemon.php
start() {
# Check if Daemon is already running
if [ ! -f $proc ]; then
echo -n $"Starting $prog: "
daemon $bin --log=$log
RETVAL=$?
[ $RETVAL -eq 0 ] && touch $proc
echo
fi
return $RETVAL
}
stop() {
echo -n $"Stopping $prog: "
killproc $bin
RETVAL=$?
[ $RETVAL -eq 0 ] && rm -f $proc
echo
return $RETVAL
}
restart() {
stop
start
}
reload() {
restart
}
status_at() {
status $bin
}
case "$1" in
start)
start
;;
stop)
stop
;;
reload|restart)
restart
;;
condrestart)
if [ -f $proc ]; then
restart
fi
;;
status)
status_at
;;
*)
echo $"Usage: $0 {start|stop|restart|condrestart|status}"
exit 1
esac
exit $?
exit $RETVAL
And here is the code of Daemon.php
#!/usr/bin/php
<?php
while(true){
file_put_contents('/var/log/Daemon.log', 'Running...', FILE_APPEND);
sleep(1);
}//end while
?>
UPDATE
I changed the PHP file to the following code, and it stared working. The daemon was expecting a return. But I don't understand why it goes to the main process block in PHP after the return. Could someone please explain it?
New Code.
#!/usr/bin/php
<?php
$log = '/var/log/vb_q.log';
//fork the process to work in a daemonized environment
file_put_contents($log, "Status: starting up.n", FILE_APPEND);
$pid = pcntl_fork();
if($pid == -1){
file_put_contents($log, "Error: could not daemonize process.n", FILE_APPEND);
return 1; //error
}
else if($pid){
return 0; //success
}
else{
//the main process
while(true){
file_put_contents($log, 'Running...', FILE_APPEND);
sleep(1);
}//end while
}//end if
?>
But I don't understand why it goes to the main process block in PHP
after the return. Could someone please explain it?
It does not go to the main process block after the return. The $pid = pcntl_fork() creates a child process; now there are two processes executing this same code:
the parent, where $pid is the ID of the child process, executes the block
else if($pid){
return 0; //success
}
and after the return the Daemon.php program terminates (which causes your shell script's start() function to resume)
the child, where $pid is 0, executes the block you call main process
else{
//the main process
while(true){
file_put_contents($log, 'Running...', FILE_APPEND);
sleep(1);
}//end while
}//end if
where it did not go after a return, but just thru the if … else.
It sounds like your bash script is running the php process alright, but it is running in the foreground and the bash script is waiting for it to end before it continues. Since the php script runs forever, try adding an ampersand after the command like this: daemon $bin --log=$log & to make your php process run in the background.
Try adding a running user to your daemon so that it runs with appropriate privileges instead of root.
Additionally move your touch $proc above the daemon start. To ensure it is able to create the lock file prior to starting the daemon.
The stop command looks identical to mine.
eg:
start(){
if [ ! -f $proc ]; then
echo -n "Starting $prog: "
touch $proc
daemon --user=apache --log=$log $bin
RETVAL=$?
[ $RETVAL -ne 0 ] && rm $proc
echo
else
echo -n "$prog is already running"
echo
fi
return $RETVAL
}
Also you can test your lock file to ensure you are able to access it.
. /etc/init.d/functions
#startup values
log=/var/log/Daemon.log
prog="Program Name"
proc=/var/lock/subsys/Daemon
bin=/home/user/Work/Daemon.php
if [ ! -w /var/lock/subsys ]; then
echo -n "You do not have permissions to run this service"
echo
exit 0
fi
if [ ! -x $bin ]; then
echo $bin is not executable!
echo
exit 0
fi
RETVAL=0
Update
PHP scripts are not meant to run as a normal service.
In order to control it you have to fork it for the service to continue running and allow the parent PHP process to close the script, rather than in the current thread that called it. See: http://man7.org/linux/man-pages/man3/daemon.3.html#RETURN_VALUE
For example launch a service - service never returned that it started or errored, since it is in a while loop.
You should additionally check for your child process and ensure it is assigned as a main process (session leader), after it has been forked as well. Otherwise the calling process remains the leader.
if ($pid == -1) {
return 1; //return error to service
} elseif ($pid) {
//parent process - break out of it
return 0;
} else {
/* child Process - run by calling pcntl_fork */
try {
if (posix_setsid() < 0) {
return; //error assigning a session id
}
$sid = posix_getpid(); //retrieve current process name
//... Your Code Here
} catch(\Exception $e) {
return 1;
}
}
See: http://linux.die.net/man/2/setsid

How to get pid of the process that run in background exec by shell in php

I'm working on a shell in php, and I want to display the same output as bash. When in bash you execute sleep 10 & you'll get [1] <PID>. How can I do the same in php, when I call shell using:
if (preg_match("/&\s*$/", $command)) {
$this->$shell_fn($token, '/bin/bash -c ' . escapeshellarg($command) .
" > /dev/null");
return array(
'output' => '',
'cwd' => $path
);
}
$shell_fn is variable that point to wrapper over shell_exec, exec or cgi script called by curl. Is it even possible to get the pid from php or using a shell?
If you want the pid in bash, you can do use the ! special parameter to get the pid of the most recently backgrounded process:
bash -c 'sleep 10 & echo $!'
I don't know exactly how php spawns external processes, but I imagine you'd be able to capture the echo output here, just by running the above shell command.
I use this functions to manage process:
function ProcessStart($cmdline) // return pid
{
exec( "nohup $cmdline >/dev/null 2>&1 & echo $!", $output) ;
// print_r ($output);
return (int)$output[0];
}
function ProcessStatus($pid) // return TRUE (live) o FALSE (dead)
{
exec("ps -p $pid",$output);
// print_r($output);
return ( isset($output[1]) ? TRUE : FALSE ) ;
}
function ProcessStop($pid)
{
exec("kill $pid",$output); // kill -9 ??
}

can't download file using wget with authentication while being called from php

I've created a small remote download script which downloads remote files to my server using wget.
Now here's how it works:
I have a html form, which the user can enter the URL, destination file name, and optionally username and password to authenticate, in case needed.
The form calls a php script, using AJAX, and the php script passes the information to a shell script.
Now the problem is, the shell script works flawlessly on my local linux machine, but on my server, it doesn't work with authentication(without authentication, it works just fine.)
#!/bin/bash
if test $# -eq 2
then
wget -O "$2" $1
elif test $# -eq 4
then
wget -O "$2" --http-user="$3" --http-password="$4" $1
else
wget $1
fi
it might be worth mentioning that, I own a shared server.
Thanks
EDIT:
Is it possible that the version of wget installed on the server, doesn't support http authentications???
EDIT 2:
I piped the output of wget to a file like this:
wget -O "$2" --http-user="$3" --http-password="$4" $1 | echo >> output
but the output is empty, i.e. no messages is being printed from wget!!!
And I did this too, to check if the credentials passed is ok:
echo "$3 | $4" >> credentials
And it was ok.
And this is the php code which runs the shell script:
if(isset($_POST["startdownload"]))
{
list($url, $dest, $user, $pass) = explode("|", urldecode($_POST["data"]));
$filelen = file_len($url);
$freespace = getRemainingSpace();
//die( "( Free: $freespace, File: $filelen )" );
if($filelen > $freespace - 10000)
{
$result = json_encode(array("error" => true,
"message" => "There is not enough space to download this file. ( Free: $freespace, File: $filelen )"));
die($result);
}
else
{
if($user != "NULL" && $pass != "NULL")
{
execInBackground("../dl.sh '{$url}' '../{$dest}' '{$user}' '{$pass}'| at now");
}
else
{
execInBackground("../dl.sh '{$url}' '../{$dest}' | at now");
}
$result = json_encode(array("error" => false, "message" => "Starting download..."));
die($result);
}
}
function execInBackground($cmd)
{
if (substr(php_uname(), 0, 7) == "Windows"){
pclose(popen("start /B ". $cmd, "r"));
}
else {
exec($cmd . " > /dev/null &");
}
}
Well, running this script via system/exec/shell_exec or any others, probably going to "block" the rest of the PHP script anyway. But as an answer, check out this: http://www.zarafa.com/wiki/index.php/Using_wget_and_HTTP_authentication_for_supported_downloads
wget -O "$2" --user="$3" --ask-password="$4" $1

Categories