/* nwconn.c 18-Apr-00 */ /* one process / connection */ /* (C)opyright (C) 1993,2000 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, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* history since 21-Apr-00 * * mst:25-Apr-00: added routines for sending nwconn data to nwbind * */ #include "net.h" #if 1 # define LOC_RW_BUFFERSIZE RW_BUFFERSIZE #else # define LOC_RW_BUFFERSIZE 512 #endif #include #include #include #include #if !CALL_NWCONN_OVER_SOCKET #include #include #endif #include "nwvolume.h" #include "nwfile.h" #include "connect.h" #include "nwqconn.h" #include "namspace.h" #include "nwshare.h" #include "nwconn.h" #include "trustee.h" #include "nwatalk.h" int act_pid = 0; #define FD_NCP_OUT 3 static int father_pid = -1; static ipxAddr_t from_addr; static ipxAddr_t my_addr; static struct t_unitdata ud; static uint8 ipx_pack_typ = PACKT_CORE; static int last_sequence = -9999; static IPX_DATA ipxdata; static NCPRESPONSE *ncpresponse=(NCPRESPONSE*)&ipxdata; static uint8 *responsedata=((uint8*)&ipxdata)+sizeof(NCPRESPONSE); static int requestlen; static uint8 readbuff[IPX_MAX_DATA]; static uint8 saved_readbuff[IPX_MAX_DATA]; static int saved_sequence=-1; static int rw_buffer_size = LOC_RW_BUFFERSIZE; /* default */ static NCPREQUEST *ncprequest = (NCPREQUEST*)readbuff; static uint8 *requestdata = readbuff + sizeof(NCPREQUEST); static int ncp_type; static int sock_nwbind=-1; static int sock_echo =-1; static char *prog_title; static int req_printed=0; static int scan_volume_user_disk_restrictions(uint8 volnr, uint32 sequence, uint8 *response) { struct XDATA { uint8 entries; } *xdata = (struct XDATA *)response; int result = nw_get_volume_name(volnr, NULL, 0); (void)sequence; if (result < 0) return result; /* * Keep the scan reply empty for now. The per-object quota query can be * routed through nwbind because it has a concrete object id to resolve, * but this scan call would need bindery iteration plus UNIX_USER property * lookups from nwbind-side code. nwconn does not link the bindery database * helpers, and pulling them into this process would break the existing * process split. */ xdata->entries = 0; return 1; } static int trustee_v3_to_ncp22_rights(int rights) { int ncp22 = 0; /* * NetWare trustee/access masks use bit 0x0100 for Supervisor. * Bit 0x0004 is the old Open right, not Supervisor. * * MARS keeps the same bit positions internally, including TRUSTEE_O * at 0x0004. Do not translate TRUSTEE_S down to 0x0004 here; doing * so makes clients see Open instead of Supervisor and RIGHTS prints * [ RWCEMFA] instead of [SRWCEMFA]. */ if (rights & TRUSTEE_R) ncp22 |= 0x0001; /* Read */ if (rights & TRUSTEE_W) ncp22 |= 0x0002; /* Write */ if (rights & TRUSTEE_O) ncp22 |= 0x0004; /* Open */ if (rights & TRUSTEE_C) ncp22 |= 0x0008; /* Create */ if (rights & TRUSTEE_E) ncp22 |= 0x0010; /* Erase */ if (rights & TRUSTEE_A) ncp22 |= 0x0020; /* Access Control */ if (rights & TRUSTEE_F) ncp22 |= 0x0040; /* File Scan */ if (rights & TRUSTEE_M) ncp22 |= 0x0080; /* Modify */ if (rights & TRUSTEE_S) ncp22 |= 0x0100; /* Supervisor */ return(ncp22); } static int trustee_ncp22_to_v3_rights(int ncp22) { int rights = 0; if (ncp22 & 0x0001) rights |= TRUSTEE_R; /* Read */ if (ncp22 & 0x0002) rights |= TRUSTEE_W; /* Write */ if (ncp22 & 0x0004) rights |= TRUSTEE_O; /* Open */ if (ncp22 & 0x0008) rights |= TRUSTEE_C; /* Create */ if (ncp22 & 0x0010) rights |= TRUSTEE_E; /* Erase */ if (ncp22 & 0x0020) rights |= TRUSTEE_A; /* Access Control */ if (ncp22 & 0x0040) rights |= TRUSTEE_F; /* File Scan */ if (ncp22 & 0x0080) rights |= TRUSTEE_M; /* Modify */ if (ncp22 & 0x0100) rights |= TRUSTEE_S; /* Supervisor */ return(rights); } static void ncp23_debug_dump(char *what, uint8 *data, int len) { char hex[3 * 64 + 1]; char asc[65]; int i; int n = len; char *hp = hex; if (n < 0) n = 0; if (n > 64) n = 64; for (i = 0; i < n; i++) { sprintf(hp, "%02x ", (int)data[i]); hp += 3; asc[i] = (data[i] >= 32 && data[i] < 127) ? (char)data[i] : '.'; } *hp = '\0'; asc[n] = '\0'; XDPRINTF((5,0, "%s: payload_len=%d dump_len=%d hex=`%s` ascii=`%s`", what, len, n, hex, asc)); } static int ncp22_component_path_to_dos(uint8 *src, int count, uint8 *dst, int maxlen, int *used_out) { int used = 0; int out = 0; int i; if (used_out) *used_out = 0; if (!dst || maxlen < 1 || count < 0) return(-0x9c); for (i = 0; i < count; i++) { int len = (int)src[used++]; if (len < 0 || len > 255) return(-0x9c); if (out + len + ((i > 0) ? 1 : 0) >= maxlen) return(-0x9c); if (i > 0) dst[out++] = '\\'; memcpy(dst + out, src + used, len); out += len; used += len; } dst[out] = '\0'; if (used_out) *used_out = used; return(out); } #if !CALL_NWCONN_OVER_SOCKET static char* nwconn_state; /* shared memory segment will be * attached to this pointer */ #endif #if ENABLE_BURSTMODE typedef struct { BURSTPACKET *sendburst; /* buffer for sending burstpacket * allocated and prefilled by response to * func 0x65 * max. max_packet_size */ uint8 *send_buf; /* we look from servers side * complete data buf of burst reply * file read status + file read buf * sendbuff must be 8 byte more allocated * than max_send_size ! */ int max_send_size; /* send_buf size, complete Burst DATA size */ uint32 packet_sequence; /* -> packet_sequence * will be increased after every * packet */ int burst_sequence; struct t_unitdata ud; ipxAddr_t to_addr; uint8 *recv_buf; /* complete data buf for burst read requests * must be 24 byte more allocated * than max_recv_size ! */ int max_recv_size; /* allocated size of recv_buf */ int max_burst_data_size; /* size of BURSTDATA, max. IPX_DATA - BURSTHEADER */ uint8 ipx_pack_typ; } BURST_W; static BURST_W *burst_w=NULL; #endif void nwconn_set_program_title(char *s) { memset(prog_title, 0, 49); if (s&&*s) strmaxcpy(prog_title, s, 48); else strcpy(prog_title, "()"); } static int ncp_response(int sequence, int task, int completition, int data_len) { ncpresponse->sequence = (uint8) sequence; ncpresponse->task = (uint8) task; ncpresponse->completition = (uint8) completition; last_sequence = sequence; if (req_printed) { XDPRINTF((0,0, "NWCONN NCP_RESP seq:%d, conn:%d, compl=0x%x task=%d TO %s", (int)ncpresponse->sequence, (int)ncpresponse->connection | (((int)ncpresponse->high_connection) << 8), (int)completition, (int)ncpresponse->task, visable_ipx_adr((ipxAddr_t *) ud.addr.buf))); } ud.udata.len = ud.udata.maxlen = sizeof(NCPRESPONSE) + data_len; if (t_sndudata(FD_NCP_OUT, &ud) < 0){ if (nw_debug) t_error("t_sndudata in NWCONN !OK"); return(-1); } return(0); } static int call_nwbind(int mode) /* modes 0: 'standard' call * 1: activate wdog */ { ipxAddr_t to_addr; int result; memcpy(&to_addr, &my_addr, sizeof(ipxAddr_t)); U16_TO_BE16(sock_nwbind, to_addr.sock); ud.addr.buf = (char*)&to_addr; if (mode==1) { /* reset wdogs */ NCPREQUEST buf; buf.type[0] = buf.type[1]=0x22; buf.sequence = ncprequest->sequence; buf.connection = ncprequest->connection; buf.task = ncprequest->task; buf.high_connection = ncprequest->high_connection; buf.function = 0; ud.udata.len = ud.udata.maxlen = sizeof(buf); ud.udata.buf = (char*)&buf; XDPRINTF((3, 0, "send wdog reset")); result=t_sndudata(FD_NCP_OUT, &ud); } else { ud.udata.len = ud.udata.maxlen = sizeof(NCPREQUEST) + requestlen; ud.udata.buf = (char*)&readbuff; result=t_sndudata(FD_NCP_OUT, &ud); } ud.addr.buf = (char*)&from_addr; ud.udata.buf = (char*)&ipxdata; if (result< 0){ if (nw_debug) t_error("t_sndudata in NWCONN !OK"); return(-1); } return(0); } static void pr_debug_request() { if (req_printed++) return; if (ncp_type == 0x2222) { int ufunc = 0; switch (ncprequest->function) { case 0x16 : case 0x17 : ufunc = (int) *(requestdata+2); break; case 0x57 : ufunc = (int) *(requestdata); break; default : break; } /* switch */ XDPRINTF((1, 0, "NCP REQUEST: func=0x%02x, ufunc=0x%02x, seq:%03d, task:%02d", (int)ncprequest->function, ufunc, (int)ncprequest->sequence, (int)ncprequest->task)); } else { XDPRINTF((1, 0, "Got NCP:type:0x%x, seq:%d, task:%d, func=0x%x", ncp_type, (int)ncprequest->sequence, (int)ncprequest->task, (int)ncprequest->function)); } if (requestlen > 0){ int j = requestlen; uint8 *p=requestdata; XDPRINTF((0, 2, "len %d, DATA:", j)); while (j--) { int c = *p++; if (c > 32 && c < 127) XDPRINTF((0, 3,",\'%c\'", (char) c)); else XDPRINTF((0,3, ",0x%x", c)); } XDPRINTF((0,1,NULL)); } } #if TEST_FNAME static int test_handle = -1; #endif static void handle_nwbind_request(void) /* mst:25-Apr-00 */ { int result = 0; char buf[IPX_MAX_DATA]; char *data = &(buf[sizeof(NCPRESPONSE)]); int data_len = 0; switch (ncprequest->function) { case 0x1: { /* get number and handles of open files */ struct INPUT { uint8 header[7]; /* Requestheader */ uint8 offset[4]; /* handle offset */ } *input = (struct INPUT *) (ncprequest); struct XDATA { uint8 count_handles[4]; uint8 handles[4]; } *xdata = (struct XDATA*) data; int handles = nw_get_count_open_files(xdata->handles, GET_BE32(input->offset)); U32_TO_BE32(handles, xdata->count_handles); data_len = (handles+1) * 4; } break; default : result = 0xfb; } { NCPRESPONSE *resp = (NCPRESPONSE*)&buf; ipxAddr_t to_addr; memcpy(&to_addr, &my_addr, sizeof(ipxAddr_t)); U16_TO_BE16(sock_nwbind, to_addr.sock); ud.addr.buf = (char*)&to_addr; resp->type[0] = resp->type[1]=0x32; resp->sequence = ncprequest->sequence; resp->connection = ncprequest->connection; resp->task = ncprequest->task; resp->high_connection = ncprequest->high_connection; resp->completition = result; resp->connect_status = 0; ud.udata.len = ud.udata.maxlen = sizeof(NCPRESPONSE) + data_len; ud.udata.buf = (char*)resp; XDPRINTF((3, 0, "send reply to nwbind")); result = t_sndudata(FD_NCP_OUT, &ud); ud.addr.buf = (char*)&from_addr; ud.udata.buf = (char*)&ipxdata; } } static const char *afp_call_name(int ufunc) { switch (ufunc) { case 0x03: return("AFP Delete"); case 0x04: return("AFP Get Entry ID From Name"); case 0x05: return("AFP Get File Information"); case 0x06: return("AFP Get Entry ID From NetWare Handle"); case 0x07: return("AFP Rename"); case 0x08: return("AFP Open File Fork"); case 0x0b: return("AFP Alloc Temporary Dir Handle"); case 0x0c: return("AFP Get Entry ID From Path Name"); case 0x0d: return("AFP 2.0 Create Directory"); case 0x0e: return("AFP 2.0 Create File"); case 0x0f: return("AFP 2.0 Get File Information"); case 0x10: return("AFP 2.0 Set File Information"); case 0x11: return("AFP 2.0 Scan File Information"); default: return("unknown AFP call"); } } static int afp_request_offset(void) /* * AFP NCP 0x23 calls are documented with a two byte high-low request * length followed by the AFP subfunction. Some old debug paths treated the * first payload byte as the subfunction. Accept both layouts so diagnostics * and the first implemented AFP call work with either requester encoding. */ { if (requestlen >= 3) { int plen = GET_BE16(requestdata); if (plen == requestlen - 2) return(2); } return(0); } static uint32 afp_fallback_entry_id(int volume, const struct stat *stb) /* * Build a stable local AFP entry id from Unix identity data when libatalk has * no stored CNID/AppleDouble id yet. This is not a NetWare-internal directory * base number; it is only the AFP id returned by the path-name probe. */ { uint32 hash = 2166136261U; const uint8 *p; size_t len; #define AFP_HASH_BYTES(ptr, size) do { \ p = (const uint8 *)(ptr); \ len = (size); \ while (len--) { hash ^= *p++; hash *= 16777619U; } \ } while (0) AFP_HASH_BYTES(&volume, sizeof(volume)); AFP_HASH_BYTES(&stb->st_dev, sizeof(stb->st_dev)); AFP_HASH_BYTES(&stb->st_ino, sizeof(stb->st_ino)); #undef AFP_HASH_BYTES hash &= 0x7fffffffU; if (!hash) hash = 1; return(hash); } static int afp_get_entry_id_from_path_name(uint8 *afp_req, int afp_len, uint8 *response) { uint8 dir_handle; int path_len; int volume; char unixname[PATH_MAX]; struct stat stbuff; uint32 entry_id = 0; int result; if (afp_len < 3) { XDPRINTF((2,0, "AFP Get Entry ID From Path Name rejected: short request len=%d", afp_len)); return(-0x7e); /* NCP Boundary Check Failed */ } dir_handle = afp_req[1]; path_len = (int)afp_req[2]; if (path_len < 0 || afp_len < 3 + path_len) { XDPRINTF((2,0, "AFP Get Entry ID From Path Name rejected: boundary check len=%d path_len=%d", afp_len, path_len)); return(-0x7e); } if (!nwatalk_backend_available()) { XDPRINTF((3,0, "AFP Get Entry ID From Path Name rejected: libatalk backend unavailable")); return(-0xbf); /* invalid namespace */ } volume = conn_get_kpl_unxname(unixname, sizeof(unixname), (int)dir_handle, afp_req + 3, path_len); if (volume < 0) { XDPRINTF((2,0, "AFP Get Entry ID From Path Name path resolve failed: dh=%d path='%s' result=-0x%x", (int)dir_handle, visable_data(afp_req + 3, path_len), -volume)); return(volume); } if (stat(unixname, &stbuff)) { XDPRINTF((2,0, "AFP Get Entry ID From Path Name stat failed: dh=%d path='%s' unix='%s' errno=%d", (int)dir_handle, visable_data(afp_req + 3, path_len), unixname, errno)); return(-0x9c); /* Invalid Path */ } result = nwatalk_get_entry_id(unixname, &entry_id); if (result < 0 || !entry_id) entry_id = afp_fallback_entry_id(volume, &stbuff); U32_TO_BE32(entry_id, response); XDPRINTF((3,0, "AFP Get Entry ID From Path Name: dh=%d path='%s' entry=0x%08x%s", (int)dir_handle, visable_data(afp_req + 3, path_len), entry_id, (result < 0) ? " fallback" : "")); return(4); } static void afp_copy_fixed_name(uint8 *dst, int dst_len, const uint8 *src, int src_len) { int i; memset(dst, 0, dst_len); if (!src || src_len < 1) return; if (src_len > dst_len) src_len = dst_len; for (i = 0; i < src_len; i++) { uint8 c = src[i]; if (!c) break; dst[i] = c; } } static void afp_leaf_name_from_path(uint8 *dst, int dst_len, const uint8 *path, int path_len) { int start = 0; int end = path_len; int i; if (!path || path_len < 1) { afp_copy_fixed_name(dst, dst_len, (const uint8 *)"", 0); return; } while (end > 0 && (path[end - 1] == '/' || path[end - 1] == '\\')) end--; for (i = end - 1; i >= 0; i--) { if (path[i] == ':' || path[i] == '/' || path[i] == '\\') { start = i + 1; break; } } if (start >= end) { int colon = -1; for (i = 0; i < path_len; i++) { if (path[i] == ':') { colon = i; break; } } if (colon > 0) { start = 0; end = colon; } } afp_copy_fixed_name(dst, dst_len, path + start, end - start); } static uint16 afp_basic_attributes(const struct stat *stb) { if (S_ISDIR(stb->st_mode)) return(0x0400); /* AFP_SA_SUBDIR */ return(0x0000); /* AFP_SA_NORMAL */ } static uint16 afp_basic_access_privileges(const struct stat *stb) { if (S_ISDIR(stb->st_mode)) return(0x4000 | 0x2000 | 0x8000); /* search, parental, modify attrs */ return(0x0100 | 0x0200 | 0x0400 | 0x1000 | 0x8000); /* rw open delete modify */ } static uint16 afp_count_offspring(const char *unixname, const struct stat *stb) { DIR *dir; struct dirent *de; uint32 count = 0; if (!S_ISDIR(stb->st_mode)) return(0); dir = opendir(unixname); if (!dir) return(0); while ((de = readdir(dir)) != NULL) { if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) continue; if (count < 0xffff) count++; } closedir(dir); return((uint16)count); } static int afp_get_file_information(uint8 *afp_req, int afp_len, uint8 *response) { uint8 volume_number; uint32 request_entry_id; uint16 request_mask; int path_len; int volume; char unixname[PATH_MAX]; struct stat stbuff; uint32 entry_id = 0; uint32 parent_id = 0; uint32 resource_size = 0; uint8 finder_info[NWATALK_FINDER_INFO_LEN]; uint8 empty_path = 0; int result; if (afp_len < 9) { XDPRINTF((2,0, "AFP Get File Information rejected: short request len=%d", afp_len)); return(-0x7e); /* NCP Boundary Check Failed */ } volume_number = afp_req[1]; request_entry_id = GET_BE32(afp_req + 2); request_mask = GET_BE16(afp_req + 6); path_len = (int)afp_req[8]; if (path_len < 0 || afp_len < 9 + path_len) { XDPRINTF((2,0, "AFP Get File Information rejected: boundary check len=%d path_len=%d", afp_len, path_len)); return(-0x7e); } if (!nwatalk_backend_available()) { XDPRINTF((3,0, "AFP Get File Information rejected: libatalk backend unavailable")); return(-0xbf); /* invalid namespace */ } if (!path_len) { XDPRINTF((2,0, "AFP Get File Information rejected: entry-id-only lookup unsupported vol=%d entry=0x%08x mask=0x%04x", (int)volume_number, request_entry_id, request_mask)); return(-0x9c); /* Invalid Path until persistent entry-id lookup exists */ } volume = conn_get_kpl_unxname(unixname, sizeof(unixname), 0, path_len ? afp_req + 9 : &empty_path, path_len); if (volume < 0) { XDPRINTF((2,0, "AFP Get File Information path resolve failed: vol=%d entry=0x%08x path='%s' result=-0x%x", (int)volume_number, request_entry_id, visable_data(afp_req + 9, path_len), -volume)); return(volume); } if (stat(unixname, &stbuff)) { XDPRINTF((2,0, "AFP Get File Information stat failed: vol=%d entry=0x%08x path='%s' unix='%s' errno=%d", (int)volume_number, request_entry_id, visable_data(afp_req + 9, path_len), unixname, errno)); return(-0x9c); /* Invalid Path */ } result = nwatalk_get_entry_id(unixname, &entry_id); if (result < 0 || !entry_id) entry_id = afp_fallback_entry_id(volume, &stbuff); memset(response, 0, 120); U32_TO_BE32(entry_id, response + 0); U32_TO_BE32(parent_id, response + 4); U16_TO_BE16(afp_basic_attributes(&stbuff), response + 8); U32_TO_BE32(S_ISDIR(stbuff.st_mode) ? 0 : (uint32)stbuff.st_size, response + 10); if (!S_ISDIR(stbuff.st_mode)) (void)nwatalk_get_resource_fork_size(unixname, &resource_size); U32_TO_BE32(resource_size, response + 14); U16_TO_BE16(afp_count_offspring(unixname, &stbuff), response + 18); un_date_2_nw(stbuff.st_ctime, response + 20, 1); un_date_2_nw(stbuff.st_atime, response + 22, 1); un_date_2_nw(stbuff.st_mtime, response + 24, 1); un_time_2_nw(stbuff.st_mtime, response + 26, 1); U16_TO_BE16(0, response + 28); /* Backup Date */ U16_TO_BE16(0, response + 30); /* Backup Time */ memset(finder_info, 0, sizeof(finder_info)); (void)nwatalk_get_finder_info(unixname, finder_info, sizeof(finder_info)); memcpy(response + 32, finder_info, NWATALK_FINDER_INFO_LEN); afp_leaf_name_from_path(response + 64, 32, afp_req + 9, path_len); U32_TO_BE32(get_file_owner(&stbuff), response + 96); afp_leaf_name_from_path(response + 100, 12, afp_req + 9, path_len); U16_TO_BE16(afp_basic_access_privileges(&stbuff), response + 112); /* ProDOS info at offset 114 stays zero until a real Mac namespace maps it. */ XDPRINTF((3,0, "AFP Get File Information: vol=%d entry=0x%08x mask=0x%04x path='%s' reply_entry=0x%08x%s", (int)volume_number, request_entry_id, request_mask, visable_data(afp_req + 9, path_len), entry_id, (result < 0) ? " fallback" : "")); return(120); } static int handle_ncp_serv(void) { int function = (int)ncprequest->function; int completition = 0; /* first set */ int org_nw_debug = nw_debug; int do_druck = 0; int data_len = 0; if (last_sequence == (int)ncprequest->sequence && ncp_type != 0x1111){ /* send the same again */ if (t_sndudata(FD_NCP_OUT, &ud) < 0) { if (nw_debug) t_error("t_sndudata !OK"); } XDPRINTF((3,0, "Sequence %d is written twice", (int)ncprequest->sequence)); return(0); } req_printed=0; if (nw_debug > 1){ if (nw_debug < 10 && (function==0x48 || function == 0x49)) /* read or write */ nw_debug=1; if (nw_debug < 15 && (function==0x48)) /* read */ nw_debug=1; } if (nw_debug > 5) pr_debug_request(); if (ncp_type == 0x2222) { switch (function) { /* 0.99.pl18, 25-Sep-99 * these log/lock functions are not well tested and perhaps not * ok . */ case 0x3 : { /* Log File */ struct INPUT { uint8 header[7]; /* Requestheader */ uint8 dir_handle; uint8 lock_flag; /* 0 = log, 1 = lock excl */ /* 3 = lock shared */ uint8 timeout[2]; /* HI LO */ uint8 len; uint8 path[2]; } *input = (struct INPUT *) (ncprequest); int result = nw_log_file( input->lock_flag, GET_BE16(input->timeout), input->dir_handle, input->len, input->path); if (result) completition = (uint8) -result; } break; case 0x4 : /* Lock File Set (old) */ case 0x6a : { /* Lock File Set */ /* * NCP 0x2222/04 Lock File Set (old) and NCP 0x2222/106 Lock * File Set lock all files logged by the calling client's current * task. * * SDK request: 2-byte Lock Timeout, in units of 1/18 second; * 0 means No Wait. * SDK reply: no reply data. * SDK completion: 0x00 success, 0xfe timeout, 0xff lock error. * * The newer 0x6a call replaces the old 0x04 call but has the same * request layout for the file set lock itself. MARS-NWE records * file-set members through Log File (0x03), then uses the shared * set handler for Lock/Release/Clear File Set operations. */ struct INPUT { uint8 header[7]; /* Requestheader */ uint8 timeout[2]; /* HI LO */ } *input = (struct INPUT *) (ncprequest); int result = share_handle_lock_sets( 1, /* File Set */ 0, /* Lock logged entries */ GET_BE16(input->timeout)); if (result) completition = (uint8) -result; } break; case 0x5 : /* Release File */ case 0x7 : { /* Clear File, removes file from logset */ struct INPUT { uint8 header[7]; /* Requestheader */ uint8 dir_handle; uint8 len; uint8 path[2]; } *input = (struct INPUT *) (ncprequest); int result = nw_log_file( (function==0x7) ? -2 /* unlock and unlog */ : -1, /* unlock */ 0, input->dir_handle, input->len, input->path); if (result) completition = (uint8) -result; } break; case 0x6 : /* Release File Set */ case 0x8 : { /* Clear File Set */ int result = share_handle_lock_sets( 1, /* File Set */ (function==0x8) ? -2 /* Clear */ : -1, /* Release */ 0); if (result) completition = (uint8) -result; } break; case 0x9 : { /* Log Logical Record */ struct INPUT { uint8 header[7]; /* Requestheader */ uint8 lock_flag; /* 0 = log */ /* 1 = exclusive lock */ /* 3 = shared ro lock */ uint8 timeout[2]; /* HI LO */ uint8 len; /* synch name len */ uint8 name[2]; /* synch name */ } *input = (struct INPUT *) (ncprequest); int result = nw_log_logical_record( (int) input->lock_flag, (int) GET_BE16(input->timeout), (int) input->len, input->name); if (result) completition = (uint8) -result; } break; case 0xa : { /* Log Logical Record Set */ struct INPUT { uint8 header[7]; /* Requestheader */ uint8 lock_flag; /* 0 = log */ /* 1 = exclusive lock */ /* 3 = shared ro lock */ uint8 timeout[2]; /* HI LO */ } *input = (struct INPUT *) (ncprequest); int result = share_handle_lock_sets( 2, /* Logical Record Set */ (int) input->lock_flag, (int) GET_BE16(input->timeout) ); if (result) completition = (uint8) -result; } break; case 0xb : /* Clear Logical Record */ case 0xc : { /* Release Logical Record */ /* * SDK: NCP 0x2222/11 Clear Logical Record removes one logical * record from the calling task's synchronization table. * * SDK: NCP 0x2222/12 Release Logical Record releases/unlocks one * synchronization string held by the calling client. The request * is a one-byte Synch Name Length followed by the Synch Name * (up to 128 bytes), returns no reply data, and reports success or * Unlock Error through the completion code. * * Important semantic difference: Release Logical Record leaves the * string in the caller's synchronization string table so a later * Lock Logical Record Set can relock it. Clear Logical Record * unlocks and removes it from the table. */ struct INPUT { uint8 header[7]; /* Requestheader */ uint8 len; /* synch name len */ uint8 name[2]; /* synch name */ } *input = (struct INPUT *) (ncprequest); int result = nw_log_logical_record( (function == 0xb) ? -2 /* unlock + unlog */ : -1, /* unlock */ 0, (int) input->len, input->name); if (result) completition = (uint8) -result; } break; case 0xe : /* Clear Logical Record Set */ case 0xd : { /* Release Logical Record Set */ int result = share_handle_lock_sets( 2, /* Logical Record Set */ (function==0xe) ? -2 /* Clear */ : -1, /* Release */ 0); if (result) completition = (uint8) -result; } break; case 0x12 : { /* Get Volume Info with Number */ int volume = (int)*requestdata; struct XDATA { uint8 sec_per_block[2]; uint8 total_blocks[2]; uint8 avail_blocks[2]; uint8 total_dirs[2]; uint8 avail_dirs[2]; uint8 name[16]; uint8 removable[2]; } *xdata = (struct XDATA*) responsedata; int result; memset(xdata, 0, sizeof(struct XDATA)); if ((result = nw_get_volume_name(volume, xdata->name, sizeof(xdata->name)))>-1){ struct fs_usage fsp; if (!nw_get_fs_usage(xdata->name, &fsp, entry8_flags&0x40 )) { int sector_scale=1; while (fsp.fsu_blocks/sector_scale > 0xffff) sector_scale+=2; U16_TO_BE16(sector_scale, xdata->sec_per_block); U16_TO_BE16(fsp.fsu_blocks/sector_scale, xdata->total_blocks); U16_TO_BE16(fsp.fsu_bavail/sector_scale, xdata->avail_blocks); U16_TO_BE16(fsp.fsu_files, xdata->total_dirs); U16_TO_BE16(fsp.fsu_ffree, xdata->avail_dirs); if ( get_volume_options(volume) & VOL_OPTION_REMOUNT) { U16_TO_BE16(1, xdata->removable); } else { U16_TO_BE16(0, xdata->removable); } } data_len = sizeof(struct XDATA); } else completition = (uint8) -result; } break; case 0x13 : { /* Get Station Number */ /* * This is the old one-byte connection number call used by * DOS requesters before the richer NCP 23 connection services. * The SDK describes the client-visible API as * NWGetConnectionNumber(); older low-level documentation names the * underlying simple NCP 0x13 "Get Station Number". */ if (act_connection > 0 && act_connection < 256) { *responsedata=(uint8) act_connection; data_len = 1; } else { XDPRINTF((1, 0, "Get Station Number failed, conn=%d", act_connection)); completition = 0xff; } } break; case 0x14 : { /* GET DATE und TIME */ struct SERVER_DATE { uint8 year; uint8 mon; uint8 day; uint8 std; uint8 min; uint8 sec; uint8 day_of_week; } *mydate = (struct SERVER_DATE*) responsedata; struct tm *s_tm; time_t timer; time(&timer); s_tm = localtime(&timer); mydate->year = (uint8) s_tm->tm_year; mydate->mon = (uint8) s_tm->tm_mon+1; mydate->day = (uint8) s_tm->tm_mday; mydate->std = (uint8) s_tm->tm_hour; mydate->min = (uint8) s_tm->tm_min; mydate->sec = (uint8) s_tm->tm_sec; mydate->day_of_week = (uint8) s_tm->tm_wday; /* Wochentag */ data_len = sizeof(struct SERVER_DATE); } break; case 0x15 : return(-1); /* nwbind must do this call */ case 0x16 : { /* uint8 len = *(requestdata+1); */ uint8 *p = requestdata +2; switch (*p) { case 0 : { /******** SetDirektoryHandle *************/ struct INPUT { uint8 header[7]; /* Requestheader */ uint8 div[3]; /* 0x0, dlen, ufunc */ uint8 target_dir_handle; /* to change */ uint8 source_dir_handle; uint8 pathlen; uint8 path[2]; } *input = (struct INPUT *) (ncprequest); completition = (uint8)-nw_set_dir_handle((int)input->target_dir_handle, (int)input->source_dir_handle, input->path, (int)input->pathlen, (int)(ncprequest->task)); } break; case 0x1 : { /******** GetDirektoryPATH ***************/ struct INPUT { uint8 header[7]; /* Requestheader */ uint8 div[3]; /* 0x0, dlen, ufunc */ uint8 dir_handle; } *input = (struct INPUT *) (ncprequest); struct XDATA { uint8 len; uint8 name[256]; } *xdata = (struct XDATA*) responsedata; int result = nw_get_directory_path((int)input->dir_handle, xdata->name, sizeof(xdata->name)); if (result > -1){ xdata->len = (uint8) result; data_len = result + 1; xdata->name[result] = '\0'; XDPRINTF((5,0, "GetDirektoryPATH=%s", xdata->name)); } else completition = (uint8)-result; } break; case 0x2 : { /* Scan Direktory Information */ /******** Scan Dir Info ****************/ struct INPUT { uint8 header[7]; /* Requestheader */ uint8 div[3]; /* 0x0, dlen, ufunc */ uint8 dir_handle; /* Verzeichnis Handle */ uint8 sub_dir_nmbr[2]; /* HI LOW */ /* firsttime 1 */ uint8 len; /* kann auch 0 sein */ uint8 path[2]; } *input = (struct INPUT *) (ncprequest); struct XDATA { uint8 sub_dir_name[16]; uint8 create_date_time[4]; uint8 owner_id[4]; /* HI LOW */ uint8 max_right_mask; /* inherited right mask */ uint8 reserved; /* Reserved by Novell */ uint8 sub_dir_nmbr[2]; /* HI LOW */ } *xdata = (struct XDATA*) responsedata; int result; memcpy(xdata->sub_dir_nmbr, input->sub_dir_nmbr, 2); result = nw_scan_dir_info((int)input->dir_handle, input->path, (int)input->len, xdata->sub_dir_nmbr, xdata->sub_dir_name, xdata->create_date_time, xdata->owner_id); if (result > -1){ xdata->max_right_mask = (uint8)result; data_len = sizeof(struct XDATA); XDPRINTF((5,0,"Scan Dir Info max_right_mask=%d", (int)result)); } else completition = (uint8)-result; } break; case 0x3 : { /* Get Direktory Rights */ /******** Get Eff Dir Rights ****************/ struct XDATA { uint8 eff_right_mask; /* Effektive Right to Dir, old! */ } *xdata = (struct XDATA*) responsedata; int result = nw_get_eff_dir_rights( (int)*(p+1), p+3, (int)*(p+2), 0); if (result > -1) { int ncp22_rights = trustee_v3_to_ncp22_rights(result); xdata->eff_right_mask = (uint8)ncp22_rights; data_len = 1; XDPRINTF((5,0,"NCP22/3 Get Dir Rights=%d ncp22=%d", (int)result, (int)ncp22_rights)); } else completition = (uint8) -result; } break; case 0x4 : { /* Modify Max Right Mask */ /******** MODIFY MAX RIGHT MASK ****************/ /* * Request (NetWare 2.x compatible NCP 22/4): * byte directory handle * byte grant rights mask * byte revoke rights mask * byte path length * path bytes * * New mask is: (old_mask | grant_mask) & ~revoke_mask. * * No reply data. */ int result = nw_modify_max_right_mask( (int)*(p+1), p+5, (int)*(p+4), (int)*(p+2), (int)*(p+3)); if (result) completition = (uint8)-result; } break; case 0x5 : { /* Get Volume Number 0 .. 31 */ /******** GetVolume Number ***************/ /* p+1 = namelen */ /* p+2 = data z.b 'SYS' */ struct XDATA { uint8 volume; /* Nummer */ } *xdata = (struct XDATA*) responsedata; int result = nw_get_volume_number(p+2, (int)*(p+1)); if (result > -1) { xdata->volume = (uint8) result; data_len = 1; } else completition = (uint8) -result; } break; case 0x6 : { /* Get Volume Name from 0 .. 31 */ /******** Get Volume Name ***************/ struct XDATA { uint8 namelen; uint8 name[16]; } *xdata = (struct XDATA*) responsedata; int result = nw_get_volume_name((int)*(p+1), xdata->name, sizeof(xdata->name)); if (result > -1) { xdata->namelen = (uint8) result; data_len = result+1; } else completition = (uint8) -result; } break; case 0xa : { /* create directory */ /******** Create Dir *********************/ int dir_handle = (int) *(p+1); #if 0 int rightmask = (int) *(p+2); #endif int pathlen = (int) *(p+3); uint8 *path = p+4; int code = nw_mk_rd_dir(dir_handle, path, pathlen, 1); if (code) completition = (uint8) -code; } break; case 0xb : { /* delete dirrctory */ /******** Delete DIR *********************/ int dir_handle = (int) *(p+1); #if 0 int reserved = (int) *(p+2); /* Res. by NOVELL */ #endif int pathlen = (int) *(p+3); uint8 *path = p+4; int code = nw_mk_rd_dir(dir_handle, path, pathlen, 0); if (code) completition = (uint8) -code; } break; case 0xd : { /* Add Trustees to DIR */ /******** AddTrustesstoDir ***************/ struct INPUT { uint8 header[7]; /* Requestheader */ uint8 div[3]; /* 0x0, dlen, ufunc */ uint8 dir_handle; /* Verzeichnis Handle */ uint8 trustee_id[4]; /* Trustee Object ID */ uint8 trustee_right_mask; uint8 pathlen; uint8 path[2]; } *input = (struct INPUT *) (ncprequest); uint32 trustee_id = GET_BE32(input->trustee_id); int ncp22_rights = (int)input->trustee_right_mask; int trustee_rights = trustee_ncp22_to_v3_rights(ncp22_rights); int copylen = input->pathlen; uint8 pathbuf[256]; int raw_len = requestlen - (int)((uint8 *)&input->dir_handle - readbuff); int result; ncp23_debug_dump("NCP22/0D AddTrustee raw", (uint8 *)&input->dir_handle, raw_len); if (copylen > 255) copylen = 255; memcpy(pathbuf, input->path, copylen); pathbuf[copylen] = '\0'; result = nw_add_trustee( input->dir_handle, input->path, input->pathlen, trustee_id, trustee_rights, 0); XDPRINTF((5,0, "NCP22/0D AddTrustee: dh=%d pathlen=%d path=`%s` obj=0x%08lx ncp22=0x%02x rights=0x%03x rc=%d", input->dir_handle, input->pathlen, pathbuf, (unsigned long)trustee_id, ncp22_rights, trustee_rights, result)); if (result) completition = (uint8) -result; } break; case 0xe : { /* remove trustees */ struct INPUT { uint8 header[7]; /* Requestheader */ uint8 div[3]; /* 0x0, dlen, ufunc */ uint8 dir_handle; /* Handle */ uint8 trustee_id[4]; /* Trustee Object ID */ uint8 reserved; uint8 pathlen; uint8 path[2]; } *input = (struct INPUT *) (ncprequest); uint32 trustee_id = GET_BE32(input->trustee_id); int copylen = input->pathlen; uint8 pathbuf[256]; int raw_len = requestlen - (int)((uint8 *)&input->dir_handle - readbuff); int result; ncp23_debug_dump("NCP22/0E DelTrustee raw", (uint8 *)&input->dir_handle, raw_len); if (copylen > 255) copylen = 255; memcpy(pathbuf, input->path, copylen); pathbuf[copylen] = '\0'; result = nw_del_trustee( input->dir_handle, input->path, input->pathlen, trustee_id, 0); /* normal */ XDPRINTF((5,0, "NCP22/0E DelTrustee: dh=%d pathlen=%d path=`%s` obj=0x%08lx rc=%d", input->dir_handle, input->pathlen, pathbuf, (unsigned long)trustee_id, result)); if (result) completition = (uint8) -result; } break; case 0xf : { /* rename dir */ /******** Rename DIR *********************/ int dir_handle = (int) *(p+1); int oldpathlen = (int) *(p+2); uint8 *oldpath = p+3; int newpathlen = (int) *(oldpath + oldpathlen); uint8 *newpath = oldpath + oldpathlen + 1; int code = mv_dir(dir_handle, oldpath, oldpathlen, newpath, newpathlen); if (code) completition = (uint8) -code; } break; case 0x12 : /* Allocate Permanent Dir Handle */ /******** Allocate Permanent DIR Handle **/ case 0x13 : /* Allocate Temp Dir Handle */ /******** Allocate Temp DIR Handle **/ case 0x16 : { /* Allocate Special Temp Dir Handle */ /******** Allocate spez temp DIR Handle **/ struct XDATA { uint8 dirhandle; /* new Dir Handle */ uint8 right_mask; /* 0xff effektive Right MAsk ? */ } *xdata = (struct XDATA*) responsedata; int eff_rights; int dirhandle = nw_alloc_dir_handle( (int) *(p+1), p+4, (int)*(p+3), (int)*(p+2), (*p==0x12) ? 0 : ((*p==0x13) ? 1 : 2), (int)(ncprequest->task), &eff_rights); if (dirhandle > -1){ xdata->dirhandle = (uint8) dirhandle; xdata->right_mask = eff_rights; data_len = sizeof(struct XDATA); } else completition = (uint8) -dirhandle; } break; case 0x14 : { /* deallocate Dir Handle */ /******** Free DIR Handle ****************/ int err_code = nw_free_dir_handle((int)*(p+1), (int)(ncprequest->task)); if (err_code) completition = (uint8) -err_code; } break; case 0x15 : { /* liefert Volume Information */ /******** Get Volume Info with Handle ****/ struct XDATA { uint8 sectors[2]; uint8 total_blocks[2]; uint8 avail_blocks[2]; uint8 total_dirs[2]; /* anz dirs */ uint8 avail_dirs[2]; /* free dirs */ uint8 name[16]; /* SYS Name */ uint8 removable[2]; } *xdata = (struct XDATA*)responsedata; int result = nw_get_vol_number((int)*(p+1)); memset(xdata, 0, sizeof(struct XDATA)); if (result > -1) { int volume = result; result = nw_get_volume_name(volume, xdata->name, sizeof(xdata->name) ); if (result > -1) { struct fs_usage fsp; if (!nw_get_fs_usage(xdata->name, &fsp, entry8_flags&0x40 )) { int sector_scale=1; while (fsp.fsu_blocks/sector_scale > 0xffff) sector_scale+=2; U16_TO_BE16(sector_scale, xdata->sectors); U16_TO_BE16(fsp.fsu_blocks/sector_scale, xdata->total_blocks); U16_TO_BE16(fsp.fsu_bavail/sector_scale, xdata->avail_blocks); U16_TO_BE16(fsp.fsu_files, xdata->total_dirs); U16_TO_BE16(fsp.fsu_ffree, xdata->avail_dirs); if (get_volume_options(volume) & VOL_OPTION_REMOUNT) { U16_TO_BE16(1, xdata->removable); } else { U16_TO_BE16(0, xdata->removable); } } data_len = sizeof(struct XDATA); XDPRINTF((5,0,"GIVE VOLUME INFO from :%s:", xdata->name)); result = 0; } } completition = (uint8)-result; } break; case 0x17 : { /* Extract a Base Handle */ /* * NCP 0x2222/22/23 Extract a Base Handle. * * WebSDK: request carries DirectoryHandle. Reply returns a * 10-byte ServerNetworkAddress plus a 4-byte opaque * HandleID. The handle must have been allocated with Alloc * Permanent Directory Handle. The returned HandleID is used * by NCP 0x16/0x18 Restore an Extracted Base Handle. * * MARS-NWE keeps the HandleID opaque to the client and maps * it to the current connection's saved volume/path tuple. */ struct XDATA { uint8 server_network_address[10]; uint8 handle_id[4]; } *xdata = (struct XDATA*)responsedata; int result; memcpy(xdata->server_network_address, my_addr.net, 4); memcpy(xdata->server_network_address+4, my_addr.node, 6); result = nw_extract_base_handle((int)*(p+1), xdata->handle_id); if (result) completition = (uint8)-result; else data_len = sizeof(struct XDATA); } break; case 0x18 : { /* Restore Directory Handle */ /* * NCP 0x2222/22/24 Restore an Extracted Base Handle. * * WebSDK: request carries the 10-byte ServerNetworkAddress * and 4-byte HandleID returned by Extract a Base Handle. * Reply returns NewDirectoryHandle and AccessRightsMask. * * The old SDK API exposes this as NWRestoreDirectoryHandle() * and uses a 14-byte save buffer produced by * NWSaveDirectoryHandle(). Rust nwserver and lwared do not * implement this older save/restore pair; newer clients * typically use the ordinary allocate/set directory-handle * calls instead. Keep this implementation conservative and * connection-local rather than guessing a global NetWare * directory-base number. */ struct INPUT { uint8 server_network_address[10]; uint8 handle_id[4]; } *input = (struct INPUT*)(p+1); struct XDATA { uint8 dirhandle; uint8 right_mask; } *xdata = (struct XDATA*)responsedata; int eff_rights = 0; int result; if (memcmp(input->server_network_address, my_addr.net, 4) || memcmp(input->server_network_address+4, my_addr.node, 6)) { completition = 0xfd; /* Bad Station Number */ break; } result = nw_restore_base_handle(input->handle_id, (int)(ncprequest->task), &eff_rights); if (result > -1) { xdata->dirhandle = (uint8)result; xdata->right_mask = (uint8)eff_rights; data_len = sizeof(struct XDATA); } else completition = (uint8)-result; } break; case 0x19 : { /* Set Directory Information * Modifies basic directory information as creation date and * directory rights mask. DOS namespace. */ struct INPUT { uint8 header[7]; /* Requestheader */ uint8 div[3]; /* 0x0, dlen, ufunc */ uint8 dir_handle; uint8 creation_date[2]; uint8 creation_time[2]; uint8 owner_id[4]; uint8 new_max_rights; uint8 pathlen; uint8 path[2]; } *input = (struct INPUT *) (ncprequest); int result = nw_set_dir_info( input->dir_handle, input->path, input->pathlen, GET_BE32(input->owner_id), (int)input->new_max_rights, input->creation_date, input->creation_time); if (result<0) completition = (uint8) -result; /* No REPLY */ } break; case 0x1a : { /* Get Pathname of A Volume Dir Pair */ /* * Old NetWare 2.x compatibility call: * byte volume * word directory entry number (Hi-Lo) * * Reply: * byte path length * byte path[path length] * * This is the older string form of the NCP23/F3 mapping. * NCP23/F3 is preferred for 32-bit directory numbers and * namespace-aware callers. */ struct XDATA { uint8 pathlen; uint8 pathname[255]; } *xdata = (struct XDATA*)responsedata; int volume = (int)*(p+1); uint32 dirnum = (uint32)GET_BE16(p+2); uint8 comps[256]; uint8 pathbuf[255]; int result; int pos = 0; int out = 0; int first = 1; result = map_directory_number_to_path(volume, dirnum, 0, comps, sizeof(comps)); if (result > -1) { while (pos < result) { int l = (int)comps[pos++]; if (l <= 0 || pos + l > result) { result = -0x9c; break; } if (!first) { if (out >= (int)sizeof(pathbuf)) { result = -0x9c; break; } pathbuf[out++] = '\\'; } if (out + l > (int)sizeof(pathbuf)) { result = -0x9c; break; } memcpy(pathbuf + out, comps + pos, l); out += l; pos += l; first = 0; } } if (result > -1) { xdata->pathlen = (uint8)out; memcpy(xdata->pathname, pathbuf, out); data_len = out + 1; } else completition = (uint8)(-result); } break; case 0x1e : { /* SCAN a Directory, e.g. used by ndir.exe */ struct INPUT { uint8 header[7]; /* Requestheader */ uint8 div[3]; /* 0x0, dlen, ufunc */ uint8 dir_handle; /* Verzeichnis Handle */ uint8 attrib; /* Search Attrib z.B. 0x6 */ uint8 searchsequence[4]; /* 32 bit */ uint8 len; uint8 data[2]; } *input = (struct INPUT *) (ncprequest); int result = nw_scan_a_directory( responsedata, input->dir_handle, input->data, input->len, input->attrib, GET_BE32(input->searchsequence)); if (result > -1) data_len = result; else completition = (uint8) (-result); } break; case 0x1f : { /* SCAN a root dir ???? */ struct INPUT { uint8 header[7]; /* Requestheader */ uint8 div[3]; /* 0x0, dlen, ufunc */ uint8 dir_handle; /* Verzeichnis Handle */ uint8 dont_know1; /* ???? 0xc0 */ uint8 dont_know2; /* ???? 0xfa */ } *input = (struct INPUT *) (ncprequest); int result = nw_scan_a_root_dir( responsedata, input->dir_handle); if (result > -1) data_len = result; else completition = (uint8) (-result); } break; case 0x20 : { /* Scan Volume's User Disk Restrictions */ /* * NCP 0x2222/22/32 Scan Volume's User Disk Restrictions. * * WebSDK / headers: * Request: Volume Number, Sequence. Sequence starts at * zero and is incremented by the number of entries returned * by previous calls. * Reply: Number Of Entries followed by up to twelve * Object ID / Restriction pairs. Restrictions are reported * in 4K blocks. * * The Rust nwserver and lwared implementations both return * an empty list after validating the volume. MARS-NWE keeps * that SDK-compatible unrestricted result for non-quota * builds, and fills entries from the existing Linux quota * backend when QUOTA_SUPPORT is enabled and a restricted * bindery user maps to a Unix uid. */ uint8 volnr = *(p+1); uint32 sequence = GET_BE32(p+2); int result = scan_volume_user_disk_restrictions( volnr, sequence, responsedata); if (result > -1) data_len = result; else completition = (uint8) (-result); } break; case 0x21 : { /* change Vol restrictions for Obj */ XDPRINTF((5, 0, "Change vol restrictions")); } return(-2); /* nwbind must do prehandling */ case 0x22 : { /* remove Vol restrictions for Obj */ XDPRINTF((5, 0, "Remove vol restrictions")); } return(-2); /* nwbind must do prehandling */ case 0x25 : { /* Set Entry, Set Directory File Information * sets or changes the file or directory information to the * values entered in 'Change Bits'. * NO REPLY * used by ncopy.exe, flag.exe */ struct INPUT { uint8 header[7]; /* Requestheader */ uint8 div[3]; /* 0x0, dlen, ufunc */ uint8 dir_handle; uint8 attrib; NW_SET_DIR_INFO f; } *input = (struct INPUT *) (ncprequest); int result = nw_set_a_directory_entry( input->dir_handle, input->f.u.f.name, input->f.u.f.namlen, input->attrib, GET_BE32(input->f.searchsequence), &(input->f)); if (result < 0) { completition = (uint8)(-result); XDPRINTF((5,0, "NCP22/25 SetDirFileInfo: dh=%d attr=0x%02x seq=0x%08lx result=%d cc=0x%02x", (int)input->dir_handle, (int)input->attrib, (unsigned long)GET_BE32(input->f.searchsequence), result, (unsigned int)completition)); } } break; case 0x26 : { /* Scan file or Dir for ext trustees */ int sequence = (int)*(p+2); /* trustee sequence */ struct XDATA { uint8 entries; uint8 ids[80]; /* 20 id's */ uint8 trustees[40]; /* 20 trustees's */ } *xdata = (struct XDATA*) responsedata; uint32 ids[20]; int trustees[20]; int result = nw_scan_for_trustee( (int)*(p+1), /* dir handle */ sequence, p+4, /* path */ (int)*(p+3), /* pathlen */ 20, /* max entries */ ids, trustees, 1); /* extended */ if (result > -1) { int i = -1; uint8 *idsp = xdata->ids; uint8 *trp = xdata->trustees; memset(xdata, 0, sizeof(*xdata)); xdata->entries = result; while(++i < result) { int ncp22_rights = trustee_v3_to_ncp22_rights(trustees[i]); U32_TO_BE32(ids[i], idsp); idsp+=4; U16_TO_16(ncp22_rights, trp); /* LO - HI */ trp+=2; } data_len = sizeof(struct XDATA); } else completition = (uint8) (-result); } break; case 0x27 : { /* Add Ext Trustees to DIR or File */ struct INPUT { uint8 header[7]; /* Requestheader */ uint8 div[3]; /* 0x0, dlen, ufunc */ uint8 dir_handle; /* Handle */ uint8 trustee_id[4]; /* Trustee Object ID */ uint8 trustee_rights[2]; /* lo - hi */ uint8 pathlen; uint8 path[2]; } *input = (struct INPUT *) (ncprequest); uint32 trustee_id = GET_BE32(input->trustee_id); int ncp22_rights = GET_16(input->trustee_rights); int trustee_rights = trustee_ncp22_to_v3_rights(ncp22_rights); int copylen = input->pathlen; uint8 pathbuf[256]; int raw_len = requestlen - (int)((uint8 *)&input->dir_handle - readbuff); int result; ncp23_debug_dump("NCP22/27 SetTrustee raw", (uint8 *)&input->dir_handle, raw_len); if (copylen > 255) copylen = 255; memcpy(pathbuf, input->path, copylen); pathbuf[copylen] = '\0'; result = nw_add_trustee( input->dir_handle, input->path, input->pathlen, trustee_id, trustee_rights, 1); /* extended */ XDPRINTF((5,0, "NCP22/27 SetTrustee: dh=%d pathlen=%d path=`%s` obj=0x%08lx ncp22=0x%04x rights=0x%03x rc=%d", input->dir_handle, input->pathlen, pathbuf, (unsigned long)trustee_id, ncp22_rights, trustee_rights, result)); if (result) completition = (uint8) -result; } break; case 0x28 : { /* Scan File Physical ??? */ struct INPUT { uint8 header[7]; /* Requestheader */ uint8 div[3]; /* 0x0, dlen, ufunc */ uint8 dir_handle; /* directory handle */ uint8 attrib; /* Search Attrib ?? 0x2f */ uint8 searchsequence[4]; /* 32 bit */ uint8 len; uint8 data[2]; } *input = (struct INPUT *) (ncprequest); /* we try, whether this is ok ????? */ int result = nw_scan_a_directory( responsedata, input->dir_handle, input->data, input->len, input->attrib, GET_BE32(input->searchsequence)); if (result > -1) data_len = result; else completition = (uint8) (-result); } break; /* * NCP 0x2222/22/41 Get Object Disk Usage And Restrictions. * * WebSDK / headers: * Request: Volume Number, Object ID (high-low) * Reply: Restriction and In Use, both 32-bit values in 4K * blocks. * * A restriction value of 0x40000000 means that the object has no * disk restriction. NetWare also treats unknown/invalid object * IDs as a successful unrestricted/no-use result. * * With QUOTA_SUPPORT enabled this call needs bindery prehandling: * nwbind maps the Object ID to a Unix uid before * handle_after_bind() calls nw_get_vol_restrictions(). Without * quota support, keep the SDK-compatible fallback local so builds * on hosts without quota support do not need the quota backend. */ case 0x29 : { /* Get Object Disk Usage And Restrictions */ #if QUOTA_SUPPORT XDPRINTF((5, 0, "Read vol restrictions")); return(-2); /* nwbind must do prehandling */ #else #if DO_DEBUG uint8 volnr = *(p+1); uint32 id = GET_BE32(p+2); #endif struct XDATA { uint8 restriction[4]; uint8 inuse[4]; } *xdata = (struct XDATA*) responsedata; XDPRINTF((5,0, "Get vol restriction fallback vol=%d, id=0x%lx", (int)volnr, id)); U32_TO_32(0x40000000, xdata->restriction); U32_TO_32(0x0, xdata->inuse); data_len=sizeof(struct XDATA); #endif } break; case 0x2a : { /* Get Eff. Rights of DIR's and Files */ struct XDATA { uint8 eff_rights[2]; /* LO-HI */ } *xdata = (struct XDATA*) responsedata; int dir_handle = (int)*(p+1); int pathlen = (int)*(p+2); uint8 *path = p+3; int copylen = pathlen; uint8 pathbuf[256]; int result; if (copylen > 255) copylen = 255; memcpy(pathbuf, path, copylen); pathbuf[copylen] = '\0'; result = nw_get_eff_dir_rights(dir_handle, path, pathlen, 1); if (result > -1){ int ncp22_rights = trustee_v3_to_ncp22_rights(result); U16_TO_16(ncp22_rights, xdata->eff_rights); data_len = sizeof(struct XDATA); XDPRINTF((5,0, "NCP22/42 GetEffectiveRights: dh=%d pathlen=%d path=`%s` rights=0x%04x ncp22=0x%04x", dir_handle, pathlen, pathbuf, result, ncp22_rights)); } else { completition = (uint8) (-result); XDPRINTF((5,0, "NCP22/42 GetEffectiveRights: dh=%d pathlen=%d path=`%s` rc=%d", dir_handle, pathlen, pathbuf, result)); } } break; case 0x2b : { /* remove ext trustees */ struct INPUT { uint8 header[7]; /* Requestheader */ uint8 div[3]; /* 0x0, dlen, ufunc */ uint8 dir_handle; /* Handle */ uint8 trustee_id[4]; /* Trustee Object ID */ uint8 reserved; uint8 pathlen; uint8 path[2]; } *input = (struct INPUT *) (ncprequest); uint32 trustee_id = GET_BE32(input->trustee_id); int copylen = input->pathlen; uint8 pathbuf[256]; int raw_len = requestlen - (int)((uint8 *)&input->dir_handle - readbuff); int result; ncp23_debug_dump("NCP22/2B DelTrustee raw", (uint8 *)&input->dir_handle, raw_len); if (copylen > 255) copylen = 255; memcpy(pathbuf, input->path, copylen); pathbuf[copylen] = '\0'; result = nw_del_trustee( input->dir_handle, input->path, input->pathlen, trustee_id, 1); /* extended */ XDPRINTF((5,0, "NCP22/2B DelTrustee: dh=%d pathlen=%d path=`%s` obj=0x%08lx rc=%d", input->dir_handle, input->pathlen, pathbuf, (unsigned long)trustee_id, result)); if (result) completition = (uint8) -result; } break; case 0x2c : { /* Get Volume and Purge Information */ /* new Call since V3.11 */ /* ncpfs need this call */ int volume = (int) *(p+1); struct XDATA { uint8 total_blocks[4]; /* LOW-HI !! */ uint8 avail_blocks[4]; uint8 purgeable_blocks[4]; uint8 not_purgeable_blocks[4]; uint8 total_dirs[4]; uint8 avail_dirs[4]; uint8 reserved_by_novell[4]; uint8 sec_per_block; uint8 namlen; uint8 name[1]; } *xdata = (struct XDATA*) responsedata; uint8 name[100]; int result = nw_get_volume_name(volume, name, sizeof(name)); if (result > -1){ struct fs_usage fsp; memset(xdata, 0, sizeof(struct XDATA)); if (!nw_get_fs_usage(name, &fsp, 0)) { xdata->sec_per_block = 8; /* hard coded */ U32_TO_32(fsp.fsu_blocks/8, xdata->total_blocks); U32_TO_32(fsp.fsu_bavail/8, xdata->avail_blocks); U32_TO_32(fsp.fsu_files, xdata->total_dirs); U32_TO_32(fsp.fsu_ffree, xdata->avail_dirs); } xdata->namlen = strlen((char*)name); strmaxcpy(xdata->name, name, xdata->namlen); data_len = xdata->namlen + 30; } else completition = (uint8) -result; } break; case 0x2d : { /* Get Direktory Information */ int dir_handle = (int) *(p+1); struct XDATA { uint8 total_blocks[4]; uint8 avail_blocks[4]; uint8 total_dirs[4]; uint8 avail_dirs[4]; uint8 reserved_by_novell[4]; uint8 sec_per_block; uint8 namlen; uint8 name[1]; /* Volume Name */ } *xdata = (struct XDATA*) responsedata; int result = nw_get_vol_number(dir_handle); uint8 name[100]; if (result > -1) result = nw_get_volume_name(result, name, sizeof(name)); if (result > -1) { struct fs_usage fsp; memset(xdata, 0, sizeof(struct XDATA)); if (!nw_get_fs_usage(name, &fsp, 0)) { xdata->sec_per_block = 8; /* hard coded */ U32_TO_32(fsp.fsu_blocks/8, xdata->total_blocks); U32_TO_32(fsp.fsu_bavail/8, xdata->avail_blocks); U32_TO_32(fsp.fsu_files, xdata->total_dirs); U32_TO_32(fsp.fsu_ffree, xdata->avail_dirs); } xdata->namlen = strlen((char*)name); strmaxcpy(xdata->name, name, xdata->namlen); data_len = xdata->namlen + 22; } else completition = (uint8) -result; } break; case 0x2e : { /* Rename or Move (old) */ /* * NCP 22 / subfunction 46 (0x2e): Rename Or Move (old) * * Request: * byte source directory handle * byte search attributes * byte source path component count * source path components: byte len + bytes, repeated * byte destination directory handle * byte destination path component count * destination path components: byte len + bytes, repeated * * No reply data. This old call uses component-counted * paths, unlike the plain length-prefixed NCP 69 rename. */ uint8 srcpath[256]; uint8 dstpath[256]; int src_handle = (int)*(p+1); int searchattr = (int)*(p+2); int src_count = (int)*(p+3); int used = 0; int srclen; int dstlen; int result; uint8 *q; srclen = ncp22_component_path_to_dos(p+4, src_count, srcpath, sizeof(srcpath), &used); if (srclen < 0) { completition = (uint8)(-srclen); break; } q = p + 4 + used; dstlen = ncp22_component_path_to_dos(q+2, (int)*(q+1), dstpath, sizeof(dstpath), NULL); if (dstlen < 0) { completition = (uint8)(-dstlen); break; } XDPRINTF((5,0, "NCP22/2E RenameOrMove: src_h=%d dst_h=%d attr=0x%02x src=`%s` dst=`%s`", src_handle, (int)*q, searchattr, srcpath, dstpath)); result = nw_mv_files(searchattr, src_handle, srcpath, srclen, (int)*q, dstpath, dstlen); XDPRINTF((5,0, "NCP22/2E RenameOrMove: file_result=%d", result)); /* * nw_mv_files() is correct for file rename/move. For a * directory source it may return either Invalid Path (0x9c) * or "not found" (0xff), depending on the search attribute * shape. Directories need the directory mover, and * NCP22/2E can provide different source/destination handles. */ if (result == -0x9c || result == -0xff) { int dir_result = nw_mv_dir_between_handles(src_handle, srcpath, srclen, (int)*q, dstpath, dstlen); XDPRINTF((5,0, "NCP22/2E RenameOrMove: directory fallback result=%d", dir_result)); result = dir_result; } if (result < 0) completition = (uint8)(-result); } break; #if WITH_NAME_SPACE_CALLS case 0x2f : { /* Fill namespace buffer */ /* ncopy use this call */ int volume = (int) *(p+1); /* (p+2) == 0xe4 or 0xe2 sometimes ???? */ int result=fill_namespace_buffer( volume, responsedata); if (result > -1) { data_len = result; } else completition = (uint8) -result; } break; case 0x30 : { /* Get Name Space Directory Entry */ int volume = (int) *(p+1); uint32 basehandle = GET_32(p+2); int namespace = (int) *(p+6); int result=get_namespace_dir_entry( volume, basehandle, namespace, responsedata); if (result > -1) { data_len = result; } else completition = (uint8) -result; } break; #endif case 0x32 : { /* Get Object Effective Rights */ /* * Client32/NWCalls export: * NWNCP22s50GetObjEffectRights * * Observed request layout from Client32/NCPWIN32: * byte subfunction 0x32 * dword object id (big endian) * byte directory handle * byte path length * byte[] path * * Reply: * word effective rights mask, low/high. * * mars_nwe's trustee engine currently computes effective * rights for the active connection object. For the normal * NWGetEffectiveRights/NWGetObjectEffectiveRights use from * a logged-in client this object id is the current user. */ struct XDATA { uint8 eff_rights[2]; /* LO-HI */ } *xdata = (struct XDATA*) responsedata; uint32 object_id = GET_BE32(p+1); int dir_handle = (int)*(p+5); int pathlen = (int)*(p+6); uint8 *path = p+7; int result; if (object_id && object_id != (uint32)act_obj_id) { int save_act_obj_id = act_obj_id; /* * Best effort for explicit-object callers. Group * membership is still the connection's group list, which * is correct for the usual current-user call and avoids * changing bindery/group state in this low-level handler. */ act_obj_id = (int)object_id; result = nw_get_eff_dir_rights(dir_handle, path, pathlen, 1); act_obj_id = save_act_obj_id; } else { result = nw_get_eff_dir_rights(dir_handle, path, pathlen, 1); } if (result > -1) { int ncp22_rights = trustee_v3_to_ncp22_rights(result); U16_TO_16(ncp22_rights, xdata->eff_rights); data_len = sizeof(struct XDATA); } else completition = (uint8)(-result); } break; case 0x33 : { /* Get Extended Volume Information */ /* * NCP 0x2222/22/51 Get Extended Volume Information * * WebSDK / nwvol.h context: * Request: * byte VolumeNumber * Reply: * word VolInfoReplyLen (Lo-Hi) * NWVolExtendedInfo VolumeInfo (VolInfoReplyLen bytes) * byte VolNameLen * byte VolumeName[VolNameLen] * * NWVolExtendedInfo contains 33 little-endian 32-bit fields: * volume type, status flags, sector/cluster geometry, total and * free cluster counts, suballocation/limbo/compression/migration * counters, directory-entry counters, EA counters, a Directory * Services object id, and the last-modified date/time. * * MARS-NWE maps the Unix filesystem data we already expose via * the older volume-information calls to the core geometry and * capacity fields. NetWare-specific suballocation, limbo, * compression, migration, EA, and DS fields are reported as zero. */ struct XDATA { uint8 vol_info_reply_len[2]; uint8 vol_type[4]; uint8 status_flag[4]; uint8 sector_size[4]; uint8 sectors_per_cluster[4]; uint8 vol_size_in_clusters[4]; uint8 free_clusters[4]; uint8 sub_alloc_freeable_clusters[4]; uint8 freeable_limbo_sectors[4]; uint8 nonfreeable_limbo_sectors[4]; uint8 avail_sub_alloc_sectors[4]; uint8 nonuseable_sub_alloc_sectors[4]; uint8 sub_alloc_clusters[4]; uint8 num_data_streams[4]; uint8 num_limbo_data_streams[4]; uint8 oldest_del_file_age_in_ticks[4]; uint8 num_compressed_data_streams[4]; uint8 num_compressed_limbo_data_streams[4]; uint8 num_noncompressible_data_streams[4]; uint8 precompressed_sectors[4]; uint8 compressed_sectors[4]; uint8 num_migrated_data_streams[4]; uint8 migrated_sectors[4]; uint8 clusters_used_by_fat[4]; uint8 clusters_used_by_dirs[4]; uint8 clusters_used_by_ext_dirs[4]; uint8 total_dir_entries[4]; uint8 unused_dir_entries[4]; uint8 total_ext_dir_extants[4]; uint8 unused_ext_dir_extants[4]; uint8 ext_attrs_defined[4]; uint8 ext_attr_extants_used[4]; uint8 directory_services_object_id[4]; uint8 vol_last_modified_date_and_time[4]; uint8 vol_name_len; uint8 vol_name[16]; } *xdata = (struct XDATA*) responsedata; uint8 name[100]; int volume = (int) *(p+1); int result = nw_get_volume_name(volume, name, sizeof(name)); memset(xdata, 0, sizeof(struct XDATA)); if (result > -1) { struct fs_usage fsp; int namlen = strlen((char*)name); if (namlen > 16) namlen = 16; U16_TO_16(33 * 4, xdata->vol_info_reply_len); U32_TO_32(3, xdata->vol_type); /* VINetWare386v31 */ U32_TO_32(512, xdata->sector_size); U32_TO_32(8, xdata->sectors_per_cluster); /* 4 KiB clusters */ if (!nw_get_fs_usage(name, &fsp, 0)) { U32_TO_32(fsp.fsu_blocks/8, xdata->vol_size_in_clusters); U32_TO_32(fsp.fsu_bavail/8, xdata->free_clusters); U32_TO_32(fsp.fsu_files, xdata->total_dir_entries); U32_TO_32(fsp.fsu_ffree, xdata->unused_dir_entries); } xdata->vol_name_len = namlen; strmaxcpy(xdata->vol_name, name, namlen); data_len = 2 + (33 * 4) + 1 + namlen; XDPRINTF((5,0, "NCP22/33 GetExtendedVolumeInfo: vol=%d name=`%s` len=%d", volume, name, data_len)); } else { completition = (uint8) -result; } } break; default: completition = 0xfb; /* unkwown request */ break; } /* switch *p */ } break; case 0x17 : { /* FILE SERVER ENVIRONMENT */ /* uint8 len = *(requestdata+1); */ uint8 ufunc = *(requestdata+2); uint8 *rdata = requestdata+3; switch (ufunc) { #if FUNC_17_02_IS_DEBUG case 0x02 : { /* I hope this call isn't used */ /* now missused as a debug switch :) */ struct XDATA { uint8 nw_debug; /* old level */ } *xdata = (struct XDATA*) responsedata; if (*rdata == NWCONN) { xdata->nw_debug = (uint8)org_nw_debug; nw_debug = org_nw_debug = (int) *(rdata+1); data_len = 1; } else return(-1); } break; #endif case 0x14: /* Login Objekt, unencrypted passwords */ case 0x18: /* crypt_keyed LOGIN */ return(-2); /* nwbind must do prehandling */ case 0x0f: { /* Scan File Information */ struct INPUT { uint8 header[7]; /* Requestheader */ uint8 div[3]; /* 0, len + ufunc */ uint8 sequence[2]; /* z.B. 0xff, 0xff */ uint8 dir_handle; uint8 search_attrib; /* 0: NONE */ /* 02: HIDDEN */ /* 04: SYSTEM */ /* 06: BOTH */ /* 0x10: DIR */ uint8 len; uint8 data[2]; /* Name */ } *input = (struct INPUT *)ncprequest; struct XDATA { uint8 sequence[2]; /* next sequence */ /* NW_FILE_INFO f; */ uint8 f[sizeof(NW_FILE_INFO)]; uint8 owner_id[4]; uint8 archive_date[2]; uint8 archive_time[2]; uint8 reserved[56]; } *xdata = (struct XDATA*)responsedata; int len = input->len; int searchsequence; NW_FILE_INFO f; uint32 owner; memset(xdata, 0, sizeof(struct XDATA)); searchsequence = nw_search( (uint8*) &f, &owner, (int)input->dir_handle, (int) GET_BE16(input->sequence), (int) input->search_attrib & ~0x10, /* this routine is only for scanning files ^^^^^^ */ input->data, len); if (searchsequence > -1) { memcpy(xdata->f, &f, sizeof(NW_FILE_INFO)); U16_TO_BE16((uint16) searchsequence, xdata->sequence); U32_TO_BE32(owner, xdata->owner_id); data_len = sizeof(struct XDATA); } else completition = (uint8) (- searchsequence); } break; case 0x10: { /* Set File Information */ struct INPUT { uint8 header[7]; /* Requestheader */ uint8 div[3]; /* 0, len + ufunc */ uint8 f[sizeof(NW_FILE_INFO) - 14]; /* no name */ uint8 owner_id[4]; uint8 archive_date[2]; uint8 archive_time[2]; uint8 reserved[56]; uint8 dir_handle; uint8 search_attrib; /* 0: NONE */ /* 02: HIDDEN */ /* 04: SYSTEM */ /* 06: BOTH */ /* 0x10: DIR */ uint8 len; uint8 data[2]; /* Name */ } *input = (struct INPUT *)ncprequest; NW_FILE_INFO f; int result; memcpy(((uint8*)&f)+14, input->f, sizeof(NW_FILE_INFO)-14); result = nw_set_file_information((int)input->dir_handle, input->data, (int)input->len, (int)input->search_attrib, &f); /* no reply packet */ if (result <0) completition = (uint8)-result; } break; case 0x47 : { /* SCAN BINDERY OBJECT TRUSTEE PATH */ struct INPUT { uint8 header[7]; /* Requestheader */ uint8 div[3]; /* 0x0, dlen, ufunc */ uint8 volume; uint8 sequence[2]; /* trustee searchsequence */ uint8 id[4]; /* Trustee Object ID */ } *input = (struct INPUT *) (ncprequest); struct XDATA { uint8 nextsequence[2]; uint8 id[4]; uint8 access_mask; uint8 pathlen; uint8 path[1]; } *xdata = (struct XDATA*) responsedata; int sequence=GET_BE16(input->sequence); int access_mask=0; uint32 id=GET_BE32(input->id); int result=nw_scan_user_trustee( input->volume, &sequence, id, &access_mask, xdata->path); if (result > 0) { U16_TO_BE16(sequence, xdata->nextsequence); memcpy(xdata->id, input->id, 4); xdata->access_mask=(uint8)access_mask; xdata->pathlen=result; data_len = 8+result; } else if (!result) { memset(xdata, 0, 8); data_len = 8; } else completition = (uint8)(-result); } break; case 0x64: { /* create queue */ #if 0 int q_typ = GET_BE16(rdata); #endif int q_name_len = *(rdata+2); #if 0 uint8 *q_name = rdata+3; #endif uint8 *dirhandle = rdata+3+q_name_len; int pathlen = *(rdata+3+q_name_len+1); uint8 *path = rdata+3+q_name_len+2; uint8 new_path[257]; int result = conn_get_full_path(*dirhandle, path, pathlen, new_path, sizeof(new_path)); if (result > -1) { int diffsize = result - pathlen; *dirhandle = 0; memcpy(path, new_path, result); if (diffsize) requestlen+=diffsize; /* !!!!!! */ return(-1); /* nwbind must do the rest */ } else completition = (uint8)(-result); } break; case 0x68: /* create queue job and file old */ case 0x79: /* create queue job and file */ return(-2); /* nwbind must do prehandling */ case 0x6C: /* Get Queue Job Entry old */ case 0x7A: { /* Read Queue Job Entry */ uint32 q_id = GET_BE32(rdata); int job_id = GET_BE16(rdata+4); uint32 fhandle = get_queue_job_fhandle(q_id, job_id); U32_TO_BE32(fhandle, rdata+8); requestlen+=6; /* !!!!!! */ } return(-1); /* nwbind must do the rest */ case 0x69: /* close file and start queue old ?? */ case 0x7f: { /* close file and start queue */ struct INPUT { uint8 header[7]; /* Requestheader */ uint8 packetlen[2]; /* lo - hi */ uint8 func; /* 0x7f or 0x69 */ uint8 queue_id[4]; /* Queue ID */ uint8 job_id[4]; /* result from creat queue */ /* if 0x69 then only first 2 byte ! */ } *input = (struct INPUT *) (ncprequest); uint32 q_id = GET_BE32(input->queue_id); int job_id = (ufunc==0x69) ? GET_BE16(input->job_id) : GET_BE16(input->job_id); int result = close_queue_job(q_id, job_id); if (result < 0) { completition = (uint8)-result; } else { return(-2); /* nwbind must do next */ } } break; case 0x71 : /* service queue job (old) */ case 0x7c : /* service queue job */ return(-2); /* nwbind must do prehandling */ case 0x72 : /* finish queue job (old) */ case 0x73 : /* abort queue job (old) */ case 0x83 : /* finish queue job */ case 0x84 : { /* abort queue job */ struct INPUT { uint8 header[7]; /* Requestheader */ uint8 packetlen[2]; /* low high */ uint8 func; /* 0x7f or 0x69 */ uint8 queue_id[4]; /* Queue ID */ uint8 job_id[4]; /* result from creat queue */ /* if 0x69 then only first 2 byte ! */ } *input = (struct INPUT *) (ncprequest); uint32 q_id = GET_BE32(input->queue_id); int job_id = GET_BE16(input->job_id); int result = finish_abort_queue_job(q_id, job_id); if (result <0) completition=(uint8) -result; else return(-1); /* nwbind must do the rest */ } break; case 0xf3: { /* Map Directory Number TO PATH */ int payload_len = requestlen - 3; int result; if (payload_len < 0) payload_len = 0; ncp23_debug_dump("NCP23/F3 Map Directory Number TO PATH", rdata, payload_len); /* * Request: volume byte, directory number dword LO-HI, namespace byte. * Reply: length-preceded path components, no volume component. */ if (payload_len >= 6) { int volume = (int)rdata[0]; uint32 dirnum = GET_32(rdata+1); int namspace = (int)rdata[5]; result = map_directory_number_to_path(volume, dirnum, namspace, responsedata, sizeof(IPX_DATA) - sizeof(NCPRESPONSE)); if (result > -1) data_len = result; else completition = (uint8)(-result); } else { completition = 0x9c; } } break; case 0xf4: { /* Map PATH TO Dir Entry */ int payload_len = requestlen - 3; int result; if (payload_len < 0) payload_len = 0; ncp23_debug_dump("NCP23/F4 Map PATH TO Dir Entry", rdata, payload_len); /* * Request: dir handle byte, path length byte, path bytes. * Reply: volume byte, directory number dword LO-HI. */ if (payload_len >= 2 && payload_len >= 2 + (int)rdata[1]) { struct XDATA { uint8 volume; uint8 dirnum[4]; } *xdata = (struct XDATA*)responsedata; result = conn_map_path_to_dir_entry((int)rdata[0], rdata+2, (int)rdata[1], &(xdata->volume), xdata->dirnum); if (result) completition = (uint8)(-result); else data_len = sizeof(struct XDATA); } else { completition = 0x9c; } } break; default : return(-1); break; } /* switch (ufunc) */ } /* case 0x17 */ break; case 0x18 : /* End of Job */ if (!(entry8_flags&0x200)) /* pcz: 14-Apr-00 */ free_connection_task_jobs(ncprequest->task); nw_free_handles(ncprequest->task); return(-1); /* nwbind must do a little rest */ break; case 0x19 : /* logout, some of this call is handled in ncpserv. */ free_queue_jobs(); nw_free_handles(-1); set_nw_user(-1, -1, 0, 0, NULL, -1, NULL, 0, NULL); return(-1); /* nwbind must do a little rest */ break; case 0x1a : /* Log Physical Record */ case 0x1c : /* Release Physical Record */ case 0x1e : /* Clear Physical Record */ { /* * SDK: NCP 0x2222/26 Log Physical Record records one * byte range in the caller's logged data block table. * Lock Flag 0 logs for future locking, 1 locks * exclusive, and 3 locks shareable/read-only. * * SDK: NCP 0x2222/28 Release Physical Record releases * one locked byte range but leaves it in the logged * table so a later Lock Physical Record Set can relock * it. The request carries a reserved byte, a 6-byte * NetWare file handle, Start Offset, and Record Length; * it returns no reply data and reports Unlock Error * through the completion code. * * SDK: NCP 0x2222/30 Clear Physical Record releases the * range if it is locked and removes it from the logged * table. * * The physical-record set table is maintained alongside * the existing low-level byte-range lock implementation: * log/lock records are added on successful 0x1a calls, * release leaves the set entry intact, and clear removes * the matching set entry after a successful unlock. */ struct INPUT { uint8 header[7]; /* Requestheader */ uint8 lock_flag; /* 0=log/reserved, 1=excl */ /* 3=shared */ uint8 ext_fhandle[2]; /* all zero / high handle */ uint8 fhandle[4]; /* Filehandle */ uint8 offset[4]; uint8 size[4]; uint8 timeout[2]; } *input = (struct INPUT *)ncprequest; int fhandle = GET_32 (input->fhandle); uint32 offset= GET_BE32(input->offset); uint32 size = GET_BE32(input->size); uint16 timeout = GET_BE16(input->timeout); int result; if (function == 0x1a) { /* log or lock */ result = nw_log_physical_record( fhandle, offset, size, timeout, (int)input->lock_flag); if (!result) result = share_set_physrec_add_rm( (int)input->lock_flag, fhandle, offset, size, timeout); } else { result = nw_log_physical_record( fhandle, offset, size, timeout, (function == 0x1c) ? -1 /* unlock only */ : -2 /* unlock + unlog */ ); if (!result && function == 0x1e) result = share_set_physrec_add_rm( -2, fhandle, offset, size, timeout); } if (result) completition = (uint8)-result; } break; case 0x1b : /* Lock Physical Record Set (old) */ case 0x6e : { /* Lock Physical Record Set */ /* * SDK: NCP 0x2222/27 Lock Physical Record Set (old) * and NCP 0x2222/110 Lock Physical Record Set lock all * byte ranges logged by the calling client. * * SDK request: one-byte Lock Flag followed by a 2-byte * Lock Timeout in 1/18 second units. Lock Flag bit 1 * selects shareable/read-only locks; otherwise the set is * locked exclusive/read-write. The reply carries no data * and completion reports success, timeout, or lock error. * * MARS-NWE stores physical-record set entries from Log * Physical Record and routes the set lock through the * shared synchronization-set handler. */ struct INPUT { uint8 header[7]; uint8 lock_flag; uint8 timeout[2]; } *input = (struct INPUT *)ncprequest; int lock_flag = (input->lock_flag & 0x02) ? 3 : 1; int result = share_handle_lock_sets( 4, /* Physical Record Set */ lock_flag, GET_BE16(input->timeout)); if (result) completition = (uint8)-result; } break; case 0x1d : /* Release Physical Record Set */ case 0x1f : { /* Clear Physical Record Set */ /* * SDK: NCP 0x2222/29 Release Physical Record Set * releases all byte ranges locked by the calling client * but leaves them in the client's data byte range table * for future Lock Physical Record Set calls. * * SDK: NCP 0x2222/31 Clear Physical Record Set releases * all locked ranges and clears the caller's data byte * range table. Both calls have no reply data; Clear * carries a one-byte Lock Flags field documented as * 0 = Not Locked. */ int result = share_handle_lock_sets( 4, /* Physical Record Set */ (function==0x1f) ? -2 /* Clear */ : -1, /* Release */ 0); if (result) completition = (uint8)-result; } break; case 0x20 : /* Semaphore */ return(-1); /* handled by nwbind */ case 0x21 : { /* Negotiate Buffer Size, Packetsize */ uint8 *getsize=responsedata; int buffer_size = (int) (GET_BE16((uint8*)requestdata)); /* Der Novell-Client der PAM's Net/E-Ethernetkarte f�r Atari ST/TT meldet ein Packetsize von 0 wenn nwserv NACH dem Novell Client NET_S1.PRG gestartet wird. Da 0 in jedem Falle ein unsinniger Wert ist, wird rw_buffer_size nicht verwendet. Hayo Schmidt <100305.1424@compuserve.com>, 7-Dec-97 */ if (buffer_size >= 512) { rw_buffer_size = min(LOC_RW_BUFFERSIZE, buffer_size); XDPRINTF((3,0, "Negotiate Buffer size = 0x%04x,(%d)", (int) rw_buffer_size, (int) rw_buffer_size)); } else { XDPRINTF((1,0, "Invalid Packetsize = %d, " "Negotiate Buffer Size is set to %d", buffer_size, rw_buffer_size)); } U16_TO_BE16(rw_buffer_size, getsize); data_len = 2; } break; case 0x22 : { /* Transaction Tracking System (TTS) calls */ int ufunc = (int) *requestdata; /* * WebSDK / headers: * NCP 0x2222/34/00 TTS Is Available has no reply data. * Its completion code is the status value: 0x00 means * Transaction Tracking Unavailable, 0xfd means Disabled, * and 0xff means Available. The SDK headers expose this * as NWTTSIsAvailable(). * * MARS-NWE does not implement transaction tracking. Report * the documented unavailable status for the availability * probe, but keep the state-changing TTS subfunctions * unsupported rather than pretending to begin, end, or abort * transactions without rollback semantics. * * Cross-check: lwared and the Rust nwserver code do not * provide a fuller TTS transaction implementation to mirror. */ if (!ufunc) completition=0; /* TTS unavailable */ else completition=0xfb; /* request not known */ } break; case 0x23 : { /* div AFP Calls */ int afp_off = afp_request_offset(); uint8 *afp_req = requestdata + afp_off; int afp_len = requestlen - afp_off; int ufunc = (afp_len > 0) ? (int)*afp_req : -1; /* * NetWare AFP calls are server-side NCP entry points for * Mac namespace semantics: AFP entry IDs, Finder Info, * AppleDouble metadata, resource forks, and per-volume Mac * namespace state. * * WebSDK / headers identify the old NCP 0x2222/35 AFP * subfunctions used by nwafp.h, including AFP Delete * (0x03), Get Entry ID From Name (0x04), Get File * Information (0x05), Get Entry ID From * NetWare Handle (0x06), Rename (0x07), Open File Fork * (0x08), Alloc Temporary Dir Handle (0x0b), Get Entry ID * From Path Name (0x0c), the AFP 2.0 create calls * (0x0d/0x0e), Get/Set File Information (0x0f/0x10), and * Scan File Information (0x11). * * Implement the path-name entry-id probe first because the * SDK helpers use it to test AFP support, then expose the * read-only AFP Get File Information query for the same * SYS:-style path inputs. Both still require * the optional libatalk backend to be present; without a Mac * namespace backend, keep returning invalid namespace. */ if (ufunc == 0x0c) { int result = afp_get_entry_id_from_path_name(afp_req, afp_len, responsedata); if (result > -1) data_len = result; else completition = (uint8)-result; } else if (ufunc == 0x05) { int result = afp_get_file_information(afp_req, afp_len, responsedata); if (result > -1) data_len = result; else completition = (uint8)-result; } else { XDPRINTF((3,0, "AFP call rejected: ufunc=0x%02x (%s), Mac namespace unavailable, libatalk backend=%s", ufunc, afp_call_name(ufunc), nwatalk_backend_available() ? "enabled" : "disabled")); completition=0xbf; /* we say invalid namespace here */ } } break; case 0x3b : /* commit file to disk */ case 0x3d : /* commit file */ { struct INPUT { uint8 header[7]; /* Requestheader */ uint8 reserve; uint8 ext_fhandle[2]; /* all zero */ uint8 fhandle[4]; /* filehandle */ } *input = (struct INPUT *)ncprequest; uint32 fhandle = GET_32(input->fhandle); int result=nw_commit_file(fhandle); if (result<0) completition=(uint8)-result; } break; case 0x3e : { /* FILE SEARCH INIT */ /* returns dhandle for searchings */ int dir_handle = (int)*requestdata; int len = (int)*(requestdata+1); /* pathlen */ uint8 *p = requestdata+2; /* path */ struct XDATA { uint8 volume; /* Volume */ uint8 dir_id[2]; /* Direktory ID */ uint8 searchsequence[2]; uint8 dir_rights; /* Rights */ } *xdata= (struct XDATA*) responsedata; int volume; int searchsequence; int dir_id; int rights = nw_open_dir_handle(dir_handle, p, len, &volume, &dir_id, &searchsequence); if (rights >-1) { xdata->volume = (uint8)volume; U16_TO_BE16((uint16)dir_id, xdata->dir_id); U16_TO_BE16((uint16)searchsequence, xdata->searchsequence); xdata->dir_rights = (uint8)rights; data_len = sizeof(struct XDATA); } else completition = (uint8) -rights; } break; case 0x3f : { /* file search continue */ /* Dir_id is from file search init */ struct INPUT { uint8 header[7]; /* Requestheader */ uint8 volume; /* Volume ID */ uint8 dir_id[2]; /* from File Search Init */ uint8 searchsequence[2]; /* sequence FFFF = first entry */ uint8 search_attrib; /* Attribute */ /* 0 none, 2 HIDDEN, * 4 System , 6 Both, * 0x10 Dir */ uint8 len; /* fnname len */ uint8 data[2]; /* fnname with wildcards */ } *input = (struct INPUT *) ncprequest; int len=input->len ; /* FN Length */ struct XDATA { uint8 searchsequence[2]; /* same as request sequence */ uint8 dir_id[2]; /* Direktory ID */ /* is correct !! */ union { NW_DIR_INFO d; NW_FILE_INFO f; } u; } *xdata = (struct XDATA*)responsedata; int searchsequence = nw_dir_search( (uint8*) &(xdata->u), (int) GET_BE16(input->dir_id), (int) GET_BE16(input->searchsequence), (int) input->search_attrib, input->data, len); if (searchsequence > -1) { U16_TO_BE16((uint16) searchsequence, xdata->searchsequence); memcpy(xdata->dir_id, input->dir_id, 2); data_len = sizeof(struct XDATA); } else completition = (uint8) (- searchsequence); } break; case 0x40 : /* Search for a File */ { struct INPUT { uint8 header[7]; /* Requestheader */ uint8 sequence[2]; /* z.B. 0xff, 0xff */ uint8 dir_handle; /* z.B 0x1 */ uint8 search_attrib; /* z.B. 0x6 */ uint8 len; uint8 data[2]; /* Name */ } *input = (struct INPUT *)ncprequest; struct XDATA { uint8 sequence[2]; /* answer sequence */ uint8 reserved[2]; /* z.B 0x0 0x0 */ union { NW_DIR_INFO d; NW_FILE_INFO f; } u; } *xdata = (struct XDATA*)responsedata; int len = input->len; uint8 my_sequence[2]; int searchsequence; uint32 owner; memcpy(my_sequence, input->sequence, 2); searchsequence = nw_search( (uint8*) &(xdata->u), &owner, (int)input->dir_handle, (int) GET_BE16(my_sequence), (int) input->search_attrib, input->data, len); if (searchsequence > -1) { U16_TO_BE16((uint16) searchsequence, xdata->sequence); data_len = sizeof(struct XDATA); } else completition = (uint8) (- searchsequence); } break; case 0x41 : { /* open file for reading */ struct INPUT { uint8 header[7]; /* Requestheader */ uint8 dirhandle; /* Dirhandle */ uint8 attrib; /* z.B. 0x6 od. 0x4e */ /* O_RDWR|TRUNC 0x6, O_RDONLY 0x6 */ uint8 len; /* namelaenge */ uint8 data[2]; /* Name */ } *input = (struct INPUT *)ncprequest; struct XDATA { uint8 ext_fhandle[2]; /* all zero */ uint8 fhandle[4]; /* File Handle */ uint8 reserved[2]; /* reserved by novell */ NW_FILE_INFO fileinfo; } *xdata= (struct XDATA*)responsedata; int fhandle=nw_creat_open_file((int)input->dirhandle, input->data, input->len, &(xdata->fileinfo), (int)input->attrib, 0x1, /* read access */ 0, (int)(ncprequest->task)); if (fhandle > -1){ U32_TO_32(fhandle, xdata->fhandle); xdata->ext_fhandle[0]=0; xdata->ext_fhandle[1]=0; xdata->reserved[0]=0; xdata->reserved[1]=0; data_len = sizeof(struct XDATA); } else completition = (uint8) (-fhandle); } break; case 0x42 : /* close file */ { struct INPUT { uint8 header[7]; /* Requestheader */ uint8 reserve; uint8 ext_fhandle[2]; /* all zero */ uint8 fhandle[4]; /* filehandle */ } *input = (struct INPUT *)ncprequest; uint32 fhandle = GET_32(input->fhandle); completition = (uint8)(-nw_close_file(fhandle, 0, (int)(ncprequest->task))); #if TEST_FNAME if (!completition && fhandle == test_handle) { do_druck++; test_handle = -1; } #endif } break; case 0x43 : /* creat file, overwrite if exist */ case 0x4D : /* create new file */ { struct INPUT { uint8 header[7]; /* Requestheader */ uint8 dirhandle; uint8 attribute; /* creat Attribute */ uint8 len; uint8 data[1]; /* Name */ } *input = (struct INPUT *)ncprequest; struct XDATA { uint8 ext_fhandle[2]; uint8 fhandle[4]; /* Filehandle */ uint8 reserved[2]; /* reserved by NOVELL */ NW_FILE_INFO fileinfo; } *xdata= (struct XDATA*)responsedata; int fhandle=nw_creat_open_file( (int)input->dirhandle, input->data, (int)input->len, &(xdata->fileinfo), (int)input->attribute, /* 0, 0x2, mst: 26-Sep-99 */ 0x13, /* pcz: 14-Nov-99 */ (function==0x43) ? 1 : 2, (int)(ncprequest->task)); if (fhandle > -1){ data_len = sizeof(struct XDATA); U32_TO_32 (fhandle, xdata->fhandle); xdata->ext_fhandle[0]=0; xdata->ext_fhandle[1]=0; xdata->reserved[0]=0; xdata->reserved[1]=0; #ifdef TEST_FNAME input->data[input->len] = '\0'; if (strstr(input->data, TEST_FNAME)){ test_handle = fhandle; do_druck++; } #endif } else completition = (uint8) (-fhandle); } break; case 0x44 : /* file(s) delete */ { struct INPUT { uint8 header[7]; /* Requestheader */ uint8 dirhandle; /* 0x0 */ uint8 searchattributes; /* 0 none, 2 Hidden, 4 System, 6 Both */ uint8 len; uint8 data[2]; /* Name */ } *input = (struct INPUT *)ncprequest; int err_code = nw_delete_files((int)input->dirhandle, (int)input->searchattributes, input->data, (int)input->len); if (err_code < 0) completition = (uint8) -err_code; } break; case 0x45 : /* rename file */ { struct INPUT { uint8 header[7]; /* Requestheader */ uint8 dir_handle; uint8 searchattrib; uint8 len; uint8 data[2]; /* Name */ } *input = (struct INPUT *)ncprequest; uint8 *p = input->data+input->len; /* reserve z.B. 0x1 */ /* + 1 = len2 */ /* + 1 = data2 */ int errcode = nw_mv_files( (int)input->searchattrib, (int)input->dir_handle, input->data,(int)input->len, (int)input->dir_handle, p+2, (int)*(p+1) ); if (errcode < 0) completition = (uint8) -errcode; } break; case 0x46 : /* set file attributes */ { struct INPUT { uint8 header[7]; /* Requestheader */ uint8 access; /* 0x80, od 0x0 */ /* 0x80 for example is shared */ uint8 dir_handle; uint8 attrib; /* search attrib */ uint8 len; uint8 data[2]; /* filename */ } *input = (struct INPUT *)ncprequest; completition = (uint8) (-nw_set_file_attributes((int)input->dir_handle, input->data, (int)input->len, (int)input->attrib, (int)input->access)); } break; case 0x47 : /* move pointer to end of file ???? */ /* and return filesize ? */ { struct INPUT { uint8 header[7]; /* Requestheader */ uint8 filler; uint8 ext_filehandle[2]; /* all zero */ uint8 fhandle[4]; /* Dateihandle */ } *input = (struct INPUT *)ncprequest; struct XDATA { uint8 size[4]; /* Position ??? */ } *xdata=(struct XDATA*)responsedata; int fhandle = GET_32(input->fhandle); int size = nw_seek_file(fhandle, 0); if (size > -1) { data_len = sizeof(struct XDATA); U32_TO_BE32(size, xdata->size); } else completition = (uint8) -size; } break; case 0x48 : /* read file */ { struct INPUT { uint8 header[7]; /* Requestheader */ uint8 filler; uint8 ext_fhandle[2]; /* all zero */ uint8 fhandle[4]; /* filehandle */ uint8 offset[4]; uint8 max_size[2]; /* byte to readd */ } *input = (struct INPUT *)ncprequest; struct XDATA { uint8 size[2]; /* read bytes */ uint8 data[2]; /* read data */ } *xdata=(struct XDATA*)responsedata; int fhandle = GET_32 (input->fhandle); int max_size = GET_BE16(input->max_size); off_t offset = GET_BE32(input->offset); int zusatz = (offset & 1) ? 1 : 0; int size; if (max_size > rw_buffer_size) { XDPRINTF((1,0, "wanted read=%d byte > %d", max_size, rw_buffer_size)); size = -0x88; /* we say wrong filehandle */ } else size = nw_read_file(fhandle, xdata->data+zusatz, max_size, offset); if (size > -1) { U16_TO_BE16(size, xdata->size); data_len=size+zusatz+2; } else completition = (uint8) -size; } break; case 0x49 : { /* write file */ struct INPUT { uint8 header[7]; /* Requestheader */ uint8 filler; /* 0 Filler ?? */ uint8 ext_handle[2]; uint8 fhandle[4]; /* Dateihandle */ uint8 offset[4]; /* SEEK OFFSET */ uint8 size[2]; /* Datasize */ uint8 data[2]; /* Schreibdaten */ } *input = (struct INPUT *)ncprequest; off_t offset = GET_BE32(input->offset); int fhandle = GET_32 (input->fhandle); int input_size = GET_BE16(input->size); int size = nw_write_file(fhandle, input->data, input_size, offset); if (size < 0) completition = (uint8) -size; else if (size < input_size) completition = (uint8)0xff; } break; case 0x4a : { /* File SERVER COPY */ /* should be OK */ struct INPUT { uint8 header[7]; /* Requestheader */ uint8 reserved; /* Reserved by Novell */ uint8 qext_fhandle[2]; /* ext Filehandle */ uint8 qfhandle[4]; /* Quellfile */ uint8 zext_fhandle[2]; /* ext Filehandle */ uint8 zfhandle[4]; /* Zielfile */ uint8 qoffset[4]; /* SourceFile Offset */ uint8 zoffset[4]; /* DestFile Offset */ uint8 size[4]; /* copysize */ } *input = (struct INPUT *)ncprequest; int qfhandle = GET_32 (input->qfhandle); int zfhandle = GET_32 (input->zfhandle); off_t qoffset = GET_BE32(input->qoffset); off_t zoffset = GET_BE32(input->zoffset); uint32 input_size = GET_BE32(input->size); int size = nw_server_copy(qfhandle, qoffset, zfhandle, zoffset, input_size); if (size < 0) completition = (uint8) -size; else { struct XDATA { uint8 zsize[4]; /* real transfered Bytes */ } *xdata= (struct XDATA*)responsedata; U32_TO_BE32(size, xdata->zsize); data_len = sizeof(struct XDATA); } } break; case 0x4b : { /* set date of file, file will be closed later */ struct INPUT { uint8 header[7]; /* Requestheader */ uint8 filler; uint8 reserve[2]; /* ext Filehandle */ uint8 fhandle[4]; /* Dateihandle */ uint8 zeit[2]; /* time */ uint8 datum[2]; /* date */ } *input = (struct INPUT *)ncprequest; int result = nw_set_fdate_time(GET_32(input->fhandle), input->datum, input->zeit); if (result <0) completition = (uint8) -result; } break; case 0x4c : { /* open file */ struct INPUT { uint8 header[7]; /* Requestheader */ uint8 dirhandle; /* Dirhandle */ uint8 attrib; /* z.B. 0x6 od. 0x4e */ /* O_RDWR|TRUNC 0x6, O_RDONLY 0x6 */ uint8 access; /* z.B. 0x9 od 0x11 od. 0x13 */ /* O_RDWR|TRUNC 0x13, O_RDONLY 0x11 */ /* O_RDWR|TRUNC|O_DENYNONE 0x3 */ /* 0x10 BINAERMODUS ?? */ /* 0x02 do write */ uint8 len; /* namelaenge */ uint8 data[2]; /* Name */ } *input = (struct INPUT *)ncprequest; struct XDATA { uint8 ext_fhandle[2]; /* all zero */ uint8 fhandle[4]; /* Dateihandle */ uint8 reserved[2]; /* reserved by Novell */ NW_FILE_INFO fileinfo; } *xdata= (struct XDATA*)responsedata; int fhandle=nw_creat_open_file((int)input->dirhandle, input->data, input->len, &(xdata->fileinfo), (int)input->attrib, (int)input->access, 0, (int)(ncprequest->task)); if (fhandle > -1){ U32_TO_32 (fhandle, xdata->fhandle); xdata->ext_fhandle[0]=0; xdata->ext_fhandle[1]=0; xdata->reserved[0]=0; xdata->reserved[1]=0; data_len = sizeof(struct XDATA); #ifdef TEST_FNAME input->data[input->len] = '\0'; if (strstr(input->data, TEST_FNAME)){ test_handle = fhandle; do_druck++; } #endif } else completition = (uint8) (-fhandle); } break; #if WITH_NAME_SPACE_CALLS case 0x56 : /* some extended atrribute calls */ { int result = handle_func_0x56(requestdata, responsedata, ncprequest->task); if (result > -1) data_len = result; else completition=(uint8)-result; } break; case 0x57 : /* some new namespace calls */ { int result = handle_func_0x57(requestdata, responsedata, ncprequest->task); if (result > -1) data_len = result; else completition=(uint8)-result; } break; #endif #ifdef _MAR_TESTS_XX case 0x5f : { /* ????????????? UNIX Client */ /* a 4.1 Server also do not know this call */ struct INPUT { uint8 header[7]; /* Requestheader */ uint8 unknown[4]; /* 0x10, 0,0,0 */ } *input = (struct INPUT *)ncprequest; completition = 0; } break; #endif case 0x61 : #if ENABLE_BURSTMODE if (server_version_flags&1) { /* enable Burstmode */ /* Negotiate Buffer Size, Packetsize new ? */ int wantsize = GET_BE16((uint8*)requestdata); /* wantsize is here max. * phys. packet size without MAC-header * e.g. 1500 if ethernet */ int flags = (int) *(requestdata+2); /**** flags *********************** * CHECKSUMMING_REQUESTED 1 * SIGNATURE_REQUESTED 2 * COMPLETE_SIGNATURES_REQUESTED 4 * ENCRYPTION_REQUESTED 8 * LIP_DISABLED 0x80 **********************************/ struct XDATA { uint8 getsize[2]; uint8 socket[2]; /* echo socket */ uint8 flags; /* zero */ } *xdata= (struct XDATA*)responsedata; memset(xdata, 0, sizeof(*xdata)); wantsize = min(IPX_MAX_DATA+30, wantsize); rw_buffer_size = min(RW_BUFFERSIZE, wantsize-64); U16_TO_BE16(wantsize, xdata->getsize); U16_TO_BE16(sock_echo, xdata->socket); data_len = sizeof(*xdata); XDPRINTF((2,0, "Packet Burst negotiate buffer: want=0x%04x reply=0x%04x rw_buffer=0x%04x echo_socket=0x%04x flags=0x%x", (int) GET_BE16((uint8*)requestdata), (int) wantsize, (int) rw_buffer_size, (int) sock_echo, flags)); } else #endif { XDPRINTF((2,0, "Function '0x61' (Burst) not enabled")); completition = 0xfb; /* unknown request */ nw_debug=0; } break; case 0x65 : /* Packet Burst Connection Request */ #if ENABLE_BURSTMODE if (server_version_flags&1) { /* enable burstmode */ struct INPUT { uint8 header[7]; /* Requestheader */ uint8 connid[4]; /* RANDOM ID */ /* build by time() */ uint8 max_packet_size[4]; /* HI-LO */ /* max_packet_size is here max. * phys. packet size without MAC-header * e.g. 1500 if ethernet */ uint8 target_socket[2]; /* HI-LO */ uint8 max_send_size[4]; /* HI-LO */ uint8 max_recv_size[4]; /* HI-LO */ } *input = (struct INPUT *)ncprequest; struct XDATA { uint8 server_id[4]; /* RANDOM ID */ /* build by time() */ uint8 max_packet_size[4]; /* HI-LO */ uint8 max_send_size[4]; /* HI-LO */ uint8 max_recv_size[4]; /* HI-LO */ } *xdata= (struct XDATA*) responsedata; int client_socket=GET_BE16(input->target_socket); uint32 max_packet_size=min(sizeof(IPX_DATA), GET_BE32(input->max_packet_size)-30); U32_TO_BE32(max_packet_size + 30, xdata->max_packet_size); if (!burst_w) burst_w=(BURST_W*)xcmalloc(sizeof(BURST_W)); xfree(burst_w->sendburst); xfree(burst_w->send_buf); xfree(burst_w->recv_buf); burst_w->max_burst_data_size= max_packet_size-sizeof(BURSTPACKET); burst_w->sendburst= (BURSTPACKET*)xcmalloc(max_packet_size); burst_w->ud.udata.buf = (char*)(burst_w->sendburst); burst_w->sendburst->type[0]=0x77; burst_w->sendburst->type[1]=0x77; burst_w->sendburst->streamtyp=2; /* BIG_SEND_BURST */ U32_TO_BE32(time(NULL), burst_w->sendburst->source_conn); U16_TO_16(act_connection, burst_w->sendburst->source_conn); /* we need to identify it */ memcpy(xdata->server_id, burst_w->sendburst->source_conn, 4); memcpy(burst_w->sendburst->dest_conn, input->connid, 4); burst_w->max_send_size= min(max_burst_send_size, GET_BE32(input->max_recv_size)); burst_w->send_buf=xcmalloc(burst_w->max_send_size+8); burst_w->max_recv_size= min(max_burst_recv_size, GET_BE32(input->max_send_size)); #if 1 /* MUST BE REMOVED LATER !!! */ /* we don't want fragmented receive packets */ if (burst_w->max_recv_size > burst_w->max_burst_data_size-24) burst_w->max_recv_size =burst_w->max_burst_data_size-24; #endif burst_w->recv_buf=xcmalloc(burst_w->max_recv_size+24); #if 1 U32_TO_BE32(0x5ff22, burst_w->sendburst->delaytime); #endif U32_TO_BE32(burst_w->max_recv_size, xdata->max_recv_size); U32_TO_BE32(burst_w->max_send_size, xdata->max_send_size); burst_w->ipx_pack_typ = PACKT_CORE; burst_w->ud.opt.len = sizeof(uint8); burst_w->ud.opt.maxlen = sizeof(uint8); burst_w->ud.opt.buf = (char*)&(burst_w->ipx_pack_typ); memcpy(&(burst_w->to_addr), &from_addr, sizeof(ipxAddr_t)); U16_TO_BE16(client_socket, burst_w->to_addr.sock); burst_w->ud.addr.len = sizeof(ipxAddr_t); burst_w->ud.addr.maxlen = sizeof(ipxAddr_t); burst_w->ud.addr.buf = (char*)&(burst_w->to_addr); data_len = sizeof(*xdata); XDPRINTF((2,0, "Packet Burst connection accepted: client_socket=0x%04x max_packet=%u max_data=%u send=%u recv=%u", client_socket, (unsigned)(max_packet_size + 30), (unsigned)burst_w->max_burst_data_size, (unsigned)burst_w->max_send_size, (unsigned)burst_w->max_recv_size)); } else #endif { XDPRINTF((2,0, "Packet Burst Connection Request not enabled")); nw_debug=0; completition = 0xfb; /* unknown request */ } break; case 0x68 : /* NDS NCP, NDS Fragger Protokoll ?? */ XDPRINTF((2,0, "NDS Fragger Protokoll not supportet")); nw_debug=0; completition = 0xfb; /* unknown request */ break; default : completition = 0xfb; /* unknown request */ break; } /* switch function */ } else if (ncp_type == 0x1111) { free_queue_jobs(); (void) nw_init_connect(); last_sequence = -9999; } else { XDPRINTF((1,0, "WRONG TYPE:0x%x", ncp_type)); completition = 0xfb; } if (nw_debug && (completition == 0xfb || (do_druck == 1))) { /* UNKWON FUNCTION od. TYPE */ pr_debug_request(); if (completition == 0xfb) { int req_len = requestlen - sizeof(NCPREQUEST); int subfunc = -1; if (req_len > 2 && (function == 0x15 || function == 0x16 || function == 0x17)) subfunc = requestdata[2]; else if (req_len > 0 && function == 0x20) subfunc = requestdata[0]; if (subfunc > -1) XDPRINTF((0,0, "UNKNOWN FUNCTION or TYPE: type=0x%x func=0x%x ufunc=0x%x", ncp_type, function, subfunc)); else XDPRINTF((0,0, "UNKNOWN FUNCTION or TYPE: type=0x%x func=0x%x", ncp_type, function)); } else if (data_len){ int j = data_len; uint8 *p = responsedata; XDPRINTF((0,2, "RSPONSE: len %d, DATA:", data_len)); while (j--) { int c = *p++; if (c > 32 && c < 127) XDPRINTF((0,3,",\'%c\'", (char) c)); else XDPRINTF((0,3,",0x%x", c)); } XDPRINTF((0,1, NULL)); } } ncp_response(ncprequest->sequence, ncprequest->task, completition, data_len); nw_debug = org_nw_debug; return(0); } static void handle_after_bind() { NCPREQUEST *ncprequest = (NCPREQUEST*) saved_readbuff; uint8 *requestdata = saved_readbuff + sizeof(NCPREQUEST); uint8 *bindresponse = readbuff + sizeof(NCPRESPONSE); int data_len = 0; int completition = 0; switch (ncprequest->function) { /* QUOTA support from: Matt Paley */ case 0x16 : { uint8 ufunc = *(requestdata+2); switch (ufunc) { case 0x21: { /* change Vol restrictions for Obj */ uint8 volnr = *(requestdata+3); uint32 id = GET_BE32(requestdata+4); uint32 blocks = GET_32(requestdata+8); int gid = ((int *) bindresponse)[0]; int uid = ((int *) bindresponse)[1]; int perm = ((int *) bindresponse)[2]; int result; XDPRINTF((5, 0, "Change vol rest id=%x vol=%d blocks=%d gid=%d uid=%d p=%d", (int) id, (int) volnr, (int) blocks, (int) gid, (int) uid, (int) perm)); if (perm == 0) { result = nw_set_vol_restrictions(volnr, uid, blocks); } else { result = -0x85; } if (result < 0) completition = (uint8)-result; } break; case 0x22: { /* Remove Vol restrictions for Obj */ uint8 volnr = *(requestdata+3); uint32 id = GET_BE32(requestdata+4); int gid = ((int *) bindresponse)[0]; int uid = ((int *) bindresponse)[1]; int perm = ((int *) bindresponse)[2]; int result; XDPRINTF((1, 0, "Remove vol rest id=%x vol=%d gid=%d uid=%d p=%d", (int) id, (int) volnr, (int) gid, (int) uid, (int) perm)); if (perm == 0) { result = nw_set_vol_restrictions(volnr, uid, 0); } else { result = -0x85; } if (result < 0) completition = (uint8)-result; } break; case 0x29: { /* Get Vol restrictions for Obj */ uint8 volnr = *(requestdata+3); uint32 id = GET_BE32(requestdata+4); int gid = ((int *) bindresponse)[0]; int uid = ((int *) bindresponse)[1]; int perm = ((int *) bindresponse)[2]; uint32 quota, used; int result; struct XDATA { uint8 restriction[4]; uint8 inuse[4]; } *xdata = (struct XDATA*) responsedata; XDPRINTF((5, 0, "Get vol rest id=%x vol=%d gid=%d uid=%d p=%d", (int) id, (int) volnr, (int) gid, (int) uid, (int) perm)); if (perm == 0) { result = nw_get_vol_restrictions(volnr, uid, "a, &used); } else { result = -0x85; } data_len = 8; if (result == 0) { U32_TO_32(quota, xdata->restriction); U32_TO_32(used, xdata->inuse); } else { U32_TO_32(0x40000000, xdata->restriction); U32_TO_32(0x0, xdata->inuse); completition = (uint8) -result; } } break; default : completition = 0xfb; } break; } case 0x17 : { /* FILE SERVER ENVIRONMENT */ uint8 ufunc = *(requestdata+2); switch (ufunc) { case 0x14: /* Login Objekt, unencrypted passwords */ case 0x18: { /* crypt_keyed LOGIN */ int grpcount = * (int*)(bindresponse + 4 * sizeof(int)); uint32 *grps = (uint32*)(bindresponse + 5 * sizeof(int)); int unxloginlen = (int)*(uint8*)(grps+grpcount); uint8 *unxloginname = (uint8*)(grps+grpcount)+1; uint8 objname[48]; /* ncpserv have changed the structure */ if (ufunc==0x14) { xstrmaxcpy(objname, requestdata+6, (int) *(requestdata+5)); } else if (ufunc==0x18){ xstrmaxcpy(objname, requestdata+14, (int) *(requestdata+13)); } else objname[0]='\0'; set_nw_user(*((int*)bindresponse), /* gid */ *((int*)(bindresponse+sizeof(int))), /* uid */ *((int*)(bindresponse + 2 * sizeof(int))), /* id_flags */ *((uint32*)(bindresponse + 3 * sizeof(int))), /* id */ objname, /* login name */ unxloginlen, unxloginname, grpcount, grps); } break; case 0x68: /* create queue job and file old */ case 0x79: { /* create queue job and file */ /* nwbind made prehandling */ struct INPUT { uint8 header[7]; /* Requestheader */ uint8 packetlen[2]; /* low high */ uint8 func; /* 0x79 or 0x68 */ uint8 queue_id[4]; /* Queue ID */ uint8 queue_job[280]; /* oldsize is 256 */ } *input = (struct INPUT *) (ncprequest); uint32 q_id = GET_BE32(input->queue_id); uint8 *qjob = bindresponse; int result = creat_queue_job( (int) ncprequest->task, q_id, qjob, responsedata, (ufunc == 0x68) ); if (result > -1) data_len=result; else completition = (uint8) -result; } break; case 0x69: /* close file and start queue old ?? */ case 0x7f: { /* close file and start queue */ struct INPUT { uint8 header[7]; /* Requestheader */ uint8 packetlen[2]; /* low high */ uint8 func; /* 0x7f or 0x69 */ uint8 queue_id[4]; /* Queue ID */ uint8 job_id[4]; /* result from creat queue */ /* if 0x69 then only 2 byte ! */ } *input = (struct INPUT *) (ncprequest); struct RINPUT { uint8 client_area[152]; uint8 prc_len; /* len of printcommand */ uint8 prc[1]; /* printcommand */ } *rinput = (struct RINPUT *) (bindresponse); uint32 q_id = GET_BE32(input->queue_id); int job_id = (ufunc==0x69) ? GET_BE16(input->job_id) : GET_BE16(input->job_id); int result = close_queue_job2(q_id, job_id, rinput->client_area, rinput->prc, rinput->prc_len); if (result < 0) completition = (uint8)-result; } break; case 0x71 : /* service queue job (old) */ case 0x7c : { /* service queue job */ struct INPUT { uint8 header[7]; /* Requestheader */ uint8 packetlen[2]; /* low high */ uint8 func; /* 0x7c,0x71 */ uint8 queue_id[4]; /* Queue ID */ uint8 job_typ[2]; /* service typ */ } *input = (struct INPUT *) (ncprequest); uint32 q_id = GET_BE32(input->queue_id); uint8 *qjob = bindresponse; int result = service_queue_job((int)ncprequest->task, q_id, qjob, responsedata, ufunc==0x71); if (result > -1) data_len=result; else completition = (uint8) -result; } break; default : completition = 0xfb; } } break; default : completition = 0xfb; } /* switch */ ncp_response(ncprequest->sequence, ncprequest->task, completition, data_len); } #if ENABLE_BURSTMODE static int send_burst(int offset, int datasize, int flags) { BURSTPACKET *sb=burst_w->sendburst; U32_TO_BE32(burst_w->packet_sequence++, sb->packet_sequence); U32_TO_BE32(offset, sb->burstoffset); U16_TO_BE16(datasize, sb->datasize); U16_TO_BE16(0, sb->missing); sb->flags = (uint8)flags; memcpy(sb+1, burst_w->send_buf+offset, datasize); burst_w->ud.udata.len = burst_w->ud.udata.maxlen = datasize+sizeof(BURSTPACKET); XDPRINTF((8, 0, "Packet Burst send packet: seq=%u off=%d size=%d flags=0x%x", (unsigned)(burst_w->packet_sequence-1), offset, datasize, flags)); if (t_sndudata(FD_NCP_OUT, &(burst_w->ud)) < 0){ if (nw_debug) t_error("t_sndudata in NWCONN !OK"); return(-1); } return(0); } #include static void sleep_mu(int mu) { struct timeval t; t.tv_sec = 0; t.tv_usec = mu; (void) select(1, NULL, NULL, NULL, &t); } static void handle_burst_response(uint32 offset, int size) { BURSTPACKET *sb=burst_w->sendburst; U16_TO_BE16(burst_w->burst_sequence, sb->burst_seq); U16_TO_BE16(burst_w->burst_sequence+1, sb->ack_seq); U32_TO_BE32(size, sb->burstsize); XDPRINTF((3, 0, "Packet Burst response: seq=%u offset=%u size=%d max_packet_data=%d", (unsigned)burst_w->burst_sequence, (unsigned)offset, size, burst_w->max_burst_data_size)); while (size) { int sendsize=min(size, burst_w->max_burst_data_size); int flags=0; size-=sendsize; if (!size) flags|=0x10; /* EndOfBurst */ send_burst(offset, sendsize, flags); #if 0 sleep_mu(2); #endif offset+=sendsize; } } static void handle_burst(BURSTPACKET *bp, int len) { if (burst_w) { uint32 burstoffset = GET_BE32(bp->burstoffset); int burstsequence = GET_BE16(bp->burst_seq); int datasize = GET_BE16(bp->datasize); XDPRINTF((6, 0, "Packet Burst recv packet: seq=%d flags=0x%x off=%u datasize=%d len=%d", burstsequence, bp->flags, (unsigned)burstoffset, datasize, len)); if (datasize && !(bp->flags & 0x80)) { /* copy if no System Packet */ if (datasize+burstoffset > burst_w->max_recv_size+24) { XDPRINTF((1, 0, "recv burstpacket offs=%d+size=%d > max_recv+24=%d", burstoffset, datasize, burst_w->max_recv_size+24)); return; } memcpy(burst_w->recv_buf+burstoffset, bp+1, datasize); } if (bp->flags & 0x10) { /* last packet, now action */ /* 0x10 = EOB flag */ struct REQ { uint8 function[4]; /* lo-hi 1=READ, 2=WRITE */ uint8 fhandle[4]; /* from open file */ uint8 reserved1[4]; /* all zero */ uint8 reserved2[4]; /* ??? c8,0 od. c9,f0 */ uint8 file_offset[4]; /* HI-LO */ uint8 file_size [4]; /* HI-LO */ uint8 data[2]; /* only Write */ } *req=(struct REQ*)(burst_w->recv_buf); int function=GET_32(req->function); if (function == 1 || function == 2) { /* Read or Write */ uint32 fhandle = GET_32(req->fhandle); uint32 foffset = GET_BE32(req->file_offset); uint32 fsize = GET_BE32(req->file_size); if (function == 1) { /* Read Request */ struct XDATA { uint8 resultcode[4]; /* lo-hi , * 0=noerror=OK, * 1=init-err, * 2=IO-err, * 3=no data */ uint8 readbytes[4]; /* hi-lo */ } *xdata= (struct XDATA*)burst_w->send_buf; int zusatz = 0; /* (foffset & 1) ? 1 : 0; */ int size; XDPRINTF((2, 0, "Packet Burst READ request: fh=0x%x off=%u size=%u seq=%d", (unsigned)fhandle, (unsigned)foffset, (unsigned)fsize, burstsequence)); size = nw_read_file(fhandle, burst_w->send_buf+sizeof(struct XDATA), fsize, foffset); if (zusatz) { XDPRINTF((1, 0, "foffset=%d, fsize=%d", foffset, fsize)); } if (size > -1) { U32_TO_32(0, xdata->resultcode); U32_TO_BE32(size, xdata->readbytes); XDPRINTF((2, 0, "Packet Burst READ reply: fh=0x%x off=%u requested=%u read=%d", (unsigned)fhandle, (unsigned)foffset, (unsigned)fsize, size)); } else { U32_TO_32(3, xdata->resultcode); U32_TO_BE32(0, xdata->readbytes); size=0; } burst_w->burst_sequence = burstsequence; handle_burst_response(0, size+sizeof(struct XDATA)); } else { /* Write Request */ struct XDATA { uint8 resultcode[4]; /* lo-hi , * 0=noerror=OK, * 4=write error */ } *xdata= (struct XDATA*)burst_w->send_buf; int size; XDPRINTF((2, 0, "Packet Burst WRITE request: fh=0x%x off=%u size=%u seq=%d", (unsigned)fhandle, (unsigned)foffset, (unsigned)fsize, burstsequence)); size = nw_write_file(fhandle, req->data, fsize, foffset); U32_TO_32(size==fsize ? 0 : 4, xdata->resultcode); XDPRINTF((2, 0, "Packet Burst WRITE reply: fh=0x%x off=%u requested=%u written=%d result=%s", (unsigned)fhandle, (unsigned)foffset, (unsigned)fsize, size, size==fsize ? "ok" : "error")); burst_w->burst_sequence = burstsequence; handle_burst_response(0, sizeof(struct XDATA)); } } else { XDPRINTF((1, 0, "burst unknow function=0x%x", function)); } req->function[0]=0; } else if (bp->flags & 0x80) { /* System Flag */ int missing=GET_BE16(bp->missing); uint8 *p=(uint8*)(bp+1); burst_w->burst_sequence = burstsequence; XDPRINTF((3, 0, "Packet Burst missing-list request: seq=%d missing=%d", burstsequence, missing)); while (missing--){ int offs=GET_BE32(p); int size=GET_BE16(p+4); XDPRINTF((3, 0, "Packet Burst resend range: off=%d size=%d", offs, size)); handle_burst_response(offs, size); p+=6; } } } else { XDPRINTF((1, 0, "burst_w not allocated")); } } #endif static void close_all(void) { nw_exit_connect(); close(0); close(FD_NCP_OUT); } static int fl_get_int=0; /* signals * &01 sig_quit * &02 sig_hup * &04 sig_usr1 * &08 sig_usr2 */ static void sig_quit(int rsig) { XDPRINTF((2, 0, "Got Signal=%d", rsig)); fl_get_int |= 1; } static void sig_pipe(int rsig) { XDPRINTF((1, 0, "Got SIG_PIPE")); signal(SIGPIPE, sig_pipe); } static void sig_hup(int rsig) { fl_get_int |= 2; signal(SIGHUP, sig_hup); } static void sig_usr1(int rsig) { fl_get_int |= 4; } static void sig_usr2(int rsig) { fl_get_int |= 8; } static void get_new_debug(void) { get_ini_debug(3); fl_get_int &= ~2; } static void handle_extern_command(void) { fl_get_int &= ~4; signal(SIGUSR1, sig_usr1); } static void handle_sigusr2(void) { char fn[256]; FILE *f; fl_get_int &= ~8; sprintf(fn, "/tmp/nwconn%04d.log", act_connection); if (seteuid(0)) {} unlink(fn); /* security: mst:18-Apr-00 */ f=fopen(fn, "w"); (void)reseteuid(); if (f) { log_file_module(f); fclose(f); } else errorp(0, "handle_sigusr2", "cannot open %s for writing", fn); signal(SIGUSR2, sig_usr2); } static void set_sig(void) { signal(SIGTERM, sig_quit); signal(SIGQUIT, sig_quit); signal(SIGINT, sig_quit); signal(SIGPIPE, sig_pipe); signal(SIGHUP, sig_hup); signal(SIGUSR1, sig_usr1); signal(SIGUSR2, sig_usr2); if (use_mmap) signal(SIGBUS, sig_bus_mmap); /* in nwfile.c */ } #include int main(int argc, char **argv) { #if !CALL_NWCONN_OVER_SOCKET int shm_id; #endif time_t last_time=time(NULL); #if CALL_NWCONN_OVER_SOCKET if (argc != 4 || 3!=sscanf(argv[3], "()INIT-:%x,%x,%x-", &father_pid, &sock_nwbind, &sock_echo)) { fprintf(stderr, "usage nwconn connid FROM_ADDR ()INIT-:pid,nwbindsock,echosock-\n"); exit(1); } #else if (argc != 4 || 4!=sscanf(argv[3], "()INIT-:%x,%x,%x,%x-", &father_pid, &sock_nwbind, &sock_echo, &shm_id)) { fprintf(stderr, "usage nwconn connid FROM_ADDR ()INIT-:pid,nwbindsock,echosock,shm_id-\n"); exit(1); } #endif prog_title=argv[3]; if (setuid(0)) {} if (setgid(0)) {} act_connection = atoi(*(argv+1)); #if !CALL_NWCONN_OVER_SOCKET nwconn_state = shmat(shm_id, NULL, SHM_W); if (nwconn_state == (char *)-1) { errorp(0, "Can't attach shared memory segment", NULL); exit(1); } #endif init_tools(NWCONN, 0); memset(saved_readbuff, 0, sizeof(saved_readbuff)); XDPRINTF((3, 0, "FATHER PID=%d, ADDR=%s CON:%d", father_pid, *(argv+2), act_connection)); adr_to_ipx_addr(&from_addr, *(argv+2)); if (nw_init_connect()) exit(1); act_pid = getpid(); #ifdef LINUX set_emu_tli(); #endif last_sequence = -9999; if (get_ipx_addr(&my_addr)) exit(1); #if CALL_NWCONN_OVER_SOCKET # if 1 # ifdef SIOCIPXNCPCONN { int conn = act_connection; int result = ioctl(0, SIOCIPXNCPCONN, &conn); XDPRINTF((3, 0, "ioctl:SIOCIPXNCPCONN result=%d", result)); } # endif # endif #endif set_default_guid(); nwconn_set_program_title(NULL); ud.opt.len = sizeof(uint8); ud.opt.maxlen = sizeof(uint8); ud.opt.buf = (char*)&ipx_pack_typ; ud.addr.len = sizeof(ipxAddr_t); ud.addr.maxlen = sizeof(ipxAddr_t); ud.addr.buf = (char*)&from_addr; ud.udata.buf = (char*)&ipxdata; U16_TO_BE16(0x3333, ncpresponse->type); ncpresponse->task = (uint8) 1; /* allways 1 */ ncpresponse->connection = (uint8)act_connection; ncpresponse->high_connection = (uint8)(act_connection >> 8); set_sig(); while ( !(fl_get_int&1) ) { int data_len; /* We should reply 'Request Being Processed' if request arrived twice * or more and nwconn actually busy, if nwconn is free, we are simply * resend previous reply. * We are set the flag in shared memory indicating what nwconn is busy * and check it later in ncpserv. /lenz */ #if !CALL_NWCONN_OVER_SOCKET nwconn_state[act_connection] = 0; /* nwconn is free */ #endif data_len = read(0, readbuff, sizeof(readbuff)); #if !CALL_NWCONN_OVER_SOCKET nwconn_state[act_connection] = 1; /* nwconn is busy */ #endif /* this read is a pipe or a socket read, * depending on CALL_NWCONN_OVER_SOCKET */ if (fl_get_int) { if (fl_get_int & 1) break; if (fl_get_int & 2) get_new_debug(); if (fl_get_int & 4) handle_extern_command(); if (fl_get_int & 8) handle_sigusr2(); } if (data_len > 0) { XDPRINTF((99, 0, "NWCONN GOT DATA len = %d",data_len)); ncpresponse->connect_status = (uint8) 0; ncpresponse->task = ncprequest->task; if ((ncp_type = (int)GET_BE16(ncprequest->type)) == 0x3333) { /* this is a response packet */ data_len -= sizeof(NCPRESPONSE); if (saved_sequence > -1 && ((int)(ncprequest->sequence) == saved_sequence) && !ncprequest->function) { /* comes from nwbind */ handle_after_bind(); } else { /* OK for direct sending */ XDPRINTF((6,0, "NWCONN:direct sending:type 0x3333, completition=0x%x, len=%d", (int)(ncprequest->function), data_len)); if (data_len) memcpy(responsedata, readbuff+sizeof(NCPRESPONSE), data_len); ncpresponse->connect_status = ((NCPRESPONSE*)readbuff)->connect_status; ncp_response(ncprequest->sequence, ncprequest->task, ncprequest->function, data_len); } saved_sequence = -1; } else { /* this calls I must handle, it is a request */ act_time=time(NULL); act_ncpsequence=(int)(ncprequest->sequence); if (act_time > last_time+60 && saved_sequence == -1) { /* ca. 0.5 min. reset wdogs, 5 min as in original is too long for me. /lenz*/ call_nwbind(1); last_time=act_time; } #if ENABLE_BURSTMODE if (ncp_type == 0x7777) { /* BURST-MODE */ XDPRINTF((2, 0, "Packet Burst data packet received: len=%d", data_len)); handle_burst((BURSTPACKET*)readbuff, data_len); } else #endif if (ncp_type == 0x2121) { /* request from nwbind */ /* mst:25-Apr-00 */ requestlen = data_len - sizeof(NCPREQUEST); handle_nwbind_request(); } else { int result; requestlen = data_len - sizeof(NCPREQUEST); if (0 != (result = handle_ncp_serv()) ) { if (result == -2) { /* here the actual call must be saved * because we need it later, when the request to nwbind * returns. */ memcpy(saved_readbuff, readbuff, data_len); saved_sequence = (int)(ncprequest->sequence); } else saved_sequence = -1; /* this call must go to nwbind */ call_nwbind(0); } } } } } /* while */ if (seteuid(0)) {} # ifdef SIOCIPXNCPCONN { int conn = -act_connection; (void)ioctl(0, SIOCIPXNCPCONN, &conn); } # endif close_all(); XDPRINTF((3,0, "leave nwconn pid=%d", getpid())); return(0); }