From cb4d9c8a9ee8d5fa54b6196c9d5f41a0b019c8db Mon Sep 17 00:00:00 2001 From: Mario Fetka Date: Mon, 1 Jun 2026 20:32:01 +0000 Subject: [PATCH] docs: document ncp22 quota and trustee layouts --- TODO.md | 58 ++++++++++++++++----- src/nwbind.c | 22 ++++++-- src/nwconn.c | 142 +++++++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 187 insertions(+), 35 deletions(-) diff --git a/TODO.md b/TODO.md index cc688b4..221d254 100644 --- a/TODO.md +++ b/TODO.md @@ -186,21 +186,23 @@ Follow-up: Current status: -- `NCP 0x2222/22` is handled in `src/nwconn.c`, not forwarded to `nwbind.c`. +- `NCP 0x2222/22` is handled in `src/nwconn.c`, with selected quota-related + subfunctions forwarded to `src/nwbind.c` for bindery/ObjectID prehandling. - The group header is documented inline as `SubFuncStrucLen` (Hi-Lo), `SubFunctionCode`, and subfunction payload. - The first NetWare 1.x/2.x/3.x-compatible directory services subfunctions now have inline SDK request/reply layout documentation: `22/00` Set Directory Handle, `22/01` Get Directory Path, - `22/02` Scan Directory Information, `22/03` Get Effective Directory Rights, `22/04` Modify Maximum Rights Mask, `22/05` Get - Volume Number, and `22/06` Get Volume Name. + `22/02` Scan Directory Information, `22/03` Get Effective Directory Rights, + `22/04` Modify Maximum Rights Mask, `22/05` Get Volume Number, and `22/06` + Get Volume Name. - The old SDK PDF table for `22/00` repeats `TargetDirectoryHandle` for the second payload byte, but the remarks describe a source handle; MARS-NWE parses the byte as `SourceDirectoryHandle`. This is documented inline but not changed. -- No NetWare 1.x/2.x/3.x SDK/PDF entries were found for direct `22/07`, `22/08`, or - `22/09` during this audit. The next documented direct directory calls - continue at `22/0a`. +- No NetWare 1.x/2.x/3.x SDK/PDF entries were found for direct `22/07`, + `22/08`, or `22/09` during this audit. The next documented direct directory + calls continue at `22/0a`. - `22/0a` Create Directory, `22/0b` Delete Directory, `22/0d` Add Trustee to Directory, `22/0e` Delete Trustee from Directory, and `22/0f` Rename Directory now have inline request-layout documentation. @@ -240,10 +242,29 @@ Current status: - `22/1f` consumes the documented `DirectoryHandle`; legacy source comments expected two extra unknown bytes after it, but the SDK request has no such fields and the helper ignores them. -- `22/20` reads `VolumeNumber` and `Sequence` in the normal NCP 22 payload - positions. The WebSDK/PDF table for this call shows `VolumeNumber` one byte - later than the common group-header alignment; treat this as an offset - ambiguity until verified with a direct test caller. +- `22/20` reads `VolumeNumber` in the normal NCP 22 payload position, but the + WebSDK/PDF table for this call shows `VolumeNumber` one byte later than the + common group-header alignment. The code also reads `Sequence` with + `GET_BE32()` although the SDK/PDF documents Lo-Hi; treat both as audit items + until verified with a direct test caller. +- `22/21` Add User Disk Space Restriction, `22/22` Remove User Disk Space + Restrictions, `22/25` Set Directory Entry Information, `22/26` Scan File or + Directory for Extended Trustees, `22/27` Add Extended Trustee to Directory or + File, `22/28` Scan Directory Disk Space, and `22/29` Get Object Disk Usage + and Restrictions now have inline request/reply layout documentation. +- `22/21` and `22/22` are forwarded to `nwbind.c` for quota prehandling; both + layers are documented. The shared `nwbind` prehandler reads ObjectID from + the documented payload position. +- `22/26`, `22/27`, and `22/29` match the documented request payload offsets. +- `22/25` matches the documented payload field order, but the current parser + reads Sequence with `GET_BE32()` although the SDK/PDF documents Lo-Hi. +- `22/21` includes a documented DiskSpaceLimit field, but the current shared + quota prehandler in `nwbind.c` does not consume it before returning the + uid/gid/permission tuple. +- `22/28` matches the documented payload offsets, but the current parser reads + Sequence with `GET_BE32()` although the SDK/PDF documents Lo-Hi; it also + returns the normal directory scan structure from `nw_scan_a_directory()` + rather than the full documented Scan Directory Disk Space reply. Follow-up: @@ -266,10 +287,19 @@ Follow-up: - Verify whether `22/1f` should continue accepting legacy callers that send the two extra bytes described by the old source comment, even though the SDK request only contains `DirectoryHandle`. -- Verify `22/20` VolumeNumber offset against a direct test caller; the WebSDK - table appears shifted by one byte compared with the normal NCP 22 group - header and the current parser. -- Continue the `0x2222/22` audit from `22/21` Add User Disk Space Restriction +- Verify `22/20` VolumeNumber offset and Sequence byte order against a direct + test caller; the WebSDK table appears shifted by one byte compared with the + normal NCP 22 group header, and current code uses `GET_BE32()` although the + SDK/PDF documents Lo-Hi. +- Decide whether `22/21` should pass the documented DiskSpaceLimit through the + quota prehandling path or whether the current behavior is intentionally + handled later in the quota backend. +- Verify `22/25` Sequence byte order; current code uses `GET_BE32()` although + the SDK/PDF documents Lo-Hi. +- Verify `22/28` Sequence byte order and reply shape; current code uses + `GET_BE32()` and delegates to the normal directory scan reply rather than the + documented Scan Directory Disk Space reply. +- Continue the `0x2222/22` audit from `22/30` Get Name Space Directory Entry onward, keeping each patch to a small logical endpoint block. diff --git a/src/nwbind.c b/src/nwbind.c index 1cc31ff..8cd7035 100644 --- a/src/nwbind.c +++ b/src/nwbind.c @@ -756,10 +756,24 @@ static void handle_fxx(int gelen, int func) } else if (0x16 == func) { switch (ufunc) { /* QUOTA support from: Matt Paley */ - case 0x21 : /* Change volume restrictions */ - case 0x22 : /* Remove volume restrictions */ - case 0x29 : { /* Read volume restrictions */ - /* Returns 3 integers, uid, gid, 0=OK/1=Permission denied */ + case 0x21 : /* Add User Disk Space Restriction, 0x2222/22/33 */ + case 0x22 : /* Remove User Disk Space Restrictions, 0x2222/22/34 */ + case 0x29 : { /* Get Object Disk Usage And Restrictions, 0x2222/22/41 */ + /* + * Forwarded from src/nwconn.c NCP 0x2222/22. The shared quota + * prehandler sees only the subfunction payload as rdata: + * + * rdata[0] VolumeNumber + * rdata[1..4] ObjectID (Hi-Lo) + * rdata[5..8] DiskSpaceLimit (Lo-Hi, only for 22/33) + * + * Parser comparison: ObjectID is read from the documented position + * for all three subfunctions. DiskSpaceLimit for 22/33 is not + * consumed by this prehandler; handle_after_bind() receives only the + * uid/gid/permission tuple produced below. + * + * Returns 3 integers, uid, gid, 0=OK/1=Permission denied. + */ uint32 id = GET_BE32(rdata+1); internal_act=1; if (get_guid((int*) responsedata, (int*)(responsedata+sizeof(int)), diff --git a/src/nwconn.c b/src/nwconn.c index 735f5cd..3c4aacb 100644 --- a/src/nwconn.c +++ b/src/nwconn.c @@ -4229,12 +4229,12 @@ static int handle_ncp_serv(void) * entries per call. * * Parser comparison: current parser reads VolumeNumber from - * the first payload byte and Sequence as Lo-Hi via GET_32(). - * The Micro Focus WebSDK table shows VolumeNumber one byte - * later than the normal NCP 22 group header would imply; the - * local parser follows the common group-header alignment. - * This offset ambiguity is recorded in TODO for direct-test - * verification. + * the first payload byte and Sequence with GET_BE32(), while + * the SDK/PDF documents Sequence as Lo-Hi. The Micro Focus + * WebSDK table shows VolumeNumber one byte later than the + * normal NCP 22 group header would imply; the local parser + * follows the common group-header alignment. Both items are + * recorded in TODO for direct-test verification. * * The Rust nwserver and lwared implementations both return * an empty list after validating the volume. MARS-NWE keeps @@ -4252,22 +4252,70 @@ static int handle_ncp_serv(void) } break; - case 0x21 : { /* change Vol restrictions for Obj */ + case 0x21 : { /* Add User Disk Space Restriction */ + /* + * NCP 0x2222/22/33 Add User Disk Space Restriction. + * + * SDK request payload after the group header: + * byte VolumeNumber + * long ObjectID (Hi-Lo) + * long DiskSpaceLimit (Lo-Hi, 4K blocks) + * + * SDK completion: 0x00 success, 0x8c no set privileges, + * 0x96 server out of memory, 0x98 disk map error. + * + * Parser comparison: this dispatcher only recognizes the + * subfunction and forwards prehandling to nwbind. The + * forwarded parser in src/nwbind.c maps ObjectID from the + * documented payload position, but the current quota + * prehandle does not consume DiskSpaceLimit. That is + * recorded in TODO for a behavior audit; this comment does + * not change wire behavior. + */ XDPRINTF((5, 0, "Change vol restrictions")); } return(-2); /* nwbind must do prehandling */ - case 0x22 : { /* remove Vol restrictions for Obj */ + case 0x22 : { /* Remove User Disk Space Restrictions */ + /* + * NCP 0x2222/22/34 Remove User Disk Space Restrictions. + * + * SDK request payload after the group header: + * byte VolumeNumber + * long ObjectID (Hi-Lo) + * + * SDK completion: 0x00 success, 0x8c no set privileges, + * 0xfe user not found. + * + * Parser comparison: this dispatcher forwards the call to + * nwbind, whose quota prehandler reads ObjectID from the + * documented payload position. + */ XDPRINTF((5, 0, "Remove vol restrictions")); } return(-2); /* nwbind must do prehandling */ - case 0x25 : { /* Set Entry, Set Directory File Information - * sets or changes the file or directory information to the - * values entered in 'Change Bits'. - * NO REPLY - * used by ncopy.exe, flag.exe - */ + case 0x25 : { /* Set Directory Entry Information */ + /* + * NCP 0x2222/22/37 Set Directory Entry Information. + * + * SDK request payload after the group header: + * byte DirHandle + * byte SearchAttributes + * long Sequence (Lo-Hi) + * long ChangeBits (Lo-Hi) + * ... DOS file/directory or Macintosh namespace entry + * + * SDK completion: 0x00 success, 0x01 invalid parameter, + * 0x8c no set privileges, 0xbf invalid name space. + * + * Parser comparison: current struct layout matches the + * documented field order and fixed 148-byte payload, but it + * reads Sequence with GET_BE32() while the SDK documents + * Sequence as Lo-Hi. ChangeBits is handled later by + * nw_set_a_directory_entry() as Lo-Hi. This endpoint is + * used by ncopy.exe and flag.exe. + */ struct INPUT { uint8 header[7]; /* Requestheader */ uint8 div[3]; /* 0x0, dlen, ufunc */ @@ -4295,7 +4343,27 @@ static int handle_ncp_serv(void) } break; - case 0x26 : { /* Scan file or Dir for ext trustees */ + case 0x26 : { /* Scan File or Directory for Extended Trustees */ + /* + * NCP 0x2222/22/38 Scan File or Directory for Extended + * Trustees. + * + * SDK request payload after the group header: + * byte DirHandle + * byte Sequence + * byte PathLen + * byte Path[PathLen] + * + * SDK reply payload: + * byte NumberOfEntries + * long ObjectID[20] (Hi-Lo) + * word TrusteeRights[20] + * + * Parser comparison: current parser and reply layout match + * the documented payload offsets. Rights are converted + * from mars_nwe trustee bits back to the NCP 22 mask before + * serialization. + */ int sequence = (int)*(p+2); /* trustee sequence */ struct XDATA { uint8 entries; @@ -4331,7 +4399,23 @@ static int handle_ncp_serv(void) } break; - case 0x27 : { /* Add Ext Trustees to DIR or File */ + case 0x27 : { /* Add Extended Trustee to Directory or File */ + /* + * NCP 0x2222/22/39 Add Extended Trustee to Directory or + * File. + * + * SDK request payload after the group header: + * byte DirHandle + * long ObjectID (Hi-Lo) + * word TrusteeRights (Lo-Hi) + * byte PathLen + * byte Path[PathLen] + * + * Parser comparison: current parser matches the documented + * payload layout and converts the NCP 22 rights mask to the + * internal trustee-rights representation before calling the + * existing trustee backend. + */ struct INPUT { uint8 header[7]; /* Requestheader */ uint8 div[3]; /* 0x0, dlen, ufunc */ @@ -4370,7 +4454,28 @@ static int handle_ncp_serv(void) } break; - case 0x28 : { /* Scan File Physical ??? */ + case 0x28 : { /* Scan Directory Disk Space */ + /* + * NCP 0x2222/22/40 Scan Directory Disk Space. + * + * SDK request payload after the group header: + * byte DirectoryHandle + * byte SearchAttributes + * long Sequence (Lo-Hi) + * byte SearchPatternLen + * byte SearchPattern[SearchPatternLen] + * + * SDK reply is the extended disk-space scan entry, including + * Sequence, data/resource fork size, deleted-file fields, + * inherited rights, and namespace fork-size data. + * + * Parser comparison: current payload offsets match, but the + * Sequence is read with GET_BE32() while the SDK documents + * Lo-Hi. The current implementation delegates to + * nw_scan_a_directory(), returning the normal directory-scan + * structure rather than the full documented disk-space scan + * reply. Both differences are recorded in TODO. + */ struct INPUT { uint8 header[7]; /* Requestheader */ uint8 div[3]; /* 0x0, dlen, ufunc */ @@ -4410,6 +4515,9 @@ static int handle_ncp_serv(void) * handle_after_bind() calls nw_get_vol_restrictions(). Without * quota support, keep the SDK-compatible fallback local so builds * on hosts without quota support do not need the quota backend. + * + * Parser comparison: request payload is VolumeNumber followed by + * ObjectID (Hi-Lo), matching the documented layout. */ case 0x29 : { /* Get Object Disk Usage And Restrictions */ #if QUOTA_SUPPORT