Linux screen managment on root through php user - php

I want to make a script that would run something in screen on root user. This has to be done through php system() function therefore I need to find out way to sudo to root and pass a password, all using PHP.

If you really need to sudo from PHP (not recommended), it's best to only allow specific commands and not require password for them.
For example, if PHP is running as the apache user, and you need to run /usr/bin/myapp, you could add the following to /etc/sudoers (or wherever sudoers is):
apache ALL = (root) NOPASSWD:NOEXEC: /usr/bin/myapp
This means that user apache can run /usr/bin/myapp as root without password, but the app can't execute anything else.

I'm sure there must be a better way to do whatever it is you're trying to accomplish than whatever mechanism you're trying to create.
If you simply want to write messages from a php script to a single screen session somewhere, try this:
In php
Open a file with append-write access:
$handle = fopen("/var/log/from_php", "wb");
Write to your file:
fwrite($handle, "Sold another unit to " . $customer . "\n");
In your screen session
tail -F /var/log/from_php
If you can't just run tail in a screen session, you can use the write(1) utility to write messages to different terminals. See write(1) and mesg(1) for details on this mechanism. (I don't like it as much as the logfile approach, because that is durable and can be searched later. But I don't know exactly what you're trying to accomplish, so this is another option that might work better than tail -F on a log file.)

Related

why is my "at job" not executing my php script when created through a php webpage?

$output = shell_exec('echo "php '.$realFile.'" | at '.$targTime.' '.$targDate.' 2>&1');
print $output;
Can someone please help me figure out why the above line isn't doing what it's supposed to be doing? The idea is for it to create an 'at' job that will execute a php script. If I switch to the user apache(which will ideally control the at function when the php file is complete) I can run
echo "php $realFile.php" | at 00:00 05/30/17
and it'll do EXACTLY what I want. The problem is in the above snippet from my php file it will not create the at job correctly. when I do a at -c job# on both of them the job made from my file is about a 3rd the length missing the User info and everything. It basically starts at PATH= and goes down. Doesn't include HOSTNAME=, SHELL=, SSH_CLIENT=, SSH_TTY=, USER=. I assume it needs most of this info to run correctly. The end output (below)is always the same though it just doesn't have any of the top part for some reason. Let me know if you need more info. I didn't want to paste all of my code here as it contains job specific information.
${SHELL:-/bin/sh} << 'marcinDELIMITER0e4bb3e8'
php "$realFile".php
marcinDELIMITER0e4bb3e8
It doesn't seem to be a permission issue because I can su to apache and run the exact command needed. The folder the files are located in are also owned by apache. I've also resulted to giving each file I try to run 777 or 755 permissions through chmod so I don't think that's the issue.
I figured out a coupe ways around it a while back. The way I'm using right now is an ssh2 connect to my own server as root and creating it that way. No compromise as you have to enter the password manually each time. Really bad work around. The main issue is that apache doesn't have the correct permissions to do everything needed for the AT job so someone figuring that out would be awesome. Another option I found on a random webpage would be to use sudo through the php script, but basically the same minus having to reconnect to your own server. Any other options would be appreciated.
Reading the manual and logs would be a good place to start. In particular:
The value of the SHELL environment variable at the time of at invocation will determine which shell is used to execute the at job commands. If SHELL is unset when at is invoked, the user’s login shell will be used; otherwise, if SHELL is set when at is invoked, it must contain the path of a shell interpreter executable that will be used to run the commands at the specified time.
Other things to check are that the user is included in at.allow, SELinux is disabled and the webserver is not running chrrot.

Don't want php script to execute the shell command as apache user when it is executed through browser?

I have created a PHP script that generates some .gz files, when I execute the PHP script through command line (cli), it generate the .gz file having 'desert' as user but when the script is executed through browser it generates the .gz file with 'nobody' as user which should not happen. I want the generated file to have 'desert' user rather than 'nobody' user when the script is executed through browser.
Here is the code I have created:
$file='test';
$newFileGZipCommand = 'cat '.$file.'_new | gzip > '.$file.'.gz';
//$newFileGZipCommand = 'sudo -u desert cat '.$file.'_new | gzip > '.$file.'.gz'; // This does not work
$newFileGZipCommandExecute = shell_exec($newFileGZipCommand);
//chmod($file.'.gz',0777) or die("Unable to change file permission");
//chown($file.'.gz', 'directu') or die("Unable to change file Owner");
I tried doing changing the file permissions and owner through chmod() and chown() functions in php but it say "chown(): operation not permitted".
Any pointer to this is highly appreciated.
[Note: I cannot change the httpd.conf or any other configuration files]
Sudo normally requires an interactive shell to enter your password. That's obviously not going to happen in a PHP script. If you're sure you know what you're doing and you've got your security issues covered, try allowing the Apache user to run sudo without a password, but only for certain commands.
For example, adding the following line in your sudoers file will allow Apache to run sudo without a password, only for the gzip command.
nobody ALL=NOPASSWD: gzip
Adjust the path and add any arguments to suit your needs.
Caution:
There might still be complications due to the way PHP calls shell
commands.
Remember that it's very risky to allow the web server to
run commands as root!
Another alternative:
Write a shell script with the suid bit to make it run as root no matter who calls it.
Probably a better alternative:
Write the commands to a queue and have cron pick them up, validate them (only allow known good requests), and run them, then mark that queue complete with the date and result.
Your end-user can then click/wait for update using ajax.
Hope it helps resolve your answer.

