/* 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 void grant_usage_error(void) { fprintf(stdout, "Command line arguments violate grammar defined for GRANT.\n\n"); } static void grant_invalid_right_error(void) { fprintf(stdout, "Specified rights unreadable or invalid. Spaces required between each right.\n\n"); } static void grant_usage_ex(int leading_blanks, int bell_after_options, int trailing_blanks) { int i; for (i = 0; i < leading_blanks; i++) fprintf(stdout, "\n"); fprintf(stdout, "Usage: GRANT rightslist* [FOR path] TO [USER | GROUP] name [options]\n"); fprintf(stdout, "Options: /SubDirectories | /Files\n"); if (bell_after_options) fprintf(stdout, "\a"); fprintf(stdout, "\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"); for (i = 0; i < trailing_blanks; i++) fprintf(stdout, "\n"); } static void grant_usage(void) { grant_usage_ex(0, 0, 0); } static void grant_usage_help(void) { grant_usage_ex(2, 0, 1); } static void grant_usage_after_error(void) { grant_usage_ex(0, 1, 2); } static void grant_header_path(char *out, char *path, int max) { char *p; tool_header_path(out, path, max); /* Novell GRANT displays server and volume as SERVER/SYS: while * RIGHTS uses SERVER\SYS:. Keep the rest of the path with DOS * backslashes. */ p = strchr(out, '\\'); if (p && strchr(out, ':') && p < strchr(out, ':')) *p = '/'; } static void grant_rights_bracket(uint16 rights, char *out) { /* Novell displays Supervisor as the full effective right mask. */ if (rights & NCP_RIGHT_SUPER) rights |= NCP_RIGHT_ALL_386; 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 uint16 grant_expand_supervisor_rights(uint16 rights) { /* Novell GRANT expands Supervisor to the full trustee mask before * storing it. This keeps the wire value and the printed result in * sync with Novell: GRANT S reports and sends [SRWCEMFA], not just * [S ]. */ if (rights & NCP_RIGHT_SUPER) rights |= NCP_RIGHT_ALL_386; return(rights); } 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 (tool_strsame(s, "ALL")) { *rights = NCP_RIGHT_ALL_386; return(0); } if (tool_strsame(s, "N") || tool_strsame(s, "NONE")) { *rights = 0; return(0); } if (tool_strsame(s, "S") || tool_strsame(s, "SUPERVISOR")) { *rights |= NCP_RIGHT_SUPER; return(0); } if (tool_strsame(s, "R") || tool_strsame(s, "READ")) { *rights |= NCP_RIGHT_READ; return(0); } if (tool_strsame(s, "W") || tool_strsame(s, "WRITE")) { *rights |= NCP_RIGHT_WRITE; return(0); } if (tool_strsame(s, "C") || tool_strsame(s, "CREATE")) { *rights |= NCP_RIGHT_CREATE; return(0); } if (tool_strsame(s, "E") || tool_strsame(s, "ERASE")) { *rights |= NCP_RIGHT_DELETE; return(0); } if (tool_strsame(s, "M") || tool_strsame(s, "MODIFY")) { *rights |= NCP_RIGHT_MODIFY; return(0); } if (tool_strsame(s, "F") || tool_strsame(s, "FILESCAN") || tool_strsame(s, "FILE") || tool_strsame(s, "SCAN")) { *rights |= NCP_RIGHT_SEARCH; return(0); } if (tool_strsame(s, "A") || tool_strsame(s, "ACCESS") || tool_strsame(s, "CONTROL") || tool_strsame(s, "ACCESSCONTROL")) { *rights |= NCP_RIGHT_OWNER; return(0); } return(-1); } static int grant_last_rc = 0; static int grant_set_one(char *path, uint16 dhandle, uint32 object_id, uint16 rights) { int rc; /* Novell GRANT uses the old NCP22/27 SetTrustee path. Prefer that * path and keep the NCP87 add-trustee call only as a compatibility * fallback for clients/servers that do not accept the old call. */ rc = c32_ncp22_set_trustee_rights(path, dhandle, object_id, rights); if (rc) { rc = c32_ncp87_add_trustee_rights(path, dhandle, object_id, rights, 0xffff, NULL, NULL, NULL); } grant_last_rc = rc; return(rc); } /* * 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; tool_join_path(pattern, path, "*.*", sizeof(pattern)); if (_dos_findfirst(pattern, _A_SUBDIR, &ff) == 0) { do { if ((ff.attrib & _A_SUBDIR) && !tool_is_dot_dir(ff.name)) { tool_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 || tool_is_help_arg(argv[1])) { if (argc < 2) { fprintf(stdout, "\n"); grant_usage_error(); grant_usage_after_error(); return(1); } grant_usage_help(); return(0); } /* * GRANT rightslist* [FOR path] TO [USER|GROUP] name [options] */ while (i < argc) { if (tool_strsame(argv[i], "FOR") || tool_strsame(argv[i], "TO")) break; if (tool_is_option(argv[i])) break; if (grant_add_right_word(argv[i], &rights)) { fprintf(stdout, "\n"); grant_invalid_right_error(); grant_usage_after_error(); return(1); } have_rights = 1; i++; } if (!have_rights || i >= argc) { fprintf(stdout, "\n"); grant_usage_error(); grant_usage_after_error(); return(1); } if (tool_strsame(argv[i], "FOR")) { i++; if (i >= argc) { fprintf(stdout, "\n"); grant_usage_error(); grant_usage_after_error(); return(1); } path = argv[i++]; } if (i >= argc || !tool_strsame(argv[i], "TO")) { fprintf(stdout, "\n"); grant_usage_error(); grant_usage_after_error(); return(1); } i++; if (i < argc && tool_strsame(argv[i], "USER")) { objtype = GRANT_BINDERY_USER; i++; } else if (i < argc && tool_strsame(argv[i], "GROUP")) { objtype = GRANT_BINDERY_GROUP; i++; } if (i >= argc) { fprintf(stdout, "\n"); grant_usage_error(); grant_usage_after_error(); return(1); } objname = argv[i++]; while (i < argc) { if (!tool_is_option(argv[i])) { fprintf(stdout, "\n"); grant_usage_error(); grant_usage_after_error(); 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 (tool_strsame(argv[i], "/FILES") || tool_strsame(argv[i], "-FILES") || tool_strsame(argv[i], "/F") || tool_strsame(argv[i], "-F")) { i++; continue; } if (tool_strsame(argv[i], "/SUBDIRECTORIES") || tool_strsame(argv[i], "-SUBDIRECTORIES") || tool_strsame(argv[i], "/S") || tool_strsame(argv[i], "-S")) { recurse_subdirs = 1; i++; continue; } fprintf(stdout, "\n"); grant_usage_error(); grant_usage_after_error(); return(1); } rights = grant_expand_supervisor_rights(rights); if (tool_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) { char header[300]; grant_header_path(header, path, sizeof(header)); fprintf(stdout, "\n%s\n", header); if (objtype == GRANT_BINDERY_GROUP) fprintf(stdout, "\aGroup \"%s\" not found.\n", objname); else fprintf(stdout, "\aUser \"%s\" not found.\n", objname); 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) { char header[300]; grant_header_path(header, path, sizeof(header)); fprintf(stdout, "\n%s\n", header); fprintf(stdout, "Invalid path or no match for pattern specified.\n\n"); return(grant_last_rc ? grant_last_rc : 1); } { char header[300]; char base[80]; char bracket[10]; grant_header_path(header, path, sizeof(header)); tool_basename(base, path, sizeof(base)); grant_rights_bracket(rights, bracket); fprintf(stdout, "\n%s\n", header); fprintf(stdout, "%-33.33sRights set to [%s]\n\n", base, bracket); } return(0); }