Remote Access: Unterschied zwischen den Versionen
Sv (Diskussion | Beiträge) Add Filesystem Info feature; document OpenSSH SFTP extensions (posix-rename, hardlink, statvfs, fsync); correct stale limitations/future-work entries. |
Sv (Diskussion | Beiträge) password authentication: URL form, code API, auth order; launcher menu entries |
||
| (6 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt) | |||
| Zeile 1: | Zeile 1: | ||
{{Languages|Remote Access| |
{{Languages|Remote Access|label=Deutsch}} |
||
'''Fernzugriff''' bezeichnet die Möglichkeit, einen entfernten |
'''Fernzugriff''' bezeichnet die Möglichkeit, einen entfernten |
||
| Zeile 7: | Zeile 7: | ||
sind unterstützt, in absteigender Empfehlungsreihenfolge: |
sind unterstützt, in absteigender Empfehlungsreihenfolge: |
||
* '''SSH und SFTP''' (empfohlen) — verschlüsselte Shell und sichere |
* '''SSH und SFTP''' (empfohlen) — verschlüsselte Shell und sichere Dateiübertragung über einen SSH-2-Tunnel. Reine Smalltalk-Implementierung in <code>exept:libcrypt/ssh</code>; keine externe Abhängigkeit von OpenSSL oder libssh. Für alles mit Zugangsdaten oder sensiblen Nutzdaten. |
||
* '''Lokale Kommando-Shell''' — fork + exec auf der lokalen Maschine. Für die Anbindung lokaler Werkzeuge und für die lokale Seite eines hybriden Workflows. |
|||
Dateiübertragung über einen SSH-2-Tunnel. Reine |
|||
* '''Telnet''' (veraltet) — Klartext-Terminalsitzung. Keine Verschlüsselung, Passwörter im Klartext auf der Leitung. Nur einsetzen, wenn die Gegenstelle keine Alternative bietet. |
|||
Smalltalk-Implementierung in <code>exept:libcrypt/ssh</code>; |
|||
keine externe Abhängigkeit von OpenSSL oder libssh. Für alles |
|||
mit Zugangsdaten oder sensiblen Nutzdaten. |
|||
* '''Lokale Kommando-Shell''' — fork + exec auf der lokalen |
|||
Maschine. Für die Anbindung lokaler Werkzeuge und für die |
|||
lokale Seite eines hybriden Workflows. |
|||
* '''Telnet''' (veraltet) — Klartext-Terminalsitzung. Keine |
|||
Verschlüsselung, Passwörter im Klartext auf der Leitung. Nur |
|||
einsetzen, wenn die Gegenstelle keine Alternative bietet. |
|||
= SSH und SFTP = |
= SSH und SFTP = |
||
| Zeile 26: | Zeile 18: | ||
SFTP-v3-Subsystem (draft-ietf-secsh-filexfer-02). Zwei Schichten: |
SFTP-v3-Subsystem (draft-ietf-secsh-filexfer-02). Zwei Schichten: |
||
* '''<code>SSH::Client</code>''' — programmatischer SSH-Zugriff |
* '''<code>SSH::Client</code>''' — programmatischer SSH-Zugriff (entferntes <code>exec</code>, TTY-Shell, Agent-Weiterleitung, ProxyJump-Bastion). |
||
(entferntes <code>exec</code>, TTY-Shell, Agent-Weiterleitung, |
|||
ProxyJump-Bastion). |
|||
* '''<code>SSH::SftpFilename</code>''' — eine |
* '''<code>SSH::SftpFilename</code>''' — eine |
||
<code>Filename</code>-Unterklasse, die es dem restlichen ST/X |
|||
erlaubt, einen entfernten SFTP-Pfad zu behandeln wie eine lokale |
|||
Datei. |
|||
Die folgenden Abschnitte sind nutzeraufgaben-zuerst aufgebaut: |
Die folgenden Abschnitte sind nutzeraufgaben-zuerst aufgebaut: |
||
| Zeile 52: | Zeile 42: | ||
<pre> |
<pre> |
||
sftp://[user@]host[:port]/remote/path |
sftp://[user[:password]@]host[:port]/remote/path |
||
</pre> |
</pre> |
||
Fehlt <code>user</code>, wird der lokale Login-Name verwendet, Port |
Fehlt <code>user</code>, wird der lokale Login-Name verwendet, Port |
||
ist standardmäßig 22, Pfad standardmäßig <code>/</code>. |
ist standardmäßig 22, Pfad standardmäßig <code>/</code>. Das |
||
optionale <code>:password</code>-Segment ist das RFC-3986-Userinfo-Passwort |
|||
— wann es angebracht ist und welche Sicherheitsabwägungen |
|||
damit verbunden sind, beschreibt [[#Passwort-Authentifizierung]]. |
|||
Wenn vorhanden, dient es als USERAUTH-Fallback nach den üblichen |
|||
Publickey-/Agent-Versuchen und wird '''niemals''' wieder von der |
|||
druckbaren URL-Form ausgegeben — das Protokollieren des |
|||
Dateinamens leakt also nicht das Credential. |
|||
Die Schaltfläche '''Refresh''' in der Symbolleiste |
|||
(Pfeil-Kreis-Symbol zwischen ''Forward'' und ''DirectoryUp'') liest |
|||
Baum und Inhalts-Panel auf Anforderung neu ein. Funktioniert |
|||
einheitlich für lokale und SFTP-Pfade; bei SFTP wird zusätzlich der |
|||
per-Datei-STAT-Cache geleert, sodass Änderungen, die direkt auf |
|||
der Gegenseite gemacht wurden, sofort sichtbar werden — ohne auf |
|||
den Ablauf der 5-Sekunden-Cache-TTL zu warten. |
|||
Der kleine Pfeil neben dem Refresh-Symbol öffnet ein Aufklappmenü |
|||
mit einem einzelnen Kontrollkästchen, '''Automatic Refresh''', das |
|||
den Hintergrund-Task an- bzw. abschaltet, der alle expandierten |
|||
Baumeinträge auf externe Änderungen prüft. Die Vorgabe richtet |
|||
sich nach der aktuellen Wurzel: |
|||
* Lokales Dateisystem → '''an''' (10-Sekunden-Zyklus, entspricht dem bisherigen Verhalten). |
|||
* SFTP → '''aus'''. Jeder Zyklus kostet einen STAT-Roundtrip pro Kind — für eine Handvoll lokaler Verzeichnisse harmlos, über das Netz schmerzhaft. Bei Bedarf manuell auf Refresh klicken, um Änderungen zu sehen. |
|||
Beim Wechsel zwischen lokalen und SFTP-Wurzeln wird der Schalter |
|||
automatisch umgelegt — aber nur, sofern man ihn für die |
|||
vorherige Wurzel nicht selbst verstellt hat. Eine explizite |
|||
Benutzerwahl bleibt über Navigationen hinweg erhalten. |
|||
Das Menü '''Tools''' im FileBrowserV2 bietet vier Aktionen — die |
Das Menü '''Tools''' im FileBrowserV2 bietet vier Aktionen — die |
||
| Zeile 62: | Zeile 81: | ||
sichtbar: |
sichtbar: |
||
* '''Generate SSH Key Pair...''' — öffnet den |
* '''Generate SSH Key Pair...''' — öffnet den Schlüsselerzeugungs-Dialog, siehe [[#Einen SSH-Schlüssel erzeugen]] unten. |
||
* '''SSH Connect...''' — öffnet ein interaktives VT100-Terminal zu einem entfernten Host. |
|||
Schlüsselerzeugungs-Dialog, siehe |
|||
* '''SFTP Connect...''' — navigiert diesen Browser-Tab über SFTP auf ein entferntes Dateisystem. |
|||
[[#Einen SSH-Schlüssel erzeugen]] unten. |
|||
* '''Filesystem Info...''' — zeigt Größe, freien Platz und Belegung des Dateisystems, das das aktuell angezeigte Verzeichnis enthält. Funktioniert einheitlich für lokale und SFTP-Pfade; bei SFTP setzt der Aufruf voraus, daß der Server die Erweiterung |
|||
* '''SSH Connect...''' — öffnet ein interaktives VT100-Terminal |
|||
<code>statvfs@openssh.com</code> ankündigt (jedes moderne OpenSSH |
|||
zu einem entfernten Host. |
|||
tut das). Größen werden in IEC-Binäreinheiten ausgegeben (MiB, |
|||
* '''SFTP Connect...''' — navigiert diesen Browser-Tab über SFTP |
|||
GiB, TiB) — gewählt wird die größte Einheit, die einen Wert ≥ 1 |
|||
auf ein entferntes Dateisystem. |
|||
liefert, damit ein TB-großes Volume als ''X TiB'' statt |
|||
* '''Filesystem Info...''' — zeigt Größe, freien Platz und Belegung |
|||
''10240 GiB'' erscheint. |
|||
des Dateisystems, das das aktuell angezeigte Verzeichnis enthält. |
|||
Funktioniert einheitlich für lokale und SFTP-Pfade; bei SFTP |
|||
== Aus dem Launcher == |
|||
setzt der Aufruf voraus, daß der Server die Erweiterung |
|||
<code>statvfs@openssh.com</code> ankündigt (jedes moderne OpenSSH |
|||
Das Untermenü '''Workspace''' im Launcher enthält zwei eigenständige |
|||
tut das). Größen werden in IEC-Binäreinheiten ausgegeben (MiB, |
|||
Einträge (nur sichtbar bei geladenem SSH-Paket): |
|||
GiB, TiB) — gewählt wird die größte Einheit, die einen Wert ≥ 1 |
|||
liefert, damit ein TB-großes Volume als ''X TiB'' statt |
|||
* '''SSH Terminal''' — fragt nach einem Ziel der Form <code>user[:password]@host[:port]</code> und öffnet ein VT100-Terminal als eigenständiges Fenster. Das ist das Launcher-Pendant zum FileBrowserV2-Eintrag '''Tools → SSH Connect...'''. |
|||
''10240 GiB'' erscheint. |
|||
* '''SFTP Connection''' — fragt nach einem SFTP-Ziel (gleiche URL-Grammatik wie in der FileBrowserV2-Adresszeile, siehe [[#Aus dem FileBrowserV2]]) und öffnet einen frischen FileBrowserV2, der bereits dorthin navigiert ist. |
|||
Beide Einträge unterstützen die in [[#Passwort-Authentifizierung]] |
|||
beschriebene URL-Form mit eingebettetem Passwort. |
|||
== Aus expecco-Aktionen == |
== Aus expecco-Aktionen == |
||
| Zeile 85: | Zeile 108: | ||
in der expecco-Aktionspalette bereit: |
in der expecco-Aktionspalette bereit: |
||
* '''CmdShell - Open SSH Remote Connection''' — öffnet eine |
* '''CmdShell - Open SSH Remote Connection''' — öffnet eine SSH-Sitzung über das plattformeigene <code>ssh</code>-Binary (PuTTYs <code>plink</code> unter Windows). |
||
* '''CmdShell - Open SSH Remote Connection and PublicKey''' — dasselbe, jedoch mit expliziter Public-Key-Authentifizierung. |
|||
SSH-Sitzung über das plattformeigene <code>ssh</code>-Binary |
|||
(PuTTYs <code>plink</code> unter Windows). |
|||
* '''CmdShell - Open SSH Remote Connection and PublicKey''' — |
|||
dasselbe, jedoch mit expliziter Public-Key-Authentifizierung. |
|||
Voraussetzung: ein eingerichtetes Schlüsselpaar (privater |
Voraussetzung: ein eingerichtetes Schlüsselpaar (privater |
||
| Zeile 108: | Zeile 128: | ||
Der Dialog fragt alle Parameter in einem Formular ab: |
Der Dialog fragt alle Parameter in einem Formular ab: |
||
* '''Comment''' — wird in den erzeugten Schlüssel eingebettet |
* '''Comment''' — wird in den erzeugten Schlüssel eingebettet (Voreinstellung <code>stx@<hostname></code>). |
||
(Voreinstellung <code>stx@<hostname></code>). |
|||
* '''Storage''': |
* '''Storage''': |
||
** ''Save to disk file only'' — schreibt |
** ''Save to disk file only'' — schreibt |
||
<code>~/.ssh/id_ed25519_stx</code> (oder wohin man will) samt |
|||
zugehöriger <code>.pub</code>-Datei daneben. |
|||
** ''Save to disk AND load into ssh-agent'' — schreibt die Datei |
** ''Save to disk AND load into ssh-agent'' — schreibt die Datei UND übergibt den Schlüssel dem laufenden ssh-agent. |
||
** ''Load into ssh-agent only'' — der Schlüssel lebt nur im Speicher des Agents; nach Agent-Neustart ist er verloren. |
|||
UND übergibt den Schlüssel dem laufenden ssh-agent. |
|||
* '''Private key file''' — vollständiger Pfad; ausgegraut im Agent-only-Modus. |
|||
** ''Load into ssh-agent only'' — der Schlüssel lebt nur im |
|||
* '''Passphrase / Confirm''' — leer lässt die On-Disk-Datei unverschlüsselt (Agent-only-Modus ignoriert die Passphrase, da das OpenSSH-Agent-Wire-Protokoll nur den entschlüsselten Schlüssel transportiert). |
|||
Speicher des Agents; nach Agent-Neustart ist er verloren. |
|||
* '''Private key file''' — vollständiger Pfad; ausgegraut im |
|||
Agent-only-Modus. |
|||
* '''Passphrase / Confirm''' — leer lässt die On-Disk-Datei |
|||
unverschlüsselt (Agent-only-Modus ignoriert die Passphrase, da |
|||
das OpenSSH-Agent-Wire-Protokoll nur den entschlüsselten |
|||
Schlüssel transportiert). |
|||
Bei '''Generate''' wird die Public-Key-Zeile (dieselbe |
Bei '''Generate''' wird die Public-Key-Zeile (dieselbe |
||
| Zeile 260: | Zeile 273: | ||
# '''Dienste''' (<code>services.msc</code>) als Administrator öffnen. |
# '''Dienste''' (<code>services.msc</code>) als Administrator öffnen. |
||
# '''OpenSSH Authentication Agent''' suchen, Starttyp auf |
# '''OpenSSH Authentication Agent''' suchen, Starttyp auf '''Automatisch''' setzen, '''Starten''' anklicken. |
||
'''Automatisch''' setzen, '''Starten''' anklicken. |
|||
# In PowerShell: <code>ssh-add $HOME\.ssh\id_ed25519</code>. |
# In PowerShell: <code>ssh-add $HOME\.ssh\id_ed25519</code>. |
||
# Prüfen: <code>ssh-add -l</code>. |
# Prüfen: <code>ssh-add -l</code>. |
||
| Zeile 271: | Zeile 283: | ||
Daher einmalig systemweit setzen: |
Daher einmalig systemweit setzen: |
||
# {{Key|Win}} drücken → "Umgebungsvariablen" → „Systemumgebungs- |
# {{Key|Win}} drücken → "Umgebungsvariablen" → „Systemumgebungs- variablen bearbeiten". |
||
# '''Umgebungsvariablen''' → unter '''Benutzervariablen''', '''Neu''' klicken. |
|||
variablen bearbeiten". |
|||
# '''Umgebungsvariablen''' → unter '''Benutzervariablen''', |
|||
'''Neu''' klicken. |
|||
# Name: <code>SSH_AUTH_SOCK</code> |
# Name: <code>SSH_AUTH_SOCK</code> |
||
# Wert: <code>\\.\pipe\openssh-ssh-agent</code> |
# Wert: <code>\\.\pipe\openssh-ssh-agent</code> |
||
# Ab- und wieder anmelden (oder stx neu starten), damit die neue |
# Ab- und wieder anmelden (oder stx neu starten), damit die neue Umgebung übernommen wird. |
||
Umgebung übernommen wird. |
|||
==== PowerShell-Schnelleinrichtung ==== |
==== PowerShell-Schnelleinrichtung ==== |
||
| Zeile 316: | Zeile 325: | ||
* '''PuTTY pageant''' — eigenes Protokoll; von ST/X's |
* '''PuTTY pageant''' — eigenes Protokoll; von ST/X's |
||
<code>SSH::Agent</code> '''nicht''' unterstützt. Schlüssel zu |
|||
OpenSSH migrieren. |
|||
* '''Git für Windows ssh-agent''' — funktioniert; |
* '''Git für Windows ssh-agent''' — funktioniert; |
||
<code>SSH_AUTH_SOCK</code> auf den dort veröffentlichten Socket |
|||
zeigen lassen. |
|||
* '''WSL 2''' — ein ST/X innerhalb der WSL sieht den WSL-eigenen |
* '''WSL 2''' — ein ST/X innerhalb der WSL sieht den WSL-eigenen Agent normal; ein ST/X auf der Windows-Seite nicht. Eine Brücke per <code>npiperelay</code> + <code>socat</code> ist möglich. |
||
Agent normal; ein ST/X auf der Windows-Seite nicht. Eine |
|||
Brücke per <code>npiperelay</code> + <code>socat</code> ist |
|||
möglich. |
|||
Prüfung über die Settings-Seite |
Prüfung über die Settings-Seite |
||
| Zeile 347: | Zeile 353: | ||
(fragt einmal nach der Passphrase) und nutzt ihn für die übrige |
(fragt einmal nach der Passphrase) und nutzt ihn für die übrige |
||
Sitzung weiter. |
Sitzung weiter. |
||
== Passwort-Authentifizierung == |
|||
Empfohlen ist Public-Key-Authentifizierung (mit oder ohne |
|||
ssh-agent). Passwort-Authentifizierung ist als Fallback gedacht, |
|||
wenn keine Schlüssel verfügbar sind: Altsysteme, Ad-hoc-Zugriff |
|||
auf einen Testserver, Skripte gegen ein Konto, dessen Besitzer den |
|||
Public Key nicht hinterlegen möchte. Zu beachten: |
|||
* Das Klartext-Passwort liegt auf ST/X-Seite für die Lebensdauer des <code>SSH::Client</code> im Speicher — entsprechend behandeln wie jedes andere In-Memory-Geheimnis. |
|||
* Der Server entscheidet, welche Methoden er akzeptiert. Steht in <code>sshd_config</code> <code>PasswordAuthentication no</code>, kann keine Smalltalk-seitige Einstellung das überschreiben. |
|||
* Auf Drahtebene entspricht der Vorgang RFC 4252 §8: das Passwort wandert innerhalb der verschlüsselten SSH-Transportschicht, niemals im Klartext über das Netz. |
|||
=== Aus einer URL === |
|||
Sowohl die FileBrowserV2-Adressleiste als auch die Launcher-Dialoge |
|||
'''Workspace → SFTP Connection''' / '''Workspace → SSH |
|||
Terminal''' akzeptieren ein eingebettetes Passwort an der |
|||
standardmäßigen RFC-3986-Userinfo-Position: |
|||
<pre> |
|||
sftp://alice:s3cret@host.example.com/srv/data |
|||
ssh alice:s3cret@host.example.com:2222 |
|||
</pre> |
|||
Der Parser splittet am '''letzten''' <code>@</code>, sodass |
|||
Passwörter mit enthaltenem <code>@</code> dennoch korrekt geparst |
|||
werden; der erste <code>:</code> im Userinfo-Teil trennt Benutzer |
|||
und Passwort. Passwörter, die selbst ein <code>:</code> enthalten, |
|||
werden in dieser Form nicht unterstützt — dafür die |
|||
programmatische API unten verwenden. |
|||
Das Passwort wird aus der druckbaren URL entfernt: jede Stelle, die |
|||
am Ende den Dateinamen ausgibt (Statuszeile, |
|||
<code>printOn:</code>, <code>nameString</code>, die Breadcrumb-Leiste) |
|||
zeigt die credential-freie Form |
|||
<code>sftp://alice@host.example.com/...</code>. |
|||
=== Aus Code === |
|||
Zwei äquivalente Wege, einem <code>SSH::Client</code> ein Passwort |
|||
mitzugeben: |
|||
<pre> |
|||
"/ Literal -- am einfachsten, Passwort ist nur ein Ivar |
|||
client := SSH::Client newToHost:'host.example.com' port:22 user:'alice'. |
|||
client password:'s3cret'. |
|||
client connect. |
|||
</pre> |
|||
<pre> |
|||
"/ Callback -- lazy; das Passwort lebt nie auf dem Client. |
|||
"/ Praktisch für interaktive Abfrage, Keychain-Lookup oder ein |
|||
"/ Vault-gespeichertes Geheimnis, das nicht langlebig im Speicher |
|||
"/ liegen soll. |
|||
client passwordCallback:[ Dialog requestPassword:'SSH-Passwort' ]. |
|||
client connect. |
|||
</pre> |
|||
Sind beide gesetzt, gewinnt der Callback. Beide werden lazy |
|||
während <code>#connect</code> ausgewertet, nachdem die |
|||
Publickey-/Agent-Versuche abgelehnt wurden — ein |
|||
funktionierender Schlüssel schlägt also immer ein parallel |
|||
konfiguriertes Passwort. |
|||
=== Reihenfolge der Authentifizierungsversuche === |
|||
<code>SSH::Client>>authenticate</code> geht jedes verfügbare |
|||
Credential der Reihe nach durch und kehrt beim ersten zurück, das |
|||
der Server akzeptiert: |
|||
# ssh-agent-Identitäten, sofern <code>#useAgent</code> aufgerufen wurde und der Agent Schlüssel geladen hat. |
|||
# ed25519-Privatschlüssel-Seed, sofern <code>#privateKeyFromFile:</code> einen geladen hat. |
|||
# RSA-Privatschlüssel. |
|||
# ECDSA-Privatschlüssel. |
|||
# Passwort, sofern <code>#password:</code> / <code>#passwordCallback:</code> gesetzt ist '''und''' der Server <code>password</code> in seiner USERAUTH_FAILURE-Methodenliste weiterhin anbietet. |
|||
Jeder Schritt wird übersprungen, wenn die letzte |
|||
<code>USERAUTH_FAILURE</code>-Antwort des Servers die jeweilige |
|||
Methode aus der erlaubten Liste gestrichen hat — auf |
|||
<code>publickey</code> wird also nicht weiter herumgehämmert, |
|||
sobald der Server damit aufhört. Der Passwortversuch läuft nur, |
|||
wenn der Server <code>password</code> noch verlangt; ein falsch |
|||
konfiguriertes Passwort gegen einen reinen Schlüssel-Server erzeugt |
|||
also einen sauberen <code>SSH::AuthenticationError</code> ohne |
|||
zusätzlichen nutzlosen Roundtrip. |
|||
== Konfiguration == |
== Konfiguration == |
||
| Zeile 386: | Zeile 478: | ||
<code>SFTP/pool</code>. Per Rechtsklick: |
<code>SFTP/pool</code>. Per Rechtsklick: |
||
* '''Copy Waiters Stack to Clipboard''' — schreibt den Walkback |
* '''Copy Waiters Stack to Clipboard''' — schreibt den Walkback des letzten Eigners samt aller Waiter als Text in die Zwischenablage. Unverzichtbar, wenn ein Prozess in |
||
<code>readWait</code> innerhalb von |
|||
des letzten Eigners samt aller Waiter als Text in die |
|||
<code>withSftpClientDo:</code> klemmt. |
|||
Zwischenablage. Unverzichtbar, wenn ein Prozess in |
|||
* '''Copy List to Clipboard''' — die ganze Tabelle, ideal für eine E-Mail-Diagnose. |
|||
<code>readWait</code> innerhalb von |
|||
* '''Detect Deadlocks''' — DFS über den Wait-for-Graph, meldet Zyklen. |
|||
<code>withSftpClientDo:</code> klemmt. |
|||
* '''Copy List to Clipboard''' — die ganze Tabelle, ideal für eine |
|||
E-Mail-Diagnose. |
|||
* '''Detect Deadlocks''' — DFS über den Wait-for-Graph, meldet |
|||
Zyklen. |
|||
=== Logger === |
=== Logger === |
||
| Zeile 400: | Zeile 488: | ||
Interessante Ereignisse werden über <code>Logger</code> geloggt: |
Interessante Ereignisse werden über <code>Logger</code> geloggt: |
||
* <code>warning:</code> bei automatischem Reconnect nach toter |
* <code>warning:</code> bei automatischem Reconnect nach toter Verbindung. |
||
Verbindung. |
|||
* <code>warning:</code> bei Idle-Verdrängung eines Pool-Eintrags. |
* <code>warning:</code> bei Idle-Verdrängung eines Pool-Eintrags. |
||
* <code>warning:</code> wenn eine SSH-Schlüsseldatei nicht |
* <code>warning:</code> wenn eine SSH-Schlüsseldatei nicht geparst werden konnte — die Datei wird übersprungen. |
||
geparst werden konnte — die Datei wird übersprungen. |
|||
== Einschränkungen == |
== Einschränkungen == |
||
* '''Nur SFTP v3.''' Kein SETSTAT (kein entferntes |
* '''Nur SFTP v3.''' Kein SETSTAT (kein entferntes chmod / chown / utime), kein SSH_FXP_READLINK exponiert (<code>#isSymbolicLink</code> liefert immer <code>false</code>, |
||
<code>#linkInfo</code> die normale stat-Info). Einige |
|||
chmod / chown / utime), kein SSH_FXP_READLINK exponiert |
|||
SFTPv5+-Annehmlichkeiten werden dennoch über OpenSSH-spezifische |
|||
(<code>#isSymbolicLink</code> liefert immer <code>false</code>, |
|||
SSH_FXP_EXTENDED-Aufrufe nutzbar — siehe |
|||
<code>#linkInfo</code> die normale stat-Info). Einige |
|||
[[#OpenSSH-SFTP-Erweiterungen]] weiter unten. |
|||
SFTPv5+-Annehmlichkeiten werden dennoch über OpenSSH-spezifische |
|||
* '''Serialisierung pro Host.''' Zwei gleichzeitige Operationen am selben Host stehen am Host-Mutex an. Siehe [[#Ausblick]]. |
|||
SSH_FXP_EXTENDED-Aufrufe nutzbar — siehe |
|||
* '''<code>#renameTo:</code>-Fallback hat ein TOCTOU-Fenster.''' Bei Servern, die <code>posix-rename@openssh.com</code> ankündigen (jedes moderne OpenSSH tut das), ist das Überschreiben atomar. Beim seltenen Server, der das nicht tut, wird auf Delete-dann-Rename ausgewichen und ein anderer Prozess kann sich dazwischenschieben. |
|||
[[#OpenSSH-SFTP-Erweiterungen]] weiter unten. |
|||
* '''<code>#isNonEmptyDirectory</code> ist eine Heuristik.''' Liefert immer <code>#isDirectory</code> (die genaue Antwort würde drei Roundtrips pro Verzeichnis-Symbol kosten, was das ursprüngliche Baum-Ausklappen unerträglich gebremst hatte). |
|||
* '''Serialisierung pro Host.''' Zwei gleichzeitige Operationen |
|||
am selben Host stehen am Host-Mutex an. Siehe [[#Ausblick]]. |
|||
* '''<code>#renameTo:</code>-Fallback hat ein TOCTOU-Fenster.''' |
|||
Bei Servern, die <code>posix-rename@openssh.com</code> ankündigen |
|||
(jedes moderne OpenSSH tut das), ist das Überschreiben atomar. |
|||
Beim seltenen Server, der das nicht tut, wird auf |
|||
Delete-dann-Rename ausgewichen und ein anderer Prozess kann sich |
|||
dazwischenschieben. |
|||
* '''<code>#isNonEmptyDirectory</code> ist eine Heuristik.''' |
|||
Liefert immer <code>#isDirectory</code> (die genaue Antwort |
|||
würde drei Roundtrips pro Verzeichnis-Symbol kosten, was das |
|||
ursprüngliche Baum-Ausklappen unerträglich gebremst hatte). |
|||
== Implementierungsdetails == |
== Implementierungsdetails == |
||
| Zeile 473: | Zeile 548: | ||
Der Stack nutzt heute vier OpenSSH-Erweiterungen: |
Der Stack nutzt heute vier OpenSSH-Erweiterungen: |
||
* <code>posix-rename@openssh.com</code> — atomares |
* <code>posix-rename@openssh.com</code> — atomares rename-mit-Überschreiben. Wird automatisch von |
||
<code>SftpFilename>>renameTo:</code> aufgegriffen; die |
|||
rename-mit-Überschreiben. Wird automatisch von |
|||
Delete-dann-Rename-Fallback-Variante kommt nur bei Servern zum |
|||
<code>SftpFilename>>renameTo:</code> aufgegriffen; die |
|||
Einsatz, die die Erweiterung nicht haben. |
|||
Delete-dann-Rename-Fallback-Variante kommt nur bei Servern zum |
|||
* <code>hardlink@openssh.com</code> — Erzeugt einen POSIX-Hardlink. Verfügbar als <code>SftpFilename>>createHardLinkAs:</code>. |
|||
Einsatz, die die Erweiterung nicht haben. |
|||
* <code>hardlink@openssh.com</code> — Erzeugt einen POSIX-Hardlink. |
|||
Verfügbar als <code>SftpFilename>>createHardLinkAs:</code>. |
|||
* <code>statvfs@openssh.com</code> — POSIX- |
* <code>statvfs@openssh.com</code> — POSIX- |
||
<code>statvfs(3)</code>-typische Dateisystem-Statistik. |
|||
Verfügbar als <code>SftpFilename>>fileSystemInfo</code>; |
|||
das Ergebnis ist form-kompatibel zu |
|||
<code>OperatingSystem getDiskInfoOf:</code>, sodass Aufrufer |
|||
lokale und entfernte Pfade einheitlich behandeln können. |
|||
Treibt den Menü-Eintrag '''Tools → Filesystem Info...''' an, |
|||
der am Anfang dieser Seite beschrieben ist. |
|||
* <code>fsync@openssh.com</code> — schreibt den |
* <code>fsync@openssh.com</code> — schreibt den serverseitigen Schreibpuffer eines geöffneten Handles auf Platte. Liegt als |
||
<code>SftpClient>>fsyncHandle:</code> bereit; noch nicht |
|||
serverseitigen Schreibpuffer eines geöffneten Handles auf |
|||
in eine "Durable-Write"-API auf Filename-Ebene eingebunden. |
|||
Platte. Liegt als |
|||
<code>SftpClient>>fsyncHandle:</code> bereit; noch nicht |
|||
in eine "Durable-Write"-API auf Filename-Ebene eingebunden. |
|||
Die verbleibenden OpenSSH-Erweiterungen |
Die verbleibenden OpenSSH-Erweiterungen |
||
| Zeile 508: | Zeile 579: | ||
<code>ConnectionPoolMutex</code> bewacht: |
<code>ConnectionPoolMutex</code> bewacht: |
||
* '''Lazy-Aufbau''' — TCP + KEX + userauth + SFTP-INIT laufen |
* '''Lazy-Aufbau''' — TCP + KEX + userauth + SFTP-INIT laufen erst beim ersten SFTP-Aufruf, nicht in <code>forUrl:</code>. |
||
* '''Serialisierung pro Host''' — SFTP-Anfragen an einen bestimmten Host werden durch einen <code>RecursionLock</code> mit dem Namen <code>SFTP/<user@host:port></code> serialisiert (sichtbar im SemaphoreMonitor). |
|||
erst beim ersten SFTP-Aufruf, nicht in <code>forUrl:</code>. |
|||
* '''Serialisierung pro Host''' — SFTP-Anfragen an einen |
|||
bestimmten Host werden durch einen <code>RecursionLock</code> |
|||
mit dem Namen <code>SFTP/<user@host:port></code> |
|||
serialisiert (sichtbar im SemaphoreMonitor). |
|||
* '''Idle-Verdrängung''' — ein Pool-Eintrag, der länger als |
* '''Idle-Verdrängung''' — ein Pool-Eintrag, der länger als |
||
<code>idleEvictionSeconds</code> ungenutzt liegt, wird beim |
|||
nächsten Zugriff proaktiv geschlossen und neu geöffnet. |
|||
* '''Automatischer Reconnect''' — ein Fehler auf Transportebene |
* '''Automatischer Reconnect''' — ein Fehler auf Transportebene (Broken Pipe, EOF, MNU auf nil-Socket) verdrängt den Pool-Eintrag, öffnet einen frischen Client und wiederholt die Anfrage '''einmal'''. Anwendungsfehler aus SFTP-STATUS-Antworten werden sofort durchgereicht. |
||
(Broken Pipe, EOF, MNU auf nil-Socket) verdrängt den |
|||
Pool-Eintrag, öffnet einen frischen Client und wiederholt die |
|||
Anfrage '''einmal'''. Anwendungsfehler aus |
|||
SFTP-STATUS-Antworten werden sofort durchgereicht. |
|||
== Ausblick == |
== Ausblick == |
||
| Zeile 527: | Zeile 590: | ||
Geplant, aber noch nicht umgesetzt: |
Geplant, aber noch nicht umgesetzt: |
||
* '''Multi-Channel-Parallelität pro Host''' — aktuell bedeutet eine TCP- plus eine SFTP-Verbindung pro Host, dass N gleichzeitige Anfragen serialisieren. Pipelining über mehrere SshClients im Pool (bevorzugt) oder ein transport-seitiger Reader-Prozess, der eingehende Pakete in Pro-Kanal-Postfächer demultiplext, würde es dem Baum-Panel erlauben, weiter aufzulisten, während das Inhalts-Panel eine große Datei liest. |
|||
* '''Multi-Channel-Parallelität pro Host''' — aktuell bedeutet |
|||
* '''Genaues <code>#isNonEmptyDirectory</code>''' via OPEN_DIR + READ_DIR (nur erstes Batch) + CLOSE — drei Roundtrips pro Sondierung; lohnt erst, wenn der SftpClient Anfragen pipelinen kann. |
|||
eine TCP- plus eine SFTP-Verbindung pro Host, dass N |
|||
* '''SFTP-v5/v6-Aushandlung''' für erweiterte Attribute und FTP-artige Kanonisierung. (Atomares Überschreibungs-rename ist bereits über die OpenSSH-Erweiterung |
|||
gleichzeitige Anfragen serialisieren. Pipelining über mehrere |
|||
<code>posix-rename@openssh.com</code> abgedeckt; siehe |
|||
SshClients im Pool (bevorzugt) oder ein transport-seitiger |
|||
[[#OpenSSH-SFTP-Erweiterungen]].) |
|||
Reader-Prozess, der eingehende Pakete in |
|||
Pro-Kanal-Postfächer demultiplext, würde es dem Baum-Panel |
|||
erlauben, weiter aufzulisten, während das Inhalts-Panel eine |
|||
große Datei liest. |
|||
* '''Genaues <code>#isNonEmptyDirectory</code>''' via OPEN_DIR |
|||
+ READ_DIR (nur erstes Batch) + CLOSE — drei Roundtrips pro |
|||
Sondierung; lohnt erst, wenn der SftpClient Anfragen pipelinen |
|||
kann. |
|||
* '''SFTP-v5/v6-Aushandlung''' für erweiterte Attribute und |
|||
FTP-artige Kanonisierung. (Atomares Überschreibungs-rename |
|||
ist bereits über die OpenSSH-Erweiterung |
|||
<code>posix-rename@openssh.com</code> abgedeckt; siehe |
|||
[[#OpenSSH-SFTP-Erweiterungen]].) |
|||
= Kommando-Shell = |
= Kommando-Shell = |
||
| Zeile 582: | Zeile 633: | ||
= Siehe auch = |
= Siehe auch = |
||
* [[SSH Client|SSH::Client]] — die SSH-Schicht (exec, TTY, |
* [[SSH Client|SSH::Client]] — die SSH-Schicht (exec, TTY, Agent-Weiterleitung, ProxyJump). |
||
Agent-Weiterleitung, ProxyJump). |
|||
* [[FileBrowserV2]] — die Haupt-UI dieses Stacks. |
* [[FileBrowserV2]] — die Haupt-UI dieses Stacks. |
||
* [[ClaudeCode plugin|Claude Code]] — nutzt denselben SSH-Stack |
* [[ClaudeCode plugin|Claude Code]] — nutzt denselben SSH-Stack als HTTPS-Transport. |
||
als HTTPS-Transport. |
|||
* [[Wikipedia:Secure Shell|RFC 4251 (SSH-2 Architecture)]] |
* [[Wikipedia:Secure Shell|RFC 4251 (SSH-2 Architecture)]] |
||
* [[Wikipedia:Telnet|RFC 854 (Telnet Protocol)]] |
* [[Wikipedia:Telnet|RFC 854 (Telnet Protocol)]] |
||
Aktuelle Version vom 8. Juni 2026, 14:26 Uhr
| Language: | Deutsch • English |
|---|
Fernzugriff bezeichnet die Möglichkeit, einen entfernten Rechner oder ein entferntes Netzwerk aus diesem expecco-Image heraus zu bedienen — Shells zu öffnen, Befehle abzusetzen, Dateien zu verschieben oder ein Testgerät anzusteuern. Drei Protokoll-Familien sind unterstützt, in absteigender Empfehlungsreihenfolge:
- SSH und SFTP (empfohlen) — verschlüsselte Shell und sichere Dateiübertragung über einen SSH-2-Tunnel. Reine Smalltalk-Implementierung in
exept:libcrypt/ssh; keine externe Abhängigkeit von OpenSSL oder libssh. Für alles mit Zugangsdaten oder sensiblen Nutzdaten. - Lokale Kommando-Shell — fork + exec auf der lokalen Maschine. Für die Anbindung lokaler Werkzeuge und für die lokale Seite eines hybriden Workflows.
- Telnet (veraltet) — Klartext-Terminalsitzung. Keine Verschlüsselung, Passwörter im Klartext auf der Leitung. Nur einsetzen, wenn die Gegenstelle keine Alternative bietet.
SSH und SFTP
Der SSH-Stack deckt das vollständige SSH-2-Protokoll ab (RFC 4251–4254, RFC 5656, RFC 8709, RFC 8731) inklusive der chacha20-poly1305-Transportchiffrierung von OpenSSH sowie das SFTP-v3-Subsystem (draft-ietf-secsh-filexfer-02). Zwei Schichten:
SSH::Client— programmatischer SSH-Zugriff (entferntesexec, TTY-Shell, Agent-Weiterleitung, ProxyJump-Bastion).SSH::SftpFilename— eine
Filename-Unterklasse, die es dem restlichen ST/X
erlaubt, einen entfernten SFTP-Pfad zu behandeln wie eine lokale
Datei.
Die folgenden Abschnitte sind nutzeraufgaben-zuerst aufgebaut: zuerst das, was der Anwender sieht und tut, darunter die expecco-Bibliotheks-Anbindung, ganz unten Implementierungsdetails für Interessierte.
Aus dem FileBrowserV2
Im Adress-Dropdown eine sftp://-URL einfügen. Der
Browser-Tab füllt sich wie bei einem lokalen Pfad.
Baum-Ausklappen, Spaltensortierung (Name / Größe / mtime),
Vorschau und Doppelklick zum Öffnen im Editor verhalten sich
normal. Der erste Klick auf einen Host dauert ~200–500 ms
(TCP + KEX + Auth); folgende Klicks nutzen die gepoolte
Verbindung weiter.
URL-Syntax:
sftp://[user[:password]@]host[:port]/remote/path
Fehlt user, wird der lokale Login-Name verwendet, Port
ist standardmäßig 22, Pfad standardmäßig /. Das
optionale :password-Segment ist das RFC-3986-Userinfo-Passwort
— wann es angebracht ist und welche Sicherheitsabwägungen
damit verbunden sind, beschreibt #Passwort-Authentifizierung.
Wenn vorhanden, dient es als USERAUTH-Fallback nach den üblichen
Publickey-/Agent-Versuchen und wird niemals wieder von der
druckbaren URL-Form ausgegeben — das Protokollieren des
Dateinamens leakt also nicht das Credential.
Die Schaltfläche Refresh in der Symbolleiste (Pfeil-Kreis-Symbol zwischen Forward und DirectoryUp) liest Baum und Inhalts-Panel auf Anforderung neu ein. Funktioniert einheitlich für lokale und SFTP-Pfade; bei SFTP wird zusätzlich der per-Datei-STAT-Cache geleert, sodass Änderungen, die direkt auf der Gegenseite gemacht wurden, sofort sichtbar werden — ohne auf den Ablauf der 5-Sekunden-Cache-TTL zu warten.
Der kleine Pfeil neben dem Refresh-Symbol öffnet ein Aufklappmenü mit einem einzelnen Kontrollkästchen, Automatic Refresh, das den Hintergrund-Task an- bzw. abschaltet, der alle expandierten Baumeinträge auf externe Änderungen prüft. Die Vorgabe richtet sich nach der aktuellen Wurzel:
- Lokales Dateisystem → an (10-Sekunden-Zyklus, entspricht dem bisherigen Verhalten).
- SFTP → aus. Jeder Zyklus kostet einen STAT-Roundtrip pro Kind — für eine Handvoll lokaler Verzeichnisse harmlos, über das Netz schmerzhaft. Bei Bedarf manuell auf Refresh klicken, um Änderungen zu sehen.
Beim Wechsel zwischen lokalen und SFTP-Wurzeln wird der Schalter automatisch umgelegt — aber nur, sofern man ihn für die vorherige Wurzel nicht selbst verstellt hat. Eine explizite Benutzerwahl bleibt über Navigationen hinweg erhalten.
Das Menü Tools im FileBrowserV2 bietet vier Aktionen — die drei SSH-spezifischen sind nur bei geladener SSH-Bibliothek sichtbar:
- Generate SSH Key Pair... — öffnet den Schlüsselerzeugungs-Dialog, siehe #Einen SSH-Schlüssel erzeugen unten.
- SSH Connect... — öffnet ein interaktives VT100-Terminal zu einem entfernten Host.
- SFTP Connect... — navigiert diesen Browser-Tab über SFTP auf ein entferntes Dateisystem.
- Filesystem Info... — zeigt Größe, freien Platz und Belegung des Dateisystems, das das aktuell angezeigte Verzeichnis enthält. Funktioniert einheitlich für lokale und SFTP-Pfade; bei SFTP setzt der Aufruf voraus, daß der Server die Erweiterung
statvfs@openssh.com ankündigt (jedes moderne OpenSSH
tut das). Größen werden in IEC-Binäreinheiten ausgegeben (MiB,
GiB, TiB) — gewählt wird die größte Einheit, die einen Wert ≥ 1
liefert, damit ein TB-großes Volume als X TiB statt
10240 GiB erscheint.
Aus dem Launcher
Das Untermenü Workspace im Launcher enthält zwei eigenständige Einträge (nur sichtbar bei geladenem SSH-Paket):
- SSH Terminal — fragt nach einem Ziel der Form
user[:password]@host[:port]und öffnet ein VT100-Terminal als eigenständiges Fenster. Das ist das Launcher-Pendant zum FileBrowserV2-Eintrag Tools → SSH Connect.... - SFTP Connection — fragt nach einem SFTP-Ziel (gleiche URL-Grammatik wie in der FileBrowserV2-Adresszeile, siehe #Aus dem FileBrowserV2) und öffnet einen frischen FileBrowserV2, der bereits dorthin navigiert ist.
Beide Einträge unterstützen die in #Passwort-Authentifizierung beschriebene URL-Form mit eingebettetem Passwort.
Aus expecco-Aktionen
Das Expecco-RemoteAccess-Plugin (Expecco::RemoteAccessImportPlugin) stellt folgende Testaktionen in der expecco-Aktionspalette bereit:
- CmdShell - Open SSH Remote Connection — öffnet eine SSH-Sitzung über das plattformeigene
ssh-Binary (PuTTYsplinkunter Windows). - CmdShell - Open SSH Remote Connection and PublicKey — dasselbe, jedoch mit expliziter Public-Key-Authentifizierung.
Voraussetzung: ein eingerichtetes Schlüsselpaar (privater
Schlüssel auf dieser Maschine, öffentlicher Teil in der
~/.ssh/authorized_keys des Zielhosts). Schlüssel
erzeugen entweder über den Dialog unten oder über
ssh-keygen.
Das Plugin fügt zusätzlich eine Settings-Seite hinzu: Extras → Settings → Plugins → Remote Access — SSH Keys mit einer einzelnen Schaltfläche Generate SSH Key Pair..., die denselben Dialog öffnet.
Einen SSH-Schlüssel erzeugen
Der Dialog (FileBrowserV2 / Settings-Seite)
Der Dialog fragt alle Parameter in einem Formular ab:
- Comment — wird in den erzeugten Schlüssel eingebettet (Voreinstellung
stx@<hostname>). - Storage:
- Save to disk file only — schreibt
~/.ssh/id_ed25519_stx (oder wohin man will) samt
zugehöriger .pub-Datei daneben.
- Save to disk AND load into ssh-agent — schreibt die Datei UND übergibt den Schlüssel dem laufenden ssh-agent.
- Load into ssh-agent only — der Schlüssel lebt nur im Speicher des Agents; nach Agent-Neustart ist er verloren.
- Private key file — vollständiger Pfad; ausgegraut im Agent-only-Modus.
- Passphrase / Confirm — leer lässt die On-Disk-Datei unverschlüsselt (Agent-only-Modus ignoriert die Passphrase, da das OpenSSH-Agent-Wire-Protokoll nur den entschlüsselten Schlüssel transportiert).
Bei Generate wird die Public-Key-Zeile (dieselbe
ssh-ed25519 AAAA... comment-Zeichenfolge, die
ssh-keygen ausgibt) in die System-Zwischenablage kopiert — zum
direkten Einfügen in die ~/.ssh/authorized_keys des
Zielhosts.
Aus einem Workspace
Für Headless-Deployments, Sandbox-Builds oder Skripte stellt
SSH::Client einen reinen Smalltalk-Schlüsselgenerator
bereit, dessen Ausgabe bit-kompatibel zu
ssh-keygen -t ed25519 ist:
| seed comment priv |
seed := SSH::Client generateEd25519Seed.
comment := 'stx@', OperatingSystem getHostName.
"/ Passphrase-verschlüsselt auf Platte speichern"
priv := (Filename homeDirectory / '.ssh' / 'id_ed25519_stx') pathName.
SSH::Client
saveOpenSshEd25519Seed:seed
toFile:priv
comment:comment
passphrase:'choose-something-long'.
"/ UND in den laufenden Agent laden"
SSH::Client addEd25519SeedToAgent:seed comment:comment.
"/ Public-Key-Zeile zum Einfügen in authorized_keys ausgeben"
Transcript showCR:
(SSH::Client authorizedKeysLineForEd25519Seed:seed comment:comment).
Die so erzeugten Schlüssel sind mit den OpenSSH-Werkzeugen voll
interoperabel (ssh-keygen -y -f ... rekonstruiert den
öffentlichen Schlüssel, ssh-keygen -p -f ... ändert
die Passphrase usw.).
Mit den Shell-Werkzeugen
Der klassische Weg funktioniert weiterhin:
ssh-keygen -t ed25519 -C "stx@your.host" ssh-copy-id user@remotehost ssh-add ~/.ssh/id_ed25519
ssh-agent vorbereiten
Der Weg über den Agent ist dem direkten Lesen von Schlüsseldateien deutlich vorzuziehen: er hält verschlüsselte private Schlüssel einmal pro Sitzung entsperrt und kann Identitäten verwalten (hardware-tokengestützte Schlüssel, KeePassXC-Einträge), die ST/X nie direkt sehen soll.
ST/X erkennt den Agent-Pfad automatisch, sobald
$SSH_AUTH_SOCK zum Zeitpunkt des Starts von stx
in der Prozessumgebung gesetzt ist. Eine spätere Zuweisung aus
einem Workspace nützt nichts.
Linux / macOS
Die meisten Desktop-Distributionen starten einen Agent automatisch beim Login (gnome-keyring unter GNOME, ssh-agent.service unter systemd, KWallet unter KDE). Prüfen im Terminal:
echo $SSH_AUTH_SOCK # /run/user/1000/keyring/ssh oder ähnlich ssh-add -l # listet geladene Identitäten ssh-add ~/.ssh/id_ed25519 # eigene laden, falls nicht da
Läuft gar kein Agent, dieses Snippet in die Shell-rc-Datei aufnehmen:
# ~/.bashrc oder ~/.zshrc
if [ -z "$SSH_AUTH_SOCK" ]; then
eval "$(ssh-agent -s)" > /dev/null
fi
ST/X muss aus einer Shell gestartet werden, die diese rc bereits
gelesen hat — ein Desktop-Launcher aus dem Dateimanager erbt die
Variable nicht. Empfehlung: ein kleines Wrapper-Skript unter
~/.local/bin/, das die rc sourcet und dann stx
startet.
Die Settings-Seite (Extras → Settings → Plugins → Remote Access — SSH Keys) zeigt an, ob das laufende Image einen Agent sieht.
Permanente Einrichtung via systemd
Für einen wirklich sitzungsübergreifenden Agent (überlebt Desktop-
Abmeldung, kommt beim nächsten Login wieder hoch) die bei den
meisten Distros mit dem Paket openssh-clients
ausgelieferte Per-User-systemd-Unit aktivieren:
systemctl --user enable --now ssh-agent.service
Anschließend SSH_AUTH_SOCK in der Shell-rc auf den
User-Service-Socket zeigen lassen (ersetzt das
eval $(ssh-agent -s)-Snippet oben):
export SSH_AUTH_SOCK="${XDG_RUNTIME_DIR}/ssh-agent.socket"
Schlüssel automatisch beim ersten Einsatz laden
Um den manuellen ssh-add-Schritt zu sparen, kann
OpenSSH Schlüssel beim ersten Bedarf selbst in den Agent laden.
In ~/.ssh/config eintragen:
Host *
AddKeysToAgent yes
IdentityFile ~/.ssh/id_ed25519
Die erste SSH-Verbindung fragt dann einmal nach der Passphrase und übergibt den entsperrten Schlüssel an den Agent; weitere Verbindungen nutzen die gespeicherte Identität ohne Prompt.
Windows
Windows 10+ bringt das native OpenSSH inklusive Agent-Dienst mit. Einmalige Einrichtung:
- Dienste (
services.msc) als Administrator öffnen. - OpenSSH Authentication Agent suchen, Starttyp auf Automatisch setzen, Starten anklicken.
- In PowerShell:
ssh-add $HOME\.ssh\id_ed25519. - Prüfen:
ssh-add -l.
Der Windows-OpenSSH-Agent lauscht auf einer Named Pipe
(\\.\pipe\openssh-ssh-agent), nicht auf einem
Unix-Socket. ST/X unterstützt beide Transporte, jedoch setzt das
Windows-ssh-add SSH_AUTH_SOCK nicht selbst.
Daher einmalig systemweit setzen:
- Vorlage:Key drücken → "Umgebungsvariablen" → „Systemumgebungs- variablen bearbeiten".
- Umgebungsvariablen → unter Benutzervariablen, Neu klicken.
- Name:
SSH_AUTH_SOCK - Wert:
\\.\pipe\openssh-ssh-agent - Ab- und wieder anmelden (oder stx neu starten), damit die neue Umgebung übernommen wird.
PowerShell-Schnelleinrichtung
Derselbe Aufbau aus einer Administrator-PowerShell heraus, z.B. für Skripte oder unbeaufsichtigte Bereitstellung:
# Agent jetzt und bei jedem Neustart starten (permanent).
Set-Service -Name ssh-agent -StartupType Automatic
Start-Service ssh-agent
# SSH_AUTH_SOCK dauerhaft für den Benutzer setzen (übersteht Reboots).
[Environment]::SetEnvironmentVariable(
'SSH_AUTH_SOCK',
'\\.\pipe\openssh-ssh-agent',
'User')
# Schlüssel laden (fragt nach Passphrase, falls die Datei verschlüsselt ist).
ssh-add $HOME\.ssh\id_ed25519
Für einen einmaligen Agent-Start ohne dauerhafte Aktivierung
(z.B. Einzelsitzung) die Set-Service-Zeile weglassen
und nur Start-Service ssh-agent ausführen. Die
env-var-Zeile lässt sich ebenfalls weglassen, wenn
SSH_AUTH_SOCK nur in der aktuellen Shell gebraucht
wird — dann statt der [Environment]-Variante
$env:SSH_AUTH_SOCK = '...' verwenden.
Auf stark abgespeckten Windows-Installationen ist der ssh-agent-Dienst eventuell nicht vorhanden. Einmalig nachrüsten über Einstellungen → Apps → Optionale Features → OpenSSH- Client.
Alternative Agenten:
- PuTTY pageant — eigenes Protokoll; von ST/X's
SSH::Agent nicht unterstützt. Schlüssel zu
OpenSSH migrieren.
- Git für Windows ssh-agent — funktioniert;
SSH_AUTH_SOCK auf den dort veröffentlichten Socket
zeigen lassen.
- WSL 2 — ein ST/X innerhalb der WSL sieht den WSL-eigenen Agent normal; ein ST/X auf der Windows-Seite nicht. Eine Brücke per
npiperelay+socatist möglich.
Prüfung über die Settings-Seite (Extras → Settings → Plugins → Remote Access — SSH Keys) — die Anzeige dort meldet, ob das laufende Image den Agent sieht.
Schlüssel automatisch beim ersten Einsatz laden
Windows-OpenSSH speichert agent-geladene Schlüssel nicht
über Agent-Neustarts hinweg. Um nicht nach jedem Reboot manuell
ssh-add aufrufen zu müssen, dieselbe Lazy-Load-
Konfiguration in %USERPROFILE%\.ssh\config
eintragen:
Host *
AddKeysToAgent yes
IdentityFile ~/.ssh/id_ed25519
OpenSSH lädt den Schlüssel dann beim ersten Einsatz in den Agent (fragt einmal nach der Passphrase) und nutzt ihn für die übrige Sitzung weiter.
Passwort-Authentifizierung
Empfohlen ist Public-Key-Authentifizierung (mit oder ohne ssh-agent). Passwort-Authentifizierung ist als Fallback gedacht, wenn keine Schlüssel verfügbar sind: Altsysteme, Ad-hoc-Zugriff auf einen Testserver, Skripte gegen ein Konto, dessen Besitzer den Public Key nicht hinterlegen möchte. Zu beachten:
- Das Klartext-Passwort liegt auf ST/X-Seite für die Lebensdauer des
SSH::Clientim Speicher — entsprechend behandeln wie jedes andere In-Memory-Geheimnis. - Der Server entscheidet, welche Methoden er akzeptiert. Steht in
sshd_configPasswordAuthentication no, kann keine Smalltalk-seitige Einstellung das überschreiben. - Auf Drahtebene entspricht der Vorgang RFC 4252 §8: das Passwort wandert innerhalb der verschlüsselten SSH-Transportschicht, niemals im Klartext über das Netz.
Aus einer URL
Sowohl die FileBrowserV2-Adressleiste als auch die Launcher-Dialoge Workspace → SFTP Connection / Workspace → SSH Terminal akzeptieren ein eingebettetes Passwort an der standardmäßigen RFC-3986-Userinfo-Position:
sftp://alice:s3cret@host.example.com/srv/data ssh alice:s3cret@host.example.com:2222
Der Parser splittet am letzten @, sodass
Passwörter mit enthaltenem @ dennoch korrekt geparst
werden; der erste : im Userinfo-Teil trennt Benutzer
und Passwort. Passwörter, die selbst ein : enthalten,
werden in dieser Form nicht unterstützt — dafür die
programmatische API unten verwenden.
Das Passwort wird aus der druckbaren URL entfernt: jede Stelle, die
am Ende den Dateinamen ausgibt (Statuszeile,
printOn:, nameString, die Breadcrumb-Leiste)
zeigt die credential-freie Form
sftp://alice@host.example.com/....
Aus Code
Zwei äquivalente Wege, einem SSH::Client ein Passwort
mitzugeben:
"/ Literal -- am einfachsten, Passwort ist nur ein Ivar client := SSH::Client newToHost:'host.example.com' port:22 user:'alice'. client password:'s3cret'. client connect.
"/ Callback -- lazy; das Passwort lebt nie auf dem Client. "/ Praktisch für interaktive Abfrage, Keychain-Lookup oder ein "/ Vault-gespeichertes Geheimnis, das nicht langlebig im Speicher "/ liegen soll. client passwordCallback:[ Dialog requestPassword:'SSH-Passwort' ]. client connect.
Sind beide gesetzt, gewinnt der Callback. Beide werden lazy
während #connect ausgewertet, nachdem die
Publickey-/Agent-Versuche abgelehnt wurden — ein
funktionierender Schlüssel schlägt also immer ein parallel
konfiguriertes Passwort.
Reihenfolge der Authentifizierungsversuche
SSH::Client>>authenticate geht jedes verfügbare
Credential der Reihe nach durch und kehrt beim ersten zurück, das
der Server akzeptiert:
- ssh-agent-Identitäten, sofern
#useAgentaufgerufen wurde und der Agent Schlüssel geladen hat. - ed25519-Privatschlüssel-Seed, sofern
#privateKeyFromFile:einen geladen hat. - RSA-Privatschlüssel.
- ECDSA-Privatschlüssel.
- Passwort, sofern
#password:/#passwordCallback:gesetzt ist und der Serverpasswordin seiner USERAUTH_FAILURE-Methodenliste weiterhin anbietet.
Jeder Schritt wird übersprungen, wenn die letzte
USERAUTH_FAILURE-Antwort des Servers die jeweilige
Methode aus der erlaubten Liste gestrichen hat — auf
publickey wird also nicht weiter herumgehämmert,
sobald der Server damit aufhört. Der Passwortversuch läuft nur,
wenn der Server password noch verlangt; ein falsch
konfiguriertes Passwort gegen einen reinen Schlüssel-Server erzeugt
also einen sauberen SSH::AuthenticationError ohne
zusätzlichen nutzlosen Roundtrip.
Konfiguration
Alle Stellschrauben sind klassenseitig auf
SSH::SftpFilename erreichbar:
| Accessor | Voreinstellung | Steuert |
|---|---|---|
#idleEvictionSeconds: |
240 (4 Min) | Wie lange
eine gepoolte Verbindung im Leerlauf liegen darf, bevor sie beim
nächsten Zugriff proaktiv geschlossen und neu geöffnet wird.
Liegt knapp unter dem typischen
|
#attrsCacheTtlSeconds: |
5 | Maximales Alter (s)
eines gecachten STAT, bevor |
#closeAllConnections |
(Aktion) | Reißt jede
gepoolte Verbindung ab. Nützlich nach einem bekannt schlechten Netzereignis, vor einem bewussten Identitätswechsel oder zum sauberen Image-Shutdown. |
Diagnose
SemaphoreMonitor
SemaphoreMonitor über das Untermenü „Status" des
Launchers öffnen. Der pro-Host-SFTP-Mutex erscheint als
SFTP/<user@host:port>, der pool-weite Mutex als
SFTP/pool. Per Rechtsklick:
- Copy Waiters Stack to Clipboard — schreibt den Walkback des letzten Eigners samt aller Waiter als Text in die Zwischenablage. Unverzichtbar, wenn ein Prozess in
readWait innerhalb von
withSftpClientDo: klemmt.
- Copy List to Clipboard — die ganze Tabelle, ideal für eine E-Mail-Diagnose.
- Detect Deadlocks — DFS über den Wait-for-Graph, meldet Zyklen.
Logger
Interessante Ereignisse werden über Logger geloggt:
warning:bei automatischem Reconnect nach toter Verbindung.warning:bei Idle-Verdrängung eines Pool-Eintrags.warning:wenn eine SSH-Schlüsseldatei nicht geparst werden konnte — die Datei wird übersprungen.
Einschränkungen
- Nur SFTP v3. Kein SETSTAT (kein entferntes chmod / chown / utime), kein SSH_FXP_READLINK exponiert (
#isSymbolicLinkliefert immerfalse,
#linkInfo die normale stat-Info). Einige
SFTPv5+-Annehmlichkeiten werden dennoch über OpenSSH-spezifische
SSH_FXP_EXTENDED-Aufrufe nutzbar — siehe
#OpenSSH-SFTP-Erweiterungen weiter unten.
- Serialisierung pro Host. Zwei gleichzeitige Operationen am selben Host stehen am Host-Mutex an. Siehe #Ausblick.
#renameTo:-Fallback hat ein TOCTOU-Fenster. Bei Servern, dieposix-rename@openssh.comankündigen (jedes moderne OpenSSH tut das), ist das Überschreiben atomar. Beim seltenen Server, der das nicht tut, wird auf Delete-dann-Rename ausgewichen und ein anderer Prozess kann sich dazwischenschieben.#isNonEmptyDirectoryist eine Heuristik. Liefert immer#isDirectory(die genaue Antwort würde drei Roundtrips pro Verzeichnis-Symbol kosten, was das ursprüngliche Baum-Ausklappen unerträglich gebremst hatte).
Implementierungsdetails
Für Leser, die die Architektur verstehen wollen. Fünf Klassen, von oben nach unten:
| Klasse | Aufgabe |
|---|---|
SSH::SftpFilename |
Filename-Unterklasse, die
öffentliche API. Bildet |
SSH::SftpClient |
SFTP-v3-Protokoll
(Request/Response-Codec, listDir, stat, open, read, write, mkdir). Wird von SftpFilename angesteuert. |
SSH::Channel |
SSH-Kanal-Multiplexer (CHANNEL_OPEN,
DATA, EOF, CLOSE, WINDOW_ADJUST). Eine logische Sitzung pro Channel-Instanz. |
SSH::Client |
High-Level-SSH-Client: öffnet den
Transport, führt KEX, Hostschlüssel-Prüfung und userauth durch und verteilt anschließend Kanäle. |
SSH::Transport |
Drahtschicht. Banner- und
KEXINIT-Austausch, ChaCha20-Poly1305-Paket-Framing, sendSeq / recvSeq, Heartbeat, SSH_MSG_DISCONNECT. |
OpenSSH-SFTP-Erweiterungen
SFTP v3 (Entwurf draft-ietf-secsh-filexfer-02) ist bewusst
minimal gehalten. OpenSSH bringt einen offenen
Erweiterungsmechanismus mit: der Server listet im
SSH_FXP_VERSION-Reply die Erweiterungsnamen auf, die
er versteht, und der Client ruft sie über
SSH_FXP_EXTENDED(200)-Pakete mit dem
Erweiterungsnamen als erstem String auf. Jede Erweiterung wird
über SSH::SftpClient>>supportsExtension:
feature-detektiert; Aufrufer fallen zurück, wenn der Server sie
nicht ankündigt.
Der Stack nutzt heute vier OpenSSH-Erweiterungen:
posix-rename@openssh.com— atomares rename-mit-Überschreiben. Wird automatisch von
SftpFilename>>renameTo: aufgegriffen; die
Delete-dann-Rename-Fallback-Variante kommt nur bei Servern zum
Einsatz, die die Erweiterung nicht haben.
hardlink@openssh.com— Erzeugt einen POSIX-Hardlink. Verfügbar alsSftpFilename>>createHardLinkAs:.statvfs@openssh.com— POSIX-
statvfs(3)-typische Dateisystem-Statistik.
Verfügbar als SftpFilename>>fileSystemInfo;
das Ergebnis ist form-kompatibel zu
OperatingSystem getDiskInfoOf:, sodass Aufrufer
lokale und entfernte Pfade einheitlich behandeln können.
Treibt den Menü-Eintrag Tools → Filesystem Info... an,
der am Anfang dieser Seite beschrieben ist.
fsync@openssh.com— schreibt den serverseitigen Schreibpuffer eines geöffneten Handles auf Platte. Liegt als
SftpClient>>fsyncHandle: bereit; noch nicht
in eine "Durable-Write"-API auf Filename-Ebene eingebunden.
Die verbleibenden OpenSSH-Erweiterungen
(lsetstat@openssh.com, fstatvfs@openssh.com)
werden in der angekündigten Liste erkannt, aber nicht auf
Filename-Ebene gekapselt — es gibt dafür noch keinen
Filename-seitigen Aufrufer.
Verbindungs-Pooling
Alle SftpFilename-Instanzen, die auf dasselbe Tripel
user@host:port zeigen, teilen sich einen
SSH::Client samt einem SSH::SftpClient.
Der Pool ist klassenseitig und wird von einem einzigen
ConnectionPoolMutex bewacht:
- Lazy-Aufbau — TCP + KEX + userauth + SFTP-INIT laufen erst beim ersten SFTP-Aufruf, nicht in
forUrl:. - Serialisierung pro Host — SFTP-Anfragen an einen bestimmten Host werden durch einen
RecursionLockmit dem NamenSFTP/<user@host:port>serialisiert (sichtbar im SemaphoreMonitor). - Idle-Verdrängung — ein Pool-Eintrag, der länger als
idleEvictionSeconds ungenutzt liegt, wird beim
nächsten Zugriff proaktiv geschlossen und neu geöffnet.
- Automatischer Reconnect — ein Fehler auf Transportebene (Broken Pipe, EOF, MNU auf nil-Socket) verdrängt den Pool-Eintrag, öffnet einen frischen Client und wiederholt die Anfrage einmal. Anwendungsfehler aus SFTP-STATUS-Antworten werden sofort durchgereicht.
Ausblick
Geplant, aber noch nicht umgesetzt:
- Multi-Channel-Parallelität pro Host — aktuell bedeutet eine TCP- plus eine SFTP-Verbindung pro Host, dass N gleichzeitige Anfragen serialisieren. Pipelining über mehrere SshClients im Pool (bevorzugt) oder ein transport-seitiger Reader-Prozess, der eingehende Pakete in Pro-Kanal-Postfächer demultiplext, würde es dem Baum-Panel erlauben, weiter aufzulisten, während das Inhalts-Panel eine große Datei liest.
- Genaues
#isNonEmptyDirectoryvia OPEN_DIR + READ_DIR (nur erstes Batch) + CLOSE — drei Roundtrips pro Sondierung; lohnt erst, wenn der SftpClient Anfragen pipelinen kann. - SFTP-v5/v6-Aushandlung für erweiterte Attribute und FTP-artige Kanonisierung. (Atomares Überschreibungs-rename ist bereits über die OpenSSH-Erweiterung
posix-rename@openssh.com abgedeckt; siehe
#OpenSSH-SFTP-Erweiterungen.)
Kommando-Shell
Lokale Kommando-Shell auf dieser expecco-Maschine. Typische Anwendungen: lokale Kommandozeile, lokales Hilfsprogramm, Brücke zwischen entferntem Workflow und lokalem Tool.
Das RemoteAccess-Plugin stellt bereit:
- CmdShell - Open
- CmdShell - Close
Keine Zugangsdaten, kein Netzwerk — läuft als der Benutzer des expecco-Prozesses. Ausgaben gehen in das expecco-Log.
Telnet
Warnung Telnet ist ein veraltetes Protokoll ohne Verschlüsselung. Passwörter werden im Klartext über die Leitung übertragen; jeder im Netzpfad kann sie lesen. Telnet NUR einsetzen, wenn die Gegenstelle keine Alternative bietet (typisch: alte Industriesteuerungen, Laborgeräte, eingebettete Messgeräte ohne SSH-Stack). Für alles andere #SSH und SFTP verwenden.
Das expecco-Plugin stellt bereit:
- Telnet - Open Remote Connection With Login
- Telnet - Execute Remote Command
- Example - Remote Device Control via Telnet (interne Demo)
Das Telnet-Protokoll (RFC 854) ist ein bidirektionaler 8-Bit-Byte-Strom über TCP, mit In-Band-Steuersequenzen für Terminal-Optionen. Verbindungsaufbau zum Ziel-Host:Port; nach optionalem In-Band-Login können beide Seiten Daten senden.
Siehe auch
- SSH::Client — die SSH-Schicht (exec, TTY, Agent-Weiterleitung, ProxyJump).
- FileBrowserV2 — die Haupt-UI dieses Stacks.
- Claude Code — nutzt denselben SSH-Stack als HTTPS-Transport.
- RFC 4251 (SSH-2 Architecture)
- RFC 854 (Telnet Protocol)