Dateien nach "/" hochladen

This commit is contained in:
2026-07-01 14:59:34 +02:00
commit ccd8908538
2 changed files with 452 additions and 0 deletions
+140
View File
@@ -0,0 +1,140 @@
#!/usr/bin/env python3
"""
Zwei Funktionen fuer den JViewer-Start mit IcedTea-Web:
1) JNLP-Strukturpatch (Standardaufruf):
patch_jviewer.py <input.jnlp> <output.jnlp>
- <security>/<all-permissions> bleiben UNVERAENDERT: die Jars werden
signiert (s.u.), signierter+vertrauter Code mit dieser Anforderung
bekommt regulaer AllPermission - kein Grund mehr, das zu entfernen.
- <nativelib> wird trotzdem zu <jar> umbenannt: das ist laut Fehlermeldung
"nativelib kann nicht angegeben werden sofern vertrauenswuerdige
Umgebung angefordert wird" mit <security><all-permissions/> inkompatibel,
unabhaengig davon ob signiert oder nicht.
- <codebase> bleibt UNVERAENDERT (zeigt weiter auf die echte BMC). Das ist
wichtig: IcedTea-Web erlaubt unsignierten/nicht vertrauten Apps im
Sandbox-Modus nur Netzwerkzugriff zurueck zu Host+Port der Codebase. Der
KVM-Redirection-Socket (Port 7578) geht an dieselbe IP wie die BMC/
Codebase, aber einen anderen Port - wuerde man die Codebase auf einen
lokalen Proxy umbiegen, wuerde der Zugriff verboten (getestet, "access
denied SocketPermission").
2) Manifest-Patch fuer ein bereits von IcedTea-Web heruntergeladenes,
gecachtes Jar (wird NACH einem ersten, absichtlich fehlschlagenden
javaws-Lauf aufgerufen, der nur zum Befuellen des Caches dient):
patch_jviewer.py --strip-manifest <jarfile> [<jarfile> ...]
Frueherer Ansatz: entfernte "Permissions: all-permissions" aus dem
Manifest, um IcedTea-Webs hartcodierte Forced-Sandbox fuer UNSIGNIERTEN
Code mit dieser Deklaration zu umgehen. Wird seit Einfuehrung der
Selbstsignierung NICHT MEHR aufgerufen (das Attribut wird fuer signierten,
vertrauten Code wieder gebraucht) - Funktion bleibt nur als Fallback im
Code, falls Signierung aus irgendeinem Grund nicht moeglich ist.
"""
import os
import re
import sys
import zipfile
def localname(t):
"""Tag-Namen ohne Namespace-Praefix, egal ob die JNLP ein xmlns deklariert
oder nicht (manche AMI-Firmwarestaende tun es, manche nicht)."""
return t.split("}", 1)[-1] if "}" in t else t
def is_tag(el, name):
return localname(el.tag) == name
def strip_all_permissions_from_manifest(jar_path):
with zipfile.ZipFile(jar_path, "r") as zin:
manifest_name = "META-INF/MANIFEST.MF"
try:
manifest = zin.read(manifest_name).decode("utf-8", "replace")
except KeyError:
print(f"(kein Manifest in {jar_path}, nichts zu tun)")
return
# Manifest-Continuation-Zeilen (beginnen mit einem Leerzeichen) an die
# vorherige Zeile anhaengen, damit "Permissions: all-permissions"
# sicher als eine logische Zeile erkannt wird.
lines = manifest.splitlines()
logical = []
for line in lines:
if line.startswith(" ") and logical:
logical[-1] += line[1:]
else:
logical.append(line)
filtered = [l for l in logical if not re.match(r"(?i)^permissions\s*:", l)]
if filtered == logical:
print(f"(Permissions-Attribut in {jar_path} nicht vorhanden, nichts zu tun)")
return
new_manifest = "\n".join(filtered) + "\n"
entries = {}
for item in zin.infolist():
entries[item] = zin.read(item.filename)
tmp_path = jar_path + ".tmp"
with zipfile.ZipFile(tmp_path, "w", zipfile.ZIP_DEFLATED) as zout:
for item, data in entries.items():
if item.filename == manifest_name:
data = new_manifest.encode("utf-8")
zout.writestr(item, data)
os.replace(tmp_path, jar_path)
print(f"Manifest gepatcht (Permissions: all-permissions entfernt): {jar_path}")
def patch_jnlp(src, dst):
import xml.etree.ElementTree as ET
tree = ET.parse(src)
root = tree.getroot()
# Falls die JNLP ein xmlns deklariert (z.B. xmlns="http://www.w3.org/1999/xhtml"),
# dieselbe Namespace-URI beim Schreiben wieder als Default-Namespace nutzen,
# damit ET keine ns0:-Praefixe einfuegt.
root_ns = localname(root.tag)
if root.tag != root_ns:
ns_uri = root.tag[1:root.tag.index("}")]
ET.register_namespace("", ns_uri)
# <security>/<all-permissions> bleiben unangetastet (s. Docstring oben) -
# nur <nativelib> zu <jar> umbenennen (Namespace-Praefix des Originaltags beibehalten)
for el in root.iter():
if is_tag(el, "nativelib"):
prefix = el.tag[: el.tag.index("}") + 1] if "}" in el.tag else ""
el.tag = f"{prefix}jar"
tree.write(dst, encoding="UTF-8", xml_declaration=True)
print(f"Gepatchte JNLP geschrieben: {dst}")
def main():
args = sys.argv[1:]
if args and args[0] == "--strip-manifest":
jar_paths = args[1:]
if not jar_paths:
print("Benutzung: patch_jviewer.py --strip-manifest <jarfile> [<jarfile> ...]")
sys.exit(1)
for jar_path in jar_paths:
strip_all_permissions_from_manifest(jar_path)
return
if len(args) != 2:
print("Benutzung: patch_jviewer.py <input.jnlp> <output.jnlp>")
print(" oder: patch_jviewer.py --strip-manifest <jarfile> [<jarfile> ...]")
sys.exit(1)
patch_jnlp(args[0], args[1])
if __name__ == "__main__":
main()
+312
View File
@@ -0,0 +1,312 @@
#!/bin/bash
set -e
BASE="$(cd "$(dirname "$0")" && pwd)"
echo "=== JViewer Auto Starter ==="
echo "Ordner: $BASE"
# Altes Log löschen, damit nie ein Log aus einem früheren Lauf verwechselt wird
rm -f "$BASE/jviewer-debug.log"
if [ "$1" != "-c" ] || [ -z "$2" ]; then
echo "Benutzung:"
echo "$0 -c datei.jnlp"
exit 1
fi
JNLP="$2"
if [ "${JNLP:0:1}" != "/" ]; then
JNLP="$BASE/$JNLP"
fi
if [ ! -f "$JNLP" ]; then
echo "JNLP nicht gefunden:"
echo "$JNLP"
exit 1
fi
echo "JNLP:"
echo "$JNLP"
# ---------------------------------------------------------------------------
# Java 8 suchen / herunterladen (Temurin JDK von Adoptium - JDK statt JRE,
# weil wir jarsigner/keytool brauchen um die Jars selbst zu signieren, s.u.)
# ---------------------------------------------------------------------------
JAVA=$(find "$BASE/java8" -type f -name java 2>/dev/null | head -1)
JARSIGNER=$(find "$BASE/java8" -type f -name jarsigner 2>/dev/null | head -1)
if [ -z "$JAVA" ] || [ -z "$JARSIGNER" ]; then
echo "Kein vollständiges Java8-JDK gefunden (java+jarsigner) - lade neu..."
rm -rf "$BASE/java8"
mkdir -p "$BASE/java8"
(
cd "$BASE/java8"
wget -O java8.tar.gz \
"https://api.adoptium.net/v3/binary/latest/8/ga/linux/x64/jdk/hotspot/normal/eclipse"
tar xf java8.tar.gz
rm java8.tar.gz
)
JAVA=$(find "$BASE/java8" -type f -name java | head -1)
JARSIGNER=$(find "$BASE/java8" -type f -name jarsigner | head -1)
fi
if [ -z "$JAVA" ] || [ -z "$JARSIGNER" ]; then
echo "Java8-JDK (java + jarsigner) konnte nicht bereitgestellt werden"
exit 1
fi
KEYTOOL="$(dirname "$JARSIGNER")/keytool"
JAVA_HOME="$(dirname "$(dirname "$JAVA")")"
echo
echo "Java:"
echo "$JAVA"
"$JAVA" -version
echo "jarsigner: $JARSIGNER"
echo "keytool: $KEYTOOL"
# ---------------------------------------------------------------------------
# javaws finden (icedtea-netx). Wird NICHT lokal erwartet, sondern im System
# gesucht (z.B. /usr/bin/javaws aus dem Paket "icedtea-netx").
# ---------------------------------------------------------------------------
JAVAWS=""
for CAND in "$BASE/javaws" "$(command -v javaws 2>/dev/null)" /usr/bin/javaws; do
if [ -n "$CAND" ] && [ -x "$CAND" ]; then
JAVAWS="$CAND"
break
fi
done
if [ -z "$JAVAWS" ]; then
echo "javaws wurde nicht gefunden."
echo "Bitte installieren: sudo apt install icedtea-netx"
exit 1
fi
echo
echo "javaws:"
echo "$JAVAWS"
# ---------------------------------------------------------------------------
# Eigene, isolierte Umgebung (HOME) für IcedTea-Web, damit Systemeinstellungen
# nicht stören und nichts außerhalb von $BASE verändert wird.
# ---------------------------------------------------------------------------
export HOME="$BASE/runtime-home"
# IcedTea-Web folgt zuerst XDG_CONFIG_HOME/XDG_CACHE_HOME, falls diese im
# System bereits gesetzt sind - dann wird HOME ignoriert und die echte
# System-Config (~/.config/icedtea-web) verwendet statt unserer eigenen.
# Deshalb XDG-Variablen explizit auf unseren eigenen Bereich zwingen.
export XDG_CONFIG_HOME="$HOME/.config"
export XDG_CACHE_HOME="$HOME/.cache"
# Cache wird bei jedem Lauf frisch geleert (Jars sollen neu von der BMC
# geladen und neu gepatcht/signiert werden). Der Config-Ordner wird NICHT
# mehr komplett gelöscht: falls die automatische Zertifikatsvertrauensstellung
# unten nicht zuverlässig greift und stattdessen ein GUI-Dialog erscheint, in
# dem man einmalig "Diesem Zertifikat immer vertrauen" klickt, soll diese
# Entscheidung über Neustarts hinweg erhalten bleiben statt jedes Mal verworfen
# zu werden.
rm -rf "$XDG_CACHE_HOME/icedtea-web"
mkdir -p "$XDG_CONFIG_HOME/icedtea-web"
mkdir -p "$XDG_CACHE_HOME/icedtea-web"
# JAVA_HOME/PATH auf das heruntergeladene Java8 zwingen, damit javaws nicht
# irgendeine System-Java-Version verwendet.
export JAVA_HOME
export PATH="$JAVA_HOME/bin:$PATH"
# Hinweis: deployment.javaws.jre.0.*, deployment.javaws.cache.* und
# deployment.manifest.attribute.check werden von dieser IcedTea-Web-Version
# nicht erkannt ("Eigenschaft ist unbekannt" im Log) und wurden deshalb
# entfernt. Das heruntergeladene Java8 wird stattdessen ueber JAVA_HOME/PATH
# erzwungen (s.o.) - das greift laut Log zuverlaessig ("your JRE - 1.8.0_492").
# Die Sandbox-Beschraenkung fuer unsignierten Code wird nicht per Config,
# sondern durch Selbstsignierung der Jars geloest (siehe unten).
cat > "$XDG_CONFIG_HOME/icedtea-web/deployment.properties" <<EOF
deployment.security.level=ALLOW_UNSIGNED
deployment.proxy.type=0
deployment.user.cachedir=$XDG_CACHE_HOME/icedtea-web
EOF
# ---------------------------------------------------------------------------
# JNLP patchen (patch_jviewer.py):
# - <security>/<all-permissions> bleiben unverändert (Jars werden signiert,
# s.u. - signierter+vertrauter Code mit dieser Anforderung bekommt regulär
# AllPermission)
# - <nativelib> zu <jar> ändern (inkompatibel mit <security><all-permissions/>,
# unabhängig von Signierung)
# - <codebase> bleibt UNVERÄNDERT (zeigt weiter auf die echte BMC), damit
# IcedTea-Webs Sandbox-Regel "Netzwerkzugriff nur zurück zum Codebase-Host"
# den KVM-Redirection-Socket (Port 7578, selbe IP wie die BMC) erlaubt,
# falls Vertrauen aus irgendeinem Grund doch nicht greift.
# ---------------------------------------------------------------------------
echo
echo "Patch JNLP"
FIXED="$BASE/fixed-$(basename "$JNLP")"
rm -f "$FIXED"
if [ ! -f "$BASE/patch_jviewer.py" ]; then
echo "FEHLER: $BASE/patch_jviewer.py fehlt."
exit 1
fi
python3 "$BASE/patch_jviewer.py" "$JNLP" "$FIXED"
PATCH_RC=$?
if [ "$PATCH_RC" -ne 0 ]; then
echo "FEHLER: patch_jviewer.py ist mit Exitcode $PATCH_RC abgebrochen."
exit 1
fi
if [ ! -f "$FIXED" ]; then
echo "FEHLER: $FIXED wurde nicht erzeugt."
exit 1
fi
echo
echo "Kontrolle:"
if grep -q "nativelib" "$FIXED"; then
echo "FEHLER: JNLP wurde NICHT gepatcht (nativelib noch vorhanden)."
exit 1
fi
echo "(nativelib wurde in jar umbenannt - ok)"
# ---------------------------------------------------------------------------
# 1. Lauf: absichtlich nur zum Befüllen des Caches. javaws lädt die Original-
# jars von der echten BMC in den eigenen Cache und wird danach vermutlich mit
# einem Berechtigungsfehler abbrechen (Manifest deklariert "all-permissions",
# ist aber unsigniert) - das ist an dieser Stelle erwartet und kein Problem.
# ---------------------------------------------------------------------------
echo
echo "Lauf 1/2: Cache befüllen (Abbruch danach ist normal)"
cd "$BASE"
set +e
"$JAVAWS" -verbose "$FIXED" >"$BASE/jviewer-debug-pass1.log" 2>&1
set -e
CACHED_JARS=$(find "$XDG_CACHE_HOME/icedtea-web" -type f -name '*.jar' 2>/dev/null)
if [ -z "$CACHED_JARS" ]; then
echo "FEHLER: Nach Lauf 1 wurden keine Jars im Cache gefunden."
echo "--- jviewer-debug-pass1.log ---"
cat "$BASE/jviewer-debug-pass1.log"
exit 1
fi
echo "Im Cache gefundene Jars:"
echo "$CACHED_JARS"
# ---------------------------------------------------------------------------
# Jars selbst signieren (selbstsigniertes Zertifikat). Das Manifest-Attribut
# "Permissions: all-permissions" bleibt dabei UNVERÄNDERT im Jar (frühere
# Script-Version entfernte es, um die Forced-Sandbox für UNSIGNIERTEN Code zu
# umgehen - das Attribut wird jetzt für signierten, vertrauten Code aber
# gerade gebraucht, um volle Rechte statt Sandbox zu bekommen).
# ---------------------------------------------------------------------------
# Unsignierter Code bekommt von IcedTea-Web nur die restriktive Sandbox
# (Socket-Permission ist an Host UND Port der Codebase gebunden - der
# KVM-Redirection-Port 7578 unterscheidet sich vom Codebase-Port 443 und wird
# deshalb verweigert, s. DEVLOG). Signierter Code mit "Permissions:
# all-permissions" bekommt nach einmaligem Vertrauen des Zertifikats volle
# Rechte statt Sandbox - deshalb signieren wir hier selbst und importieren
# das Zertifikat in IcedTea-Webs Trusted-Certs-Store, damit kein manueller
# Klick nötig ist (Best-Effort - Pfad/Format ist nicht offiziell dokumentiert
# und wurde nicht auf dem Zielsystem verifiziert, siehe DEVLOG).
# ---------------------------------------------------------------------------
echo
echo "Signiere gecachte Jars (selbstsigniertes Zertifikat)"
SIGNING_DIR="$BASE/signing"
KEYSTORE="$SIGNING_DIR/jviewer.jks"
CERT="$SIGNING_DIR/jviewer.crt"
ALIAS="jviewer"
STOREPASS="jviewer-local"
mkdir -p "$SIGNING_DIR"
if [ ! -f "$KEYSTORE" ]; then
echo "Erzeuge neues Signier-Schlüsselpaar (einmalig, wird unter $SIGNING_DIR aufbewahrt)"
"$KEYTOOL" -genkeypair \
-keystore "$KEYSTORE" -storepass "$STOREPASS" -keypass "$STOREPASS" \
-alias "$ALIAS" -keyalg RSA -keysize 2048 -validity 3650 \
-dname "CN=JViewer Local, OU=jviewer, O=local, L=local, S=local, C=DE"
fi
"$KEYTOOL" -exportcert -rfc \
-keystore "$KEYSTORE" -storepass "$STOREPASS" -alias "$ALIAS" -file "$CERT"
# shellcheck disable=SC2086
for JAR in $CACHED_JARS; do
"$JARSIGNER" -keystore "$KEYSTORE" -storepass "$STOREPASS" "$JAR" "$ALIAS"
done
# Zertifikat in IcedTea-Webs Trusted-Certs-Store eintragen, damit kein
# Vertrauens-Dialog erscheinen muss. Falls das nicht greift, fragt IcedTea-Web
# beim 2. Lauf per GUI-Dialog nach - dort einmalig "immer vertrauen" wählen.
TRUSTED_CERTS_DIR="$XDG_CONFIG_HOME/icedtea-web/security"
TRUSTED_CERTS_STORE="$TRUSTED_CERTS_DIR/trusted.certs"
TRUSTED_STOREPASS="changeit"
mkdir -p "$TRUSTED_CERTS_DIR"
"$KEYTOOL" -importcert -noprompt \
-keystore "$TRUSTED_CERTS_STORE" -storepass "$TRUSTED_STOREPASS" \
-alias "$ALIAS" -file "$CERT" || echo "Hinweis: Import in Trusted-Certs-Store fehlgeschlagen - ggf. manuell im GUI-Dialog bestätigen."
# ---------------------------------------------------------------------------
# 2. Lauf: mit -Xoffline, damit die (jetzt gepatchten und signierten) Cache-
# Dateien verwendet werden, ohne dass IcedTea-Web sie erneut von der BMC
# herunterlädt und damit den Patch überschreibt.
# ---------------------------------------------------------------------------
echo
echo "Lauf 2/2: Starte JViewer (offline, aus gepatchtem Cache):"
echo "$FIXED"
"$JAVAWS" -Xoffline -verbose "$FIXED" 2>&1 | tee "$BASE/jviewer-debug.log"
echo
echo "Log:"
echo "$BASE/jviewer-debug.log"
read -p "ENTER zum Beenden"