Move common DOS utility helper code into tools.c and expose it through net.h. This removes duplicated command-local helpers from GRANT, RIGHTS, FLAG, FLAGDIR and the trustee helper layer. The shared helpers cover case-insensitive argument comparison, help and option detection, /FILES and /SUBDIRS parsing, current network directory handle lookup, current volume prefix formatting, uppercase DOS path copying, basename/header-path handling, wildcard detection and simple path joining/splitting. Keep the command frontends smaller and less coupled so the current multicall utility can later be split into smaller grouped multicall binaries, such as trustee tools, login/session tools and file/flag tools. Update the DOS utilities README for the newer Client32 and trustee commands. Document RIGHTS, GRANT, REVOKE and REMOVE in the status, feature, command and install sections. Add command reference entries for the trustee tools, including Novell-style syntax, supported rights, recursive/file options and missing-trustee behavior. Also mention the shared trustee helper layer and common tools.c helpers used by the newer command frontends.
272 lines
7.3 KiB
C
272 lines
7.3 KiB
C
/* rights.c - Novell RIGHTS-like DOS utility, read-only v4 */
|
|
|
|
#include "net.h"
|
|
#include "c32ncp.h"
|
|
#include <dos.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
|
|
#ifndef S_IFDIR
|
|
#define S_IFDIR 0040000
|
|
#endif
|
|
|
|
#define NW_RIGHT_S 0x01
|
|
#define NW_RIGHT_R 0x02
|
|
#define NW_RIGHT_W 0x04
|
|
#define NW_RIGHT_C 0x08
|
|
#define NW_RIGHT_E 0x10
|
|
#define NW_RIGHT_M 0x20
|
|
#define NW_RIGHT_F 0x40
|
|
#define NW_RIGHT_A 0x80
|
|
|
|
/* NCP effective-rights bits returned by NCP87 subfunction 29. */
|
|
#define NCP_RIGHT_READ 0x0001
|
|
#define NCP_RIGHT_WRITE 0x0002
|
|
#define NCP_RIGHT_OPEN 0x0004
|
|
#define NCP_RIGHT_CREATE 0x0008
|
|
#define NCP_RIGHT_DELETE 0x0010
|
|
#define NCP_RIGHT_OWNER 0x0020
|
|
#define NCP_RIGHT_SEARCH 0x0040
|
|
#define NCP_RIGHT_MODIFY 0x0080
|
|
#define NCP_RIGHT_SUPER 0x0100
|
|
|
|
static uint8 rights_map_ncp_mask(uint16 ncp_rights);
|
|
|
|
|
|
static void rights_usage(void)
|
|
{
|
|
fprintf(stdout, "Usage: RIGHTS [path]\n\n");
|
|
fprintf(stdout, "Rights = All | Supervisor | Read | Write | Create | Erase\n");
|
|
fprintf(stdout, " Modify | File scan | Access Control\n");
|
|
}
|
|
|
|
static void rights_parent_path(char *dst, char *src, int max)
|
|
{
|
|
char tmp[260];
|
|
char *p;
|
|
|
|
tool_upcopy(tmp, src, sizeof(tmp));
|
|
|
|
p = strrchr(tmp, '\\');
|
|
if (!p) p = strrchr(tmp, ':');
|
|
|
|
if (!p) {
|
|
dst[0] = '\0';
|
|
return;
|
|
}
|
|
|
|
if (*p == ':') {
|
|
p++;
|
|
*p = '\0';
|
|
} else {
|
|
*p = '\0';
|
|
}
|
|
|
|
strmaxcpy(dst, tmp, max - 1);
|
|
}
|
|
|
|
static int rights_path_is_dir(char *path)
|
|
{
|
|
struct stat st;
|
|
|
|
if (tool_is_current_path(path))
|
|
return(1);
|
|
|
|
if (stat(path, &st) == 0) {
|
|
if (st.st_mode & S_IFDIR)
|
|
return(1);
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
static int rights_effective_mask(char *path, int is_dir, uint8 *mask)
|
|
{
|
|
uint8 connid = 0;
|
|
uint8 dhandle = 0;
|
|
uint8 eff = 0;
|
|
char usepath[260];
|
|
int newhandle;
|
|
uint16 ncp_rights = 0;
|
|
|
|
if (mask) *mask = 0;
|
|
|
|
if (tool_current_dhandle(&connid, &dhandle))
|
|
return(-1);
|
|
|
|
/*
|
|
* Prefer the explicit Client32 NCP87 effective-rights request. This is
|
|
* the DOS Client32 equivalent of ncpfs ncp_get_eff_directory_rights().
|
|
* It works for both files and directories, so pass the requested path
|
|
* itself instead of mapping files to their parent directory.
|
|
*/
|
|
if (!c32_ncp87_get_effective_rights(tool_is_current_path(path) ? "" : path,
|
|
(uint16)dhandle,
|
|
&ncp_rights,
|
|
NULL, NULL, NULL)) {
|
|
if (mask) *mask = rights_map_ncp_mask(ncp_rights);
|
|
return(0);
|
|
}
|
|
|
|
/*
|
|
* Fallback for older requesters/paths: allocate a temporary directory
|
|
* handle and use the returned old-style effective-rights byte.
|
|
* This cannot directly target a file, so files are mapped to their parent.
|
|
*/
|
|
if (tool_is_current_path(path)) {
|
|
usepath[0] = '\0';
|
|
} else if (is_dir) {
|
|
tool_upcopy(usepath, path, sizeof(usepath));
|
|
} else {
|
|
rights_parent_path(usepath, path, sizeof(usepath));
|
|
}
|
|
|
|
newhandle = alloc_temp_dir_handle(dhandle, usepath, 0, &eff);
|
|
if (newhandle < 0) {
|
|
if (usepath[0]) {
|
|
int subdir = 1;
|
|
int r = ncp_16_02(dhandle, (uint8 *)usepath, &subdir,
|
|
NULL, NULL, NULL);
|
|
if (r >= 0) {
|
|
eff = (uint8)r;
|
|
} else {
|
|
return(-1);
|
|
}
|
|
} else {
|
|
eff = 0xff;
|
|
}
|
|
} else {
|
|
dealloc_dir_handle(newhandle);
|
|
}
|
|
|
|
if (mask) *mask = eff;
|
|
return(0);
|
|
}
|
|
|
|
|
|
static uint8 rights_map_ncp_mask(uint16 ncp_rights)
|
|
{
|
|
uint8 mask = 0;
|
|
|
|
if (ncp_rights & NCP_RIGHT_SUPER) mask |= NW_RIGHT_S;
|
|
if (ncp_rights & NCP_RIGHT_READ) mask |= NW_RIGHT_R;
|
|
if (ncp_rights & NCP_RIGHT_WRITE) mask |= NW_RIGHT_W;
|
|
if (ncp_rights & NCP_RIGHT_CREATE) mask |= NW_RIGHT_C;
|
|
if (ncp_rights & NCP_RIGHT_DELETE) mask |= NW_RIGHT_E;
|
|
if (ncp_rights & NCP_RIGHT_MODIFY) mask |= NW_RIGHT_M;
|
|
if (ncp_rights & NCP_RIGHT_SEARCH) mask |= NW_RIGHT_F;
|
|
if (ncp_rights & NCP_RIGHT_OWNER) mask |= NW_RIGHT_A;
|
|
|
|
return(mask);
|
|
}
|
|
|
|
|
|
static void rights_mask_string(uint8 mask, char *out)
|
|
{
|
|
out[0] = (mask & NW_RIGHT_S) ? 'S' : '-';
|
|
out[1] = (mask & NW_RIGHT_R) ? 'R' : '-';
|
|
out[2] = (mask & NW_RIGHT_W) ? 'W' : '-';
|
|
out[3] = (mask & NW_RIGHT_C) ? 'C' : '-';
|
|
out[4] = (mask & NW_RIGHT_E) ? 'E' : '-';
|
|
out[5] = (mask & NW_RIGHT_M) ? 'M' : '-';
|
|
out[6] = (mask & NW_RIGHT_F) ? 'F' : '-';
|
|
out[7] = (mask & NW_RIGHT_A) ? 'A' : '-';
|
|
out[8] = '\0';
|
|
}
|
|
|
|
/*
|
|
* Novell RIGHTS layout:
|
|
* - lines with star: two leading blanks, star, blank, text
|
|
* - lines without star: four leading blanks, text
|
|
* Keep the right-column letter at a fixed-ish DOS-screen position.
|
|
*/
|
|
static void rights_print_line(int have, int star, char *text, char letter)
|
|
{
|
|
(void)have;
|
|
|
|
if (star)
|
|
fprintf(stdout, " * %-43s(%c)\n", text, letter);
|
|
else
|
|
fprintf(stdout, " %-43s(%c)\n", text, letter);
|
|
}
|
|
|
|
static void rights_display(char *path, int is_dir, uint8 mask)
|
|
{
|
|
char hdr[300];
|
|
char mstr[10];
|
|
|
|
tool_header_path(hdr, path, sizeof(hdr));
|
|
rights_mask_string(mask, mstr);
|
|
|
|
fprintf(stdout, "%s\n", hdr);
|
|
|
|
if (is_dir)
|
|
fprintf(stdout, "Your Effective Rights for this directory are [%s]\n", mstr);
|
|
else
|
|
fprintf(stdout, "Your Effective Rights for this file are [%s]\n", mstr);
|
|
|
|
if (is_dir) {
|
|
rights_print_line(mask & NW_RIGHT_S, 0, "You have Supervisor Rights to Directory.", 'S');
|
|
rights_print_line(mask & NW_RIGHT_R, 1, "May Read from File.", 'R');
|
|
rights_print_line(mask & NW_RIGHT_W, 1, "May Write to File.", 'W');
|
|
rights_print_line(mask & NW_RIGHT_C, 0, "May Create Subdirectories and Files.", 'C');
|
|
rights_print_line(mask & NW_RIGHT_E, 0, "May Erase Directory.", 'E');
|
|
rights_print_line(mask & NW_RIGHT_M, 0, "May Modify Directory.", 'M');
|
|
rights_print_line(mask & NW_RIGHT_F, 0, "May Scan for Files.", 'F');
|
|
rights_print_line(mask & NW_RIGHT_A, 0, "May Change Access Control.", 'A');
|
|
|
|
fprintf(stdout, "\n");
|
|
fprintf(stdout, " * Has no effect on directory.\n\n");
|
|
fprintf(stdout, " Entries in Directory May Inherit [%s] rights.\n", mstr);
|
|
if (mask == 0xff)
|
|
fprintf(stdout, " You have ALL RIGHTS to Directory Entry.\n");
|
|
} else {
|
|
rights_print_line(mask & NW_RIGHT_S, 0, "You have Supervisor Rights to File.", 'S');
|
|
rights_print_line(mask & NW_RIGHT_R, 0, "May Read from File.", 'R');
|
|
rights_print_line(mask & NW_RIGHT_W, 0, "May Write to File.", 'W');
|
|
rights_print_line(mask & NW_RIGHT_C, 1, "May Create Subdirectories and Files.", 'C');
|
|
rights_print_line(mask & NW_RIGHT_E, 0, "May Erase File.", 'E');
|
|
rights_print_line(mask & NW_RIGHT_M, 0, "May Modify File.", 'M');
|
|
rights_print_line(mask & NW_RIGHT_F, 0, "May Scan for File.", 'F');
|
|
rights_print_line(mask & NW_RIGHT_A, 0, "May Change Access Control.", 'A');
|
|
|
|
fprintf(stdout, "\n");
|
|
fprintf(stdout, " * Create is necessary to salvage a file that has been deleted.\n\n");
|
|
if (mask == 0xff)
|
|
fprintf(stdout, " You have ALL RIGHTS to Directory Entry.\n");
|
|
}
|
|
}
|
|
|
|
int func_rights(int argc, char *argv[], int mode)
|
|
{
|
|
char *path = ".";
|
|
uint8 mask = 0;
|
|
int is_dir;
|
|
|
|
(void)mode;
|
|
|
|
if (argc > 2) {
|
|
rights_usage();
|
|
return(1);
|
|
}
|
|
|
|
if (argc == 2) {
|
|
if (tool_is_help_arg(argv[1])) {
|
|
rights_usage();
|
|
return(0);
|
|
}
|
|
path = argv[1];
|
|
}
|
|
|
|
is_dir = rights_path_is_dir(path);
|
|
|
|
if (rights_effective_mask(path, is_dir, &mask)) {
|
|
fprintf(stdout, "Specified path not locatable.\n");
|
|
return(1);
|
|
}
|
|
|
|
rights_display(path, is_dir, mask);
|
|
return(0);
|
|
}
|