Change static IP address from PHP script on raspbian - php

I want to change the static IP address for interface eth0 on my raspberry pi 4 from a web page. I am running buster lite 4.19 with no desktop. From what I understand, I need to modify the "static ip_address=" line in the /etc/dhcpcd.conf file to make the change permanent.
I can execute the following command and it works fine until I restart the controller.
ifconfig eth0 192.168.1.10 netmask 255.255.255.0
I found this link which works great from the command line.
Using sed to change ip addresses in dhcpcd.conf file
I attempted to use the exec() command to execute the commands from the php script. The read works fine but the sed operation does not write anything. I am assuming a permissions issue but not sure how to overcome this. I am using the following commands in my code.
$newIPcidr = "192.168.1.10/24";
$cmd = "cat /etc/dhcpcd.conf | grep -e '^static ip_address=' | cut -d= -f2";
$curIP = exec($cmd);
$cmd = "sudo sed -i -e \"s#^static ip_address=" . $curIP . "\b#static ip_address=" . $newIPcidr . "#g\" /etc/dhcpcd.conf";
$output = exec($cmd);
Is there a better way to do this?
Thanks in advance for any help on this!

I think your problem is the generic one of executing a command as root when you are not root.
There are several ways around this:
1/. write a specific script or binary that executes as root.
2/. use sudo and ensure that the pi web identity (www-data) has an entry in the /etc/sudoers file to enable it to execute the command you specify as root, without using a password
3/. change the permissions on the file you want to e.g. group write and make its group www-data. Hmm. I see that mine is netdev. possibly safer then to give it 666 permissions so that its world writable, and leave the group the same.
I think for a quick hack in a protected environment the latter might be easiest.
e.g sudo chmod 666 /etc/dhcpcd.conf and see if that works.
2/. is OK for reasonably secure environments.
I've used 1/. when I want all users to be able to execute something root-ish

Related

Executing a bash script via php

