Finish the c32ncp.c/c32ncp.h to ncpapi.c/ncpapi.h rename. Update the build files, include directives, dependency tracking, header guard, README references and file-level comments to use the new ncpapi naming. This matches the current split where ncpapi contains the ncpXX_YY_* protocol API wrappers and ncpcall contains the lower-level requester/transport helpers. No behavior change.
343 lines
9.3 KiB
C
343 lines
9.3 KiB
C
/*
|
|
* mars-nwe-dosutils - NetWare/DOS utility tools.
|
|
*
|
|
* Copyright (C) 2026 Mario Fetka
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/*
|
|
* Purpose: RIGHTS utility for displaying effective NetWare rights.
|
|
* Depends on: net.h, ncpapi.h, netcall.c requester helpers, ncpapi.c namespace/NCP helpers, tools.c shared utility routines.
|
|
*/
|
|
|
|
#include "net.h"
|
|
#include "ncpapi.h"
|
|
#include <dos.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
|
|
#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 void rights_ncp_path(char *dst, char *src, int max);
|
|
|
|
|
|
static void rights_usage(void)
|
|
{
|
|
fprintf(stdout, "\nUsage: RIGHTS [path]\n \n");
|
|
fprintf(stdout, " Rights = All | Supervisor | Read | Write | Create | Erase\n");
|
|
fprintf(stdout, " | Modify | File scan | Access Control\n");
|
|
}
|
|
|
|
static void rights_parent_path(char *dst, char *src, int max)
|
|
{
|
|
char tmp[260];
|
|
char *p;
|
|
|
|
tool_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 void rights_ncp_path(char *dst, char *src, int max)
|
|
{
|
|
char up[260];
|
|
char *p;
|
|
|
|
if (tool_is_current_path(src)) {
|
|
dst[0] = '\0';
|
|
return;
|
|
}
|
|
|
|
tool_upcopy(up, src, sizeof(up));
|
|
p = up;
|
|
if (p[0] && p[1] == ':') {
|
|
p += 2;
|
|
if (*p == '\\') p++;
|
|
}
|
|
while (*p == '\\') p++;
|
|
|
|
strmaxcpy(dst, p, max - 1);
|
|
}
|
|
|
|
|
|
static int rights_get_ncp_info(char *path, NCP_NDIR_INFO *info)
|
|
{
|
|
uint8 connid = 0;
|
|
uint8 dhandle = 0;
|
|
char npath[260];
|
|
|
|
if (!info)
|
|
return(1);
|
|
|
|
memset(info, 0, sizeof(*info));
|
|
|
|
if (tool_current_dhandle(&connid, &dhandle))
|
|
return(1);
|
|
|
|
rights_ncp_path(npath, path, sizeof(npath));
|
|
return(ncp87_06_obtain_ndir_info(npath, (uint16)dhandle,
|
|
info, NULL, NULL, NULL));
|
|
}
|
|
|
|
static int rights_path_exists(char *path, int *is_dir)
|
|
{
|
|
NCP_NDIR_INFO info;
|
|
|
|
if (rights_get_ncp_info(path, &info))
|
|
return(0);
|
|
|
|
if (is_dir)
|
|
*is_dir = (info.attributes & 0x10) ? 1 : 0;
|
|
|
|
return(1);
|
|
}
|
|
|
|
|
|
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 (tool_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.
|
|
*/
|
|
rights_ncp_path(usepath, path, sizeof(usepath));
|
|
if (!ncp87_1d_get_effective_rights(usepath,
|
|
(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 (tool_is_current_path(path)) {
|
|
usepath[0] = '\0';
|
|
} else if (is_dir) {
|
|
rights_ncp_path(usepath, path, sizeof(usepath));
|
|
} else {
|
|
char npath[260];
|
|
rights_ncp_path(npath, path, sizeof(npath));
|
|
rights_parent_path(usepath, npath, sizeof(usepath));
|
|
}
|
|
|
|
newhandle = alloc_temp_dir_handle(dhandle, usepath, 0, &eff);
|
|
if (newhandle < 0) {
|
|
if (usepath[0]) {
|
|
int subdir = 1;
|
|
int r = ncp16_02_get_directory_entry(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];
|
|
|
|
tool_header_path(hdr, path, sizeof(hdr));
|
|
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) {
|
|
fprintf(stdout, "Too many parameters on command line.\n");
|
|
rights_usage();
|
|
return(1);
|
|
}
|
|
|
|
if (argc == 2) {
|
|
if (tool_is_help_arg(argv[1])) {
|
|
rights_usage();
|
|
return(0);
|
|
}
|
|
path = argv[1];
|
|
}
|
|
|
|
if (!rights_path_exists(path, &is_dir)) {
|
|
fprintf(stdout, "Specified path not locatable.\n");
|
|
rights_usage();
|
|
return(1);
|
|
}
|
|
|
|
if (rights_effective_mask(path, is_dir, &mask)) {
|
|
fprintf(stdout, "Specified path not locatable.\n");
|
|
rights_usage();
|
|
return(1);
|
|
}
|
|
|
|
rights_display(path, is_dir, mask);
|
|
return(0);
|
|
}
|