dosutils: add Novell-style REVOKE and REMOVE trustee tools

Implement REVOKE and REMOVE for the Client32 DOS utilities.

REVOKE now supports Novell-style syntax:

  REVOKE rightslist* [FOR path] FROM [USER|GROUP] name [options]

and removes rights from explicit trustee assignments.  It scans the
trustee list first, updates the trustee rights mask, and deletes the
trustee entry when no rights remain.

REMOVE now supports Novell-style syntax:

  REMOVE [USER | GROUP] name [FROM path] [option]

and deletes explicit trustee assignments for users or groups.

Both tools support USER/GROUP lookup, /FILES, /SUBDIRS,
/SUBDIRECTORIES, wildcard file targets, recursive directory handling,
Novell-style help text and summary output.  Missing trustee entries are
reported with Novell-style "No trustee for the specified ..." messages.

Add shared trustee helpers and Client32 NCP87 trustee scan/delete
support.  Also adjust GRANT ALL so it matches Novell behavior by not
granting Supervisor implicitly; Supervisor must be granted explicitly.
This commit is contained in:
Mario Fetka
2026-05-24 20:23:43 +02:00
parent fc97eb8d25
commit 4cafe16980
11 changed files with 1160 additions and 7 deletions

182
c32ncp.c
View File

@@ -37,6 +37,14 @@ static uint32 c32_get_dword_lh(uint8 *p)
((uint32)p[3] << 24));
}
static uint32 c32_get_dword_hl(uint8 *p)
{
return(((uint32)p[0] << 24) |
((uint32)p[1] << 16) |
((uint32)p[2] << 8) |
(uint32)p[3]);
}
static UI c32_build_handle_path(uint8 *buf, uint8 dhandle,
uint16 dirbase, uint8 style,
int count,
@@ -593,3 +601,177 @@ int c32_ncp87_add_trustee_rights(const char *path_name,
return(0);
}
int c32_ncp87_find_trustee_rights(const char *path_name,
uint16 dir_handle,
uint32 object_id,
uint16 *rights_out,
uint16 *actual_out,
uint16 *handle_lo_out,
uint16 *handle_hi_out)
{
uint16 handle_lo, handle_hi;
uint8 hdr[16];
uint8 path[0x140];
uint8 rep0[0x120];
uint8 rep1[0x120];
uint8 rawout[32];
uint16 raw_ret_ax, raw_ret_dx;
uint16 actual_lo;
uint32 seq = 0;
UI path_len;
int rc;
if (rights_out) *rights_out = 0;
if (actual_out) *actual_out = 0;
if (handle_lo_out) *handle_lo_out = 0;
if (handle_hi_out) *handle_hi_out = 0;
if (!rights_out)
return(1);
rc = c32_get_ncp_handle(&handle_lo, &handle_hi);
if (rc)
return(10 + rc);
for (;;) {
uint16 count;
uint16 i;
uint8 *tp;
uint32 next_seq;
memset(hdr, 0, sizeof(hdr));
hdr[0] = 5; /* NCP87 subfunction 5: scan trustees */
hdr[1] = 0; /* DOS namespace */
hdr[2] = 0; /* reserved */
c32_put_word_lh(hdr + 3, 0x8006); /* SA_ALL: files/subdirs + system + hidden */
c32_put_dword_lh(hdr + 5, seq); /* search sequence, starts at zero */
path_len = c32_build_handle_path_from_dos_path(path,
(uint8)dir_handle,
0, 0,
path_name);
memset(rep0, 0, sizeof(rep0));
memset(rep1, 0, sizeof(rep1));
memset(rawout, 0, sizeof(rawout));
C32_NCP87_Raw5_Probe(handle_lo, handle_hi,
hdr, 9,
path, path_len,
rep0, sizeof(rep0),
rep1, sizeof(rep1),
rawout);
raw_ret_ax = c32_get_word_lh(rawout + 14);
raw_ret_dx = c32_get_word_lh(rawout + 16);
actual_lo = c32_get_word_lh(rawout + 18);
if (actual_out) *actual_out = actual_lo;
if (handle_lo_out) *handle_lo_out = handle_lo;
if (handle_hi_out) *handle_hi_out = handle_hi;
if (raw_ret_ax != 0 || raw_ret_dx != 0)
return(0xff); /* Client32 returns an error when no trustees are present. */
next_seq = c32_get_dword_lh(rep0 + 0);
count = c32_get_word_lh(rep0 + 4);
if (count > 20)
count = 20;
tp = rep0 + 6;
for (i = 0; i < count; i++) {
uint32 tid = c32_get_dword_hl(tp);
uint16 trights = c32_get_word_lh(tp + 4);
if (tid == object_id || c32_get_dword_lh(tp) == object_id) {
*rights_out = trights;
return(0);
}
tp += 6;
}
if (next_seq == 0xffffffffUL || next_seq == seq)
break;
seq = next_seq;
}
return(0xff); /* no trustee found / no more entries */
}
int c32_ncp87_delete_trustee_rights(const char *path_name,
uint16 dir_handle,
uint32 object_id,
uint16 *actual_out,
uint16 *handle_lo_out,
uint16 *handle_hi_out)
{
uint16 handle_lo, handle_hi;
uint8 hdr[16];
uint8 reqpath[0x180];
uint8 rep0[0x20];
uint8 rep1[0x20];
uint8 rawout[32];
uint16 raw_ret_ax, raw_ret_dx;
uint16 actual_lo;
UI path_struct_len;
UI reqpath_len;
uint8 *tp;
int rc;
if (actual_out) *actual_out = 0;
if (handle_lo_out) *handle_lo_out = 0;
if (handle_hi_out) *handle_hi_out = 0;
rc = c32_get_ncp_handle(&handle_lo, &handle_hi);
if (rc)
return(10 + rc);
memset(hdr, 0, sizeof(hdr));
hdr[0] = 11; /* NCP87 subfunction 11: delete trustee */
hdr[1] = 0; /* DOS namespace */
hdr[2] = 0; /* reserved */
c32_put_word_lh(hdr + 3, 1); /* one trustee */
memset(reqpath, 0, sizeof(reqpath));
path_struct_len = c32_build_handle_path_from_dos_path(reqpath,
(uint8)dir_handle,
0, 0,
path_name);
if (path_struct_len > 307)
return(2);
tp = reqpath + 307;
c32_put_dword_hl(tp, object_id); tp += 4;
c32_put_word_lh(tp, 0); tp += 2;
reqpath_len = (UI)(tp - reqpath);
memset(rep0, 0, sizeof(rep0));
memset(rep1, 0, sizeof(rep1));
memset(rawout, 0, sizeof(rawout));
C32_NCP87_Raw5_Probe(handle_lo, handle_hi,
hdr, 5,
reqpath, reqpath_len,
rep0, sizeof(rep0),
rep1, sizeof(rep1),
rawout);
raw_ret_ax = c32_get_word_lh(rawout + 14);
raw_ret_dx = c32_get_word_lh(rawout + 16);
actual_lo = c32_get_word_lh(rawout + 18);
if (actual_out) *actual_out = actual_lo;
if (handle_lo_out) *handle_lo_out = handle_lo;
if (handle_hi_out) *handle_hi_out = handle_hi;
if (raw_ret_ax != 0 || raw_ret_dx != 0)
return(20);
return(0);
}