dosutils: match Novell paths for flags and trustees

Move FLAG, GRANT and REMOVE closer to the request paths used by the
Novell tools and extend the DOS comparison tests.

FLAG now reads attributes through the old NCP22 directory scan path and
writes them through NCP22/25 Set Directory/File Information. This keeps
extended attributes such as Delete Inhibit and Rename Inhibit intact and
matches the Novell behavior observed in the server logs.

GRANT now prefers NCP22/27 SetTrustee with an NCP87 fallback. Supervisor
rights are expanded like Novell does, so granting S sends and reports the
full SRWCEMFA mask. The visible output, path formatting and error text
are adjusted to match the Novell baseline.

REMOVE now prefers NCP22/2B DelTrustee with an NCP87 fallback. The
DelTrustee request layout is corrected, /SUBDIRS handling is aligned
with Novell, and the output/error text is matched to the baseline.

The FLAG, FLAGDIR, GRANT and REMOVE tests now compare NPUBLIC baselines
against the PUBLIC implementations and add delayed NOPASSUSER readback
checks using DLYSTRT and the maintainer LOGIN password option.
This commit is contained in:
Mario Fetka
2026-05-28 07:54:41 +02:00
parent 0fa4a6f700
commit 5da600c2a5
23 changed files with 2653 additions and 659 deletions

272
flag.c
View File

