I have a php file which is called by a website:
example: serial_tx.php?v=W100
Within the php I write a log file where I can see which string v I received (W100 in this case).
The webserver is hosted on a Raspberry Pi and should send this data to the uart.
The files locations:
/SCRIPTS/serial_tx.php
/SCRIPTS/c/jmsend/serial_tx // the executable, compiled from a C script
If I am in the root of the webserver and, from the console of my Pi, I run
sudo /var/www/html/SCRIPTS/c/jmsend/serial_tx W100
I get the command sent correctly.
With the php file I tried with system, shell_exec and exec without success.
shell_exec("sudo /var/www/html/SCRIPTS/c/jmsend/serial_tx ".$ric);
$ric is the received command.
I tried with different path settings too (starting from Pi root or webserver root).
All the files have a 777 as permissions.
Something like this in /etc/sudoers should work to allow your web server user to run that particular command without issue:
Cmnd_Alias SERIAL = /var/www/html/SCRIPTS/c/jmsend/serial_tx *
www-data ALL=(ALL) NOPASSWD: SERIAL
Note that you must escape user input before using it:
$ric = escapeshellarg($_GET["v"]);
shell_exec("sudo /var/www/html/SCRIPTS/c/jmsend/serial_tx $ric");
You should also be aware of the differences between exec() and shell_exec(), specifically that you can't check for a failure using shell_exec().
$ric = escapeshellarg($_GET["v"]);
exec("sudo /var/www/html/SCRIPTS/c/jmsend/serial_tx $ric", $output, $return);
if ($return !== 0) {
// let the user know something didn't work
}
This assumes, of course, that your executable is written to return appropriate error codes.
Related
So I have hosted a webpage on my apache server and I'm trying to run some python and bash scripts when the user presses a button via PHP and AJAX.
Now my php file executes at python script (located in /var/www/html) which in turn executes a bash file (located in root/files).
On doing this manually in terminal, everything works perfectly fine.
But when I try to this via the webpage, the bash script isn't executed.
(I can't place the bash script in /var/www/html because it has the command to clone a git repository to the server and it gives private key shouldn't be public error when placed there)
I already tried suggestions in this answer by adding www-data to sudoers but it is still not working as expected.
Any help on this would be appreciated.
Thanks
PHP file :
if(isset($_POST['timestamp']))
{
$uid = $_POST['timestamp'];
echo "Please wait while the app is being generated".$uid;
exec("python /var/www/html/appgenserver.py $uid");
appgenserver.py
#! /usr/bin/env python
import os
import json,sys
from firebase import firebase
import requests
import subprocess
arg = sys.argv[1]
# Path to be created
path = "/root/files/"+str(arg)
print path
if not os.path.exists(path):
os.makedirs(path) #Gets executed
subprocess.call(['/root/Final/clone.sh', path) #Not getting executed
Most likeley because a bash script in its self won't be executable, it's just a plain textfile.
Your bash (and perhaps even appgenserver.py?) might be located under /root and apache probably runs as a non-priviliged user such as www-data, that user won't be able to access either your python script and in turn not the bash that the python would run.
Consider instead calling bash with the script as a parameter.
#! /usr/bin/env python
import os
import json,sys
from firebase import firebase
import requests
import subprocess
arg = sys.argv[1]
path = "/root/files/"+str(arg)
print path
if not os.path.exists(path):
os.makedirs(path)
subprocess.call(['/bin/bash', '/root/Final/clone.sh', path)
Now, this is NOT the most pretty of solutions.
But what you got before was probably a generic "Permission denied" error in the background (check your /var/log/apache/error.log).
What this does is start /bin/bash as a subprocess with the first parameter being the script you want to execute.
But you have zero error handling here and you can't interract with the process very much.
Consider doing something like this instead:
import subprocess
handle = subprocess.Popen(['/bin/bash', '/root/Final/clone.sh', 'parameter'], stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT)
while handle.poll() is None:
print(handle.stdout.read()) # There's some optimizations here to be done as well so it's not a blocking call etc.
handle.stdout.close()
handle.stdin.close()
And one last tip is not to place stuff in /root/ at all if you're integrating it into a web front-end/backend type of thing.
You're asking for trouble : )
Another way is to make use of sudo
If you modify your exec() in PHP to run exec("sudo ...") and enable your web-user to run the scripts without a password prompt it could work.
Bare in mind, it's not recommended to give www-data sudo access, rather do something like this:
# useradd -m -G www-data -s /bin/bash wwwexec
# echo "myuser ALL=NOPASSWD: /usr/bin/python" >> /etc/sudoers
and change your PHP script to have the following:
exec("sudo -u wwwexec python /var/www/html/appgenserver.py $uid");
That way at least your entire web service isn't given root access via the default username.
The way to do it
Would be to place your appgenserver.py under /var/www/cgi-bin/ instead, and create a CGI hook for .py in your apache configuration and hand over the user to the URL prividing you access to the CGI script.
That way everything should be according to best practices even tho, in theory, you could get your original solution to work.
For instance, this guide should get you started.
I'm new in using Linux, I'm trying to write a PHP code which can run .exe linux compatible file, I've made a short shell script
hello bash script:
#!/bin/bash
./program.exe file.mp4 // file.mp4 is an an input for .exe
echo "Hello World!"
shell.php:
<?php
$output = exec ("./hello ");
echo "<pre>$output</pre>";
?>
Now when I run shell.php using web browser it shows Hello World! but the .exe doesn't run, however when I run php using terminal command php shell.php, It works fine.
I think I'm having problems with permissions but I'm new with Linux and I don't know how to solve this.
Update:
I ignored the shell script and I used
<?php
$output = shell_exec ("cd /var/www/ && ./program.exe file.mp4 2>& " );
?>
also I granted access to program.exe
chmod 777 program.exe
the error I receive in the browser :could not open debug.bin!
use the absolute path to hello executable exec("sh path/to/the/file")
I'm using something similar to call an app compiled with mono on a remote ubuntu webserver and return it's output to the calling script.
For any of this to work properly wine needs to be already installed.
On Ubuntu systems try:
sudo apt-get -y install wine
You then need to know the owner of the web server process. If you are running the apache web server try the following:
cat /etc/apache2/envvars | grep "RUN"
The output will look something like this:
export APACHE_RUN_USER=www-data
export APACHE_RUN_GROUP=www-data
export APACHE_RUN_DIR=/var/run/apache2$SUFFIX
Now that you have the name of the process owner, which in this case is www-data you should ensure the file is owned the user and its group:
sudo chown www-data /var/www/program.exe
sudo chgrp www-data /var/www/program.exe
Finally, we can invoke the application from inside our PHP script by passsing it as a parameter to 'wine' and using its full file path.
<?php
$output = shell_exec("wine /var/www/program.exe file.mp4" );
?>
Any output from the above shell command sent to the command line will be saved in the PHP script variable $output.
It looks like you are trying to do some output redirection with your use of program.exe file.mp4 2>& so I've left that off of the example for clairity.
Try using the absolute path, such as exec("sh /path/to/file")
Generally, php is run as www or apache, so make sure that the execute access permission is granted to all user.
I have a C program that makes a system call (centOS 6.0) to encrypt a file, my code is:
#include <stdlib.h>
int main () {
system ("gpg -c --batch --passphrase mypass file.txt");
return 0;
}
The executable object is called encrypt_file
When I run ./encrypt_file directly through CLI it runs perfectly I obtain my file.txt.gpg, but when I try to execute it via browser I get no response.
Code in php:
shell_exec("./encrypt_file");
The reason I chose to make a c program is that I need the passphrase to be in the code but not visible, when I delete the .c file that contains the passphrase all I have left is my .exe and no visible passphrase.
I already changed permissions to apache user by issuing the following:
chown apache.apache /var/www/html/
And added the next line in /etc/sudoers:
apache ALL=(ALL) NOPASSWD:ALL
NOTE: The only command I have issues is gpg, I can make a system call with any other command that I needed to use, I can even run python scripts, and other C programs that doesn't contain anything related to gpg.
I hope a fast reply! I need to use a lot this encrypt_file!
Checking the error_log in /var/log/httpd/error_log I saw this line:
gpg: Fatal: can't create directory `/var/www/.gnupg': Permission denied
Then I found a solution at this site -> http://gnupg.10057.n7.nabble.com/Exi...pt-td7342.html
I added the --homedir option with the PATH that I found in the error.log of apache to the gpg command and it works perfectly!
Thanks to all!
I have a script in /var/www/myscript.sh which creates folders and runs the command svn update for my projects. I need to execute this script by calling it in a PHP file in the browser (i.e. Localhost/test.php). I tried using functions shell_exec() and exec() but those did not work. I ran my shell script in terminal with su www-data && ./myscript.sh and it worked. What else am I missing?
<?php
$output = shell_exec("./myscript.sh");
?>
Update 5/4/2011:
I added www-data ALL=(ALL) NOPASSWD:ALL to /etc/sudoers and it works, but this is very insecure. Is there another way to do this?
Several possibilities:
You have safe mode enabled. That way, only exec() is working, and then only on executables in safe_mode_exec_dir
exec and shell_exec are disabled in php.ini
The path to the executable is wrong. If the script is in the same directory as the php file, try exec(dirname(__FILE__) . '/myscript.sh');
You might have disabled the exec privileges, most of the LAMP packages have those disabled. Check your php.ini for this line:
disable_functions = exec
And remove the exec, shell_exec entries if there are there.
Good Luck!
Residuum did provide a correct answer to how you should get shell exec to find your script, but in regards to security, there are a couple of points.
I would imagine you don't want your shell script to be in your web root, as it would be visible to anyone with web access to your server.
I would recommend moving the shell script to outside of the webroot
<?php
$tempFolder = '/tmp';
$webRootFolder = '/var/www';
$scriptName = 'myscript.sh';
$moveCommand = "mv $webRootFolder/$scriptName $tempFolder/$scriptName";
$output = shell_exec($moveCommand);
?>
In regards to the:
i added www-data ALL=(ALL) NOPASSWD:ALL to /etc/sudoers works
You can modify this to only cover the specific commands in your script which require sudo. Otherwise, if none of the commands in your sh script require sudo to execute, you don't need to do this at all anyway.
Try running the script as the apache user (use the su command to switch to the apache user) and if you are not prompted for sudo or given permission denied, etc, it'll be fine.
ie:
sudo su apache (or www-data)
cd /var/www
sh ./myscript
Also... what brought me here was that I wanted to run a multi line shell script using commands that are dynamically generated. I wanted all of my commands to run in the same shell, which won't happen using multiple calls to shell_exec(). The answer to that one is to do it like Jenkins - create your dynamically generated multi line of commands, put it in a variable, save it to a file in a temp folder, execute that file (using shell_exec in() php as Jenkins is Java), then do whatever you want with the output, and delete the temp file
... voila
If you are having a small script that you need to run (I simply needed to copy a file), I found it much easier to call the commands on the PHP script by calling
exec("sudo cp /tmp/testfile1 /var/www/html/testfile2");
and enabling such transaction by editing (or rather adding) a permitting line to the sudoers by first calling sudo visudo and adding the following line to the very end of it
www-data ALL=(ALL) NOPASSWD:/bin/cp /tmp/testfile1 /var/www/html/testfile2
All I wanted to do was to copy a file and I have been having problems with doing so because of the root password problem, and as you mentioned I did NOT want to expose the system to have no password for all root transactions.
I don't know what the deal is here…
So I want to run an applescript: sudo osascript myscript.scpt
This works fine in the terminal, but not when I execute it via PHP's exec(); nothing happens. The console says
no tty present and no askpass program specified ; TTY=unknown ; …
I did my research, and it seems I'm missing the password for the sudo command. I tried a couple different ways to get around this, including:
writing %admin ALL=(ALL) ALL in /etc/sudoers
and proc_open() instead of exec()
none of which seem to be working, consequently driving me CrAzY!
So basically, is there a clear-cut way to get PHP to execute a simple terminal command?
EDIT: to clarify, myscript.scpt is a simple appleScript that changes the onscreen UI (for a larger project). In theory, simply osascript myscript.scpt should be enough, however the sudo is for some reason necessary to invoke some response from the system. If the sudo could be somehow eliminated, I don't think I would be having this permissions problem.
It sounds like you need to set up passwordless sudo. Try:
%admin ALL=(ALL) NOPASSWD: osascript myscript.scpt
Also comment out the following line (in /etc/sudoers via visudo), if it is there:
Defaults requiretty
I think you can bring specific access to user and command with visudo something like this:
nobody ALL = NOPASSWD: /path/to/osascript myscript.scpt
and with php:
#exec("sudo /path/to/osascript myscript.scpt ");
supposing nobody user is running apache.
php: the bash console is created, and it executes 1st script, which call sudo to the second one, see below:
$dev = $_GET['device'];
$cmd = '/bin/bash /home/www/start.bash '.$dev;
echo $cmd;
shell_exec($cmd);
/home/www/start.bash
#!/bin/bash
/usr/bin/sudo /home/www/myMount.bash $1
myMount.bash:
#!/bin/bash
function error_exit
{
echo "Wrong parameter" 1>&2
exit 1
}
..........
oc, you want to run script from root level without root privileges, to do that create and modify the /etc/sudoers.d/mount file:
www-data ALL=(ALL:ALL) NOPASSWD:/home/www/myMount.bash
dont forget to chmod:
sudo chmod 0440 /etc/sudoers.d/mount
I recently published a project that allows PHP to obtain and interact with a real Bash shell. Get it here: https://github.com/merlinthemagic/MTS
The shell has a pty (pseudo terminal device, same as you would have in i.e. a ssh session), and you can get the shell as root if desired. Not sure you need root to execute your script, but given you mention sudo it is likely.
After downloading you would simply use the following code:
$shell = \MTS\Factories::getDevices()->getLocalHost()->getShell('bash', true);
$return1 = $shell->exeCmd('/path/to/osascript myscript.scpt');
Run sudo visudo command then set -%sudo ALL=(ALL:ALL) to %sudo ALL=(ALL:ALL) NOPASSWD: ALL it will work.
I had a similar situation trying to exec() a backend command and also getting no tty present and no askpass program specified in the web server error log. Original (bad) code:
$output = array();
$return_var = 0;
exec('sudo my_command', $output, $return_var);
A bash wrapper solved this issue, such as:
$output = array();
$return_var = 0;
exec('sudo bash -c "my_command"', $output, $return_var);
Not sure if this will work in every case. Also, be sure to apply the appropriate quoting/escaping rules on my_command portion.
The best secure method is to use the crontab. ie Save all your commands in a database say, mysql table and create a cronjob to read these mysql entreis and execute via exec() or shell_exec(). Please read this link for more detailed information.
killProcess.php
I think directly calling a sudo command might be difficult because you are setting up the whole server to work without a password.
Perhaps as an alternative you could setup a CRONjob as root and monitor a flag file. Once the flag file exists it will run the osascript myscript.scpt and then delete the flag file.
This way you will keep SUDO secure from a config point of view and the server safer. To run the script you just need to touch the flag file from PHP.
It would of course introduce a delay of however many minutes you running the CRON job. It would also mean that you would have to redirect the output to a file and have a async monitor of the output, but it will depend on your application if this is a problem or not.
But it is an alternative that might protect the server.