saltcorn-samba 0.3.10 → 0.3.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +58 -0
- package/README.md +89 -0
- package/index.js +31 -0
- package/package.json +1 -1
- package/smb-client.js +63 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,64 @@ All notable changes to `saltcorn-samba` are documented here.
|
|
|
4
4
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)
|
|
5
5
|
and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
6
6
|
|
|
7
|
+
## [0.3.11] – 2026-07-05
|
|
8
|
+
|
|
9
|
+
### Fixed – **Worker-Crash / 502 durch DES-ECB auf Node 17+ / OpenSSL 3**
|
|
10
|
+
|
|
11
|
+
Symptom nach dem 0.3.10-Update:
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
node:internal/crypto/cipher:117
|
|
15
|
+
Error: error:0308010C:digital envelope routines::unsupported
|
|
16
|
+
at Cipheriv.createCipherBase ...
|
|
17
|
+
at .../@marsaud/smb2/node_modules/ntlm/lib/smbhash.js:46
|
|
18
|
+
code: 'ERR_OSSL_EVP_UNSUPPORTED'
|
|
19
|
+
worker died
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Auf der Config-Seite dann: **„Antwort war kein JSON (HTTP 502)“**.
|
|
23
|
+
|
|
24
|
+
**Ursache:** `@marsaud/smb2` benutzt über das transitive Paket `ntlm` den
|
|
25
|
+
Cipher **DES-ECB** zur Berechnung der LM/NTLM-Hashes. Node.js ab Version 17
|
|
26
|
+
ist gegen OpenSSL 3 gebaut, das DES-ECB standardmäßig blockiert. Der
|
|
27
|
+
`createCipheriv("des-ecb", ...)`-Aufruf wirft dann synchron
|
|
28
|
+
`ERR_OSSL_EVP_UNSUPPORTED`. Weil der Fehler synchron aus tiefen Callback-
|
|
29
|
+
Aufrufen kommt, tötet er den Saltcorn-Worker-Prozess → der Reverse-Proxy
|
|
30
|
+
liefert 502 → die Route liefert kein JSON.
|
|
31
|
+
|
|
32
|
+
**Fixes in diesem Release:**
|
|
33
|
+
|
|
34
|
+
1. **Präventiver Check in `smb-client.js`:** Beim ersten Aufbau eines
|
|
35
|
+
SMB-Clients wird geprüft, ob `crypto.createCipheriv("des-ecb", ...)`
|
|
36
|
+
funktioniert. Wenn nicht, wird eine saubere, ausführliche deutsche
|
|
37
|
+
Fehlermeldung mit Lieferanleitung geworfen (`E_LEGACY_CRYPTO`) — der
|
|
38
|
+
fehlerhafte NTLM-Code wird gar nicht erst betreten, der Worker überlebt.
|
|
39
|
+
2. **`/sambatest`-Route:** Der Check läuft zusätzlich explizit **vor**
|
|
40
|
+
dem `withClient`-Aufruf und liefert JSON mit `code: "E_LEGACY_CRYPTO"`,
|
|
41
|
+
`error`, `hint`, `node_version` und `openssl_version` — damit steht der
|
|
42
|
+
Diagnose-Grund direkt in der UI, nicht im Server-Log.
|
|
43
|
+
3. **Fehler-Mapping erweitert:** Falls der Crash doch mal aus einem
|
|
44
|
+
anderen Pfad kommt (z. B. spätere Reconnect-Versuche), erkennt die
|
|
45
|
+
Catch-Logik jetzt auch `ERR_OSSL_EVP_UNSUPPORTED`,
|
|
46
|
+
`digital envelope routines` und `unsupported` und liefert einen
|
|
47
|
+
verständlichen Hinweis.
|
|
48
|
+
4. **README:** Neuer Abschnitt „Troubleshooting“ mit Setup-Rezepten für
|
|
49
|
+
`NODE_OPTIONS=--openssl-legacy-provider` (Umgebungsvariable, systemd,
|
|
50
|
+
Docker/Compose, PM2, direkter Aufruf) plus Tabelle mit den häufigsten
|
|
51
|
+
Verbindungsfehlern und Diagnose-Kommandos.
|
|
52
|
+
|
|
53
|
+
### Notes
|
|
54
|
+
- Das Plugin ändert keinen Node-Startparameter selbst — das können wir aus
|
|
55
|
+
Sicherheits- und Prozessgründen nicht (Node-Flags müssen beim Prozess-
|
|
56
|
+
Start gesetzt werden). Der Fix ist eine saubere Fehlererkennung mit
|
|
57
|
+
Lösungsanleitung.
|
|
58
|
+
- Sobald Saltcorn mit `NODE_OPTIONS=--openssl-legacy-provider` läuft,
|
|
59
|
+
funktionieren Verbindungstest und alle SMB-Operationen ohne weitere
|
|
60
|
+
Anpassung.
|
|
61
|
+
- **Roadmap:** Migration weg von `@marsaud/smb2` (letzter Release 2020) hin
|
|
62
|
+
zu einer aktiv gepflegten SMB-Client-Bibliothek, damit das
|
|
63
|
+
Legacy-Provider-Flag nicht mehr nötig ist.
|
|
64
|
+
|
|
7
65
|
## [0.3.10] – 2026-07-05
|
|
8
66
|
|
|
9
67
|
### Fixed – **DNS-Fehler: `getaddrinfo ENOTFOUND "host:445"`**
|
package/README.md
CHANGED
|
@@ -331,6 +331,95 @@ Ab dann taucht das Plugin im Plugins-Store jeder Saltcorn-Instanz auf.
|
|
|
331
331
|
|
|
332
332
|
---
|
|
333
333
|
|
|
334
|
+
## Troubleshooting
|
|
335
|
+
|
|
336
|
+
### `ERR_OSSL_EVP_UNSUPPORTED` / `digital envelope routines::unsupported` / Worker stirbt / 502 Bad Gateway
|
|
337
|
+
|
|
338
|
+
Die Bibliothek `@marsaud/smb2` benutzt intern (im transitiven Paket `ntlm`)
|
|
339
|
+
den Cipher **DES-ECB**, um die NTLM/LM-Hashes zu berechnen. Ab **Node.js 17**
|
|
340
|
+
mit **OpenSSL 3** ist DES-ECB standardmäßig deaktiviert. Der Aufruf wirft
|
|
341
|
+
dann synchron:
|
|
342
|
+
|
|
343
|
+
```
|
|
344
|
+
Error: error:0308010C:digital envelope routines::unsupported
|
|
345
|
+
code: 'ERR_OSSL_EVP_UNSUPPORTED'
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
Weil der Fehler synchron aus dem NTLM-Modul kommt, **tötet er den
|
|
349
|
+
Saltcorn-Worker-Prozess**. Der davor sitzende Reverse-Proxy meldet dann
|
|
350
|
+
`502 Bad Gateway` und die Antwort ist kein JSON — was auf der Config-Seite
|
|
351
|
+
als "Antwort war kein JSON (HTTP 502)" erscheint.
|
|
352
|
+
|
|
353
|
+
**Lösung:** Saltcorn mit dem Node-Flag `--openssl-legacy-provider` starten.
|
|
354
|
+
Je nach Setup:
|
|
355
|
+
|
|
356
|
+
**(a) Umgebungsvariable (empfohlen, wirkt auf jeden Node-Aufruf)**
|
|
357
|
+
|
|
358
|
+
```bash
|
|
359
|
+
export NODE_OPTIONS="--openssl-legacy-provider"
|
|
360
|
+
saltcorn serve
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
**(b) systemd-Unit** (`/etc/systemd/system/saltcorn.service`)
|
|
364
|
+
|
|
365
|
+
```ini
|
|
366
|
+
[Service]
|
|
367
|
+
Environment=NODE_OPTIONS=--openssl-legacy-provider
|
|
368
|
+
ExecStart=/usr/bin/saltcorn serve
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
Danach:
|
|
372
|
+
```bash
|
|
373
|
+
sudo systemctl daemon-reload
|
|
374
|
+
sudo systemctl restart saltcorn
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
**(c) Docker / docker-compose**
|
|
378
|
+
|
|
379
|
+
```yaml
|
|
380
|
+
services:
|
|
381
|
+
saltcorn:
|
|
382
|
+
image: saltcorn/saltcorn:latest
|
|
383
|
+
environment:
|
|
384
|
+
NODE_OPTIONS: "--openssl-legacy-provider"
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
**(d) PM2**
|
|
388
|
+
|
|
389
|
+
```bash
|
|
390
|
+
pm2 delete saltcorn
|
|
391
|
+
NODE_OPTIONS="--openssl-legacy-provider" pm2 start saltcorn -- serve
|
|
392
|
+
pm2 save
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
**(e) Direkter Aufruf**
|
|
396
|
+
|
|
397
|
+
```bash
|
|
398
|
+
node --openssl-legacy-provider $(which saltcorn) serve
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
Nach dem Neustart im Config-Dialog erneut auf „Verbindung jetzt testen“
|
|
402
|
+
klicken — die Fehlermeldung sollte weg sein.
|
|
403
|
+
|
|
404
|
+
> **Hinweis zur Sicherheit:** `--openssl-legacy-provider` reaktiviert die
|
|
405
|
+
> alten Cipher für den gesamten Node-Prozess. Das ist für NTLM-Auth gegen
|
|
406
|
+
> Samba akzeptabel (der Cipher wird nur zur Hash-Berechnung genutzt, nicht
|
|
407
|
+
> für den Transport), aber ein Grund, mittelfristig auf eine gepflegte
|
|
408
|
+
> SMB-Client-Bibliothek zu wechseln — siehe Roadmap.
|
|
409
|
+
|
|
410
|
+
### Weitere häufige Fehler
|
|
411
|
+
|
|
412
|
+
| Symptom | Ursache | Lösung |
|
|
413
|
+
|---|---|---|
|
|
414
|
+
| `getaddrinfo ENOTFOUND host:445` | Bis v0.3.9 wurde der Port in den UNC-Pfad geschrieben | Update auf **v0.3.10+** |
|
|
415
|
+
| `ECONNREFUSED :445` | SMB-Dienst läuft nicht oder Firewall blockt Port 445 | `nc -vz <server> 445` vom Saltcorn-Host testen |
|
|
416
|
+
| `ETIMEDOUT` | Kein Netzwerkpfad (VLAN/Docker-Bridge/VPN) | Vom Saltcorn-Container aus `ping` + `nc -vz` prüfen |
|
|
417
|
+
| `STATUS_LOGON_FAILURE` | User/Passwort/Domain falsch | Zugangsdaten prüfen. Moderne Samba-Server erlauben keine leeren Passwörter |
|
|
418
|
+
| `STATUS_BAD_NETWORK_NAME` | Share existiert nicht oder Schreibweise falsch | `smbclient -L //server -U user` zur Kontrolle |
|
|
419
|
+
| Nur SMBv1 verfügbar | Server bietet SMB2/3 nicht an | In `smb.conf`: `min protocol = SMB2` |
|
|
420
|
+
|
|
421
|
+
---
|
|
422
|
+
|
|
334
423
|
## Bekannte Grenzen
|
|
335
424
|
|
|
336
425
|
- Dateien werden komplett gepuffert (`readFile` / `writeFile`). Für
|
package/index.js
CHANGED
|
@@ -47,6 +47,8 @@ const {
|
|
|
47
47
|
mimeFromName,
|
|
48
48
|
sanitizeRelativePath,
|
|
49
49
|
sanitizeFilename,
|
|
50
|
+
checkLegacyCryptoAvailable,
|
|
51
|
+
legacyCryptoErrorMessage,
|
|
50
52
|
} = require("./smb-client");
|
|
51
53
|
const treeView = require("./tree-view");
|
|
52
54
|
const fileManagerView = require("./filemanager-view");
|
|
@@ -747,6 +749,33 @@ code{background:#f4f4f4;padding:2px 6px;border-radius:3px;word-break:break-all}<
|
|
|
747
749
|
if (!testCfg.server) return jsonError(res, 400, "Please enter a Server (hostname or IP).");
|
|
748
750
|
if (!testCfg.share) return jsonError(res, 400, "Please enter a Share name.");
|
|
749
751
|
|
|
752
|
+
// Vor jedem echten SMB-Aufruf: Node/OpenSSL-Legacy-Cipher-Check.
|
|
753
|
+
// Falls DES-ECB nicht verfügbar ist (Node 17+ / OpenSSL 3 ohne
|
|
754
|
+
// --openssl-legacy-provider), übergeben wir gar nicht erst an ntlm,
|
|
755
|
+
// sonst crasht der Worker synchron und der Proxy meldet 502.
|
|
756
|
+
const cc = checkLegacyCryptoAvailable();
|
|
757
|
+
if (!cc.ok) {
|
|
758
|
+
return res.status(200).json({
|
|
759
|
+
ok: false,
|
|
760
|
+
error: legacyCryptoErrorMessage(cc.message),
|
|
761
|
+
code: "E_LEGACY_CRYPTO",
|
|
762
|
+
hint:
|
|
763
|
+
"Saltcorn mit --openssl-legacy-provider starten. " +
|
|
764
|
+
"Am einfachsten: die Umgebungsvariable NODE_OPTIONS=--openssl-legacy-provider setzen und Saltcorn neu starten. " +
|
|
765
|
+
"Details und Beispiele für systemd / Docker / PM2 stehen in der README des Plugins.",
|
|
766
|
+
attempted: {
|
|
767
|
+
server: testCfg.server,
|
|
768
|
+
share: testCfg.share,
|
|
769
|
+
port: testCfg.port,
|
|
770
|
+
domain: testCfg.domain,
|
|
771
|
+
username: testCfg.username || "(anonymous)",
|
|
772
|
+
base_path: testCfg.base_path || "(share root)",
|
|
773
|
+
},
|
|
774
|
+
node_version: process.version,
|
|
775
|
+
openssl_version: (process.versions && process.versions.openssl) || null,
|
|
776
|
+
});
|
|
777
|
+
}
|
|
778
|
+
|
|
750
779
|
const started = Date.now();
|
|
751
780
|
try {
|
|
752
781
|
const listing = await withClient(testCfg, async (client) => {
|
|
@@ -798,6 +827,8 @@ code{background:#f4f4f4;padding:2px 6px;border-radius:3px;word-break:break-all}<
|
|
|
798
827
|
hint = "The server may be offering only SMBv1 which this plugin does not support. Enable SMB2 / SMB3 on the Samba server (min protocol = SMB2 in smb.conf).";
|
|
799
828
|
else if (m.includes("traversal") || m.includes("path"))
|
|
800
829
|
hint = "The Base path could not be validated. It must be a relative sub-directory (e.g. 'projects/2026'), never start with / or \\, and must not contain '..'.";
|
|
830
|
+
else if (code === "ERR_OSSL_EVP_UNSUPPORTED" || code === "E_LEGACY_CRYPTO" || m.includes("digital envelope routines") || m.includes("unsupported"))
|
|
831
|
+
hint = "Node blockiert die Legacy-Cipher (DES-ECB), die @marsaud/smb2 für NTLM benötigt. Saltcorn mit NODE_OPTIONS=--openssl-legacy-provider neu starten. Details in der README.";
|
|
801
832
|
|
|
802
833
|
return res.status(200).json({
|
|
803
834
|
ok: false,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "saltcorn-samba",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.11",
|
|
4
4
|
"description": "Saltcorn plugin: browse, upload, rename and delete files on a Samba/CIFS share. File-manager view, directory tree, inline PDF viewer, external-app open (smb://).",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
package/smb-client.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
const path = require("path");
|
|
10
|
+
const crypto = require("crypto");
|
|
10
11
|
|
|
11
12
|
// @marsaud/smb2 is loaded lazily so the pure sanitizer helpers exported by
|
|
12
13
|
// this module can be required (e.g. from unit tests) without needing the
|
|
@@ -18,6 +19,57 @@ function getSMB2() {
|
|
|
18
19
|
return _SMB2;
|
|
19
20
|
}
|
|
20
21
|
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
// OpenSSL 3 / Node 17+ compatibility check
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
//
|
|
26
|
+
// @marsaud/smb2 -> ntlm -> smbhash.js benutzt DES-ECB für die LM/NTLM-Hashes.
|
|
27
|
+
// Node 17+ mit OpenSSL 3 blockiert DES-ECB standardmäßig; der Aufruf wirft
|
|
28
|
+
// dann `error:0308010C:digital envelope routines::unsupported`
|
|
29
|
+
// (ERR_OSSL_EVP_UNSUPPORTED). Der Fehler fliegt synchron und tötet den
|
|
30
|
+
// Saltcorn-Worker → der Reverse-Proxy meldet 502 Bad Gateway.
|
|
31
|
+
//
|
|
32
|
+
// Hier fangen wir das VOR dem eigentlichen SMB-Aufruf ab und liefern eine
|
|
33
|
+
// verständliche Fehlermeldung mit Lösungsanleitung.
|
|
34
|
+
let _cryptoOK = null;
|
|
35
|
+
function checkLegacyCryptoAvailable() {
|
|
36
|
+
if (_cryptoOK !== null) return _cryptoOK;
|
|
37
|
+
try {
|
|
38
|
+
// DES-ECB genau so aufrufen, wie es ntlm intern tut.
|
|
39
|
+
// Wenn OpenSSL 3 ohne Legacy-Provider läuft, wirft das hier.
|
|
40
|
+
const key = Buffer.alloc(8, 0);
|
|
41
|
+
const c = crypto.createCipheriv("des-ecb", key, null);
|
|
42
|
+
c.setAutoPadding(false);
|
|
43
|
+
c.update(Buffer.alloc(8, 0));
|
|
44
|
+
c.final();
|
|
45
|
+
_cryptoOK = { ok: true };
|
|
46
|
+
} catch (e) {
|
|
47
|
+
_cryptoOK = {
|
|
48
|
+
ok: false,
|
|
49
|
+
code: e && e.code,
|
|
50
|
+
message: (e && e.message) || String(e),
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
return _cryptoOK;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** Baut eine deutsche Erklärung für den Legacy-Provider-Fehler. */
|
|
57
|
+
function legacyCryptoErrorMessage(detail) {
|
|
58
|
+
return (
|
|
59
|
+
"NTLM-Authentifizierung nicht möglich: Node.js blockiert die von " +
|
|
60
|
+
"@marsaud/smb2 benötigten Legacy-Cipher (DES-ECB). Das ist ab Node 17 " +
|
|
61
|
+
"mit OpenSSL 3 der Standard. " +
|
|
62
|
+
"Lösung: Saltcorn mit dem Flag --openssl-legacy-provider starten. " +
|
|
63
|
+
"Beispiele: " +
|
|
64
|
+
"(1) direkt: `node --openssl-legacy-provider node_modules/.bin/saltcorn serve` " +
|
|
65
|
+
"(2) per Umgebungsvariable: `NODE_OPTIONS=--openssl-legacy-provider saltcorn serve` " +
|
|
66
|
+
"(3) systemd-Unit: `Environment=NODE_OPTIONS=--openssl-legacy-provider` " +
|
|
67
|
+
"(4) Docker: im Compose-File `environment: NODE_OPTIONS: --openssl-legacy-provider`. " +
|
|
68
|
+
"Danach Saltcorn neu starten. Details siehe README des Plugins. " +
|
|
69
|
+
(detail ? "[Original: " + detail + "]" : "")
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
|
|
21
73
|
// ---------------------------------------------------------------------------
|
|
22
74
|
// Path helpers
|
|
23
75
|
// ---------------------------------------------------------------------------
|
|
@@ -116,6 +168,15 @@ function buildClient(config) {
|
|
|
116
168
|
if (!share) throw new Error("Samba: share missing");
|
|
117
169
|
if (/[\\/]/.test(share)) throw new Error("Samba: share must not contain slashes");
|
|
118
170
|
|
|
171
|
+
// WICHTIG: OpenSSL-Legacy-Check VOR jedem SMB2-Aufruf. Sonst crasht
|
|
172
|
+
// ntlm/smbhash.js synchron und tötet den Worker (→ 502 am Proxy).
|
|
173
|
+
const cc = checkLegacyCryptoAvailable();
|
|
174
|
+
if (!cc.ok) {
|
|
175
|
+
const err = new Error(legacyCryptoErrorMessage(cc.message));
|
|
176
|
+
err.code = "E_LEGACY_CRYPTO";
|
|
177
|
+
throw err;
|
|
178
|
+
}
|
|
179
|
+
|
|
119
180
|
// Host und Port sauber trennen. Der Server-String darf NICHT im share-UNC-
|
|
120
181
|
// Pfad landen, sonst versucht Node's DNS "host:port" als Hostnamen aufzulösen
|
|
121
182
|
// (getaddrinfo ENOTFOUND "1.2.3.4:445"). @marsaud/smb2 nimmt den Port über
|
|
@@ -314,4 +375,6 @@ module.exports = {
|
|
|
314
375
|
toSmbPath,
|
|
315
376
|
toSmbUrl,
|
|
316
377
|
mimeFromName,
|
|
378
|
+
checkLegacyCryptoAvailable,
|
|
379
|
+
legacyCryptoErrorMessage,
|
|
317
380
|
};
|