🔒 Repository is read-only – file editing is disabled.

PaganLinux/tmp-patch-rest.py main

156 linii Raw ← Powrót
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
#!/usr/bin/env python3
"""Reszta hardeningu: faillock.conf (shadow), secure_path (sudo), hooki (8)."""
import re, sys, yaml

R = "/var/lib/pagan-sync/recipes"


# ── helper 1: podmiana wartosci klucza-scalara (shadow.build) ──
def scalar_range(text, key):
    m = re.search(r"(?m)^" + re.escape(key) + r":", text)
    if not m:
        sys.exit(f"brak klucza {key}")
    i = m.end()
    while i < len(text) and text[i] in " \t":
        i += 1
    if i < len(text) and text[i] == '"':
        j = i + 1
        while j < len(text):
            if text[j] == "\\":
                j += 2
                continue
            if text[j] == '"':
                return i, j + 1
            j += 1
    if i < len(text) and text[i] in "|>":
        line_start = text.rfind("\n", 0, m.start()) + 1
        ind = m.start() - line_start
        j = end = text.find("\n", i) + 1
        while j < len(text):
            nl = text.find("\n", j)
            if nl == -1:
                nl = len(text)
            line = text[j:nl]
            if line.strip() == "":
                j = end = nl + 1
                continue
            if (len(line) - len(line.lstrip(" "))) > ind:
                j = end = nl + 1
            else:
                break
        return text.find("\n", i) + 1, end
    sys.exit("nieobslugiwany styl")


def esc(v):
    return '"' + v.replace("\\", "\\\\").replace('"', '\\"').replace("\n", "\\n") + '"'


def edit_scalar(path, key, old, new, label):
    text = open(path, encoding="utf-8").read()
    cur = (yaml.safe_load(text) or {}).get(key) or ""
    if new in cur:
        print(f"--  {label} (juz)")
        return
    if cur.count(old) != 1:
        sys.exit(f"[{label}] {cur.count(old)} wystapien w {key}")
    nv = cur.replace(old, new, 1)
    s, e = scalar_range(text, key)
    open(path, "w", encoding="utf-8").write(text[:s] + esc(nv) + text[e:])
    print(f"OK  {label}")


# ── helper 2: edycja tekstowa tolerujaca styl (literal / escaped) ──
def edit_text(path, old, new, label):
    text = open(path, encoding="utf-8").read()
    for v in (old, old.replace("\\", "\\\\").replace("\n", "\\n").replace('"', '\\"')):
        if v in text:
            if text.count(v) != 1:
                sys.exit(f"[{label}] {text.count(v)} wystapien")
            repl = new if v == old else new.replace("\\", "\\\\").replace("\n", "\\n").replace('"', '\\"')
            open(path, "w", encoding="utf-8").write(text.replace(v, repl, 1))
            print(f"OK  {label}")
            return
    sys.exit(f"[{label}] nie znaleziono fragmentu")


def bump(path, label, expect=None):
    text = open(path, encoding="utf-8").read()
    m = re.search(r"(?m)^pkgrel:\s*'?(\d+)'?\s*$", text)
    if not m:
        sys.exit(f"[{label}] brak pkgrel")
    cur = int(m.group(1))
    if expect is not None and cur != expect:
        print(f"--  {label}: pkgrel juz {cur}")
        return
    open(path, "w", encoding="utf-8").write(text[:m.start()] + f"pkgrel: '{cur + 1}'" + text[m.end():])
    print(f"OK  {label}: pkgrel -> {cur + 1}")


# ── 1. shadow: /etc/security/faillock.conf ──
SH = f"{R}/core/shadow/PAGBUILD.yaml"
edit_scalar(SH, "build",
            "# Pliki system-* ZOSTAJA w pakiecie",
            "install -v -m755 -d ${PKGDIR}/etc/security\n"
            "cat > ${PKGDIR}/etc/security/faillock.conf << \"EOF\"\n"
            "# Blokada konta po nieudanych probach logowania (pam_faillock,\n"
            "# uzywany przez /etc/pam.d/system-auth i system-account).\n"
            "deny = 5\n"
            "fail_interval = 900\n"
            "unlock_time = 900\n"
            "# even_deny_root nie jest ustawione - root nie zostaje zablokowany.\n"
            "EOF\n"
            "\n"
            "# Pliki system-* ZOSTAJA w pakiecie",
            "shadow: /etc/security/faillock.conf")

# ── 2. sudo: secure_path ──
SU = f"{R}/core/sudo/PAGBUILD.yaml"
edit_text(SU,
          'echo "%wheel ALL=(ALL) ALL" >> ${PKGDIR}/etc/sudoers',
          'echo "Defaults secure_path=\\"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\\"" >> ${PKGDIR}/etc/sudoers\n'
          'echo "%wheel ALL=(ALL) ALL" >> ${PKGDIR}/etc/sudoers',
          "sudo: secure_path")
bump(SU, "sudo", expect=2)

# ── 3. hooki (punkt 8) ──
BA = f"{R}/core/bash/PAGBUILD.yaml"
edit_text(BA, "rm -f bin/sh\nrm -f bin/bash\n",
          "# Usuniete kasowanie /bin/sh i /bin/bash: pakiet dostarcza oba pliki,\n"
          "# a gdy transakcja padala po rm, system zostawal bez powloki.\n",
          "bash: bez rm /bin/sh")
bump(BA, "bash")

GL = f"{R}/core/glibc/PAGBUILD.yaml"
edit_text(GL, "rm -f /etc/nsswitch.conf\n",
          "# Usuniete kasowanie /etc/nsswitch.conf: plik jest w pakiecie, a pag\n"
          "# chroni zmiany uzytkownika (zapisuje .pacnew) - rm byl zbedny.\n",
          "glibc: bez rm nsswitch.conf")
bump(GL, "glibc")

NG = f"{R}/utils/nginx/PAGBUILD.yaml"
edit_text(NG,
          "(getent passwd $UN > /dev/null) && userdel $UN\n"
          "(getent group $UN > /dev/null) && groupdel $UN\n\n"
          "UN=apache\n\n"
          "(getent passwd $UN > /dev/null) && userdel $UN\n"
          "(getent group $UN > /dev/null) && groupdel $UN\n",
          "# Usuniete kasowanie uzytkownikow www/apache: userdel zostawial pliki z\n"
          "# osieroconym uid. Grupa i uzytkownik http sa tworzone ponizej.\n",
          "nginx: bez userdel")
bump(NG, "nginx")

PA = f"{R}/gui/pulseaudio/PAGBUILD.yaml"
edit_text(PA,
          "grep -qe 'autospawn = no' etc/pulse/client.conf||sudo sed '/autospawn/iautospawn = no' -i etc/pulse/client.conf",
          "grep -qe 'autospawn = no' etc/pulse/client.conf || sed -i '/autospawn/iautospawn = no' etc/pulse/client.conf",
          "pulseaudio: bez sudo")
bump(PA, "pulseaudio")

TI = f"{R}/gui/telepathy-idle/PAGBUILD.yaml"
edit_text(TI, "killall -HUP dbus-daemon 2>&1",
          "systemctl reload dbus 2>/dev/null || true",
          "telepathy-idle: reload dbus")
bump(TI, "telepathy-idle")

print("gotowe")