Good day all, I m trying to implement a web interface that will operate my wireless network.
One of the operations is to configure my card into monitor mode. pretty simple, if you run this command:
bash prepareCard.sh wlan0
and the script prepareCard.sh is as follows:
#! /bin/bash
IFACE=$1
ifconfig $IFACE down
iwconfig $IFACE mode monitor
ifconfig $IFACE up
Now I want to execute this script via a php script:
$cmd = shell_exec("bash prepareCard.sh wlan0");
when I check if the card has been set to monitor mode, nothing! it's still in management mode!!
Can you please tell me where did I go wrong?
Assuming the webserver user that is running the script does not have sufficient permissions, you can try this way to fix it:
Use command visudo to edit /etc/sudoers and add this line:
ALL ALL=(root) NOPASSWD: /absolute/path/prepareCard.sh
Make sure to set permissions 700 to the script, so no one else can edit it. Then execute your script with sudo like this:
$cmd = shell_exec("sudo /absolute/path/prepareCard.sh wlan0");
That should execute the script as root without a need to enter a password.
One good way to debug BASH scripts is to set debug mode on (either by passing an -x flag to bash in your shell_exec call, by running set -x, or in the shebang line #!/bin/bash -x). This shows you what's going on during execution of the bash script. In your case, I suggest the first case, since you don't know if the script is even being loaded in the first place.
$cmd = shell_exec("bash -x prepareCard.sh wlan0");
After that, you should have more in your $cmd variable.

Starting mjpg stream from a PHP file with shell_exec

I am trying to start the mjpg process from inside a PHP file on my Raspberry Pi. This is the code I am using in the PHP file.
<?php
//this execution does not work, nor does it echo anything if i try and echo it
$cmd = 'mjpg_streamer -i "/usr/local/lib/input_uvc.so -d /dev/video0 -y -r 640x480 -f 10" -o "/usr/local/lib/output_http.so -p 8090 -w /var/www/mjpg_streamer"';
shell_exec($cmd);
?>
<img src = "http://ip:8090/?action=stream" />
The command works if I execute it directly from the shell and the stream also works in this case, but I want the process to start whenever I access the page, which is not happening right now.
What's the mistake?
The mistake is (almost certainly) due to a permission based problem.
More than likely when you execute the mjpg_streamer library from the CLI you're logged in as someone with sudoer permissions or the like, who can easily execute this.
You must realize that the user who will be making the request to execute the mjpg_streamer library will be the same user that owns the instance of Apache handling the request.
In this scenario, the easiest way to troubleshoot this would be to log into the CLI and then su www-data (likely who owns your instance of apache) and check if you can then run it. If you get a permission denied, then you'll need to change how access to that library is granted. Changing ownership of the library is probably not the best bet, but you could likely get away with modifying the group.

shell_exec not working when excuted from browser | ssh | scp | keygen

What I want to do is:
execute "shellUnlock.php" from browser
then "scriptUNLOCK.sh" executed from the "shellUnlock.php"
then "resultUNLOCK.log" created from the scriptUNLOCK.sh
then show "resultUNLOCK.log" in browser
Notes:
For the SSH i used keygen, so i don't have to insert any password again from my server.
I used the SCP to copy "resultUNLOCK.log" created in "da.serv.er" to my own folder.
I have try it from browser, but it shows no output at all.
The script works well when I execute from putty but from shell_exec it's not work.
And I don't have access to install anything in the server.
my "shellUnlock.php" file
$myfile = fopen("nameUSER.txt", "w") or die("Unable to open file!");
$txt = "USERNAME";
fwrite($myfile, $txt);
fclose($myfile);
shell_exec('./scriptUNLOCK.sh');
if (file_exists("resultUNLOCK.log"))
echo readfile("resultUNLOCK.log");
}else{
echo "Please Try";
}
my "scriptUNLOCK.sh" script
#!/bin/bash
HOST='user#da.serv.er'
HOME='/home/web/UNLOCK'
DIR='/somewhere/script/UNLOCK/'
cd ${HOME}
while read nameUSER
do
ssh ${HOST} <<END_SCRIPT
cd ${DIR}
unlock.sh ${nameUSER} > resultUNLOCK.log
exit
END_SCRIPT
cd ${HOME}
scp ${HOST}:${DIR}resultUNLOCK.log ${HOME}
done < nameUSER.txt
Now please help me. I'm totally confused. Thanks.
If the script works fine when running it from the command line but it doesn't when you trigger it via your webserver it has to be a permission or/and path problem.
Ensure that the apache user (either www-data, www or apache by default) has write access to the UNLOCK folder and I think it will work.
And you should probably change the name of your "HOME" variable since HOME is a fix environment variable in Linux. I don't know if this is a problem, but i would change the name nevertheless to avoid disorder.
Best way would be to make it via groups
sudo usermod -a -G www-data <apache_user>
sudo chgrp -R www-data /somewhere/script/UNLOCK/
sudo chmod -R g+w /somewhere/script/UNLOCK/
So at least the user you use to login via putty must have the rights to modify the accessibility of the directory. If not, you can either contact your system administrator or use another folder you have access on.
I hope this helps.
Kind Regards
My problem solved!
Instead using shell_exec in php, i directly execute the script using crontab.
I'm sure I can find other best solution to solve this case if I have no limited time.
But the time forces me. :D
Well at least IT WORKS!
Thanks all..!

PHP shell_exec - using RSYNC as root without password

