From 86fe1ba8b714ba4d8d50b12b84ea308856294d4b Mon Sep 17 00:00:00 2001 From: Nova Date: Fri, 22 Nov 2024 19:36:13 +0100 Subject: [PATCH] Add no-posix files. --- install.py | 6 +- main.py | 251 +++++++++++++---------------------------------------- sh.py | 40 +++------ 3 files changed, 73 insertions(+), 224 deletions(-) diff --git a/install.py b/install.py index 06311e6..954d50a 100644 --- a/install.py +++ b/install.py @@ -1,6 +1,6 @@ """ Install script for the Python jailer. -Version: 0.2.0-alpha2 +Version: 0.2.0-alpha1 """ import os import shutil @@ -43,7 +43,7 @@ if setup_posix.lower() == "y": with open("./lib64", "a+") as f: f.write("symlnk /usr/lib64/") f.close() - with open("./usr/bin/sh", "a+") as f: + with open("./usr/bin/sh.py", "a+") as f: f.write("symlnk /usr/bin/shell.py") f.close() os.mkdir("./sys") @@ -85,4 +85,4 @@ else: f.write(usrname) f.close() print("Install completed! Run ./main.py to start the kernel!") -input("Press to exit! ") +input("Press to exit! ") \ No newline at end of file diff --git a/main.py b/main.py index 78d65cc..0c78223 100644 --- a/main.py +++ b/main.py @@ -1,193 +1,58 @@ -""" -This is the PyJail, a jailing tool for running Python apps in a sandboxed environment. -Version: edge0003-base0.2.1 -""" -import os -import time -import runpy - - -class PyJail: - """ - The jail manager, handles all system calls and such. - """ - def __init__(self, debug=False): - self.rootpath = "" - self.rootpath = self.fs() - self._debug = debug - with open(self.fs("/proc/klog"), "w") as f: - # Always use jailmgr.msg() from this point onwards. - f.write(f"[{time.time}] [jailmgr.__init__()] [INFO] START LOG") - f.close() - with open(self.fs("/proc/kproc"), "w") as f: - f.write("proc: jailmgr(1)") - self._program_counter = 2 - f.close() - self._resolve_symlinks = False if os.path.isdir(self.fs("/bin")) else True - - def run_program(self, path_to_bin): - """ - Runs a specified program. - """ - path_to_bin = self.fs(path_to_bin) - if path_to_bin == 3 or path_to_bin == 2: - self.msg("jailmgr.run_program()", "An error has occurred launching the program.", True, - "WARNING") - else: - with open(self.fs("/proc/kproc"), "a+") as f: - f.write(f"proc: {path_to_bin}({self._program_counter})") - self._program_counter += 1 - runpy.run_path(path_to_bin) - - def msg(self, caller: str, message: str, emit: bool = False, log_level: str = "INFO"): - """ - The custom message parser, can parse messages and alert apps of said messages. - Replaces print statements. - Args: - caller: The program that called the logger - message: Is the message to parse. - emit: If the message needs to be passed to apps. - log_level: The loglevel, either DEBUG, INFO, WARNING, ERROR, CRITICAL - """ - if self._debug is True: - emit = True - accepted_log_levels = ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"] - if log_level.upper() not in accepted_log_levels: - self.msg(f"jailmgr.msg()",f"Not accepted loglevel!! {log_level}", False, "ERROR") - return 1 - msg = f"[{time.time}] [{caller}] [{log_level}] {message}" - with open(self.fs("/proc/klog"), "a+") as f: - f.write(msg) - if emit is True: - print(msg) - return 0 - - def fs(self, check_path=None, resolve_symlinks=True): - """ - Keeps track of the jailed filesystem and makes sure any calls to any - file get done in the jailed filesystem - """ - if check_path is not None: - if os.path.exists(f"{self.rootpath}{check_path}"): - if self._resolve_symlinks is True or resolve_symlinks is True: - # This exists to ease /bin and other symlinks that are always present. - # It allows the system to drastically speed up resolving symlinks. - symlinkable_dirs = ["/bin", "/sbin", "/lib", "/lib64"] - for directory in symlinkable_dirs: - if check_path.startswith(directory): - check_path_usr_merge = f"/usr{check_path}" - return self.rootpath + check_path_usr_merge - # Well, if it doesn't start with any of them, we need to check each and every directory. - check_path_split = check_path.split("/", -1) - prepend_path = "" - for i, path in enumerate(check_path_split): - prepend_path = f"{prepend_path}/{path}" if not path.endswith("/") else f"{prepend_path}/{path}/" - check_path_split[i] = f"{prepend_path}" - check_path = "" - for i, path in enumerate(check_path_split): - if os.path.isdir(path) and i != (len(check_path_split) - 1): - # Directory is not a symlink, we can just ignore and move on. - pass - elif os.path.isdir(path) and i == (len(check_path_split) - 1): - # The last thing to access was a directory. We can safely return the full path now. - return path - elif not os.path.isdir(path) and i != (len(check_path_split) - 1): - # This was not the last thing we needed to access, so we assume it's a symlink. - # One problem is that we can't be sure, so we make sure it is a symlink. - with open(self.fs(path, False)) as f: - is_symlink = f.read() - f.close() - if is_symlink.startswith("symlnk"): - # This is a symlink! - # Symlinks always contain the full literal path that they need to access, so we can - # take that and do the same trick to split it and add the next things to it. - is_symlink_split = is_symlink.split(" ", 1) - symlink_dest = is_symlink_split[1] - symlink_dest = f"{symlink_dest}/{path}" - return symlink_dest - else: - # This is either not a symlink or an improperly configured one. - self.msg("jailmgr.fs()", "reached non-symlink file not at end of list", - False, "ERROR") - self.msg("jailmgr.fs()", "What was assumed to be a directory isn't a" - " directory nor a symlink! This might be because of a " - "typo or misconfigured symlink. The directory in question: " - f"{path}", True, "WARNING") - return 2 - - return self.rootpath + check_path - if check_path.startswith("."): - check_path = check_path.lstrip(".") - return os.getcwd() + check_path if "vfs" in os.getcwd() else 2 - elif self.rootpath in check_path: - self.msg(f"jailmgr.fs()", "Cannot parse rootpath, expected vfspath", log_level="ERROR") - return 3 - else: - # Path is not in the jailed fs, so we say it doesn't exist. - self.msg(f"jailmgr.fs()", "File/directory doesn't exist in vfspath", log_level="ERROR") - return 2 - else: - rootpath = os.getcwd() + "/vfs" - self.msg("jailmgr.fs()", message=rootpath, log_level="INFO") - return rootpath - - def kver(self): - """ - Returns the kernel version - """ - return "edge0003-base0.2.1" - - def netsock(self, ip, port, mode, msg): - """ - An easy interface to network sockets, built right into the jailmanager - - Args: - ip: The IP of the server to access. - port: The port to access the server on - mode: Either UDP, TCP or PKG (HTTP) - msg: The message to send the server - - Returns: - Whatever the server returns. - """ - if mode == "PKG": - import requests - else: - import socket - - if mode == "TCP": - try: - client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - except Exception as e: - self.msg("jailmgr.netsock()", "Socket import failed!", False, "CRITICAL") - self.msg("jailmgr.netsock()", "An unexpected error occurred!", True, "ERROR") - return None - # Connect to the server - client_socket.connect((ip, port)) - self.msg("jailmgr.netsock()", f"Connected to server at {server_ip}:{server_port}", False, "INFO") - - # Send the message to the server - client_socket.send(message.encode()) - - # Receive the response from the server - response = client_socket.recv(1024).decode() - client_socket.close() # Close the connection - self.msg("jailmgr.netsock", f"Received from server: {response}", False "INFO") - - return response - - elif mode == "PKG": - # raise NotImplementedError("TODO: PKG will be implemented later!") - file_io = requests.get(ip) - if file_io.startswith("PYPAK PMD"): - with open(self.fs(f"/usr/netsock/cache/{pkg}.pmd"), "a+") as f: - f.write(file_io) - f.close() - - - - else: - raise NotImplementedError("TODO: UDP will be implemented later!") - - # raise NotImplementedError("TODO: Netsock will be implemented once 0.3.0 comes around!") - +""" +This is a sort of OS built in Python, not bootable, but creates a custom directory structure and path definition. +This is the "kernel", it hosts all features and runs all programs. +For safety reasons the kernel is isolated, which means that with every shell instance, +A new kernel instance will follow it. Same goes for every program, it will need to call upon a brand-new kernel instance. +Version: 0.1.1-nps3 +""" +import os +import runpy + +class PyJail: + """ + The "kernel" for PyNVOS + """ + def __init__(self): + self.rootpath = "" + self.rootpath = self.fs() + + def run_program(self, path_to_bin): + """ + Runs a specified program. + """ + path_to_bin = self.fs(path_to_bin) + # print(path_to_bin) + # print(str(self.rootpath) + str(path_to_bin)) + if path_to_bin == 3 or path_to_bin == 2: + print("An error has occurred launching the program.") + else: + runpy.run_path(path_to_bin) + + def fs(self, check_path=None) -> str: + """ + Keeps track of the jailed filesystem and makes sure any calls to any + file get done in the jailed filesystem + """ + if check_path is not None: + if os.path.exists(f"{self.rootpath}{check_path}"): + if check_path.startswith("."): + check_path = check_path.lstrip(".") + return os.getcwd() + check_path if "vfs" in os.getcwd() else 2 + return self.rootpath + check_path + elif self.rootpath in check_path: + print("ERR: Cannot parse rootpath, expected vfspath") + return 3 + else: + # Path is not in the jailed fs, so we say it doesn't exist. + print("ERR: File/directory doesn't exist in vfspath") + return 2 + else: + rootpath = os.getcwd() + "/vfs" + return rootpath + + @staticmethod + def is_posix_compatible() -> bool: + """ + Returns if the kernel is POSIX compatible. + """ + return False diff --git a/sh.py b/sh.py index 034f2a4..3c344a8 100644 --- a/sh.py +++ b/sh.py @@ -1,60 +1,44 @@ """ The shell for PyNVOS -Version: 0.2.0.0400 +Version: 0.1.0-main1 """ import importlib import os import cmd -import shutil # from ..sys.krnl import Kernel print(__name__) class shell(cmd.Cmd): - jail_mgr = importlib.import_module(".jail_mgr", "vfs.sys") - jailmgr = jail_mgr.PyJail() - kver = jailmgr.kver() - intro = f"Shell started, PyNVOS {kver}" - prompt = "shell-0.2$ " + intro = "Shell started, PyNVOS 0.1.1-main1" + prompt = "shell-0.1.0$ " file = None + krnl = importlib.import_module(".jail_mgr", "vfs.sys") + kernel = krnl.Kernel() + print(str(kernel) + " " + str(type(kernel))) def do_cd(self, args): """Changes directory""" - args = shell.jailmgr.fs(args) + args = shell.kernel.fs(args) os.chdir(args) def do_exec(self, args): """Allows you to execute a file""" # Apps in /bin should be allowed to launch without first adding /bin/ or ./, just the name of the executable # So for ledit it should be just 'ledit' and not /bin/ledit.py or ./ledit.py - bins_in_bin = os.listdir(self.jailmgr.fs("/bin")) + bins_in_bin = os.listdir(shell.kernel.fs("/bin")) apps_strip = [] for apps in bins_in_bin: if apps.endswith(".py"): apps_strip.append(apps.strip(".py")) if args in apps_strip: - shell.jailmgr.run_program(f"/bin/{args}.py") + shell.kernel.run_program(f"/bin/{args}.py") else: - shell.jailmgr.run_program(args) + shell.kernel.run_program(args) def do_ls(self, none): """Lists the content of a directory""" os.listdir(os.getcwd()) - def do_pkg(self, pkg): - """Downloads packages over the internet.""" - self.jailmgr.netsock(f"https://pkg.novacow.ch/repo/{kver}/meta/{pkg}.pmd", None, "PKG", f"{pkg}") - shutil.copy(self.jailmgr.fs(f"/usr/netsock/cache/{pkg}.pmd"), self.jailmgr.fs(f"/usr/pkg/metacache/")) - with open(self.jailmgr.fs(f"/usr/pkgs/metacache/{pkg}.pmd"), "r") as f: - package_meta = f.read() - f.close() - print(package_meta) - y_n_confirmation = input("Do you want to install this package? [y/N] ") - if y_n_confirmation.lower() != "y": - print("Aborted.") - return - self.jailmgr.netsock(f"https://pkg.novacow.ch/repo/{kver}/main/static/binary/{pkg}.py", None, "PKG", f"{pkg}") - shutil.copy(self.jailmgr.fs(f"/usr/netsock/cache/{pkg}.py"), self.jailmgr.fs(f"/usr/bin/")) - def postloop(self): pass @@ -62,6 +46,6 @@ class shell(cmd.Cmd): if __name__ == '': shell().cmdloop() if __name__ == '__main__': - print("The shell can't be ran as a standalone program and must be ran in conjunction with the jail manager.") + print("The shell can't be ran as a standalone program and must be ran in conjunction with the kernel.") input("Press Enter to continue...") - exit(-1) + exit(-1) \ No newline at end of file