/* * 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: Low-level NCP bindery, filesystem and server helper routines used by multiple commands. * Depends on: net.h, netcall.c requester glue, kern_wasm.asm/kern.asm Net_Call entry point, tools.c shared utility routines. */ #include "net.h" /* ---------------- 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); }