saltcorn-samba 0.4.0 → 0.4.1
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 +44 -0
- package/index.js +18 -1
- package/package.json +1 -1
- package/smb-client.js +37 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,50 @@ 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.4.1] – 2026-07-05
|
|
8
|
+
|
|
9
|
+
### Fixed – **`QUERY_DIRECTORY failed: 0xC0000033` auf Share-Root (Samba 4.20+/4.23+)**
|
|
10
|
+
|
|
11
|
+
Symptom nach dem 0.4.0-Update: der Verbindungstest schlägt sofort fehl mit
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
Fehler: QUERY_DIRECTORY failed: 0xC0000033
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
(`STATUS_OBJECT_NAME_INVALID`). Betroffen sind Setups **ohne Basispfad** —
|
|
18
|
+
sobald ein Basispfad gesetzt ist, greift der Fehler nicht.
|
|
19
|
+
|
|
20
|
+
**Ursache:** `smb3-client` öffnet den Share-Root im SMB2-CREATE mit einem
|
|
21
|
+
leeren Filename (`""`). Moderne Samba-Versionen (bestehen jedenfalls
|
|
22
|
+
**4.20+**, bestätigt auf **4.23.9**) akzeptieren das für CREATE, weisen
|
|
23
|
+
aber das anschließende `QUERY_DIRECTORY` mit `FileIdBothDirectoryInformation`
|
|
24
|
+
auf dem leeren Namen als `OBJECT_NAME_INVALID` zurück. Vergleichbare
|
|
25
|
+
Probleme sind aus anderen Java-/Go-SMB-Client-Bibliotheken bekannt (z. B.
|
|
26
|
+
[smbj#80](https://github.com/hierynomus/smbj/issues/80)).
|
|
27
|
+
|
|
28
|
+
**Lösung:**
|
|
29
|
+
|
|
30
|
+
1. `smb-client.js#readdir("")` bekommt einen Fallback: wenn der
|
|
31
|
+
Server auf dem leeren Root mit `OBJECT_NAME_INVALID` antwortet, wird
|
|
32
|
+
die Auflistung noch einmal mit `share/.` (aktuelles Verzeichnis) und,
|
|
33
|
+
falls das ebenfalls scheitert, mit `share/*` (Wildcard) probiert.
|
|
34
|
+
Erst wenn auch das nicht klappt, wird eine deutsche Fehlermeldung mit
|
|
35
|
+
Handlungsanweisung ausgelöst.
|
|
36
|
+
2. Die `/sambatest`-Route greift auf `client.stat("")` zurück, wenn das
|
|
37
|
+
Root-`readdir` mit `OBJECT_NAME_INVALID` scheitert. `stat("")`
|
|
38
|
+
verwendet CREATE ohne `DIRECTORY_FILE`-Flag und ohne QUERY_DIRECTORY —
|
|
39
|
+
das beweist Netzwerk + Negotiate + Session-Setup + TREE_CONNECT + Auth
|
|
40
|
+
ohne die problematische Query. Der Test liefert dann `entry_count: 0`
|
|
41
|
+
und den Hinweis, dass ein Basispfad gesetzt werden sollte, sofern der
|
|
42
|
+
Server das Root-Listing nicht anders bereitstellt.
|
|
43
|
+
|
|
44
|
+
### Empfehlung
|
|
45
|
+
|
|
46
|
+
Wenn Ihr Samba-Server das Share-Root-`QUERY_DIRECTORY` weiterhin ablehnt,
|
|
47
|
+
setzen Sie in der Plugin-Config einen **Basispfad** (z. B. `daten` oder
|
|
48
|
+
`projekte`) — dann sind alle Directory-Listings innerhalb dieses
|
|
49
|
+
Unterverzeichnisses, was durchgängig funktioniert.
|
|
50
|
+
|
|
7
51
|
## [0.4.0] – 2026-07-05
|
|
8
52
|
|
|
9
53
|
### ⚠️ BREAKING CHANGES
|
package/index.js
CHANGED
|
@@ -795,8 +795,25 @@ code{background:#f4f4f4;padding:2px 6px;border-radius:3px;word-break:break-all}<
|
|
|
795
795
|
try {
|
|
796
796
|
const listing = await withClient(testCfg, async (client) => {
|
|
797
797
|
// If base_path is set, list it — that also verifies traversal.
|
|
798
|
+
// For the share-root case we first try readdir; some Samba builds
|
|
799
|
+
// reject QUERY_DIRECTORY on the empty root name, so we fall back
|
|
800
|
+
// to stat("") — that already proves the whole handshake
|
|
801
|
+
// (TCP + Negotiate + Session + TREE_CONNECT + Auth) works, which
|
|
802
|
+
// is all the connection test actually promises.
|
|
798
803
|
const rel = testCfg.base_path ? sanitizeRelativePath(testCfg.base_path) : "";
|
|
799
|
-
|
|
804
|
+
try {
|
|
805
|
+
return await client.readdir(rel);
|
|
806
|
+
} catch (err) {
|
|
807
|
+
const msg = String((err && err.message) || err || "");
|
|
808
|
+
const isRootProbe = !rel;
|
|
809
|
+
const isNameInvalid = /0xC0000033|OBJECT_NAME_INVALID/i.test(msg);
|
|
810
|
+
if (isRootProbe && isNameInvalid) {
|
|
811
|
+
// Fall back: proof-of-life via stat on share root.
|
|
812
|
+
await client.stat("");
|
|
813
|
+
return [];
|
|
814
|
+
}
|
|
815
|
+
throw err;
|
|
816
|
+
}
|
|
800
817
|
});
|
|
801
818
|
const took = Date.now() - started;
|
|
802
819
|
return res.json({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "saltcorn-samba",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "Saltcorn plugin: browse, upload, rename and delete files on a Samba/CIFS share via SMB 3.1.1 (AES-CMAC signing, optional encryption). 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
|
@@ -273,7 +273,43 @@ async function buildClient(config) {
|
|
|
273
273
|
*/
|
|
274
274
|
async readdir(rel) {
|
|
275
275
|
const full = resolvePath(rel);
|
|
276
|
-
|
|
276
|
+
let dirents;
|
|
277
|
+
try {
|
|
278
|
+
dirents = await client.readdir(full, { withFileTypes: true });
|
|
279
|
+
} catch (err) {
|
|
280
|
+
// Some Samba builds (observed on 4.20+/4.23+) reject
|
|
281
|
+
// SMB2 QUERY_DIRECTORY on the *share root* with
|
|
282
|
+
// STATUS_OBJECT_NAME_INVALID (0xC0000033) because the CREATE
|
|
283
|
+
// used an empty filename. The fallback below re-issues the
|
|
284
|
+
// request with an explicit path (".") which most Samba VFS
|
|
285
|
+
// modules accept for the current directory.
|
|
286
|
+
const status = (err && (err.status || err.code)) || "";
|
|
287
|
+
const msg = String((err && err.message) || err || "");
|
|
288
|
+
const isRoot = !rel && !basePath;
|
|
289
|
+
const isNameInvalid =
|
|
290
|
+
/0xC0000033|STATUS_OBJECT_NAME_INVALID|OBJECT_NAME_INVALID/i.test(msg) ||
|
|
291
|
+
status === 0xc0000033;
|
|
292
|
+
if (isRoot && isNameInvalid) {
|
|
293
|
+
try {
|
|
294
|
+
dirents = await client.readdir(shareName + "/.", { withFileTypes: true });
|
|
295
|
+
} catch (_) {
|
|
296
|
+
// Second fallback: an explicit wildcard segment.
|
|
297
|
+
try {
|
|
298
|
+
dirents = await client.readdir(shareName + "/*", { withFileTypes: true });
|
|
299
|
+
} catch (_) {
|
|
300
|
+
const e = new Error(
|
|
301
|
+
"QUERY_DIRECTORY auf dem Share-Root schlug fehl (" +
|
|
302
|
+
(msg || "OBJECT_NAME_INVALID") + "). " +
|
|
303
|
+
"Setzen Sie einen Basispfad im Plugin-Konfig oder prüfen Sie die Share-Definition auf dem Server."
|
|
304
|
+
);
|
|
305
|
+
e.cause = err;
|
|
306
|
+
throw e;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
} else {
|
|
310
|
+
throw err;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
277
313
|
// Parallel enrichment. Bounded to a reasonable concurrency to avoid
|
|
278
314
|
// saturating the SMB session on huge directories.
|
|
279
315
|
const CHUNK = 16;
|