I'm trying to create a PHP web interface for a staging->production publishing script. The web interface is secure (intranet,passworded etc) so I am happy to for apache act as the root user to perform the rsync. There is no password for the root user, a keyfile is used for SSH access.
I have tried sudo-ing the rysnc command in the shell script...
sudo rsync --verbose --recursive --times --perms --links --delete /tmp/dir1/* /tmp/dir2/
And allowing apache to run rsync by adding the following to the sudoers file...
apache ALL=(ALL) NOPASSWD:/usr/bin/rsync
I am using PHP shell_exec to invoke the script...
$result = shell_exec('bash /tmp/syncscript.sh 2>&1');
I get the following error...
sorry, you must have a tty to run sudo
How can I setup so I can run the rsync command as though I were the root user?
Thanks!
You might want to try what i wrote in this post if you want to use SUDO from PHP. It solved all my problems and i have a similar setup to yours, i have a DEV server internally but i want it to do things that only root can...
How to use exec() in php in combination with ssh 'hostname' command?
Good luck
In the end went for a non-sudo approach to this problem. Used phpseclib to get a connection to the box as a user that could do what I needed (not apache). And then made sure that the dirs/files that were being targetted in the rsync operation were accessible to this user.
Seems simple now I look back on it.

Sync local and remote folders using rsync from php script without typing password

How can I sync local and remote folders using rsync from inside a php script without beeing prompted to type a password?
I have already set up a public key to automate the login on remote server for my user.
So this is running without any problem from cli:
rsync -r -a -v -e "ssh -l user" --delete ~/local/file 111.111.11.111:~/remote/;
But, when I try to run the same from a PHP script (on a webpage in my local server):
$c='rsync -r -a -v -e "ssh -l user" --delete ~/local/file 111.111.11.111:~/remote/';
//exec($c,$data);
passthru($c,$data);
print_r($data);
This is what I receive:
255
And no file is uploaded from local to remote server.
Searching on the net I found this clue:
"You could use a combination of BASh and Expect shell code here, but it wouldn't be very secure, because that would automate the root login. Generate keys for nobody or apache (whatever user as which Apache is being executed). Alternatively, install phpSuExec, Suhosin, or suPHP so that the scripts are run as the user for which they were called."
Well, I don't know how to "automate the root login" for PHP, which is running as "apache". Maybe to make the script run as the actual user is a better idea, I don't know... Thanks!
UPDATE:
- As this works fine:
passthru('ssh user#111.111.11.111 | ls',$data);
Returning a list of the home foder, I can be sure, there is no problem with the automatic login. It mast be something with rsync running from the PHP script.
I also have chmod -R 0777 on the local and remote folders just in case. But I didn't get it yet.
UPDATE:
All the problem is related to the fact that "when ran on commandline, ssh use the keyfiles on $HOME/.ssh/, but under PHP, it's ran using Apache's user, so it might not have a $HOME; much less a $HOME/.ssh/id_dsa. So, either you specifically tell it which keyfile to use, or manually create that directory and its contents."
While I cannot get rsync, this is how I got to transfer the file from local to remote:
if($con=ssh2_connect('111.111.11.111',22)) echo 'ok!';
if(ssh2_auth_password($con,'apache','xxxxxx')) echo ' ok!';
if(ssh2_scp_send($con,'localfile','/remotefolder',0755)) echo ' ok!';
Local file needs: 0644
Remote folder needs: 0775
I guess if the solution wouldn't be to run php with the same user bash does...
#Yzmir Ramirez gave this suggestion: "I don't think you want to "copy the key somewhere where apache can get to it" - that's a security violation. Better to change the script to run as a secure user and then setup the .ssh keys for passwordless login between servers.
This is something I have to invest some more time. If somebody know how to do this, please, it would be of great help.
When I set this same thing up in an application of ours, I also ran into 255 errors, and found that they can mean a variety of things; it's not a particularly helpful error code. In fact, even now, after the solution's been running smoothly for well over a year, I still see an occasional 255 show up in the logs.
I will also say that getting it to work can be a bit of a pain, since there are several variables involved. One thing I found extremely helpful was to construct the rsync command in a variable and then log it. This way, I can grab the exact rsync command being used and try to run it manually. You can even su to the apache user and run it from the same directory as your script (or whatever your script is setting as the cwd), which will make it act the same as when it's run programmatically; this makes it far simpler to debug the rsync command since you're not having to deal with the web server. Also, when you run it manually, if it's failing for some unstated reason, add in verbosity flags to crank up the error output.
Below is the code we're using, slightly edited for security. Note that our code actually supports rsync'ing to both local and remote servers, since the destination is fully configurable to allow easy test installations.
try {
if ('' != $config['publishSsh']['to']['remote']):
//we're syncing with a remote server
$rsyncToRemote = escapeshellarg($config['publishSsh']['to']['remote']) . ':';
$rsyncTo = $rsyncToRemote . escapeshellarg($config['publishThemes']['to']['path']);
$keyFile = $config['publishSsh']['to']['keyfile'];
$rsyncSshCommand = "-e \"ssh -o 'BatchMode yes' -o 'StrictHostKeyChecking no' -q -i '$keyFile' -c arcfour\"";
else:
//we're syncing with the local machine
$rsyncTo = escapeshellarg($config['publishThemes']['to']['path']);
$rsyncSshCommand = '';
endif;
$log->Message("Apache running as user: " . trim(`whoami`), GLCLogger::level_debug);
$deployCommand = "
cd /my/themes/folder/; \
rsync \
--verbose \
--delete \
--recursive \
--exclude '.DS_Store' \
--exclude '.svn/' \
--log-format='Action: %o %n' \
--stats \
$rsyncSshCommand \
./ \
$rsyncTo \
2>&1
"; //deployCommand
$log->Message("Deploying with command: \n" . $deployCommand, GLCLogger::level_debug);
exec($deployCommand, $rsyncOutputLines, $returnValue);
$log->Message("rsync status code: $returnValue", GLCLogger::level_debug);
$log->Message("rsync output: \n" . implode("\n", $rsyncOutputLines), GLCLogger::level_debug);
if (0 != $returnValue):
$log->Message("Encountered error while publishing themes: <<<$returnValue>>>");
throw new Exception('rsync error');
endif;
/* ... process output ... */
} catch (Exception $e) {
/* ... handle errors ... */
}
A couple of things to notice about the code:
I'm using exec() so that I can capture the output in a variable. I then parse it so that I can log and report the results in terms of how many files were added, modified, and removed.
I'm combining rsync's standard output and standard error streams and returning both. I'm also capturing and checking the return result code.
I'm logging everything when in debug mode, including the user Apache is running as, the rsync command itself, and the output of the rsync command. This way, it's trivially easy to run the same command as the same user with just a quick copy-and-paste, as I mention above.
If you're having problems with the rsync command, you can adjust its verbosity without impact and see the output in the log.
In my case, I was able to simply point to an appropriate key file and not be overly concerned about security. That said, some thoughts on how to handle this:
Giving Apache access to the file doesn't mean that it has to be in the web directory; you can put the file anywhere that's accessible by the Apache user, even on another network machine. Depending on your other layers of security, this may or may not be an acceptable compromise.
Depending on the data you're copying, you may be able to heavily lock down the permissions of the ssh user on the other machine, so that if someone unscrupulous managed to get in there, they'd have minimal ability to do damage.
You can use suEXEC to run the script as a user other than the Apache user, allowing you to lock access to your key to that other user. Thus, someone compromising the Apache user simply would not have access to the key.
I hope this helps.
When you let the web server run the command, it runs it as its own user ("nobody" or "apache" or similar) and looks for a private key in that user's home directory/.ssh, while the private key you setup for your own user is in "/home/you/.ssh/keyfile", or however you named it.
Make ssh use that specific key with the -i parameter:
ssh -i /home/you/.ssh/keyfile
and it should work
A Simple but In-direct solution to this problem is here, which i am using.
DO NOT run rsync directly from php, it does have issues as well as it can be security risk to do so.
Rather, just prepare two scripts.
In php script, you just have to change value of one variable on filesystem from 0 to 1.
Now, on ther other side, make an rsync script, that will run forever, and will have following logic.
""
If the file has 0 in it, then do not run rsync, if it is 1, then run the rsync, then change its value back to 0 after successful run of rsync;
""
I am doing it as well.

Categories