/* * mars-nwe-dosutils - NetWare/DOS utility tools. * * Copyright (C) 2026 Mario Fetka * Copyright (C) 1993,1996 Martin Stover, Marburg, Germany * * 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: Semantically named NCP API helper implementation used by the NetWare DOS tools. * Depends on: net.h, ncpapi.h, ncpcall.c requester/transport helpers, ncp.h requester assembly declarations, and netcall.c for shared requester state. This file contains the protocol API layer above the low-level requester transport helpers. */ #include "net.h" #include "ncpapi.h" /* * Legacy bindery/login NCP API wrappers. * * These ncp16/ncp17/ncp14 wrappers used to live in ncpcall.c. They are kept * together with the other ncpXX_YY_* APIs here so all protocol wrappers live * in one NCP API layer. */ /* ---------------- 0x16 ----------------------------------- */ /* * ncp16_02_get_directory_entry * * Purpose: * Looks up a directory entry relative to a NetWare directory handle and * returns the canonical subdirectory name, creation timestamp, owner object * ID, subdirectory number and maximum rights mask. * * NCP: * Function 0x16, subfunction 0x02. MARS-NWE admin documents this old * filesystem call as Scan Directory Information / Get Directory Entry * (F216/02). * * Requester path: * Net_Call(0xE200), with a 16-bit request and reply length prefix. * * Returns: * Maximum rights mask on success, or -1 when the requester/NCP call fails. */ int ncp16_02_get_directory_entry(int dirhandle, uint8 *path, int *sub_dir, uint8 *resultpath, uint32 *creattime, uint32 *owner_id) { struct { uint16 len; uint8 func; uint8 dirhandle; uint8 sub_dir[2]; uint8 pathlen; uint8 path[256]; } req; struct { uint16 len; uint8 sub_dir_name[16]; uint8 create_date_time[4]; uint8 owner_id[4]; /* HI LOW */ uint8 max_right_mask; uint8 reserved; /* Reserved by Novell */ uint8 sub_dir_nmbr[2]; /* HI LOW */ } repl = { sizeof(repl) - sizeof(uint16) }; req.func = 0x02; U16_TO_BE16((sub_dir) ? *sub_dir : 1, req.sub_dir); req.dirhandle = (uint8) dirhandle; req.pathlen = (uint8) ((path) ? strlen(path) : 0); req.len = 5 + req.pathlen; strmaxcpy(req.path, path, req.pathlen); neterrno = Net_Call(0xE200, &req, &repl); if (neterrno) return(-1); if (resultpath) strmaxcpy(resultpath, repl.sub_dir_name, 16); if (sub_dir) *sub_dir = GET_BE16(repl.sub_dir_nmbr); if (creattime) *creattime = GET_BE32(repl.create_date_time); if (owner_id) *owner_id = GET_BE32(repl.owner_id); return((int) repl.max_right_mask); } /* ---------------- 0x17 ----------------------------------- */ /* * ncp17_02_set_debug_level * * Purpose: * Sets a MARS-NWE debug level for one server module and returns the previous * debug value. This is a MARS-NWE helper, not a normal Novell client command. * * NCP: * Function group 0x17, subfunction 0x02. * * Requester path: * Net_Call(0xE300), with a 16-bit request and reply length prefix. * * Returns: * Previous debug level on success, or -1 when the requester/NCP call fails. */ int ncp17_02_set_debug_level(int module, int debuglevel) { struct { uint16 len; uint8 func; uint8 module; uint8 debug; } req = { sizeof(req) - sizeof(uint16) }; struct { uint16 len; uint8 olddebug; } repl = { sizeof(repl) - sizeof(uint16) }; req.func = 0x2; req.module = (uint8) module; req.debug = (uint8) debuglevel; neterrno = Net_Call(0xE300, &req, &repl); if (neterrno) return(-1); return((int) repl.olddebug); } /* * ncp17_14_login_object_unencrypted * * Purpose: * Logs in a bindery object using the legacy unencrypted password call. * * NCP: * Function group 0x17, subfunction 0x14. This is the older unencrypted login * path; encrypted login normally uses the key returned by subfunction 0x17 * and the keyed-login call below. * * Requester path: * Net_Call(0xE300), with object type, counted object name and counted * password in the request body. * * Returns: * 0 on success, or -1 when the requester/NCP call fails. */ int ncp17_14_login_object_unencrypted(uint8 *objname, uint16 objtyp, uint8 *password) { struct { uint16 len; uint8 func; uint8 typ[2]; uint8 namlen; uint8 buff[48+1+128]; } req; struct { uint16 len; } repl= { 0 }; uint8 *p=req.buff; req.func = 0x14; U16_TO_BE16(objtyp, req.typ); req.namlen = min(47, strlen(objname)); memcpy(p, objname, req.namlen); p += req.namlen; *p = (uint8) min(128, strlen(password)); req.len = 4 + req.namlen + 1 + *p; memcpy(p+1, password, (int) *p); neterrno = Net_Call(0xE300, &req, &repl); if (neterrno) return(-1); return(0); } /* * ncp17_17_get_encryption_key * * Purpose: * Retrieves the 8-byte login encryption key used by the legacy bindery * encrypted login and password-change helpers. * * NCP: * Function group 0x17, subfunction 0x17. * * Requester path: * Net_Call(0xE300). The reply contains the raw 8-byte key. * * Returns: * 0 on success, or -1 when the requester/NCP call fails. */ int ncp17_17_get_encryption_key(uint8 *key) { struct { uint16 len; uint8 func; } req; struct { uint16 len; uint8 key[8]; } repl; req.len = 1; req.func = 0x17; repl.len = 8; neterrno = Net_Call(0xE300, &req, &repl); if (neterrno) return(-1); else { memcpy(key, repl.key, 8); return(0); } } /* * ncp17_18_keyed_object_login * * Purpose: * Performs keyed/encrypted bindery object login using the 8-byte challenge * returned by ncp17_17_get_encryption_key(). * * NCP: * Function group 0x17, subfunction 0x18. * * Requester path: * Net_Call(0xE300), with key, object type and counted object name. * * Returns: * 0 on success, or -1 when the requester/NCP call fails. */ int ncp17_18_keyed_object_login(uint8 *cryptkey, uint8 *objname, uint16 objtyp) { struct { uint16 len; uint8 func; uint8 key[8]; uint8 typ[2]; uint8 namlen; uint8 name[48]; } req; struct { uint16 len; } repl={ 0 }; req.len = sizeof(req) - sizeof(uint16); req.func = 0x18; U16_TO_BE16(objtyp, req.typ); req.namlen = min(sizeof(req.name), strlen(objname)); memcpy(req.key, cryptkey, 8); memcpy(req.name, objname, (int) req.namlen); neterrno = Net_Call(0xE300, &req, &repl); if (neterrno) return(-1); return(0); } /* * ncp17_35_get_bindery_object_id * * Purpose: * Resolves a bindery object name and type to its 32-bit object ID. The * canonical object name returned by the server is copied back to objname. * * NCP: * Function group 0x17, subfunction 0x35, Get Bindery Object ID * (MARS-NWE admin: F217/35; Novell SDK/WebSDK: Get Bindery Object ID). * * Requester path: * Net_Call(0xE300), with big-endian object type and counted object name. * * Returns: * Object ID on success, or 0 when the requester/NCP call fails. */ uint32 ncp17_35_get_bindery_object_id(uint8 *objname, uint16 objtyp) { struct { uint16 len; uint8 func; uint8 typ[2]; uint8 namlen; uint8 name[48]; } req; struct { uint16 len; uint8 object_id[4]; uint8 object_type[2]; uint8 object_name[48]; } repl; req.len = sizeof(req) - sizeof(uint16); repl.len = sizeof(repl) - sizeof(uint16); req.func = 0x35; U16_TO_BE16(objtyp, req.typ); req.namlen = min(sizeof(req.name), strlen(objname)); memcpy(req.name, objname, (int) req.namlen); neterrno = Net_Call(0xE300, &req, &repl); if (neterrno) return(0L); strmaxcpy(objname, repl.object_name, 47); return(GET_BE32(repl.object_id)); } /* * ncp17_36_get_bindery_object_name * * Purpose: * Resolves a 32-bit bindery object ID to its object name and type. * * NCP: * Function group 0x17, subfunction 0x36, Get Bindery Object Name * (MARS-NWE admin: F217/36; Novell SDK/WebSDK: Get Bindery Object Name). * * Requester path: * Net_Call(0xE300), with the object ID in big-endian order. * * Returns: * 0 on success, or -1 when the requester/NCP call fails. */ int ncp17_36_get_bindery_object_name(uint32 obj_id, uint8 *objname, uint16 *objtyp) { struct { uint16 len; uint8 func; uint8 id[4]; } req; struct { uint16 len; uint8 object_id[4]; uint8 object_type[2]; uint8 object_name[48]; } repl; req.len = sizeof(req) - sizeof(uint16); repl.len = sizeof(repl) - sizeof(uint16); req.func = 0x36; U32_TO_BE32(obj_id, req.id); neterrno = Net_Call(0xE300, &req, &repl); if (neterrno) return(-1); if (objname) strmaxcpy(objname, repl.object_name, 47); if (objtyp) *objtyp = GET_BE16(repl.object_type); return(0); } /* * ncp17_40_change_password_unencrypted * * Purpose: * Changes a bindery object's password using the legacy unencrypted password * call. * * NCP: * Function group 0x17, subfunction 0x40, Change Bindery Object Password * (MARS-NWE admin: F217/40). * * Requester path: * Net_Call(0xE300), with object type, counted object name, counted old * password and counted new password. * * Returns: * 0 on success, or -1 when the requester/NCP call fails. */ int ncp17_40_change_password_unencrypted(uint8 *objname, uint16 objtyp, uint8 *password, uint8 *newpassword) { struct { uint16 len; uint8 func; uint8 typ[2]; uint8 namlen; uint8 buff[48+1+128+1+128]; } req; struct { uint16 len; } repl = { 0 }; uint8 *p=req.buff; req.func = 0x40; U16_TO_BE16(objtyp, req.typ); req.namlen = min(47, strlen(objname)); memcpy(p, objname, req.namlen); p += req.namlen; *p = (uint8) min(128, strlen(password)); req.len = 4 + req.namlen + 1 + *p; memcpy(p+1, password, (int) *p); p += (1 + *p); *p = (uint8) min(128, strlen(newpassword)); req.len += (1 + *p); memcpy(p+1, newpassword, (int) *p); neterrno = Net_Call(0xE300, &req, &repl); if (neterrno) return(-1); return(0); } /* * ncp14_46_get_bindery_access_level * * Purpose: * Reads the current bindery access level and the logged-in object's object ID. * * NCP: * Bindery subfunction 0x46, Get Bindery Access Level. The historic local * wrapper was named ncp_14_46; keep the ncp14_ prefix to preserve that * protocol reference even though the call is sent through Net_Call(0xE300). * * Requester path: * Net_Call(0xE300). The reply contains one access byte followed by the * current object's 32-bit object ID in big-endian order. * * Returns: * Access level on success, or -1 when the requester/NCP call fails. */ int ncp14_46_get_bindery_access_level(uint32 *obj_id) { struct { uint16 len; uint8 func; } req; struct { uint16 len; uint8 access; uint8 id[4]; } repl; req.len = 1; req.func = 0x46; repl.len = 5; neterrno = Net_Call(0xE300, &req, &repl); if (neterrno) return(-1); else { if (obj_id) *obj_id = GET_BE32(repl.id); return(repl.access); } } /* * ncp17_4b_keyed_change_password * * Purpose: * Changes a bindery object's password using the keyed/encrypted password * change path. * * NCP: * Function group 0x17, subfunction 0x4b, Change Encrypted Bindery Object * Password (MARS-NWE admin: F217/4B). * * Requester path: * Net_Call(0xE300), with the login encryption key, object type, counted * object name, password length selector and encrypted new password bytes. * * Returns: * 0 on success, or -1 when the requester/NCP call fails. */ int ncp17_4b_keyed_change_password(uint8 *cryptkey, uint8 *objname, uint16 objtyp, int passwx, uint8 *newpassword) { struct { uint16 len; uint8 func; uint8 key[8]; uint8 typ[2]; uint8 namlen; uint8 buff[48+1+16]; } req; struct { uint16 len; } repl = { 0 }; uint8 *p = req.buff; req.func = 0x4b; memcpy(req.key, cryptkey, 8); U16_TO_BE16(objtyp, req.typ); req.namlen = (uint8) min(48, strlen(objname)); req.len = 12 + req.namlen + 1 + 16; memcpy(p, objname, (int) req.namlen); p += req.namlen; *p++ = (uint8) passwx; memcpy(p, newpassword, 16); neterrno = Net_Call(0xE300, &req, &repl); if (neterrno) return(-1); return(0); } /* * ncp17_37_scan_bindery_object * * Purpose: * Iterates over bindery objects matching an object type and name pattern. * Pass last_id as -1 for the first call and then feed back the object ID * returned in target to continue scanning. * * NCP: * Function group 0x17, subfunction 0x37, Scan Bindery Object * (MARS-NWE admin: F217/37; Novell SDK/WebSDK: Scan Bindery Object). * * Requester path: * Net_Call(0xE300), with last object ID, search object type and counted * pattern. A NULL pattern is sent as '*'. * * Returns: * 0 on success, or -1 when the requester/NCP call fails. */ int ncp17_37_scan_bindery_object(uint32 last_id, uint16 objtyp, uint8 *pattern, BINDERY_OBJECT *target) { struct { uint16 len; uint8 func; uint8 last_id[4]; uint8 typ[2]; uint8 patlen; uint8 pattern[48]; } req; struct { uint16 len; uint8 object_id[4]; uint8 object_type[2]; uint8 object_name[48]; uint8 object_flags; uint8 object_security; uint8 object_has_prop; } repl; int patlen = (pattern) ? min(48, strlen(pattern)) : 1; memset(&req, 0, sizeof(req)); memset(&repl, 0, sizeof(repl)); req.func = 0x37; U32_TO_BE32(last_id, req.last_id); U16_TO_BE16(objtyp, req.typ); req.patlen = (uint8)patlen; if (pattern) memcpy(req.pattern, pattern, patlen); else req.pattern[0] = '*'; req.len = 8 + patlen; repl.len = sizeof(repl) - sizeof(uint16); neterrno = Net_Call(0xE300, &req, &repl); if (neterrno) return(-1); if (target) { target->object_id = GET_BE32(repl.object_id); target->object_type = GET_BE16(repl.object_type); memcpy(target->object_name, repl.object_name, 48); target->object_name[48] = '\0'; deb(target->object_name); target->object_flags = repl.object_flags; target->object_security = repl.object_security; target->object_has_prop = repl.object_has_prop; } return(0); } /* * ncp17_3d_read_property_value * * Purpose: * Reads one 128-byte segment of a bindery property value and returns the * server's continuation and property flags. * * NCP: * Function group 0x17, subfunction 0x3d, Read Property Value * (MARS-NWE admin: F217/3D; Novell SDK/WebSDK: Read Property Value). * * Requester path: * Net_Call(0xE300), with object type, counted object name, segment number * and counted property name. * * Returns: * 0 on success, or -1 when the requester/NCP call fails. */ int ncp17_3d_read_property_value(uint16 objtyp, uint8 *objname, int segment, uint8 *propname, NW_PROPERTY *target) { struct { uint16 len; uint8 func; uint8 typ[2]; uint8 buff[1+48+1+1+16]; } req; struct { uint16 len; uint8 value[128]; uint8 more_flag; uint8 property_flag; } repl; uint8 *p = req.buff; int objlen = min(48, strlen(objname)); int proplen = min(16, strlen(propname)); memset(&req, 0, sizeof(req)); memset(&repl, 0, sizeof(repl)); req.func = 0x3d; U16_TO_BE16(objtyp, req.typ); *p++ = (uint8)objlen; memcpy(p, objname, objlen); p += objlen; *p++ = (uint8)segment; *p++ = (uint8)proplen; memcpy(p, propname, proplen); req.len = 6 + objlen + proplen; repl.len = sizeof(repl) - sizeof(uint16); neterrno = Net_Call(0xE300, &req, &repl); if (neterrno) return(-1); if (target) { memcpy(target->value, repl.value, 128); target->more_flag = repl.more_flag; target->property_flag = repl.property_flag; } return(0); } /* * ncp_copy_open_reply_to_handle6 * * Purpose: * Extracts the six-byte server file handle from an NCP87/01 Open/Create * reply fragment for later NCP74 Copy or NCP66 Close calls. * * Notes: * The exact handle layout is still part of the NCOPY investigation. This * helper keeps the extraction in one place so the code can be corrected * without touching the callers. */ static void ncp_copy_open_reply_to_handle6(NCP_FILE_HANDLE6 *dst, const uint8 *src) { /* * NCP 74 File Server Copy and NCP 66 Close File both take a six-byte * server file handle. Client32's NCP87 Open/Create reply supplies that * six-byte handle at the start of the first reply fragment; the following * bytes are OpenCreateAction and Reserved. * * The previous patch only copied four bytes and zero-filled h[4..5]. That * is enough to create a visible zero-length target file, but it is not the * handle that NCP74/NCP66 own. The bad close leaves Client32/MARS seeing * the target as still open, so the fallback DOS/requester open reports * "File in use during a file open" for every file. */ memset(dst->h, 0, sizeof(dst->h)); memcpy(dst->h, src, 6); } /* * ncp87_01_open_create_entry * * Purpose: * Opens or creates a namespace file/directory entry and returns the server * file handle required by copy/close style NCPs. * * NCP: * Function 0x57 / subfunction 0x01, Open/Create File or Subdirectory. * * Requester path: * Client32 raw fragment request. * * Notes: * This wrapper is currently experimental for NCOPY. Earlier tests showed * that the old INT 21h F257 path reaches MARS-NWE but does not reliably * return the open file handle to the DOS caller. */ int ncp87_01_open_create_entry(const char *path_name, uint16 dir_handle, uint8 open_create_mode, uint32 create_attrs, uint16 desired_access, uint16 search_attrs, NCP_FILE_HANDLE6 *handle_out, uint32 *file_size_out, uint8 *open_create_action_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[0x180]; uint8 rep1[0x40]; uint8 rawout[32]; uint16 raw_ret_ax, raw_ret_dx; uint16 actual_lo; UI path_len; int rc; if (handle_out) memset(handle_out, 0, sizeof(*handle_out)); if (file_size_out) *file_size_out = 0; if (open_create_action_out) *open_create_action_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 (!path_name || !handle_out) return(1); rc = ncp_get_requester_handle(&handle_lo, &handle_hi); if (rc) return(10 + rc); /* * NCP 87 subfunction 1: Open/Create File or Subdirectory. * * Request payload after the NCP87 subfunction byte: * byte NameSpace (0 = DOS) * byte OpenCreateMode (OPEN/TRUNCATE/CREATE bits) * word SearchAttributes (Lo-Hi) * dword ReturnInfoMask (Lo-Hi) * dword CreateAttributes (Lo-Hi) * word DesiredAccessRights (Lo-Hi) * NWHandlePathStruct * * The Client32 raw requester path sends the subfunction * header as fragment 0 and the NWHandlePathStruct as fragment 1. */ memset(hdr, 0, sizeof(hdr)); hdr[0] = 1; /* NCP87 subfunction 1 */ hdr[1] = 0; /* DOS namespace */ hdr[2] = open_create_mode; tool_put_word_lh(hdr + 3, search_attrs); tool_put_dword_lh(hdr + 5, 0x00000FFFUL); /* RIM_ALL, keeps size handy */ tool_put_dword_lh(hdr + 9, create_attrs); tool_put_word_lh(hdr + 13, desired_access); path_len = ncp_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)); ncp_raw_request(handle_lo, handle_hi, hdr, 15, path, path_len, rep0, sizeof(rep0), rep1, sizeof(rep1), rawout); raw_ret_ax = tool_get_word_lh(rawout + 14); raw_ret_dx = tool_get_word_lh(rawout + 16); actual_lo = tool_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); ncp_copy_open_reply_to_handle6(handle_out, rep0 + 0); if (open_create_action_out) *open_create_action_out = rep0[6]; /* NetWareInfoStruct follows FileHandle[6]/OpenCreateAction/Reserved. */ if (file_size_out) *file_size_out = tool_get_dword_lh(rep0 + 8 + 10); return(0); } /* * ncp74_file_server_copy * * Purpose: * Copies file data server-side between two already-open NetWare file * handles. * * NCP: * Function 0x4a, File Server Copy. * * Requester path: * Direct F24A Net_Call wrapper. * * Notes: * Offsets and byte count are encoded high-low. The source and destination * handles must be the six-byte server handles accepted by the file server. */ int ncp74_file_server_copy(const NCP_FILE_HANDLE6 *src, const NCP_FILE_HANDLE6 *dst, uint32 src_offset, uint32 dst_offset, uint32 count, uint32 *copied_out) { struct { uint16 len; uint8 reserved; uint8 src_handle[6]; uint8 dst_handle[6]; uint8 src_offset[4]; uint8 dst_offset[4]; uint8 count[4]; } req; struct { uint16 len; uint8 copied[4]; } repl; if (copied_out) *copied_out = 0; if (!src || !dst) return(1); memset(&req, 0, sizeof(req)); memset(&repl, 0, sizeof(repl)); memcpy(req.src_handle, src->h, 6); memcpy(req.dst_handle, dst->h, 6); tool_put_dword_hl(req.src_offset, src_offset); tool_put_dword_hl(req.dst_offset, dst_offset); tool_put_dword_hl(req.count, count); req.len = 1 + 6 + 6 + 4 + 4 + 4; repl.len = 4; neterrno = Net_Call(0xF24A, &req, &repl); if (neterrno) return(-neterrno); if (copied_out) *copied_out = tool_get_dword_hl(repl.copied); return(0); } /* * ncp66_close_file * * Purpose: * Closes a NetWare server file handle returned by an open/create wrapper. * * NCP: * Function 0x42 / decimal 66, Close File. * * Requester path: * Direct F242 Net_Call wrapper. */ int ncp66_close_file(const NCP_FILE_HANDLE6 *handle) { struct { uint8 len; uint8 reserved; uint8 handle[6]; } req; struct { uint8 len; } repl; if (!handle) return(1); memset(&req, 0, sizeof(req)); memset(&repl, 0, sizeof(repl)); memcpy(req.handle, handle->h, 6); req.len = 1 + 6; repl.len = 0; neterrno = Net_Call(0xF242, &req, &repl); if (neterrno) return(-neterrno); return(0); } /* * ncp87_06_obtain_rim_attributes * * Purpose: * Reads only the DOS attribute field for a directory entry using the * NCP87 return-information-mask mechanism. * * NCP: * Function 0x57 / subfunction 0x06, Obtain File or Subdirectory * Information, RIM_ATTRIBUTES. * * Requester path: * Client32 raw fragment request. */ int ncp87_06_obtain_rim_attributes(const char *name, uint16 dir_handle, uint32 *attr_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[0x60]; uint8 rep1[0x110]; uint8 rawout[32]; uint16 raw_ret_ax, raw_ret_dx; uint16 actual_lo; int path_len; int rc; if (!name || !attr_out) return(1); *attr_out = 0; if (actual_out) *actual_out = 0; if (handle_lo_out) *handle_lo_out = 0; if (handle_hi_out) *handle_hi_out = 0; rc = ncp_get_requester_handle(&handle_lo, &handle_hi); if (rc) return(10 + rc); memset(hdr, 0, sizeof(hdr)); hdr[0] = 6; /* NCP87 subfunction 6 */ hdr[1] = 0; /* source namespace DOS */ hdr[2] = 0; /* target namespace DOS */ tool_put_word_lh(hdr + 3, 0x0006); /* SA_ALL */ tool_put_dword_lh(hdr + 5, 0x00000004UL); /* RIM_ATTRIBUTES */ path_len = ncp_build_handle_path(path, (uint8)dir_handle, 0, 0, 1, name, NULL, NULL); memset(rep0, 0, sizeof(rep0)); memset(rep1, 0, sizeof(rep1)); memset(rawout, 0, sizeof(rawout)); ncp_raw_request(handle_lo, handle_hi, hdr, 9, path, (UI)path_len, rep0, 0x4d, rep1, 0x100, rawout); raw_ret_ax = tool_get_word_lh(rawout + 14); raw_ret_dx = tool_get_word_lh(rawout + 16); actual_lo = tool_get_word_lh(rawout + 18); if (raw_ret_ax != 0 || raw_ret_dx != 0) return(20); /* * Verified reply layout for RIM_ATTRIBUTES: * REP0+4 little-endian dword = DOS attributes * Example LOGIN.EXE: 20h archive. */ *attr_out = tool_get_dword_lh(rep0 + 4); 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; return(0); } /* * ncp87_06_obtain_ndir_info * * Purpose: * Reads the DOS namespace information block used by NDIR for Novell-style * metadata output. * * NCP: * Function 0x57 / subfunction 0x06, Obtain File or Subdirectory * Information, RIM_ALL. * * Requester path: * Client32 raw fragment request. */ int ncp87_06_obtain_ndir_info(const char *path_name, uint16 dir_handle, NCP_NDIR_INFO *info_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[0x180]; uint8 rep1[0x40]; uint8 rawout[32]; uint16 raw_ret_ax, raw_ret_dx; uint16 actual_lo; UI path_len; int rc; int namelen; if (!info_out) return(1); memset(info_out, 0, sizeof(*info_out)); if (actual_out) *actual_out = 0; if (handle_lo_out) *handle_lo_out = 0; if (handle_hi_out) *handle_hi_out = 0; rc = ncp_get_requester_handle(&handle_lo, &handle_hi); if (rc) return(10 + rc); /* * NCP87 subfunction 6: Obtain File or Subdirectory Information. * * This asks for the classic DOS info block (RIM_ALL). ncpfs' old * nw_info_struct layout is: * +00 space allocated * +04 attributes * +20 creation time/date/id * +28 modify time/date/id * +36 last access date * +38 archive time/date/id * +46 inherited rights mask * +48 directory numbers * +76 name length/name */ memset(hdr, 0, sizeof(hdr)); hdr[0] = 6; /* NCP87 subfunction 6 */ hdr[1] = 0; /* source namespace DOS */ hdr[2] = 0; /* target namespace DOS */ tool_put_word_lh(hdr + 3, 0x0006); /* SA_ALL */ tool_put_dword_lh(hdr + 5, 0x00000FFFUL); /* RIM_ALL */ path_len = ncp_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)); ncp_raw_request(handle_lo, handle_hi, hdr, 9, path, path_len, rep0, sizeof(rep0), rep1, sizeof(rep1), rawout); raw_ret_ax = tool_get_word_lh(rawout + 14); raw_ret_dx = tool_get_word_lh(rawout + 16); actual_lo = tool_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); info_out->space_allocated = tool_get_dword_lh(rep0 + 0); info_out->attributes = tool_get_dword_lh(rep0 + 4); info_out->flags = tool_get_word_lh(rep0 + 8); info_out->data_size = tool_get_dword_lh(rep0 + 10); info_out->total_size = tool_get_dword_lh(rep0 + 14); info_out->number_of_streams = tool_get_word_lh(rep0 + 18); info_out->creation_time = tool_get_word_lh(rep0 + 20); info_out->creation_date = tool_get_word_lh(rep0 + 22); info_out->creator_id = tool_get_dword_hl(rep0 + 24); info_out->modify_time = tool_get_word_lh(rep0 + 28); info_out->modify_date = tool_get_word_lh(rep0 + 30); info_out->modifier_id = tool_get_dword_hl(rep0 + 32); info_out->last_access_date = tool_get_word_lh(rep0 + 36); info_out->archive_time = tool_get_word_lh(rep0 + 38); info_out->archive_date = tool_get_word_lh(rep0 + 40); info_out->archiver_id = tool_get_dword_hl(rep0 + 42); info_out->inherited_rights = tool_get_word_lh(rep0 + 46); info_out->dir_ent_num = tool_get_dword_lh(rep0 + 48); info_out->dos_dir_num = tool_get_dword_lh(rep0 + 52); info_out->vol_number = tool_get_dword_lh(rep0 + 56); info_out->ea_data_size = tool_get_dword_lh(rep0 + 60); info_out->ea_key_count = tool_get_dword_lh(rep0 + 64); info_out->ea_key_size = tool_get_dword_lh(rep0 + 68); info_out->ns_creator = tool_get_dword_lh(rep0 + 72); namelen = rep0[76]; if (namelen > 255) namelen = 255; info_out->name_len = (uint8)namelen; memcpy(info_out->name, rep0 + 77, namelen); info_out->name[namelen] = '\0'; return(0); } /* * ncp87_07_modify_dos_info * * Purpose: * Writes selected DOS namespace metadata fields for a file or directory. * * NCP: * Function 0x57 / subfunction 0x07, Modify File or Subdirectory DOS * Information. * * Requester path: * Client32 raw fragment request. */ int ncp87_07_modify_dos_info(const char *name, uint16 dir_handle, uint32 change_mask, NCP_DOS_MODIFY_INFO *info, uint16 *actual_out, uint16 *handle_lo_out, uint16 *handle_hi_out) { uint16 handle_lo, handle_hi; uint8 modbuf[80]; uint8 path[0x140]; uint8 rep0[0x20]; uint8 rep1[0x20]; uint8 rawout[32]; uint8 *p; UI mod_len; UI path_len; uint16 raw_ret_ax, raw_ret_dx; uint16 actual_lo; int rc; if (!name || !info) return(1); if (actual_out) *actual_out = 0; if (handle_lo_out) *handle_lo_out = 0; if (handle_hi_out) *handle_hi_out = 0; rc = ncp_get_requester_handle(&handle_lo, &handle_hi); if (rc) return(10 + rc); /* * NCP 87 subfunction 7: Modify DOS information. * * DOS info payload layout verified by FLAG and MARS' NCP22/25 handler: * dword attributes * word creation time * word creation date * dword creator id (HI-LOW) * word modify time * word modify date * dword modifier id (HI-LOW) * word last access date * word archive time * word archive date * dword archiver id (HI-LOW) * word inherited rights mask * dword maximum space */ memset(modbuf, 0, sizeof(modbuf)); p = modbuf; *p++ = 7; /* subfunction: modify DOS info */ *p++ = 0; /* namespace DOS */ *p++ = 0; /* reserved */ tool_put_word_lh(p, 0x0006); p += 2; /* SA_ALL */ tool_put_dword_lh(p, change_mask); p += 4; tool_put_dword_lh(p, info->attributes); p += 4; tool_put_word_lh(p, info->creation_time); p += 2; tool_put_word_lh(p, info->creation_date); p += 2; tool_put_dword_hl(p, info->creator_id); p += 4; tool_put_word_lh(p, info->modify_time); p += 2; tool_put_word_lh(p, info->modify_date); p += 2; tool_put_dword_hl(p, info->modifier_id); p += 4; tool_put_word_lh(p, info->last_access_date); p += 2; tool_put_word_lh(p, info->archive_time); p += 2; tool_put_word_lh(p, info->archive_date); p += 2; tool_put_dword_hl(p, info->archiver_id); p += 4; tool_put_word_lh(p, info->inherited_rights); p += 2; tool_put_dword_lh(p, info->maximum_space); p += 4; mod_len = (UI)(p - modbuf); path_len = ncp_build_handle_path(path, (uint8)dir_handle, 0, 0, 1, name, NULL, NULL); memset(rep0, 0, sizeof(rep0)); memset(rep1, 0, sizeof(rep1)); memset(rawout, 0, sizeof(rawout)); ncp_raw_request(handle_lo, handle_hi, modbuf, mod_len, path, path_len, rep0, sizeof(rep0), rep1, sizeof(rep1), rawout); raw_ret_ax = tool_get_word_lh(rawout + 14); raw_ret_dx = tool_get_word_lh(rawout + 16); actual_lo = tool_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); } /* * ncp87_07_modify_dos_attributes * * Purpose: * Convenience wrapper around ncp87_07_modify_dos_info() for changing only * the DOS attributes field. * * NCP: * Function 0x57 / subfunction 0x07 with DM_ATTRIBUTES. */ int ncp87_07_modify_dos_attributes(char *name, uint16 dir_handle, uint32 attrs, uint16 *actual_out, uint16 *handle_lo_out, uint16 *handle_hi_out) { NCP_DOS_MODIFY_INFO info; memset(&info, 0, sizeof(info)); info.attributes = attrs; /* * NCP 87 modify DOS information uses DM_ATTRIBUTES (0x00000002). * RIM_ATTRIBUTES (0x00000004) is the read/obtain mask; using it here * leaves high attribute bits such as Delete/Rename Inhibit unchanged or * cleared on some servers/clients. */ return(ncp87_07_modify_dos_info(name, dir_handle, 0x00000002UL, &info, actual_out, handle_lo_out, handle_hi_out)); } /* * ncp87_1d_get_effective_rights * * Purpose: * Reads the effective rights mask for a path. * * NCP: * Function 0x57 / subfunction 0x1d, Get Effective Rights. * * Requester path: * Client32 raw fragment request with an NWHandlePathStruct. */ int ncp87_1d_get_effective_rights(const char *path_name, uint16 dir_handle, 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[0x20]; uint8 rep1[0x20]; uint8 rawout[32]; uint16 raw_ret_ax, raw_ret_dx; uint16 actual_lo; uint16 rights0; uint16 rights4; UI path_len; int rc; if (!rights_out) return(1); *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; rc = ncp_get_requester_handle(&handle_lo, &handle_hi); if (rc) return(10 + rc); /* * NCP 87 subfunction 29: Get effective rights. * * This mirrors ncpfs ncp_get_eff_directory_rights(): * byte 29 * byte source namespace * byte target namespace * word search attributes, little endian * dword reserved, zero * handle/path * * Reply is a little-endian word with NCP rights bits. */ memset(hdr, 0, sizeof(hdr)); hdr[0] = 29; hdr[1] = 0; /* source namespace DOS */ hdr[2] = 0; /* target namespace DOS */ tool_put_word_lh(hdr + 3, 0x0006); /* SA_ALL */ tool_put_dword_lh(hdr + 5, 0L); /* reserved */ path_len = ncp_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)); ncp_raw_request(handle_lo, handle_hi, hdr, 9, path, path_len, rep0, sizeof(rep0), rep1, sizeof(rep1), rawout); raw_ret_ax = tool_get_word_lh(rawout + 14); raw_ret_dx = tool_get_word_lh(rawout + 16); actual_lo = tool_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); rights0 = tool_get_word_lh(rep0 + 0); rights4 = tool_get_word_lh(rep0 + 4); /* * Most NCP replies start at REP0+0. The existing RIM_ATTRIBUTES helper * found attributes at REP0+4 on Client32. Accept the +4 location only * if +0 is empty, so restricted rights value 0 still works when +4 is * also zero. */ if (rights0 == 0 && rights4 != 0) rights0 = rights4; *rights_out = rights0; return(0); } /* * ncp87_1d_get_effective_rights_by_dirent * * Purpose: * Reads effective rights using a volume number and DOS directory number * instead of a textual path. * * NCP: * Function 0x57 / subfunction 0x1d, Get Effective Rights. * * Notes: * NDIR uses this form after obtaining directory-entry metadata. */ int ncp87_1d_get_effective_rights_by_dirent(uint8 vol_number, uint32 dos_dir_number, uint16 *rights_out, uint16 *actual_out, uint16 *handle_lo_out, uint16 *handle_hi_out) { uint16 handle_lo, handle_hi; uint8 hdr[16]; uint8 path[16]; uint8 rep0[0x20]; uint8 rep1[0x20]; uint8 rawout[32]; uint16 raw_ret_ax, raw_ret_dx; uint16 actual_lo; uint16 rights0; uint16 rights4; int rc; if (!rights_out) return(1); *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; rc = ncp_get_requester_handle(&handle_lo, &handle_hi); if (rc) return(10 + rc); /* * SDK/ncpfs-style NCP87 subfunction 29: * byte 0x1D * byte source namespace DOS * byte reserved/target namespace * word SA_ALL * dword 0 * byte volume number * dword directory number * byte dirstyle 1 * byte component count 0 */ memset(hdr, 0, sizeof(hdr)); hdr[0] = 0x1d; hdr[1] = 0; hdr[2] = 0; tool_put_word_lh(hdr + 3, 0x0006); tool_put_dword_lh(hdr + 5, 0L); memset(path, 0, sizeof(path)); path[0] = vol_number; tool_put_dword_lh(path + 1, dos_dir_number); path[5] = 1; path[6] = 0; memset(rep0, 0, sizeof(rep0)); memset(rep1, 0, sizeof(rep1)); memset(rawout, 0, sizeof(rawout)); ncp_raw_request(handle_lo, handle_hi, hdr, 9, path, 7, rep0, sizeof(rep0), rep1, sizeof(rep1), rawout); raw_ret_ax = tool_get_word_lh(rawout + 14); raw_ret_dx = tool_get_word_lh(rawout + 16); actual_lo = tool_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); rights0 = (uint16)(rep0[0] | ((uint16)rep0[1] << 8)); rights4 = (uint16)(rep0[4] | ((uint16)rep0[5] << 8)); if (rights0 == 0 && rights4 != 0) rights0 = rights4; *rights_out = rights0; return(0); } /* * ncp22_build_trustee_path * * Purpose: * Builds the volume-qualified path format required by old NCP22 trustee * calls from the DOS utility display/header path. * * Notes: * This helper intentionally strips the server component and leaves a * SYS:DIR\FILE style path for directory handle 0 requests. */ static int ncp22_build_trustee_path(char *out, const char *path_name, int max) { char header[300]; char *p; char *colon; if (!out || max < 2) return(-1); out[0] = '\0'; /* Build the same server/volume display path used by the DOS tools, then * strip the server component. NCP22/27 accepts a volume-qualified path * such as SYS:DIR\FILE with directory handle 0, matching Novell GRANT's * old trustee call as seen in the server trace. */ tool_header_path(header, (char *)(path_name ? path_name : "."), sizeof(header)); colon = strchr(header, ':'); if (!colon) return(-1); p = header; while (*p && p < colon) { if (*p == '\\' || *p == '/') { p++; break; } p++; } if (!*p || p >= colon) p = header; strmaxcpy(out, p, max - 1); return(0); } /* * ncp22_27_set_trustee_rights * * Purpose: * Adds or updates a trustee assignment using the old directory services NCP * fallback path. * * NCP: * Function 0x16 / subfunction 0x27, Add Extended Trustee. * * Requester path: * E200 Net_Call wrapper with a volume-qualified path. */ int ncp22_27_set_trustee_rights(const char *path_name, uint16 dir_handle, uint32 object_id, uint16 rights) { struct { uint16 len; uint8 func; uint8 dirhandle; uint8 trustee_id[4]; uint8 trustee_rights[2]; uint8 pathlen; uint8 path[255]; } req; struct { uint16 len; } repl; char ncppath[260]; int pathlen; (void)dir_handle; if (ncp22_build_trustee_path(ncppath, path_name, sizeof(ncppath))) return(30); pathlen = strlen(ncppath); if (pathlen > 255) return(31); memset(&req, 0, sizeof(req)); memset(&repl, 0, sizeof(repl)); req.func = 0x27; /* NCP22/27 Add Ext Trustee */ req.dirhandle = 0; /* volume-qualified path follows */ tool_put_dword_hl(req.trustee_id, object_id); tool_put_word_lh(req.trustee_rights, rights); req.pathlen = (uint8)pathlen; memcpy(req.path, ncppath, pathlen); req.len = 9 + pathlen; repl.len = 0; neterrno = Net_Call(0xE200, &req, &repl); if (neterrno) return(-neterrno); return(0); } /* * ncp22_2b_delete_trustee_rights * * Purpose: * Deletes a trustee assignment using the old directory services NCP * fallback path. * * NCP: * Function 0x16 / subfunction 0x2b, Delete Trustee. * * Requester path: * E200 Net_Call wrapper with a volume-qualified path. */ int ncp22_2b_delete_trustee_rights(const char *path_name, uint16 dir_handle, uint32 object_id) { struct { uint16 len; uint8 func; uint8 dirhandle; uint8 trustee_id[4]; uint8 reserved; uint8 pathlen; uint8 path[255]; } req; struct { uint16 len; } repl; char ncppath[260]; int pathlen; (void)dir_handle; if (ncp22_build_trustee_path(ncppath, path_name, sizeof(ncppath))) return(30); pathlen = strlen(ncppath); if (pathlen > 255) return(31); memset(&req, 0, sizeof(req)); memset(&repl, 0, sizeof(repl)); req.func = 0x2b; /* NCP22/43 Delete Trustee */ req.dirhandle = 0; /* volume-qualified path follows */ tool_put_dword_hl(req.trustee_id, object_id); req.reserved = 0; /* NCP22/2B has a reserved byte before pathlen */ req.pathlen = (uint8)pathlen; memcpy(req.path, ncppath, pathlen); req.len = 8 + pathlen; repl.len = 0; neterrno = Net_Call(0xE200, &req, &repl); if (neterrno) return(-neterrno); return(0); } /* * ncp87_0a_add_trustee_rights * * Purpose: * Adds trustee rights using the namespace-aware NCP87 trustee API. * * NCP: * Function 0x57 / subfunction 0x0a, Add Trustee Set. * * Requester path: * Client32 raw fragment request. */ int ncp87_0a_add_trustee_rights(const char *path_name, uint16 dir_handle, uint32 object_id, uint16 rights, uint16 rights_mask, 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 = ncp_get_requester_handle(&handle_lo, &handle_hi); if (rc) return(10 + rc); /* * NCP 87 subfunction 10: Add trustee. * * This mirrors ncpfs ncp_ns_trustee_add(): * byte 10 * byte namespace DOS * byte reserved * word search attributes, little endian * word rights mask, little endian * word object count, little endian * handle/path * trustee array at request offset 16 + 307 * * Client32 raw has two request fragments, so the second fragment carries * the handle/path and the padded trustee record. */ memset(hdr, 0, sizeof(hdr)); hdr[0] = 10; hdr[1] = 0; /* DOS namespace */ hdr[2] = 0; /* reserved */ tool_put_word_lh(hdr + 3, 0x8006); /* SA_ALL: files/subdirs + system + hidden */ tool_put_word_lh(hdr + 5, rights_mask); tool_put_word_lh(hdr + 7, 1); /* one trustee */ memset(reqpath, 0, sizeof(reqpath)); path_struct_len = ncp_build_handle_path_from_dos_path(reqpath, (uint8)dir_handle, 0, 0, path_name); /* * ncpfs seeks to absolute packet offset 16+307 before writing the * trustee list. The NCP request header is 7 bytes, so inside the NCP * payload the trustee list begins at: * * (16 + 307) - 7 = 316 * * Our first raw request fragment is the 9-byte subfunction header, * so the trustee list begins in the second fragment at: * * 316 - 9 = 307 */ if (path_struct_len > 307) return(2); tp = reqpath + 307; tool_put_dword_hl(tp, object_id); tp += 4; tool_put_word_lh(tp, rights); tp += 2; reqpath_len = (UI)(tp - reqpath); memset(rep0, 0, sizeof(rep0)); memset(rep1, 0, sizeof(rep1)); memset(rawout, 0, sizeof(rawout)); ncp_raw_request(handle_lo, handle_hi, hdr, 9, reqpath, reqpath_len, rep0, sizeof(rep0), rep1, sizeof(rep1), rawout); raw_ret_ax = tool_get_word_lh(rawout + 14); raw_ret_dx = tool_get_word_lh(rawout + 16); actual_lo = tool_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); } /* * ncp87_05_find_trustee_rights * * Purpose: * Scans trustee entries for a path until the requested bindery object id is * found. * * NCP: * Function 0x57 / subfunction 0x05, Scan Trustee Set. * * Requester path: * Client32 raw fragment request. */ int ncp87_05_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 = ncp_get_requester_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 */ tool_put_word_lh(hdr + 3, 0x8006); /* SA_ALL: files/subdirs + system + hidden */ tool_put_dword_lh(hdr + 5, seq); /* search sequence, starts at zero */ path_len = ncp_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)); ncp_raw_request(handle_lo, handle_hi, hdr, 9, path, path_len, rep0, sizeof(rep0), rep1, sizeof(rep1), rawout); raw_ret_ax = tool_get_word_lh(rawout + 14); raw_ret_dx = tool_get_word_lh(rawout + 16); actual_lo = tool_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 = tool_get_dword_lh(rep0 + 0); count = tool_get_word_lh(rep0 + 4); if (count > 20) count = 20; tp = rep0 + 6; for (i = 0; i < count; i++) { uint32 tid = tool_get_dword_hl(tp); uint16 trights = tool_get_word_lh(tp + 4); if (tid == object_id || tool_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 */ } /* * ncp87_0b_delete_trustee_rights * * Purpose: * Deletes trustee rights using the namespace-aware NCP87 trustee API. * * NCP: * Function 0x57 / subfunction 0x0b, Delete Trustee Set. * * Requester path: * Client32 raw fragment request. */ int ncp87_0b_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 = ncp_get_requester_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 */ tool_put_word_lh(hdr + 3, 1); /* one trustee */ memset(reqpath, 0, sizeof(reqpath)); path_struct_len = ncp_build_handle_path_from_dos_path(reqpath, (uint8)dir_handle, 0, 0, path_name); if (path_struct_len > 307) return(2); tp = reqpath + 307; tool_put_dword_hl(tp, object_id); tp += 4; tool_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)); ncp_raw_request(handle_lo, handle_hi, hdr, 5, reqpath, reqpath_len, rep0, sizeof(rep0), rep1, sizeof(rep1), rawout); raw_ret_ax = tool_get_word_lh(rawout + 14); raw_ret_dx = tool_get_word_lh(rawout + 16); actual_lo = tool_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); }