📜 ⬆️ ⬇️

Reset PHP cache via SQL query or from gun on sparrows


Good day. Faced such a task - through a SQL request to reset the PHP cache. Simply put, delete multiple files in a specific directory. At the entrance there is:

As a result, the solution came in a bundle of python + C + bash (a bit of everything). Not a little Unix way, but maybe someone will come in handy.

We wrap the command to delete the PHP cache in the bash script, thinking about its further expansion with new functionality. Generally speaking, it would be nice to pass the necessary command as a parameter. Here is the script:
#!/bin/bash function __clear_cache() { rm /var/www/html/cache/*.php } FUNCS=() FUNCS+=("__clear_cache") function function_exists() { local e for e in "${@:2}"; do [[ "$e" == "$1" ]] && return 0; done return 1 } if function_exists "$1" "${FUNCS[@]}"; then eval "$1" else echo "Function $1 does not exists" exit 1 fi 

Here we declare an array that will contain a list of functions (ie, commands) and, before calling the transmitted command (ie, functions), check if it is in the list. Otherwise, a bad user can pass something of type rm -rf ... as a parameter that will succeed in eval . Set the owner for this root script (although apache is enough, but we think about extensibility, not forgetting caution) and make the script executable:
 chown root:root sysutils chmod ugo+x sysutils 

You can run this script from the DBMS via C (a long way, since you need to bother with creating an extension to PostgreSQL) or via an unmanaged scripting language, which is plpython. But first let's think about it - the script from the DBMS will be executed with the rights of the postgres user, and only apache can delete the cache (at least). But it does not matter, there is such a thing as the SUID flag. Only here the problem is that in Linux it is impossible to set the SUID flag for scripts (for more details see here ). Rather, it is possible, but the effective user ID will still be the same as the real one. Let's try to get around this limitation by writing a small C program in which there will be a call to our script. Here is its code:
 #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <unistd.h> int main(int argc, char *argv[]) { setuid(0); char command[255]; if (argc == 2) { snprintf(command, 255, "/usr/local/bin/sysutils %s", argv[1]); system(command); } else { printf("USAGE: sysutils-core <command>\n"); } return 0; } 

First we set the effective user ID, then we call the script, passing it the parameter - the required command. Compile the program and install the SUID flag:
 gcc -o sysutils-core sysutils-core.c chmod u+s sysutils-core 

Checking:
 su postgres ./sysutils-core clear_cache 

We now turn to the DBMS part.

Install the plpython3 extension (pre-installed into the system) by executing the SQL command in the appropriate database:
 CREATE EXTENSION plpython3u; 

Or using the console:
 createlang plpython3u -h localhost -U postgres testdb 

The function in the DBMS through which the cache will be reset is of the form:
 CREATE OR REPLACE FUNCTION clear_cache ( ) RETURNS void AS $BODY$ import os os.system("/usr/local/bin/sysutils-core __clear_cache") $BODY$ LANGUAGE plpython3u VOLATILE; 

There is just a call to sysutils-core with the parameter clear_cache. Checking:
 SELECT clear_cache ( ); 

If necessary, the function call can be not only under postgres (it is this user who can create functions in unmanaged languages); in this case, when creating a function, you must specify the option - SECURITY DEFINER (an analogue of SUID in the DBMS).

That's all. If desired, you can add the transfer of arguments, new commands and, in general, manage the linux server through the DBMS. Let it be your homework.
')
UPD : A safer version of a C program (via execl ):
Hidden text
 #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <unistd.h> #include <error.h> #include <sys/wait.h> #include <errno.h> int main(int argc, char *argv[]) { setuid(0); if (argc == 2) { int status = 0; int pid = fork(); switch (pid) { case -1: printf("Fork sysutils process failed"); exit(1); case 0: execl("/bin/bash", "bash", "/usr/local/bin/sysutils", argv[1], NULL); default: wait(&status); } } else { printf("USAGE: sysutils-core <command>\n"); } return 0; } 

Source: https://habr.com/ru/post/231563/


All Articles