From 36f9dee5030fa3e19a8d28760270a28ca0de4c60 Mon Sep 17 00:00:00 2001 From: Vadim Troshchinskiy Date: Tue, 12 Nov 2024 13:29:35 +0100 Subject: [PATCH] Fix SSH key generation and extraction --- installer/opengnsys_git_installer.py | 141 ++++++++++++++++++++------- 1 file changed, 104 insertions(+), 37 deletions(-) diff --git a/installer/opengnsys_git_installer.py b/installer/opengnsys_git_installer.py index 6b6e24a..a2cd6f4 100755 --- a/installer/opengnsys_git_installer.py +++ b/installer/opengnsys_git_installer.py @@ -2,6 +2,10 @@ """Script para la instalación del repositorio git""" import os +import sys +sys.path.insert(0, "/opt/opengnsys/python3/dist-packages") + + import shutil import argparse import tempfile @@ -13,6 +17,8 @@ import grp from termcolor import cprint import git import libarchive +from libarchive.extract import * + #from libarchive.entry import FileType import urllib.request import pathlib @@ -20,6 +26,7 @@ import socket import time import requests import tempfile +import hashlib #FORGEJO_VERSION="8.0.3" FORGEJO_VERSION="9.0.0" @@ -126,8 +133,13 @@ class OpengnsysGitInstaller: self.temp_dir = None self.script_path = os.path.realpath(os.path.dirname(__file__)) - # Possible names for SSH key + # Possible names for SSH public keys + self.ssh_key_users = ["root", "opengnsys"] + self.key_names = ["id_rsa.pub", "id_ed25519.pub", "id_ecdsa.pub", "id_ed25519_sk.pub", "id_ecdsa_sk.pub"] + + # Possible names for SSH key in oglive self.key_paths = ["scripts/ssl/id_rsa.pub", "scripts/ssl/id_ed25519.pub", "scripts/ssl/id_ecdsa.pub", "scripts/ssl/id_ed25519_sk.pub", "scripts/ssl/id_ecdsa_sk.pub"] + self.key_paths_dict = {} for kp in self.key_paths: @@ -306,7 +318,11 @@ class OpengnsysGitInstaller: for file in initrd: self.__logger.debug("Archivo: %s", file) - if file.pathname in self.key_paths_dict: + pathname = file.pathname; + if pathname.startswith("./"): + pathname = pathname[2:] + + if pathname in self.key_paths_dict: data = bytearray() for block in file.get_blocks(): data = data + block @@ -340,51 +356,102 @@ class OpengnsysGitInstaller: temp_dir = tempfile.TemporaryDirectory() + #temp_dir_path = temp_dir.name() - client_key = os.path.join(temp_dir.name, "id_ed25519") - - self.__logger.debug("Writing new SSH key into %s", client_key) - subprocess.run(["/usr/bin/ssh-keygen", "-t", "ed25519", "-N", "", "-f", client_key], check=True) - - keydata_priv = None - with open(client_key, "rb") as client_file: - keydata_priv = client_file.read() - - keydata_pub = None - with open(client_key + ".pub", "rb") as client_file: - keydata_pub = client_file.read() + temp_dir_path = "/tmp/extracted" + if os.path.exists(temp_dir_path): + shutil.rmtree(temp_dir_path) - self.__logger.debug("Writing new initrd into %s", client_initrd_path_new) + pathlib.Path(temp_dir_path).mkdir(parents=True, exist_ok = True) - with libarchive.file_reader(client_initrd_path) as orig_initrd: - #self.__logger.debug("Original initrd was format %s", orig_initrd.format_name) - with libarchive.file_writer(client_initrd_path_new, "cpio") as new_initrd: + self.__logger.info("Uncompressing initrd %s into %s", client_initrd_path, temp_dir_path) + os.chdir(temp_dir_path) + libarchive.extract_file(client_initrd_path, flags = EXTRACT_UNLINK | EXTRACT_OWNER | EXTRACT_PERM | EXTRACT_FFLAGS | EXTRACT_TIME) + ssh_key_dir = os.path.join(temp_dir_path, "scripts", "ssl") - for file in orig_initrd: - self.__logger.debug("File: %s, type %i", file, file.filetype) + client_key_path = os.path.join(ssh_key_dir, "id_ed25519") + authorized_keys_path = os.path.join(ssh_key_dir, "authorized_keys") - if file.isreg(): - data = bytearray() - for block in file.get_blocks(): - data = data + block + pathlib.Path(ssh_key_dir).mkdir(parents=True, exist_ok=True) + if os.path.exists(client_key_path): + self.__logger.debug("Creating SSH key not necessary, it already is in the initrd") + else: + self.__logger.debug("Writing new SSH key into %s", client_key_path) + subprocess.run(["/usr/bin/ssh-keygen", "-t", "ed25519", "-N", "", "-f", client_key_path], check=True) - self.__logger.debug("Adding pathname %s, len %i", file.pathname, len(data)) - new_initrd.add_file_from_memory(file.pathname, len(data), bytes(data), permission = file.mode, mtime=file.mtime, ctime=file.ctime) - elif file.isdir(): - file.modi - self.__logger.debug("Pathname %s is a directory", file.pathname) - elif file.islnk(): - self.__logger.debug("Pathname %s is a symlink", file.pathname) - None - else: - self.__logger.error("Unhandled file type %s", str(file.filetype)) + public_keys = "" - new_initrd.add_file_from_memory("scripts/ssl/id_ed25519.pub", len(keydata_pub), keydata_pub) - new_initrd.add_file_from_memory("scripts/ssl/id_ed25519", len(keydata_priv), keydata_priv) - new_initrd.add_file_from_memory() + for username in self.ssh_key_users: + self.__logger.debug("Looking for keys in user %s", username) + homedir = pwd.getpwnam(username).pw_dir + for key in self.key_names: + key_path = os.path.join(homedir, ".ssh", key) + self.__logger.debug("Checking if we have %s...", key_path) + if os.path.exists(key_path): + with open(key_path, "r", encoding='utf-8') as public_key_file: + self.__logger.info("Adding %s to authorized_keys", key_path) + public_key = public_key_file.read() + public_keys = public_keys + public_key + "\n" + + self.__logger.debug("Writing %s", authorized_keys_path) + with open(authorized_keys_path, "w", encoding='utf-8') as auth_keys: + auth_keys.write(public_keys) + + + + # hardlinks in the source package are not correctly packaged back as hardlinks. + # Taking the easy option of turning them into symlinks for now. + file_hashes = {} + with libarchive.file_writer(client_initrd_path_new, "cpio_newc", "zstd") as writer: + + file_list = [] + for root, subdirs, files in os.walk(temp_dir_path): + proot = pathlib.PurePosixPath(root) + relpath = proot.relative_to(temp_dir_path) + + for file in files: + full_path = os.path.join(relpath, file) + + #self.__logger.debug("%s", full_path) + digest = None + + stat_data = os.stat(full_path) + with open(full_path, "rb") as in_file: + digest = hashlib.file_digest(in_file, "sha256").hexdigest() + + if stat_data.st_size > 0 and not os.path.islink(full_path): + if digest in file_hashes: + target_path = pathlib.Path(file_hashes[digest]) + link_path = target_path.relative_to(relpath, walk_up=True) + + self.__logger.debug("%s was a duplicate of %s, linking to %s", full_path, file_hashes[digest], link_path) + + os.unlink(full_path) + #os.link(file_hashes[digest], full_path) + os.symlink(link_path, full_path) + else: + file_hashes[digest] = full_path + + + writer.add_files(".", recursive=True ) + + os.rename(client_initrd_path, client_initrd_path + ".old") + + if os.path.exists(client_initrd_path + ".sum"): + os.rename(client_initrd_path + ".sum", client_initrd_path + ".sum.old") + + os.rename(client_initrd_path_new, client_initrd_path) + + + with open(client_initrd_path, "rb") as initrd_file: + hexdigest = hashlib.file_digest(initrd_file, "sha256").hexdigest() + with open(client_initrd_path + ".sum", "w", encoding="utf-8") as digest_file: + digest_file.write(hexdigest) + + self.__logger.info("Updated initrd %s", client_initrd_path) def install(self): """Instalar