diff --git a/CMakeLists.txt b/CMakeLists.txt index beb2fd1..b6935d5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,6 +42,8 @@ set(MARS_DOSUTILS_NEW_ONLY_TOOLS flagdir rights grant + revoke + remove ) if(MARS_NWE_BUILD_DOSUTILS) @@ -59,6 +61,9 @@ if(MARS_NWE_BUILD_DOSUTILS) flagdir.c rights.c grant.c + revoke.c + remove.c + trustee.c c32ncp.c nwcrypt.c nwdebug.c @@ -149,8 +154,19 @@ else() set(MARS_DOSUTILS_SELECTED_LEGACY_EXE "${MARS_DOSUTILS_LEGACY_NET_EXE}") endif() +set(MARS_DOSUTILS_SELECTED_LEGACY_IS_BUILT FALSE) +set(MARS_DOSUTILS_SELECTED_NEW_IS_BUILT FALSE) +if(MARS_NWE_BUILD_DOSUTILS) + if(MARS_DOSUTILS_SELECTED_LEGACY_EXE STREQUAL MARS_DOSUTILS_BUILT_NET_EXE) + set(MARS_DOSUTILS_SELECTED_LEGACY_IS_BUILT TRUE) + endif() + if(MARS_DOSUTILS_SELECTED_NEW_EXE STREQUAL MARS_DOSUTILS_BUILT_NET_EXE) + set(MARS_DOSUTILS_SELECTED_NEW_IS_BUILT TRUE) + endif() +endif() + if(MARS_NWE_INSTALL_DOSUTILS) - if(NOT EXISTS "${MARS_DOSUTILS_SELECTED_LEGACY_EXE}") + if(NOT MARS_DOSUTILS_SELECTED_LEGACY_IS_BUILT AND NOT EXISTS "${MARS_DOSUTILS_SELECTED_LEGACY_EXE}") message(FATAL_ERROR "Selected legacy/default DOS utility missing: ${MARS_DOSUTILS_SELECTED_LEGACY_EXE}. " "Commit dosutils/netold.exe, enable MARS_NWE_INSTALL_NEW_DOSUTILS, " @@ -158,7 +174,7 @@ if(MARS_NWE_INSTALL_DOSUTILS) ) endif() - if(NOT EXISTS "${MARS_DOSUTILS_SELECTED_NEW_EXE}") + if(NOT MARS_DOSUTILS_SELECTED_NEW_IS_BUILT AND NOT EXISTS "${MARS_DOSUTILS_SELECTED_NEW_EXE}") message(FATAL_ERROR "Selected new DOS utility missing: ${MARS_DOSUTILS_SELECTED_NEW_EXE}. " "Commit dosutils/net.exe or enable MARS_NWE_BUILD_DOSUTILS." diff --git a/c32ncp.c b/c32ncp.c index c438c4d..6cc7c70 100644 --- a/c32ncp.c +++ b/c32ncp.c @@ -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); +} diff --git a/c32ncp.h b/c32ncp.h index 891e474..7cf823d 100644 --- a/c32ncp.h +++ b/c32ncp.h @@ -35,4 +35,19 @@ int c32_ncp87_add_trustee_rights(const char *path_name, uint16 *handle_lo_out, uint16 *handle_hi_out); +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); + +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); + #endif diff --git a/grant.c b/grant.c index 2706a5d..b8830c5 100644 --- a/grant.c +++ b/grant.c @@ -16,10 +16,11 @@ #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) +/* 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) { diff --git a/net.c b/net.c index cd35b6e..cbee6a3 100644 --- a/net.c +++ b/net.c @@ -37,6 +37,8 @@ static struct s_net_functions { {"FLAG", "display or modify file attributes", func_flag , 0}, {"FLAGDIR","display or modify directory attributes",func_flagdir, 0}, {"GRANT", "grant trustee rights", func_grant , 0}, +{"REVOKE", "revoke trustee rights", func_revoke , 0}, +{"REMOVE", "remove trustee", func_remove , 0}, {"RIGHTS", "display effective file/directory rights",func_rights, 0}, {"SLIST", "list servers", func_slist , 0}, {"PASSWD", "change password", func_passwd , 0}, diff --git a/net.exe b/net.exe index e7db07f..431c3ab 100755 Binary files a/net.exe and b/net.exe differ diff --git a/net.h b/net.h index 6047e8b..9d4265c 100644 --- a/net.h +++ b/net.h @@ -256,7 +256,9 @@ extern int func_capture(int argc, char *argv[], int mode); /* flag.c */ extern int func_flag (int argc, char *argv[], int mode); extern int func_flagdir(int argc, char *argv[], int mode); -extern int func_grant(int argc, char *argv[], int mode); +extern int func_grant (int argc, char *argv[], int mode); +extern int func_revoke(int argc, char *argv[], int mode); +extern int func_remove(int argc, char *argv[], int mode); extern int func_rights (int argc, char *argv[], int mode); diff --git a/remove.c b/remove.c new file mode 100644 index 0000000..27017ff --- /dev/null +++ b/remove.c @@ -0,0 +1,253 @@ +/* remove.c - Novell REMOVE-like DOS utility */ + +#include "net.h" +#include "c32ncp.h" +#include "trustee.h" +#include +#include + +#ifndef _A_NORMAL +#define _A_NORMAL 0x00 +#endif + +static int remove_last_rc = 0; + +static void remove_usage_error(void) +{ + fprintf(stdout, "Command line arguments violate grammar defined for REMOVE.\n\n"); +} + +static void remove_usage(void) +{ + fprintf(stdout, "Usage: REMOVE [USER | GROUP] name [FROM path] [option]\n"); + fprintf(stdout, "Options: /Subdirs | /Files\n"); +} + +static int remove_one(char *path, uint16 dhandle, uint32 object_id, + uint16 objtype, char *objname, int forced_is_file) +{ + uint16 old_rights = 0; + int is_dir; + int rc; + + is_dir = forced_is_file ? 0 : trustee_path_is_dir(path); + + rc = c32_ncp87_find_trustee_rights(path, dhandle, object_id, &old_rights, + NULL, NULL, NULL); + remove_last_rc = rc; + if (rc) { + if (rc == 0xff) + fprintf(stdout, "No trustee for the specified %s.\n", is_dir ? "directory" : "file"); + else + fprintf(stdout, "Error scanning trustee list.\n"); + return(1); + } + + rc = c32_ncp87_delete_trustee_rights(path, dhandle, object_id, + NULL, NULL, NULL); + remove_last_rc = rc; + if (rc) { + fprintf(stdout, "Error deleting trustee.\n"); + return(1); + } + + { + char header[300]; + trustee_header_path(header, path, sizeof(header)); + fprintf(stdout, "%s\n\n", header); + } + + if (objtype == TRUSTEE_BINDERY_GROUP) + fprintf(stdout, "Group \"%s\" no longer a trustee to the specified %s.\n", + objname, is_dir ? "directory" : "file"); + else + fprintf(stdout, "User \"%s\" no longer a trustee to the specified %s.\n", + objname, is_dir ? "directory" : "file"); + + return(0); +} + +static int remove_subdirs(char *path, uint16 dhandle, uint32 object_id, + uint16 objtype, char *objname, int *count) +{ + struct find_t ff; + char pattern[260]; + char child[260]; + int rc = 0; + + if (remove_one(path, dhandle, object_id, objtype, objname, 0) == 0) + (*count)++; + else + rc = 1; + + trustee_join_path(pattern, path, "*.*", sizeof(pattern)); + + if (_dos_findfirst(pattern, _A_SUBDIR, &ff) == 0) { + do { + if ((ff.attrib & _A_SUBDIR) && !trustee_is_dot_dir(ff.name)) { + trustee_join_path(child, path, ff.name, sizeof(child)); + if (remove_subdirs(child, dhandle, object_id, objtype, objname, count)) + rc = 1; + } + } while (_dos_findnext(&ff) == 0); + } + + return(rc); +} + +static int remove_files(char *path, uint16 dhandle, uint32 object_id, + uint16 objtype, char *objname, int *count) +{ + struct find_t ff; + char dir[260]; + char pat[80]; + char spec[260]; + char target[260]; + int rc = 0; + + if (trustee_path_is_dir(path)) { + strmaxcpy(dir, path, sizeof(dir) - 1); + strmaxcpy(pat, "*.*", sizeof(pat) - 1); + } else if (trustee_path_has_wildcards(path)) { + trustee_parent_pattern(dir, pat, path, sizeof(dir), sizeof(pat)); + } else { + if (remove_one(path, dhandle, object_id, objtype, objname, 1) == 0) + (*count)++; + else + rc = 1; + return(rc); + } + + trustee_join_path(spec, dir, pat, sizeof(spec)); + if (_dos_findfirst(spec, _A_NORMAL | _A_HIDDEN | _A_SYSTEM | _A_ARCH, &ff) == 0) { + do { + if (!(ff.attrib & _A_SUBDIR)) { + trustee_join_path(target, dir, ff.name, sizeof(target)); + if (remove_one(target, dhandle, object_id, objtype, objname, 1) == 0) + (*count)++; + else + rc = 1; + } + } while (_dos_findnext(&ff) == 0); + } + + return(rc); +} + +int func_remove(int argc, char *argv[], int mode) +{ + char *path = "."; + char *objname = NULL; + char objprint[48]; + uint16 objtype = TRUSTEE_BINDERY_USER; + int objtype_given = 0; + uint8 connid = 0; + uint8 dhandle = 0; + uint32 object_id; + int use_subdirs = 0; + int use_files = 0; + int count = 0; + int i = 1; + int rc; + + (void)mode; + + if (argc < 2 || trustee_is_help(argv[1])) { + if (argc < 2) + remove_usage_error(); + remove_usage(); + return(argc < 2 ? 1 : 0); + } + + if (i < argc && trustee_same(argv[i], "USER")) { + objtype = TRUSTEE_BINDERY_USER; + objtype_given = 1; + i++; + } else if (i < argc && trustee_same(argv[i], "GROUP")) { + objtype = TRUSTEE_BINDERY_GROUP; + objtype_given = 1; + i++; + } + + if (i >= argc) { + remove_usage_error(); + remove_usage(); + return(1); + } + + objname = argv[i++]; + + if (i < argc && trustee_same(argv[i], "FROM")) { + i++; + if (i >= argc) { + remove_usage_error(); + remove_usage(); + return(1); + } + path = argv[i++]; + } + + while (i < argc) { + if (!trustee_is_option(argv[i])) { + remove_usage_error(); + remove_usage(); + return(1); + } + + if (trustee_is_files_option(argv[i])) { + use_files = 1; + i++; + continue; + } + + if (trustee_is_subdirs_option(argv[i])) { + use_subdirs = 1; + i++; + continue; + } + + remove_usage_error(); + remove_usage(); + return(1); + } + + if (use_files && use_subdirs) { + fprintf(stdout, "Remove cannot do both directories and files in a single pass.\n"); + return(1); + } + + if (trustee_current_dhandle(&connid, &dhandle)) { + fprintf(stdout, "Error: Drive not mapped to network.\n"); + return(1); + } + + object_id = trustee_lookup_object(objname, &objtype, objtype_given); + if (!object_id) { + if (objtype_given && objtype == TRUSTEE_BINDERY_GROUP) + fprintf(stdout, "Group \"%s\" not found.\n", objname); + else if (objtype_given) + fprintf(stdout, "User \"%s\" not found.\n", objname); + else + fprintf(stdout, "User or group \"%s\" not found.\n", objname); + return(1); + } + + trustee_upcopy(objprint, objname, sizeof(objprint)); + + if (use_subdirs) + rc = remove_subdirs(path, (uint16)dhandle, object_id, objtype, objprint, &count); + else if (use_files) + rc = remove_files(path, (uint16)dhandle, object_id, objtype, objprint, &count); + else { + rc = remove_one(path, (uint16)dhandle, object_id, objtype, objprint, 0); + if (!rc) + count = 1; + } + + if (use_subdirs || (!use_files && !rc)) + fprintf(stdout, "Trustee \"%s\" removed from %d directories.\n", objprint, count); + else if (use_files) + fprintf(stdout, "Trustee \"%s\" removed from %d files.\n", objprint, count); + + return(rc ? (remove_last_rc ? remove_last_rc : 1) : 0); +} diff --git a/revoke.c b/revoke.c new file mode 100644 index 0000000..087cfe7 --- /dev/null +++ b/revoke.c @@ -0,0 +1,301 @@ +/* revoke.c - Novell REVOKE-like DOS utility */ + +#include "net.h" +#include "c32ncp.h" +#include "trustee.h" + +#ifndef _A_NORMAL +#define _A_NORMAL 0x00 +#endif + +static int revoke_last_rc = 0; + +static void revoke_usage_error(void) +{ + fprintf(stdout, "Command line arguments violate grammar defined for REVOKE.\n\n"); +} + +static void revoke_usage(void) +{ + fprintf(stdout, "Usage: REVOKE rightslist* [FOR path] FROM [USER|GROUP] name [options]\n"); + fprintf(stdout, "Options: /SubDirectories | /Files\n\n"); + fprintf(stdout, "286 Rights:\t\t386 Rights:\n"); + fprintf(stdout, "---------------\t\t--------------------\n"); + fprintf(stdout, "ALL = All\t\tALL = All\n"); + fprintf(stdout, "R = Read\t\tS = Supervisor\n"); + fprintf(stdout, "W = Write\t\tR = Read\n"); + fprintf(stdout, "O = Open\t\tW = Write\n"); + fprintf(stdout, "C = Create\t\tC = Create\n"); + fprintf(stdout, "D = Delete\t\tE = Erase\n"); + fprintf(stdout, "P = Parental\t\tM = Modify\n"); + fprintf(stdout, "S = Search\t\tF = File Scan\n"); + fprintf(stdout, "M = Modify\t\tA = Access Control\n"); + fprintf(stdout, "\n* Use abbreviations listed above, separated by spaces.\n"); +} + +static int revoke_one(char *path, uint16 dhandle, uint32 object_id, + uint16 revoke_mask, int forced_is_file) +{ + uint16 old_rights = 0; + uint16 new_rights; + int is_dir; + int rc; + + is_dir = forced_is_file ? 0 : trustee_path_is_dir(path); + + rc = c32_ncp87_find_trustee_rights(path, dhandle, object_id, &old_rights, + NULL, NULL, NULL); + revoke_last_rc = rc; + if (rc) { + if (rc == 0xff) + fprintf(stdout, "No trustee for the specified %s.\n", is_dir ? "directory" : "file"); + else + fprintf(stdout, "Error scanning trustee list.\n"); + return(1); + } + + new_rights = (uint16)(old_rights & ~revoke_mask); + + if (new_rights == 0) { + rc = c32_ncp87_delete_trustee_rights(path, dhandle, object_id, + NULL, NULL, NULL); + revoke_last_rc = rc; + if (rc) { + fprintf(stdout, "Error deleting trustee.\n"); + return(1); + } + } else { + rc = c32_ncp87_add_trustee_rights(path, dhandle, object_id, new_rights, + 0xffff, NULL, NULL, NULL); + revoke_last_rc = rc; + if (rc) { + fprintf(stdout, "Fatal error revoking access rights.\n"); + return(1); + } + } + + { + char header[300]; + char bracket[10]; + trustee_header_path(header, path, sizeof(header)); + trustee_rights_bracket(new_rights, bracket); + fprintf(stdout, "%s\n\n", header); + fprintf(stdout, "Trustee's access rights set to [%s]\n", bracket); + } + + return(0); +} + +static int revoke_subdirs(char *path, uint16 dhandle, uint32 object_id, + uint16 revoke_mask, int *count) +{ + struct find_t ff; + char pattern[260]; + char child[260]; + int rc = 0; + + if (revoke_one(path, dhandle, object_id, revoke_mask, 0) == 0) + (*count)++; + else + rc = 1; + + trustee_join_path(pattern, path, "*.*", sizeof(pattern)); + + if (_dos_findfirst(pattern, _A_SUBDIR, &ff) == 0) { + do { + if ((ff.attrib & _A_SUBDIR) && !trustee_is_dot_dir(ff.name)) { + trustee_join_path(child, path, ff.name, sizeof(child)); + if (revoke_subdirs(child, dhandle, object_id, revoke_mask, count)) + rc = 1; + } + } while (_dos_findnext(&ff) == 0); + } + + return(rc); +} + +static int revoke_files(char *path, uint16 dhandle, uint32 object_id, + uint16 revoke_mask, int *count) +{ + struct find_t ff; + char dir[260]; + char pat[80]; + char spec[260]; + char target[260]; + int rc = 0; + + if (trustee_path_is_dir(path)) { + strmaxcpy(dir, path, sizeof(dir) - 1); + strmaxcpy(pat, "*.*", sizeof(pat) - 1); + } else if (trustee_path_has_wildcards(path)) { + trustee_parent_pattern(dir, pat, path, sizeof(dir), sizeof(pat)); + } else { + if (revoke_one(path, dhandle, object_id, revoke_mask, 1) == 0) + (*count)++; + else + rc = 1; + return(rc); + } + + trustee_join_path(spec, dir, pat, sizeof(spec)); + if (_dos_findfirst(spec, _A_NORMAL | _A_HIDDEN | _A_SYSTEM | _A_ARCH, &ff) == 0) { + do { + if (!(ff.attrib & _A_SUBDIR)) { + trustee_join_path(target, dir, ff.name, sizeof(target)); + if (revoke_one(target, dhandle, object_id, revoke_mask, 1) == 0) + (*count)++; + else + rc = 1; + } + } while (_dos_findnext(&ff) == 0); + } + + return(rc); +} + +int func_revoke(int argc, char *argv[], int mode) +{ + uint16 rights = 0; + char *path = "."; + char *objname = NULL; + char objprint[48]; + uint16 objtype = TRUSTEE_BINDERY_USER; + int objtype_given = 0; + uint8 connid = 0; + uint8 dhandle = 0; + uint32 object_id; + int use_subdirs = 0; + int use_files = 0; + int count = 0; + int i = 1; + int have_rights = 0; + int rc; + + (void)mode; + + if (argc < 2 || trustee_is_help(argv[1])) { + if (argc < 2) + revoke_usage_error(); + revoke_usage(); + return(argc < 2 ? 1 : 0); + } + + while (i < argc) { + if (trustee_same(argv[i], "FOR") || trustee_same(argv[i], "FROM")) + break; + if (trustee_is_option(argv[i])) + break; + if (trustee_parse_right_word(argv[i], &rights)) { + fprintf(stdout, "Invalid right specified.\n"); + revoke_usage(); + return(1); + } + have_rights = 1; + i++; + } + + if (!have_rights || i >= argc) { + revoke_usage_error(); + revoke_usage(); + return(1); + } + + if (trustee_same(argv[i], "FOR")) { + i++; + if (i >= argc) { + revoke_usage_error(); + revoke_usage(); + return(1); + } + path = argv[i++]; + } + + if (i >= argc || !trustee_same(argv[i], "FROM")) { + revoke_usage_error(); + revoke_usage(); + return(1); + } + i++; + + if (i < argc && trustee_same(argv[i], "USER")) { + objtype = TRUSTEE_BINDERY_USER; + objtype_given = 1; + i++; + } else if (i < argc && trustee_same(argv[i], "GROUP")) { + objtype = TRUSTEE_BINDERY_GROUP; + objtype_given = 1; + i++; + } + + if (i >= argc) { + revoke_usage_error(); + revoke_usage(); + return(1); + } + + objname = argv[i++]; + + while (i < argc) { + if (!trustee_is_option(argv[i])) { + revoke_usage_error(); + revoke_usage(); + return(1); + } + + if (trustee_is_files_option(argv[i])) { + use_files = 1; + i++; + continue; + } + + if (trustee_is_subdirs_option(argv[i])) { + use_subdirs = 1; + i++; + continue; + } + + revoke_usage_error(); + revoke_usage(); + return(1); + } + + if (use_files && use_subdirs) { + fprintf(stdout, "Revoke cannot do both directories and files in a single pass.\n"); + return(1); + } + + if (trustee_current_dhandle(&connid, &dhandle)) { + fprintf(stdout, "Error: Drive not mapped to Network.\n"); + return(1); + } + + object_id = trustee_lookup_object(objname, &objtype, objtype_given); + if (!object_id) { + if (objtype_given && objtype == TRUSTEE_BINDERY_GROUP) + fprintf(stdout, "Group \"%s\" not found.\n", objname); + else if (objtype_given) + fprintf(stdout, "User \"%s\" not found.\n", objname); + else + fprintf(stdout, "User or group \"%s\" not found.\n", objname); + return(1); + } + + trustee_upcopy(objprint, objname, sizeof(objprint)); + + if (use_subdirs) + rc = revoke_subdirs(path, (uint16)dhandle, object_id, rights, &count); + else if (use_files) + rc = revoke_files(path, (uint16)dhandle, object_id, rights, &count); + else { + rc = revoke_one(path, (uint16)dhandle, object_id, rights, 0); + if (!rc) + count = 1; + } + + if (use_subdirs || (!use_files && !rc)) + fprintf(stdout, "Rights for %d directories were changed for %s.\n", count, objprint); + else if (use_files) + fprintf(stdout, "Rights for %d files were changed for %s.\n", count, objprint); + + return(rc ? (revoke_last_rc ? revoke_last_rc : 1) : 0); +} diff --git a/trustee.c b/trustee.c new file mode 100644 index 0000000..2adc2cd --- /dev/null +++ b/trustee.c @@ -0,0 +1,341 @@ +/* trustee.c - shared helpers for GRANT/REVOKE/REMOVE style tools */ + +#include "net.h" +#include "trustee.h" +#include +#include + +#ifndef S_IFDIR +#define S_IFDIR 0040000 +#endif + +int trustee_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); +} + +int trustee_is_help(char *s) +{ + if (!s) return(0); + return(trustee_same(s, "/?") || trustee_same(s, "-?") || trustee_same(s, "?")); +} + +int trustee_is_option(char *s) +{ + if (!s) return(0); + return(s[0] == '/' || s[0] == '-'); +} + +int trustee_is_subdirs_option(char *s) +{ + if (!s) return(0); + return(trustee_same(s, "/SUBDIRS") || trustee_same(s, "-SUBDIRS") || + trustee_same(s, "/SUBDIRECTORIES") || trustee_same(s, "-SUBDIRECTORIES") || + trustee_same(s, "/S") || trustee_same(s, "-S")); +} + +int trustee_is_files_option(char *s) +{ + if (!s) return(0); + return(trustee_same(s, "/FILES") || trustee_same(s, "-FILES") || + trustee_same(s, "/F") || trustee_same(s, "-F")); +} + +static int trustee_get_current_drive(void) +{ + REGS regs; + + regs.h.ah = 0x19; + int86(0x21, ®s, ®s); + return((int)regs.h.al); +} + +int trustee_current_dhandle(uint8 *connid, uint8 *dhandle) +{ + uint8 flags = 0; + int drive = trustee_get_current_drive(); + + if (get_drive_info((uint8)drive, connid, dhandle, &flags)) + return(-1); + + if (!*connid || (flags & 0x80)) + return(-1); + + return(0); +} + +static int trustee_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 = trustee_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); +} + +void trustee_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; +} + +void trustee_basename(char *dst, char *src, int max) +{ + char up[260]; + char *p; + + trustee_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); +} + +void trustee_header_path(char *out, char *path, int max) +{ + char prefix[90]; + char up[260]; + + if (trustee_current_prefix(prefix, sizeof(prefix))) + prefix[0] = '\0'; + + trustee_upcopy(up, path, sizeof(up)); + + strmaxcpy(out, prefix, max - 1); + if ((int)(strlen(out) + strlen(up)) < max - 1) + strcat(out, up); +} + +void trustee_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); +} + +int trustee_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); +} + +int trustee_parse_right_word(char *s, uint16 *rights) +{ + if (trustee_same(s, "ALL")) { + *rights = TRUSTEE_RIGHT_ALL_386; + return(0); + } + + if (trustee_same(s, "N") || trustee_same(s, "NONE")) { + *rights = TRUSTEE_RIGHT_ALL_386; + return(0); + } + + if (trustee_same(s, "S") || trustee_same(s, "SUPERVISOR")) { + *rights |= TRUSTEE_RIGHT_SUPER; + return(0); + } + + if (trustee_same(s, "R") || trustee_same(s, "READ")) { + *rights |= TRUSTEE_RIGHT_READ; + return(0); + } + + if (trustee_same(s, "W") || trustee_same(s, "WRITE")) { + *rights |= TRUSTEE_RIGHT_WRITE; + return(0); + } + + if (trustee_same(s, "C") || trustee_same(s, "CREATE")) { + *rights |= TRUSTEE_RIGHT_CREATE; + return(0); + } + + if (trustee_same(s, "E") || trustee_same(s, "ERASE") || + trustee_same(s, "D") || trustee_same(s, "DELETE")) { + *rights |= TRUSTEE_RIGHT_DELETE; + return(0); + } + + if (trustee_same(s, "M") || trustee_same(s, "MODIFY")) { + *rights |= TRUSTEE_RIGHT_MODIFY; + return(0); + } + + if (trustee_same(s, "F") || trustee_same(s, "FILESCAN") || + trustee_same(s, "FILE") || trustee_same(s, "SCAN")) { + *rights |= TRUSTEE_RIGHT_SEARCH; + return(0); + } + + if (trustee_same(s, "A") || trustee_same(s, "ACCESS") || + trustee_same(s, "CONTROL") || trustee_same(s, "ACCESSCONTROL")) { + *rights |= TRUSTEE_RIGHT_OWNER; + return(0); + } + + return(-1); +} + +void trustee_rights_bracket(uint16 rights, char *out) +{ + out[0] = (rights & TRUSTEE_RIGHT_SUPER) ? 'S' : ' '; + out[1] = (rights & TRUSTEE_RIGHT_READ) ? 'R' : ' '; + out[2] = (rights & TRUSTEE_RIGHT_WRITE) ? 'W' : ' '; + out[3] = (rights & TRUSTEE_RIGHT_CREATE) ? 'C' : ' '; + out[4] = (rights & TRUSTEE_RIGHT_DELETE) ? 'E' : ' '; + out[5] = (rights & TRUSTEE_RIGHT_MODIFY) ? 'M' : ' '; + out[6] = (rights & TRUSTEE_RIGHT_SEARCH) ? 'F' : ' '; + out[7] = (rights & TRUSTEE_RIGHT_OWNER) ? 'A' : ' '; + out[8] = '\0'; +} + +uint32 trustee_lookup_object(char *name, uint16 *objtype, int objtype_given) +{ + uint8 namebuf[48]; + uint32 object_id; + + strmaxcpy(namebuf, name, sizeof(namebuf) - 1); + upstr(namebuf); + + if (objtype_given) { + return(ncp_17_35(namebuf, *objtype)); + } + + *objtype = TRUSTEE_BINDERY_USER; + object_id = ncp_17_35(namebuf, TRUSTEE_BINDERY_USER); + if (object_id) + return(object_id); + + *objtype = TRUSTEE_BINDERY_GROUP; + object_id = ncp_17_35(namebuf, TRUSTEE_BINDERY_GROUP); + return(object_id); +} + +int trustee_path_is_dir(char *path) +{ + struct stat st; + + if (!path || !*path || trustee_same(path, ".") || trustee_same(path, ".\\") || + trustee_same(path, "./")) + return(1); + + if (stat(path, &st) == 0) { + if (st.st_mode & S_IFDIR) + return(1); + } + + return(0); +} + +int trustee_path_has_wildcards(char *path) +{ + if (!path) return(0); + while (*path) { + if (*path == '*' || *path == '?') return(1); + path++; + } + return(0); +} + +void trustee_parent_pattern(char *dir, char *pattern, char *path, int maxdir, int maxpat) +{ + char tmp[260]; + char *p; + + trustee_upcopy(tmp, path, sizeof(tmp)); + p = strrchr(tmp, '\\'); + if (!p) p = strrchr(tmp, ':'); + + if (p) { + char save = *p; + *p = '\0'; + strmaxcpy(pattern, p + 1, maxpat - 1); + if (save == ':') { + *p = ':'; + *(p + 1) = '\0'; + } + strmaxcpy(dir, tmp, maxdir - 1); + } else { + strmaxcpy(dir, ".", maxdir - 1); + strmaxcpy(pattern, tmp, maxpat - 1); + } +} diff --git a/trustee.h b/trustee.h new file mode 100644 index 0000000..0f06608 --- /dev/null +++ b/trustee.h @@ -0,0 +1,40 @@ +#ifndef TRUSTEE_H +#define TRUSTEE_H + +#define TRUSTEE_BINDERY_USER 0x0001 +#define TRUSTEE_BINDERY_GROUP 0x0002 + +#define TRUSTEE_RIGHT_READ 0x0001 +#define TRUSTEE_RIGHT_WRITE 0x0002 +#define TRUSTEE_RIGHT_OPEN 0x0004 +#define TRUSTEE_RIGHT_CREATE 0x0008 +#define TRUSTEE_RIGHT_DELETE 0x0010 +#define TRUSTEE_RIGHT_OWNER 0x0020 +#define TRUSTEE_RIGHT_SEARCH 0x0040 +#define TRUSTEE_RIGHT_MODIFY 0x0080 +#define TRUSTEE_RIGHT_SUPER 0x0100 + +#define TRUSTEE_RIGHT_ALL_386 (TRUSTEE_RIGHT_SUPER | TRUSTEE_RIGHT_READ | \ + TRUSTEE_RIGHT_WRITE | TRUSTEE_RIGHT_CREATE | \ + TRUSTEE_RIGHT_DELETE | TRUSTEE_RIGHT_MODIFY | \ + TRUSTEE_RIGHT_SEARCH | TRUSTEE_RIGHT_OWNER) + +int trustee_same(char *a, char *b); +int trustee_is_help(char *s); +int trustee_is_option(char *s); +int trustee_is_subdirs_option(char *s); +int trustee_is_files_option(char *s); +int trustee_current_dhandle(uint8 *connid, uint8 *dhandle); +void trustee_upcopy(char *dst, char *src, int max); +void trustee_basename(char *dst, char *src, int max); +void trustee_header_path(char *out, char *path, int max); +void trustee_join_path(char *out, char *base, char *name, int max); +int trustee_is_dot_dir(char *name); +int trustee_parse_right_word(char *s, uint16 *rights); +void trustee_rights_bracket(uint16 rights, char *out); +uint32 trustee_lookup_object(char *name, uint16 *objtype, int objtype_given); +int trustee_path_is_dir(char *path); +int trustee_path_has_wildcards(char *path); +void trustee_parent_pattern(char *dir, char *pattern, char *path, int maxdir, int maxpat); + +#endif