Files
mars-dosutils/grant.c
Mario Fetka 4cafe16980 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.
2026-05-24 20:23:43 +02:00

521 lines
12 KiB
C

/* grant.c - Novell GRANT-like DOS utility, first Client32 implementation */
#include "net.h"
#include "c32ncp.h"
#define GRANT_BINDERY_USER 0x0001
#define GRANT_BINDERY_GROUP 0x0002
#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
/* Novell GRANT ALL assigns all normal trustee rights, not Supervisor. */
#define NCP_RIGHT_ALL_386 (NCP_RIGHT_READ | NCP_RIGHT_WRITE | \
NCP_RIGHT_CREATE | NCP_RIGHT_DELETE | \
NCP_RIGHT_MODIFY | NCP_RIGHT_SEARCH | \
NCP_RIGHT_OWNER)
static int grant_same(char *a, char *b)
{
while (*a || *b) {
int ca = *a++;
int cb = *b++;
if (ca >= 'a' && ca <= 'z') ca -= 32;
if (cb >= 'a' && cb <= 'z') cb -= 32;
if (ca != cb) return(0);
}
return(1);
}
static int grant_is_help(char *s)
{
if (!s) return(0);
return(grant_same(s, "/?") || grant_same(s, "-?") || grant_same(s, "?"));
}
static void grant_usage_error(void)
{
fprintf(stdout, "Command line arguments violate grammar defined for GRANT.\n\n");
}
static void grant_usage(void)
{
fprintf(stdout, "Usage: GRANT rightslist* [FOR path] TO [USER | GROUP] name [options]\n");
fprintf(stdout, "Options: /SubDirectories | /Files\n\n");
fprintf(stdout, "386 Rights:\n");
fprintf(stdout, "--------------------\n");
fprintf(stdout, "ALL = All\n");
fprintf(stdout, "N = No Rights\n");
fprintf(stdout, "S = Supervisor\n");
fprintf(stdout, "R = Read\n");
fprintf(stdout, "W = Write\n");
fprintf(stdout, "C = Create\n");
fprintf(stdout, "E = Erase\n");
fprintf(stdout, "M = Modify\n");
fprintf(stdout, "F = File Scan\n");
fprintf(stdout, "A = Access Control\n");
}
static int grant_get_current_drive(void)
{
REGS regs;
regs.h.ah = 0x19;
int86(0x21, &regs, &regs);
return((int)regs.h.al);
}
static int grant_current_dhandle(uint8 *connid, uint8 *dhandle)
{
uint8 flags = 0;
int drive = grant_get_current_drive();
if (get_drive_info((uint8)drive, connid, dhandle, &flags))
return(-1);
if (!*connid || (flags & 0x80))
return(-1);
return(0);
}
static int grant_current_prefix(char *out, int max)
{
uint8 connid = 0;
uint8 dhandle = 0;
uint8 flags = 0;
int drive;
char server[52];
char dpath[260];
char volume[32];
char *p;
int i = 0;
if (!out || max < 8)
return(-1);
out[0] = '\0';
drive = grant_get_current_drive();
if (get_drive_info((uint8)drive, &connid, &dhandle, &flags))
return(-1);
if (!connid || (flags & 0x80))
return(-1);
server[0] = '\0';
if (get_fs_name(connid, server))
server[0] = '\0';
dpath[0] = '\0';
if (get_dir_path(dhandle, dpath) || !dpath[0])
return(-1);
p = strchr(dpath, ':');
if (!p)
return(-1);
while (dpath + i < p && i < (int)sizeof(volume) - 1) {
volume[i] = dpath[i];
i++;
}
volume[i] = '\0';
if (!volume[0])
return(-1);
if (server[0])
sprintf(out, "%s/%s:", server, volume);
else
sprintf(out, "%s:", volume);
return(0);
}
static void grant_upcopy(char *dst, char *src, int max)
{
int i = 0;
if (!src) src = "";
while (*src && i < max - 1) {
char c = *src++;
if (c == '/') c = '\\';
if (c >= 'a' && c <= 'z') c -= 32;
dst[i++] = c;
}
dst[i] = 0;
}
static void grant_basename(char *dst, char *src, int max)
{
char up[260];
char *p;
grant_upcopy(up, src, sizeof(up));
p = strrchr(up, '\\');
if (!p) p = strrchr(up, ':');
if (p)
strmaxcpy(dst, p + 1, max - 1);
else
strmaxcpy(dst, up, max - 1);
}
static void grant_header_path(char *out, char *path, int max)
{
char prefix[90];
char up[260];
if (grant_current_prefix(prefix, sizeof(prefix)))
prefix[0] = '\0';
grant_upcopy(up, path, sizeof(up));
strmaxcpy(out, prefix, max - 1);
if ((int)(strlen(out) + strlen(up)) < max - 1)
strcat(out, up);
}
static void grant_rights_bracket(uint16 rights, char *out)
{
out[0] = (rights & NCP_RIGHT_SUPER) ? 'S' : ' ';
out[1] = (rights & NCP_RIGHT_READ) ? 'R' : ' ';
out[2] = (rights & NCP_RIGHT_WRITE) ? 'W' : ' ';
out[3] = (rights & NCP_RIGHT_CREATE) ? 'C' : ' ';
out[4] = (rights & NCP_RIGHT_DELETE) ? 'E' : ' ';
out[5] = (rights & NCP_RIGHT_MODIFY) ? 'M' : ' ';
out[6] = (rights & NCP_RIGHT_SEARCH) ? 'F' : ' ';
out[7] = (rights & NCP_RIGHT_OWNER) ? 'A' : ' ';
out[8] = '\0';
}
static void grant_rights_string(uint16 rights, char *out)
{
char *p = out;
if (rights == 0) {
strcpy(out, "N");
return;
}
if ((rights & NCP_RIGHT_ALL_386) == NCP_RIGHT_ALL_386) {
strcpy(out, "ALL");
return;
}
if (rights & NCP_RIGHT_SUPER) *p++ = 'S';
if (rights & NCP_RIGHT_READ) *p++ = 'R';
if (rights & NCP_RIGHT_WRITE) *p++ = 'W';
if (rights & NCP_RIGHT_CREATE) *p++ = 'C';
if (rights & NCP_RIGHT_DELETE) *p++ = 'E';
if (rights & NCP_RIGHT_MODIFY) *p++ = 'M';
if (rights & NCP_RIGHT_SEARCH) *p++ = 'F';
if (rights & NCP_RIGHT_OWNER) *p++ = 'A';
*p = '\0';
}
static int grant_add_right_word(char *s, uint16 *rights)
{
if (grant_same(s, "ALL")) {
*rights = NCP_RIGHT_ALL_386;
return(0);
}
if (grant_same(s, "N") || grant_same(s, "NONE")) {
*rights = 0;
return(0);
}
if (grant_same(s, "S") || grant_same(s, "SUPERVISOR")) {
*rights |= NCP_RIGHT_SUPER;
return(0);
}
if (grant_same(s, "R") || grant_same(s, "READ")) {
*rights |= NCP_RIGHT_READ;
return(0);
}
if (grant_same(s, "W") || grant_same(s, "WRITE")) {
*rights |= NCP_RIGHT_WRITE;
return(0);
}
if (grant_same(s, "C") || grant_same(s, "CREATE")) {
*rights |= NCP_RIGHT_CREATE;
return(0);
}
if (grant_same(s, "E") || grant_same(s, "ERASE")) {
*rights |= NCP_RIGHT_DELETE;
return(0);
}
if (grant_same(s, "M") || grant_same(s, "MODIFY")) {
*rights |= NCP_RIGHT_MODIFY;
return(0);
}
if (grant_same(s, "F") || grant_same(s, "FILESCAN") ||
grant_same(s, "FILE") || grant_same(s, "SCAN")) {
*rights |= NCP_RIGHT_SEARCH;
return(0);
}
if (grant_same(s, "A") || grant_same(s, "ACCESS") ||
grant_same(s, "CONTROL") || grant_same(s, "ACCESSCONTROL")) {
*rights |= NCP_RIGHT_OWNER;
return(0);
}
return(-1);
}
static int grant_is_option(char *s)
{
if (!s) return(0);
return(s[0] == '/' || s[0] == '-');
}
static int grant_last_rc = 0;
static int grant_set_one(char *path, uint16 dhandle,
uint32 object_id, uint16 rights)
{
int rc;
rc = c32_ncp87_add_trustee_rights(path,
dhandle,
object_id,
rights,
0xffff,
NULL, NULL, NULL);
grant_last_rc = rc;
return(rc);
}
static int grant_is_dot_dir(char *name)
{
if (!name) return(0);
if (name[0] == '.' && name[1] == '\0') return(1);
if (name[0] == '.' && name[1] == '.' && name[2] == '\0') return(1);
return(0);
}
static void grant_join_path(char *out, char *base, char *name, int max)
{
int len;
out[0] = '\0';
strmaxcpy(out, base, max - 1);
len = strlen(out);
if (len > 0 && out[len - 1] != '\\' && out[len - 1] != '/' &&
out[len - 1] != ':') {
if (len < max - 1) {
out[len++] = '\\';
out[len] = '\0';
}
}
if ((int)(strlen(out) + strlen(name)) < max - 1)
strcat(out, name);
}
/*
* Apply the grant to PATH and every directory below it.
*
* This intentionally walks through the DOS redirector, not through another
* NCP search helper, so it works with the same mapped-drive view that the
* user passed to GRANT.
*/
static int grant_set_subdirs(char *path, uint16 dhandle,
uint32 object_id, uint16 rights)
{
struct find_t ff;
char pattern[260];
char child[260];
int rc = 0;
if (grant_set_one(path, dhandle, object_id, rights))
rc = 1;
grant_join_path(pattern, path, "*.*", sizeof(pattern));
if (_dos_findfirst(pattern, _A_SUBDIR, &ff) == 0) {
do {
if ((ff.attrib & _A_SUBDIR) && !grant_is_dot_dir(ff.name)) {
grant_join_path(child, path, ff.name, sizeof(child));
if (grant_set_subdirs(child, dhandle, object_id, rights))
rc = 1;
}
} while (_dos_findnext(&ff) == 0);
}
return(rc);
}
int func_grant(int argc, char *argv[], int mode)
{
uint16 rights = 0;
char *path = ".";
char *objname = NULL;
uint16 objtype = GRANT_BINDERY_USER;
uint8 connid = 0;
uint8 dhandle = 0;
uint8 namebuf[48];
uint32 object_id;
int recurse_subdirs = 0;
int i = 1;
int have_rights = 0;
int rc;
(void)mode;
if (argc < 2 || grant_is_help(argv[1])) {
if (argc < 2)
grant_usage_error();
grant_usage();
return(argc < 2 ? 1 : 0);
}
/*
* GRANT rightslist* [FOR path] TO [USER|GROUP] name [options]
*/
while (i < argc) {
if (grant_same(argv[i], "FOR") || grant_same(argv[i], "TO"))
break;
if (grant_is_option(argv[i]))
break;
if (grant_add_right_word(argv[i], &rights)) {
grant_usage_error();
grant_usage();
return(1);
}
have_rights = 1;
i++;
}
if (!have_rights || i >= argc) {
grant_usage_error();
grant_usage();
return(1);
}
if (grant_same(argv[i], "FOR")) {
i++;
if (i >= argc) {
grant_usage_error();
grant_usage();
return(1);
}
path = argv[i++];
}
if (i >= argc || !grant_same(argv[i], "TO")) {
grant_usage_error();
grant_usage();
return(1);
}
i++;
if (i < argc && grant_same(argv[i], "USER")) {
objtype = GRANT_BINDERY_USER;
i++;
} else if (i < argc && grant_same(argv[i], "GROUP")) {
objtype = GRANT_BINDERY_GROUP;
i++;
}
if (i >= argc) {
grant_usage_error();
grant_usage();
return(1);
}
objname = argv[i++];
while (i < argc) {
if (!grant_is_option(argv[i])) {
grant_usage_error();
grant_usage();
return(1);
}
/*
* /FILES is harmless because the explicit path is passed to the
* NCP87 trustee-add call. /SUBDIRECTORIES recursively applies the
* same grant to all subdirectories below the given path.
*/
if (grant_same(argv[i], "/FILES") || grant_same(argv[i], "-FILES") ||
grant_same(argv[i], "/F") || grant_same(argv[i], "-F")) {
i++;
continue;
}
if (grant_same(argv[i], "/SUBDIRECTORIES") ||
grant_same(argv[i], "-SUBDIRECTORIES") ||
grant_same(argv[i], "/S") || grant_same(argv[i], "-S")) {
recurse_subdirs = 1;
i++;
continue;
}
grant_usage_error();
grant_usage();
return(1);
}
if (grant_current_dhandle(&connid, &dhandle)) {
fprintf(stdout, "Specified path not locatable.\n");
return(1);
}
strmaxcpy(namebuf, objname, sizeof(namebuf) - 1);
upstr(namebuf);
object_id = ncp_17_35(namebuf, objtype);
if (!object_id) {
fprintf(stdout, "Object not found.\n");
return(1);
}
if (recurse_subdirs)
rc = grant_set_subdirs(path, (uint16)dhandle, object_id, rights);
else
rc = grant_set_one(path, (uint16)dhandle, object_id, rights);
if (rc) {
fprintf(stdout, "Could not add trustee rights. rc=%d\n", grant_last_rc);
return(grant_last_rc ? grant_last_rc : 1);
}
{
char header[300];
char base[80];
char bracket[10];
grant_header_path(header, path, sizeof(header));
grant_basename(base, path, sizeof(base));
grant_rights_bracket(rights, bracket);
fprintf(stdout, "%s\n", header);
fprintf(stdout, "%-29.29sRights set to [%s]\n", base, bracket);
}
return(0);
}