/* * 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 . */ /* * Purpose: REMOVE utility for removing trustee rights from NetWare directories and files. * Depends on: net.h, ncpapi.h, trustee.h/trustee.c trustee helpers, netcall.c requester helpers, tools.c shared utility routines. */ #include "net.h" #include "ncpapi.h" #include "trustee.h" #include #include #ifndef _A_NORMAL #define _A_NORMAL 0x00 #endif static int remove_last_rc = 0; static void remove_usage(void) { fprintf(stdout, "\n"); fprintf(stdout, "Usage: REMOVE [USER | GROUP] name [FROM path] [option]\n"); fprintf(stdout, "Options: /Subdirs | /Files \n"); } static void remove_usage_after_error(void) { fprintf(stdout, "\007\n"); fprintf(stdout, "Usage: REMOVE [USER | GROUP] name [FROM path] [option]\n"); fprintf(stdout, "Options: /Subdirs | /Files \n"); fprintf(stdout, "\n"); } static void remove_header_path(char *out, char *path, int max) { char *p; tool_header_path(out, path, max); /* Novell REMOVE 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 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; /* Without /FILES, Novell REMOVE reports directory-oriented messages even * if the specified path cannot be located. */ is_dir = forced_is_file ? 0 : 1; rc = ncp87_05_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 = ncp22_2b_delete_trustee_rights(path, dhandle, object_id); if (rc) rc = ncp87_0b_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]; remove_header_path(header, path, sizeof(header)); fprintf(stdout, "%s\n", header); } if (objtype == TRUSTEE_BINDERY_GROUP) fprintf(stdout, "Group \"%s\" no longer a trustee to the specified %s.\n\n", objname, is_dir ? "directory" : "file"); else fprintf(stdout, "User \"%s\" no longer a trustee to the specified %s.\n\n", objname, is_dir ? "directory" : "file"); return(0); } static int remove_subdirs_inner(char *path, uint16 dhandle, uint32 object_id, uint16 objtype, char *objname, int *count, int include_this) { struct find_t ff; char pattern[260]; char child[260]; int rc = 0; if (include_this) { if (remove_one(path, dhandle, object_id, objtype, objname, 0) == 0) (*count)++; else 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 (remove_subdirs_inner(child, dhandle, object_id, objtype, objname, count, 1)) rc = 1; } } while (_dos_findnext(&ff) == 0); } return(rc); } static int remove_subdirs(char *path, uint16 dhandle, uint32 object_id, uint16 objtype, char *objname, int *count) { /* Novell REMOVE /SUBDIRS affects the subdirectories under the specified * start directory, not the start directory itself. */ return(remove_subdirs_inner(path, dhandle, object_id, objtype, objname, count, 0)); } 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 (tool_has_wildcards(path)) { tool_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); } tool_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)) { tool_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 || tool_is_help_arg(argv[1])) { if (argc < 2) { remove_usage_after_error(); return(1); } remove_usage(); return(argc < 2 ? 1 : 0); } if (i < argc && tool_strsame(argv[i], "USER")) { /* Novell treats "REMOVE USER FROM path" as an object lookup for * USER, not as a grammar error. */ if ((i + 1) < argc && tool_strsame(argv[i + 1], "FROM")) { objtype_given = 0; } else { objtype = TRUSTEE_BINDERY_USER; objtype_given = 1; i++; } } else if (i < argc && tool_strsame(argv[i], "GROUP")) { if ((i + 1) < argc && tool_strsame(argv[i + 1], "FROM")) { objtype_given = 0; } else { objtype = TRUSTEE_BINDERY_GROUP; objtype_given = 1; i++; } } if (i >= argc) { remove_usage_after_error(); return(1); } objname = argv[i++]; if (i < argc && tool_strsame(argv[i], "FROM")) { i++; if (i >= argc) { remove_usage_after_error(); return(1); } path = argv[i++]; } while (i < argc) { if (!tool_is_option(argv[i])) { remove_usage_after_error(); 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_after_error(); return(1); } if (use_files && use_subdirs) { fprintf(stdout, "Remove cannot do both directories and files in a single pass.\n"); return(1); } if (tool_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, "\007Group \"%s\" not found.\n", objname); else if (objtype_given) fprintf(stdout, "\007User \"%s\" not found.\n", objname); else fprintf(stdout, "\007User or group \"%s\" not found.\n", objname); return(1); } tool_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\n", objprint, count); else if (use_files) fprintf(stdout, "Trustee \"%s\" removed from %d files.\n\n", objprint, count); return(rc ? (remove_last_rc ? remove_last_rc : 1) : 0); }