I am trying to start a php (under apache) process (by calling the apache from a browser), that will survive shutting down the apache server (sudo service apache2 stop). Even when I make sure the created process has no parent (parent 1), and has its own session, still, somehow, the process is died when I stop the apache (or restart the apache)
I created a test.php file:
<?php
exec('setsid nohup sleep 1000 > /dev/null 2>/dev/null &');
?>
When running doing HTTP GET to this test.php, indeed we get an immediate OK response, and the process still lives.
But, when we do:
sudo service apache2 stop
The sleep process dies.
How can someone kill a process when the process doesn't belong to its group or session, and when the process is not a child?
Apache will probably have a list of the spawned processes and kills them individually, and not as a group. In that case, all processes in the list will be kill(2)ed. But see below next paragraph for a possibility.
Look at the man pages for the kill(2) system call. In the ERRORS section, the only possibilities to fail are:
EINVAL, meaning an invalid signal number has been passed. Doesn't apply here.
ESRCH, the process (or process group) doesn't exist. Doesn't apply also.
EPERM, you don't have permission to send a signal. This applies here, but the only processes (and this has nothing to do with process hierarchies or parental relationships) you are allowed to send signals to are the processes that run with real/saved user id equals the effective user id of the sender process. So, as Apache has a registry of all the processes it launches, it is normal that it is able to kill the process.
Anyway, have you tried to create a process, from that process create a subprocess, and execute the setsid in the grandchild subprocess? That way, there's no chance for the Apache process to have it registered in the list of spawned processes. I have not tried that, but it could work.
From the FreeBSD kill(2) manual page:
For a process to have permission to send a signal to a process designated
by pid, the user must be the super-user, or the real or saved user ID of
the receiving process must match the real or effective user ID of the
sending process. A single exception is the signal SIGCONT, which may
always be sent to any process with the same session ID as the sender.
(emphasis is mine) in linux, it's almost the same, except
... (if the sending process) have the CAP_KILL capability in the user namespace of the target process...
but this doesn't apply here.
I'm curious on why the apache server needs to be shut down, but im inclined to say you might try a different strategy altogether using a containerized solution. Exposing an nginx docker container that can trigger your php process would likely be more stable than using Apache, as the docker daemon always runs as root. I think it depends on the specific needs of your use case though, so explaining why you need to shut down Apache might get you better answers.
List all active processes (e.g. ps aux). The processes, which were created by Apache run as user www-data.
When you stop Apache service, I suspect they will be terminated based on that or some internal list. apache2.service stop calls apachectl -k graceful-stop. This will SIGTERM all "child processes". Unfortunately, I was unable to find the exact place in the code. Maybe someone could do that to verify the hypothesis.
A solution:
Run the process as another user. How you go about that depends on your case. You will have to define some kind of interface.
For example, you could have another process listen on localhost or use a Unix domain socket. The same will be achieved by using gearman, as #Akshay Vanjare pointed out in the comments.
Your PHP script can then call to the interface.
No solutions:
It is a bad idea to control a daemon this way, see this answer.
As user www-data you cannot start a process as another password protected user, because su asks for pass and switching UID is not a good idea.
For testing, I set up a user with empty password and used su - NEW_USER -c "COMMAND" in PHP script. Do not do this in any system you care about. It is insecure. Very insecure. And you will have a new process every time the script is called. You would have to take care to kill it.
Further thoughts:
I also tried a few alternatives to "nohup" the command, such as daemonizing, fork(), disown etc. They did not work for me.
I did not try hard in the new process to ignore SIGTERM. maybe it is possible to solve the question that way, too.
To me, it makes sense for Apache to do (aggressive) clean up when it is stopped. It is behavior I would expect from a web browser, which has to handle a lot of children.
First about my answer, it's not a good idea to control dameon from the web.
Once this said, you can have a php script that write a flag or somthing like that either on a database, a file, redis, etc.
On the other side make a PHP script that you schedule with cron for looking for the flag. If found, the script can start a PHP daemon that will detach. Pay attention to running the cron script and the PHP daemon with secured user & rights.
But once again be carefull with security concern.
From the PHP developer perspective I don't think there is a way to achieve that.
Or you can implement a queue and worker to do your tasks/executions.
and for that you can either use Redis or any other database.
https://laravel.com/docs/9.x/queues
You can write a service that then you can control with sudo service start|stop|restart
You can use visudo to edit sudoers file to allow www-data to use sudo to run a specific sh file, without being prompted by password. This sh file will contain the line service your_service start.
Example: I wanted to be able to restart apache2 from a client side ajax request.
Context: file server with no screen/keyboard attached. I have SSH setup, but I don't want to launch a client in my laptop. I protect the restart page with apache password protected directory, along with other administrative pages. For example: I have a page to restart/shutdown the whole system.
I did this:
Register a service to run with sudo service apache_restarter_service start
This service file calls a simple sh script, a two lines script: sleep 1 second and then call service apache2 restart.
Use visudo to edit sudoers file. Allow user www-data to use sudo to run a sh script that calls service apache_restarter_service start.
The service file is used only to start a process with root privileges, and it doesn't need to be long lived, so no need for Restart=always in service definition. This process cannot be killed by apache and apache won't even know about it. It will only know that the sh script returned 0.
Example of changes to sudoers file:
www-data ALL=(ALL) NOPASSWD:/opt/apache_restarter/from_php.sh
from_php.sh only calls service apache_restarter_service start. No need for sudo here, because your php script already used sudo when calling from_php.sh.
from_php.sh is needed here, because you don't want php to call service directly. Because a BUG in, or an ATTACK against, your script may do harm to your server. This way, we only authorized from_php.sh in sudoers.
The php script must call from_php.sh with sudo. You can use exec("sudo /opt/apache_restarter/from_php.sh"). An & at the end is not needed, because apache won't be restarted immediately.
Example of service definition file apache_restarter_service.service:
[Unit]
Description=Apache restarter one shot
After=multi-user.target
StartLimitIntervalSec=0
[Service]
Type=simple
Restart=no
User=root
ExecStart=/opt/apache_restarter/run.sh
[Install]
WantedBy=multi-user.target
To avoid the service to run once the system is restarter. No harm really, but also useless. You can have the service always disabled and enable it in from.php script before starting it. Or just tune the service file to not run one time at system start.
You can tune StartLimitIntervalSec=0 to your needs.
You can tune User=root to a safer, less privileged user. In my case I don't care but maybe you do. You may want to use www-data. I don't know why that may not work, but I didn't tried to use www-data so far.
You can write run.sh in many ways and to do different tasks. The simpler of which would be to simply wait 1 second and then restart apache with service apache2 restart.
While my interest is to be able to restart apache from client side, this also applies to spawn a process that won't be terminated when apache is stopped/restarted.
I also tried with nohup, &, setsid and whatnot. I will save people some time. Nothing works. Apache should be terminating all child processes as already suggested.
Update 2022-12-04
I got into the following situation: need to start a python3 web server into alternate port to provide file server statistics.
Why? This is the concept, if nobody interested in the statistics (iostat, ifstat, etc) then the stats_server.py is not even running (wasting RAM/CPU). So, having stats_server.py starting with system is overkill.
Once a user visit http://FILE_SERVER_IP/stats_launch.php, or from JavaScript fetch, the program stats_server.py must be launched and listen in http://FILE_SERVER_IP:ALTERNATE_PORT. You may also need to handle CORS headers to be able to fetch from the alternate port.
Also, it keep running and updating the stats with a second, or half second, interval, and saving to its own memory, so it can calculate averages or rates per second. Doing this server side gives more precision and less latency that just send the raw samples to client side.
This URL can be visited directly (you will see the output of iostat and ifstat, and values calculated by the python script, in plain text format), or user can load FILE_SERVER_IP/stats.html, where a fetch from JavaScript will periodically load that text plain output, and parse into nice HTML/CSS.
You may think that everything can be solved by fork or by using os.getpid(), os.getsid() and os.setsid() inside the python script, to detach it from the original session and avoid termination with parent process (search stackoverflow for use cases) and it will if your www-data user has the right permissions.
Otherwise I still recommend the visudo approach above. You still need to detach if you start your python file from a .sh file, the difference is that now you have the permissions to do so.
I am working on a game panel and I building it in PHP and BASH. So, the web panel controls the game severs by running bash scripts when buttons are pressed. So far so good. My problems come when I need to run the bash scripts because the user running them needs sudo privileges or the scripts will have a an unexpected behavior:
Should I create a new user and give it sudo privileges, then login to the server via SSH (through PHP)? If so how can I store the login credentials safely so if a hacker breaches my website he won't find them?
Should I give www-data sudo privileges to the specific scripts? Is this a dangerous approach?
Is there any better and more secure way to run bash scripts from a webpage?
I am a newbie PHP developer and my first project is a game panel running on Ubuntu server. Please have mercy. :)
I wouldn't run any bash scripts directly from PHP, instead I would decouple the two by using a message queue.
Have the PHP script send a message to an exchange and mark the action as "in progress". Then have a bash script run as a consumer for a queue that receives the message, process it and run the necessary script. Finally pass the message on to another queue which is consumed by PHP and update the action status as "completed" or "failed", depending on the outcome. This is not a synchronous process but it's the safer way to handle it.
Suggested reading:
RabbitMQ
RabbitMQ and bash
What you are trying to do here is very dangerous, if you can execute bash scripts from within a web page you will be hacked and the hacker will have full access on your machine.
What you need to do depends on what your project is, but basically you want to setup some form of server that will run you bash commands and have your web page call that server. This is not straight forward.
I am compiling and executing a C program that uses a PHP System Command on Windows XP Server.
If the C program contains a System command like System("shutdown -a") or any system command, then it turns my system down.
I want these kinds of commands to be denied. How do I show "permission denied" as an output when a program tries to run a system command?
Here is my code.
PHP script contains-
system(gcc code.c -o out); system(out.exe);
IF C program contains-
int main() { system("shutdown -r"); }
Is there a way to block those commands from being run?
Windows runas command
You might be able to use windows runas command to run a command as a specific user. And in that user's profile, set a list of white listed commands. https://superuser.com/questions/42537/is-there-any-sudo-command-for-windows
Roll your own command white list
Create a list of commands in PHP or C that are allowed to be run through the C program, and if the command isn't on the approved list, it is denied. Or of you like to live dangerously, create a black list, and define a bunch of things you don't want run.
Ok, so the simple answer is "Don't run as root" (then the user can only access files he/she has created, so not so much chance of doing damage)
The more sophisticated answer is to farm out the running of the code onto a virtual machine within the server. A virtual machine can be cloned from a template (or whatever the VM software calls such a thing) in fairly short time. Within a VM, the code running there has no access to the "REAL" machine that it runs on, so if the user wants to destroy his/her virtual machine, that is his/her problem - just have to request a "new virtual machine" before they can continue working.
Background: I am writing a script for a company that will allow users to create FTP accounts through a web interface. In the background, the script must run a bunch of commands:
Add the user to the system (useradd)
Open and edit various files
mail the user via sendmail
and a few other things...
I'm basically looking for the most secure way of doing this. I've heard of the setuid method, the sudo method, and of course, running httpd as a priviledged user. There will be sanity checks on the data entered of course before any commands are executed (ie. only alphanumeric characters in usernames)
What is the method used by the popular scripts out there (webmin for example), as it must be fairly secure?
I would set up a queue that the web-bound script can write to.
Then I'd have some privileged process read from that queue and take appropriate action. You could drive a command-line script via a cron job, or write a little daemon in PHP that checks the queue and does the work more frequently than cron allows.
That way, the only code that can run privileged is your little worker script, and you don't need to provide any path for the web-bound script to gain the necessary but dangerous privileges.
Create a script that accepts a command line option, validates it, and execs useradd. Add your httpd's user to the sudoers file with a NOLOGIN directive, JUST for that one process.
That way, you don't have to worry about writing a daemon that will always run with root privileges, and your script would also return immediately. If you just used a setuid root script, other users on the same system could exec your script (unless you checked their real user ID) .
I'll start by saying that running httpd as root is a very bad idea.
The safest way to do this is have complete privilege separation between the webserver UI and the effector - one obvious way of doing that is to run a server as root accepting local connections only which the UI sends its requests to (a simple way of doing this is via inetd/xinetd - which means you don't have to bother with all the complications of establishing a daemon process).
You would also need some sort of trust mechanism between the UI and the effector - a shared secret would suffice - so that other programs on the system can't call the effector. Using a trust system which relies on challenge based auth or asymmetric encryption means that you no longer have to worry about the local connection constraint.
Finally, you need a well defined protocol by which the UI and effector communicate.
This is a lot more complex than using sudo, but is more secure (e.g. sudo just allows users to execute specific files as a different uid - you hope that the file contains the right program).
Setuid has many of the same drawbacks as sudo with the added complication that (in most cases) if it starts another program - then it will do so as the original uid.
HTH
C.
The Setup:
I have a LAMP server (Ubuntu 9.10) which is also hooked up to my HDTV. Upon boot, one user is automatically logged in so as to have a desktop environment on screen.
What I want:
I've been developing a remote, web interface in PHP for various things (play music, for example). However, I've hit a snag in that I would like to run a windowed program and have it display on the TV. Obviously, since PHP/Apache is running under the user www-data, this isn't going to happen just by running my command via exec().
Is there a Linux command that can run it as the currently logged in session of my other user, or a program that?
The (X) program starting uses the DISPLAY variable to determine which X session to hook up to. You'll need to figure out which X session the user currently has, if this is a one-user box is's most likely to be :0.
Then you could write a simple bash script to
1. Set the DISPLAY (and other variables as needed)
2. Execute.
--
Another solution would be to write the necessary information to a flat file and then have a cron job checking for updates every one or three seconds. The cron can be configured to run as a specified user. Ugly, but sould work.
As mataisf says - you need to set the DISPLAY variable so the program knows where to generate the window. However there is an authentication system which prevents unauthorized programs from access an X server (the place where the keyboard, screen and mouse are). One way around this is to let any program connecting from the local machine have access:
xhost +localhost
....but a better solution would be to run the program as the user logged in. There are lots of different ways to do this - but probably the most practical is via sudo, e.g.
sudo -u console_user program
Note that before you do this you might want to set the HOME variable so that xauth works properly (you can do this with the -H flag for sudo).
Note that you need to configure the program, the console_user and the webserver user in the /etc/sudoers file.
C.