SSH connections with PHP

I'm currently working on a project to make changes to the system with PHP (e.g. change the config file of Nginx / restarting services).
The PHP scripts are running on localhost. In my opinion the best (read: most secure) way is to use SSH to make a connection. I considering one of the following options:
Option 1: store username / password in php session and prompt for sudo
Using phpseclib with a username / password, save these values in a php session and prompt for sudo for every command.
Option 2: use root login
Using phpseclib with the root username and password in the login script. In this case you don't have to ask the user for sudo. (not really a safe solution)
<?php
include('Net/SSH2.php');
$ssh = new Net_SSH2('www.domain.tld');
if (!$ssh->login('root', 'root-password')) {
exit('Login Failed');
}
?>
Option 3: Authenticate using a public key read from a file
Use the PHP SSHlib with a public key to authenticate and place the pubkey outside the www root.
<?php
$connection = ssh2_connect('shell.example.com', 22, array('hostkey' => 'ssh-rsa'));
if (ssh2_auth_pubkey_file($connection, 'username', '/home/username/.ssh/id_rsa.pub', '/home/username/.ssh/id_rsa', 'secret')) {
echo "Public Key Authentication Successful\n";
} else {
die('Public Key Authentication Failed');
}
?>
Option 4: ?
I suggest you to do this in 3 simple steps:
First.
Create another user (for example runner) and make your sensitive data (like user/pass, private key, etc) accessible just for this user. In other words deny your php code to have any access to these data.
Second.
After that create a simple blocking fifo pipe and grant write access to your php user.
Last.
And finally write a simple daemon to read lines from the fifo and execute it for example by ssh command. Run this daemon with runner user.
To execute a command you just need to write your command in the file (fifo pipe). Outputs could be redirected in another pipe or some simple files if needed.
to make fifo use this simple command:
mkfifo "FIFONAME"
The runner daemon would be a simple bash script like this:
#!/bin/bash
while [ 1 ]
do
cmd=$(cat FIFONAME | ( read cmd ; echo $cmd ) )
# Validate the command
ssh 192.168.0.1 "$cmd"
done
After this you can trust your code, if your php code completely hacked, your upstream server is secure yet. In such case, attacker could not access your sensitive data at all. He can send commands to your runner daemon, but if you validate the command properly, there's no worry.
:-)
Method 1
I'd probably use the suid flag. Write a little suid wrapper in C and make sure all commands it executes are predefined and can not be controlled by your php script.
So, you create your wrapper and get the command from ARGV. so a call could look like this:
./wrapper reloadnginx
Wrapper then executes /etc/init.d/nginx reload.
Make sure you chown wrapper to root and chmod +s. It will then spawn the commands as root but since you predefined all the commands your php script can not do anything else as root.
Method 2
Use sudo and set it up for passwordless execution for certain commands. That way you achieve the same effect and only certain applications can be spawned as root. You can't however control the arguments so make sure there is no privilege escalation in these binaries.
You really don't want to give a PHP script full root access.
If you're running on the same host, I would suggest to either directly write the configuration files and (re)start services or to write a wrapper script.
The first option obviously needs a very high privilege level, which I would not recommend to do. However, it will be the most simple to implement. Your other named options with ssh do not help much, as a possible attacker still may easily get root privileges
The second option is way more secure and involves to write a program with high level access, which only takes specified input files, e.g. from a directory. The php-script is merely a frontend for the user and will write said input files and thus only needs very low privileges. That way, you have a separation between your high- and low privileges and therefore mitigate the risk, as it is much easier to secure a program, with which a possible attacker may only work indirectly through text files. This option requires more work, but is a lot more secure.
You can extend option 3 and use SSH Keys without any library
$command = sprintf('ssh -i%s -o "StrictHostKeyChecking no" %s#%s "%s"',
$path, $this->getUsername(), $this->getAddress(), $cmd );
return shell_exec( $command );
I use it quite a lot in my project. You can have a look into SSH adapter I created.
The problem with above is you can't make real time decisions (while connected to a server). If you need real time try PHP extension called SSH2.
ps. I agree with you. SSH seams to be the most secure option.
You can use setcap to allow Nginx to bind to port 80/443 without having to run as root. Nginx only has to run as root to bind on port 80/443 (anything < 1024). setcap is detailed in this answer.
There are a few cavets though. You'll have to chown the log files to the right user (chown -R nginx:nginx /var/log/nginx), and config the pid file to be somewhere else other than /var/run/ (pid /path/to/nginx.pid).
lawl0r provides a good answer for setuid/sudo.
As a last restort you could reload the configuration periodically using a cron job if it has changed.
Either way you don't need SSH when it's on the same system.
Dude that is totally wrong.
You do not want to change any config files you want to create new files and then include them in default config files.
Example for apache you have *.conf files and include directive. It is totally insane to change default config files. That is how I do it.
You do not need ssh or anything like that.
Belive me it is better and safer if you will.

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.