@@ -18,6 +18,7 @@
#define FLAG_NW_NS_DOS 0x00
#define FLAG_SA_ALL 0x0006
#define FLAG_RIM_ATTRIBUTES 0x00000004UL
#define FLAG_DM_ATTRIBUTES 0x00000002UL
#define NWFA_RO 0x00000001UL
#define NWFA_H 0x00000002UL
@@ -134,6 +135,142 @@ static int flag_ncp87_obtain_attrs(char *name, uint32 *attrs)
return(0);
}
static int flag_copy_ncp22_name(uint8 *dst, char *src, uint8 *len_out)
{
char tmp[260];
int len;
if (!dst || !len_out)
return(-1);
if (!src)
src = "";
tool_upcopy(tmp, src, sizeof(tmp));
if (strchr(tmp, '\\') || strchr(tmp, '/') || strchr(tmp, ':'))
return(-1);
len = strlen(tmp);
if (len < 1 || len > 12)
return(-1);
memcpy(dst, tmp, len);
*len_out = (uint8)len;
return(0);
}
static int flag_ncp22_1e_obtain_attrs(char *name, uint32 *attrs)
{
struct {
uint16 len;
uint8 func;
uint8 dirhandle;
uint8 search_attributes;
uint8 searchsequence[4];
uint8 namlen;
uint8 name[12];
} req;
struct {
uint16 len;
uint8 data[128];
} repl;
uint8 connid = 0;
uint8 dhandle = 0;
uint8 namlen = 0;
if (tool_current_dhandle(&connid, &dhandle))
return(-1);
memset(&req, 0, sizeof(req));
memset(&repl, 0, sizeof(repl));
if (flag_copy_ncp22_name(req.name, name, &namlen))
return(-1);
req.func = 0x1e; /* Scan directory */
req.dirhandle = dhandle;
req.search_attributes = 0x06; /* hidden/system */
U32_TO_BE32(0xffffffffUL, req.searchsequence);
req.namlen = namlen;
req.len = (uint16)(1 + 1 + 1 + 4 + 1 + namlen);
repl.len = sizeof(repl.data);
neterrno = Net_Call(0xE200, &req, &repl);
if (neterrno)
return(-1);
/*
* NCP22/30 Scan Directory returns:
* dword searchsequence
* dword subdir
* dword attributes
* ...
*/
if (attrs)
*attrs = flag_get_dword_lh(repl.data + 8);
return(0);
}
static int flag_ncp22_25_modify_attrs(char *name, uint32 attrs)
{
struct {
uint16 len;
uint8 func;
uint8 dirhandle;
uint8 search_attributes;
uint8 searchsequence[4];
uint8 change_bits[4];
uint8 subdir[4];
uint8 attributes[4];
uint8 uniqueid;
uint8 flags;
uint8 namespace;
uint8 namlen;
uint8 name[12];
uint8 rest[104];
} req;
struct {
uint16 len;
} repl;
uint8 connid = 0;
uint8 dhandle = 0;
if (tool_current_dhandle(&connid, &dhandle))
return(-1);
memset(&req, 0, sizeof(req));
memset(&repl, 0, sizeof(repl));
req.func = 0x25; /* Set directory/file information */
req.dirhandle = dhandle;
req.search_attributes = 0x06; /* hidden/system */
U32_TO_BE32(0xffffffffUL, req.searchsequence);
U32_TO_32(FLAG_DM_ATTRIBUTES, req.change_bits);
U32_TO_32(attrs, req.attributes);
if (flag_copy_ncp22_name(req.name, name, &req.namlen))
return(-1);
req.len = sizeof(req) - sizeof(req.len);
neterrno = Net_Call(0xE200, &req, &repl);
if (neterrno)
return(-1);
return(0);
}
static int flag_obtain_attrs(char *name, uint32 *attrs)
{
if (!flag_ncp22_1e_obtain_attrs(name, attrs))
return(0);
return(flag_ncp87_obtain_attrs(name, attrs));
}
static int flag_ncp87_modify_attrs(char *name, uint32 attrs)
{
struct {
@@ -174,7 +311,7 @@ static int flag_ncp87_modify_attrs(char *name, uint32 attrs)
*p++ = 0; /* reserved */
flag_put_word_lh(p, FLAG_SA_ALL); p += 2;
flag_put_dword_lh(p, FLAG_RIM_ATTRIBUTES); p += 4; /* modify mask */
flag_put_dword_lh(p, FLAG_DM_ATTRIBUTES); p += 4; /* modify mask: DM_ATTRIBUTES */
flag_put_dword_lh(p, attrs); p += 4; /* Attributes */
/*
@@ -342,7 +479,7 @@ static void flag_display_one(char *name, uint32 attr)
{
fprintf(stdout, " %-23s ", name);
flag_print_attrs(attr);
fprintf(stdout, "\n");
fprintf(stdout, " \n");
}
static void flag_display_one_paged(char *name, uint32 attr,
@@ -353,6 +490,93 @@ static void flag_display_one_paged(char *name, uint32 attr,
}
static char *flag_last_sep(char *s)
{
char *last = NULL;
char *p;
for (p = s; *p; p++) {
if (*p == '\\' || *p == '/' || *p == ':')
last = p;
}
return(last);
}
static void flag_split_pattern(char *pattern, char *parent, int parent_size,
char *leaf, int leaf_size)
{
char temp[260];
char *sep;
int plen;
parent[0] = '\0';
leaf[0] = '\0';
strmaxcpy(temp, pattern, sizeof(temp) - 1);
sep = flag_last_sep(temp);
if (!sep) {
strmaxcpy(leaf, temp, leaf_size - 1);
return;
}
if (*(sep + 1)) {
strmaxcpy(leaf, sep + 1, leaf_size - 1);
} else {
strmaxcpy(leaf, "*.*", leaf_size - 1);
}
plen = (int)(sep - temp);
/*
* Keep drive-root paths as "F:\" rather than "F:".
*/
if (*sep == ':' && (*(sep + 1) == '\\' || *(sep + 1) == '/'))
plen += 2;
else if (*sep == ':' || *sep == '\\' || *sep == '/')
plen += 1;
if (plen >= parent_size)
plen = parent_size - 1;
memcpy(parent, temp, plen);
parent[plen] = '\0';
}
static int flag_enter_parent(char *pattern, char *leaf, int leaf_size,
char *oldcwd, int oldcwd_size)
{
char parent[260];
oldcwd[0] = '\0';
flag_split_pattern(pattern, parent, sizeof(parent), leaf, leaf_size);
if (!leaf[0])
strmaxcpy(leaf, "*.*", leaf_size - 1);
if (!parent[0])
return(0);
if (!getcwd(oldcwd, oldcwd_size))
oldcwd[0] = '\0';
if (chdir(parent)) {
if (oldcwd[0])
chdir(oldcwd);
return(-1);
}
return(0);
}
static void flag_leave_parent(char *oldcwd)
{
if (oldcwd[0])
chdir(oldcwd);
}
static int flag_list(char *pattern)
{
struct find_t ff;
@@ -368,7 +592,7 @@ static int flag_list(char *pattern)
if (!(ff.attrib & _A_SUBDIR)) {
uint32 nwattrs;
if (flag_ncp87_obtain_attrs(ff.name, &nwattrs))
if (flag_obtain_attrs(ff.name, &nwattrs))
nwattrs = (uint32)ff.attrib;
flag_display_one_paged(ff.name, nwattrs, &line_count, &continuous);
@@ -397,22 +621,23 @@ static int flag_apply(char *pattern, uint32 setbits, uint32 clearbits)
strmaxcpy(fname, ff.name, sizeof(fname) - 1);
if (flag_ncp87_obtain_attrs(fname, &attrs))
if (flag_obtain_attrs(fname, &attrs))
attrs = (uint32)ff.attrib;
newattrs = (attrs | (uint32)setbits) & ~((uint32)clearbits);
if (newattrs != attrs) {
if (flag_ncp87_modify_attrs(fname, newattrs)) {
if (flag_ncp22_25_modify_attrs(fname, newattrs) &&
flag_ncp87_modify_attrs(fname, newattrs)) {
unsigned dosattr = (newattrs & (_A_RDONLY|_A_HIDDEN|_A_SYSTEM|_A_ARCH));
if (_dos_setfileattr(fname, dosattr)) {
fprintf(stderr, "You don't have rights to change : %s\n", fname);
fprintf(stdout, "You don't have rights to change : %s\n", fname);
continue;
}
}
}
if (flag_ncp87_obtain_attrs(fname, &attrs))
if (flag_obtain_attrs(fname, &attrs))
attrs = newattrs;
flag_display_one(fname, newattrs);
@@ -454,20 +679,33 @@ int func_flag(int argc, char *argv[], int mode)
have_change = 1;
}
if (have_change) {
rc = flag_apply(path, setbits, clearbits);
if (rc < 0) {
fprintf(stderr, "Files could not be found with pattern \"%s\"\n", path);
{
char leaf[260];
char oldcwd[260];
if (flag_enter_parent(path, leaf, sizeof(leaf), oldcwd, sizeof(oldcwd))) {
flag_split_pattern(path, oldcwd, sizeof(oldcwd), leaf, sizeof(leaf));
fprintf(stdout, "Files could not be found with pattern \"%s\"\a", leaf);
return(1);
}
return(0);
}
if (have_change) {
rc = flag_apply(leaf, setbits, clearbits);
flag_leave_parent(oldcwd);
if (rc < 0) {
fprintf(stdout, "Files could not be found with pattern \"%s\"\a", leaf);
return(1);
}
rc = flag_list(path);
if (rc < 0) {
fprintf(stderr, "Files could not be found with pattern \"%s\"\n", path);
return(1);
return(0);
}
rc = flag_list(leaf);
flag_leave_parent(oldcwd);
if (rc < 0) {
fprintf(stdout, "Files could not be found with pattern \"%s\"\a", leaf);
return(1);
}
}
return(0);