lundi 14 septembre 2020

Server administration by web browser

I'd like to build a web interface like ISPConfig, cPanel, Webmin that would allow me to administer my server using a web browser, for example: after clicking a button on a web page a "dnf update' command would be sent to the server and the server would be updated.

While the web interface itself might not be a big problem, building an engine for it that would be able to receive and execute the commands would.

A solution i'm thinking of now would be to build a Python program that would create and read a named pipe from one unprivileged user and then execute the commands. I'm a beginner in Python and this is a great opportunity for me to learn more.

Here's what i've come up with so far:

#!/usr/bin/python3

import os
import sys
import atexit
import platform

# The UID ang GID of the pipe file to be owned by.
TARGET_UID=1000
TARGET_GID=1000

# Set up the FIFO
PIPE_FILE = 'comms.fifo'

### FUNCTION BLOCK ###

def check_OS():
    """Checking if the program is running on Linux."""
    OS=platform.system()
    if OS != "Linux":
        print("This service can only run on Linux! It will be stopped now.") 
        quit()

def if_exists_FILE(FILE):
    """Check if a file is accessible/exists."""
    try:
        with open(FILE, encoding='utf-8') as f:
            f.close()
    except FileNotFoundError:
        return False
    return True

def exec_CMD(CMD):
    """Executes system command based on the permissions the program runs with. It's assumed that the command has already been filtered for security."""
    print(f"\x1b[6;30;42m" + f">>>> COMMAND START : \"{CMD.strip()}\" <<<<" + "\x1b[0m")
    os.system(CMD.strip())
    print(f"\x1b[6;30;42m" + f">>>> COMMAND END   : \"{CMD.strip()}\" <<<<" + "\x1b[0m" + "\n")
    
def prep_FIFO(PIPE_FILE):
    """Creates the named pipe and sets permissions."""
    os.mkfifo(PIPE_FILE,0o600)
    # Ownership of the pipe needs to be changed so that normal users
    # can send stuff to it.
    os.chown(PIPE_FILE, TARGET_UID, TARGET_GID)

### FUNCTION BLOCK ###

check_OS()

# Remove the PIPE_FILE if it already exists to avoid errors on the program's startup.
if if_exists_FILE(PIPE_FILE):
    print("Pipe file already exists and it's going to be removed.")
    os.remove(FILE)

prep_FIFO(PIPE_FILE)
    
# Make sure to clean up after ourselves
def cleanup_PIPE():
    os.remove(PIPE_FILE)
atexit.register(cleanup_PIPE)

print ("Waiting for commands.")

# Go into reading loop
while True:
    with open(PIPE_FILE, 'r') as FIFO:
        for LINE in FIFO:
            exec_CMD(LINE)

I need it to run on Linux, be secure and be made according to best practices and so on. I can't just let the commands be received and blindly executed. I should find out how to run it properly as a Linux daemon, so it should be able to log messages/errors etc.

I hope i am going the right way with this.

Thank you in advance for all tips, thoughts.




Aucun commentaire:

Enregistrer un commentaire