/* rights.c - Novell RIGHTS-like DOS utility, read-only v4 */ #include "net.h" #include "c32ncp.h" #include #include #include #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 int rights_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 rights_is_help(char *s) { if (!s) return(0); return(rights_same(s, "/?") || rights_same(s, "-?") || rights_same(s, "?")); } 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 int rights_get_current_drive(void) { REGS regs; regs.h.ah = 0x19; int86(0x21, ®s, ®s); return((int)regs.h.al); } static int rights_current_dhandle(uint8 *connid, uint8 *dhandle) { uint8 flags = 0; int drive = rights_get_current_drive(); if (get_drive_info((uint8)drive, connid, dhandle, &flags)) return(-1); if (!*connid || (flags & 0x80)) return(-1); return(0); } static int rights_is_current_path(char *path) { if (!path || !*path) return(1); if (rights_same(path, ".")) return(1); if (rights_same(path, ".\\")) return(1); if (rights_same(path, "./")) return(1); return(0); } static void rights_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 rights_parent_path(char *dst, char *src, int max) { char tmp[260]; char *p; rights_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 (rights_is_current_path(path)) return(1); if (stat(path, &st) == 0) { if (st.st_mode & S_IFDIR) return(1); } return(0); } static int rights_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 = rights_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 rights_make_header_path(char *out, char *path) { char up[260]; char prefix[90]; if (rights_current_prefix(prefix, sizeof(prefix))) prefix[0] = '\0'; if (rights_is_current_path(path)) { strcpy(out, prefix); return; } rights_upcopy(up, path, sizeof(up)); strcpy(out, prefix); strcat(out, up); } 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 (rights_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(rights_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 (rights_is_current_path(path)) { usepath[0] = '\0'; } else if (is_dir) { rights_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]; rights_make_header_path(hdr, path); 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 (rights_is_help(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); }