Rename the remaining C32-prefixed transport helpers, probe helpers, types and constants to protocol-oriented NCP names. This removes implementation-oriented c32/C32 naming from the shared NCP API and transport layer while keeping the current c32ncp.c/c32ncp.h file names until the later ncpapi.c/ncpapi.h rename. The new names avoid conflicts by using ncp_* helper names and NCP_* type/constant prefixes. No behavior change.
1928 lines
53 KiB
C
1928 lines
53 KiB
C
/*
|
|
* 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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/*
|
|
* Purpose: Semantically named NCP API helper implementation used by the NetWare DOS tools.
|
|
* Depends on: net.h, c32ncp.h, ncpcall.c requester/transport helpers, and netcall.c for shared requester state. This file is planned to become ncpapi.c.
|
|
*/
|
|
|
|
#include "net.h"
|
|
#include "c32ncp.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 the file can later be
|
|
* renamed to ncpapi.c.
|
|
*/
|
|
|
|
/* ---------------- 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 Raw5 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 Raw5 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_Raw5_Probe(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 Raw5 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_Raw5_Probe(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 Raw5 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_Raw5_Probe(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 Raw5 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_Raw5_Probe(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 Raw5 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_Raw5_Probe(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_Raw5_Probe(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 Raw5 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 Raw5 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 Raw5 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_Raw5_Probe(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 Raw5 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_Raw5_Probe(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 Raw5 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_Raw5_Probe(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);
|
|
}
|