how to set up a php mysql site quickly?

I am looking for ways to setup a basic site quickly.
I have a basic site which works with a databasem, templates, css, js and so on.
No I want to be able to quickly set up a site. What shoudld happen when i start the script is:
ask for some variables
on submit:
create a folder in the webroot
copy the standard site to that map
create a database based on a default db
add the new site to my vhost file
restart apache
add the new site to my host file
start de basic site in a browser.
What is the best way to create this script? How can I accomplish this?
Here's a complete (untested) hack that does about what you said. If you're comfortable in php then use that. Pseudo script:
#!/usr/bin/env php
<?php
echo "Site setup v0.0\n";
if($argc != 2){
echo "Usage:\n script sitename\n";
}
//set vars
$sitename = $argv[1];
$src_folder = "/path/to/some/folder";
$template_db ="template_site";
//copy files
`mkdir $sitename`;
`cp -R $src_folder $sitename`;
//copy template db
$dblink = mysql_connect("localhost");
if(!mysql_query($dblink, "CREATE DATABASE site_$sitename; USE site_$sitename;"))exit(-1);
$r = mysql_query($dblink, "SHOW TABLES FROM $template_db");
while($row = mysql_fetch_array($r)){
$table = $row[0];
mysql_query($dblink, "CREATE TABLE $table AS SELECT $template_db.$table");
}
//conf and restart apache
$f = fopen("httpd.conf","a");//open for append
fwrite("<VirtualHost $sitename> bla bla </VirtualHost>");
fclose($f);
`sudo apachectl -k restart`; //you'll be asked for a password here
//open in browser
`open http://$sitename/`; //on mac anyway...
?>
Make the file executable with
chmod +x filename
Remember that to run scripts in the current folder you need to add ./. Like
./scriptname sitename
Also note the slanted quotes ` <- They start a shell command. The first line is called a shebang-line (yes like that old 80s band, or what was it..) and tells a shell what to use to execute the file. (Env is a utility program that kinda finds other programs, in this case php. Good if you want to run the script in systems where php has different install locations.)
Also please note that this script is just pseudo code—it does not work! Don't run it before modifying it!
This is something you have to do on the server so you can use any language you prefer. It's just about copying files, append text to files and execute some shell commands.
Well, it depends on what OS you are using, if you use Linux you can create simple script to do this, it basicly should contain a sequence of commands to set this up.
#!/bin/sh
mkdir /var/www/sitename
cp -au /var/www/skeleton/* /var/www/newfolder
etcetera.
You can then launch your script by running it from command line with some parameters
./initiatesite.sh newsite.com databasename addwhateverparameteryouwant here.
More info on passing parameters to a shell script: http://osr600doc.sco.com/en/SHL_automate/_Passing_to_shell_script.html
You can write a shell script that basically accomplishes all of that.
So I guess you would have a web front end handled by php which takes some parameters, and have that php script invoke a shell script (via system call) on your server to set up your db, copy files, append some lines to vhost config, etc
If this is not for your own use but for clients, I would take extra care to make sure all input is untainted and secure first.
You can't do that in PHP unless you run PHP as root (bad idea).
Think about what you want to do specifically and how you would do it. Starting the site in a browser is a user-specific desktop action, restarting the server is a root action as is all the copying/editing/moving stuff.
Maybe a proper installer would be more suited towards what you're trying to accomplish. It sounds like you're working with Windows -- do you only want to provide an installation for Windows? For Linux you'd need a shell script, for example.
The best way to write this would be as a command line script, which you can write in PHP if you want. Use the $argv variable to get an array of the command line variables. Make sure that this PHP file is NOT web accessible.
Also, I would use SVN to do a export to the folder for the new site. This will ensure that you have the most up to date code and that it's a clean copy.

Categories