- add GRANT as a new multi-call DOS utility - implement Client32 NCP87 trustee-add helper - resolve USER and GROUP bindery objects before granting rights - support Novell-style rights lists, including ALL and N - support directory trustee grants - support file trustee grants via /FILES - implement recursive grants via /SUBDIRECTORIES - accept /SUBDIRS as a compatibility alias - format GRANT success output close to Novell GRANT - add GRANT comparison scripts for normal and recursive test cases
520 lines
12 KiB
C
520 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
|
|
|
|
#define NCP_RIGHT_ALL_386 (NCP_RIGHT_SUPER | 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, ®s, ®s);
|
|
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);
|
|
}
|