From 5e6805dd31bb9cb04168fce10368e6e1397f2858 Mon Sep 17 00:00:00 2001 From: Mario Fetka Date: Sun, 13 Nov 2011 00:40:40 +0100 Subject: [PATCH] mars_dosutils-0.01 --- doc | 46 ++++++ e.pck | Bin 0 -> 1848 bytes kern.asm | 201 +++++++++++++++++++++++++++ kern.h | 12 ++ kern.lst | 317 ++++++++++++++++++++++++++++++++++++++++++ login.bat | 4 + login.c | 215 ++++++++++++++++++++++++++++ makefile | 40 ++++++ map.c | 252 +++++++++++++++++++++++++++++++++ mk.bat | 4 + ncpcall.c | 285 ++++++++++++++++++++++++++++++++++++++ net.c | 74 ++++++++++ net.exe | Bin 0 -> 51020 bytes net.h | 202 +++++++++++++++++++++++++++ netcall.c | 408 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ nwcrypt.c | 213 ++++++++++++++++++++++++++++ nwcrypt.h | 7 + nwdebug.c | 36 +++++ nwtests.c | 46 ++++++ slist.c | 15 ++ teste.c | 95 +++++++++++++ tools.c | 201 +++++++++++++++++++++++++++ 22 files changed, 2673 insertions(+) create mode 100755 doc create mode 100755 e.pck create mode 100755 kern.asm create mode 100755 kern.h create mode 100755 kern.lst create mode 100755 login.bat create mode 100755 login.c create mode 100755 makefile create mode 100755 map.c create mode 100755 mk.bat create mode 100755 ncpcall.c create mode 100755 net.c create mode 100755 net.exe create mode 100755 net.h create mode 100755 netcall.c create mode 100755 nwcrypt.c create mode 100755 nwcrypt.h create mode 100755 nwdebug.c create mode 100755 nwtests.c create mode 100755 slist.c create mode 100755 teste.c create mode 100755 tools.c diff --git a/doc b/doc new file mode 100755 index 0000000..9b7bb04 --- /dev/null +++ b/doc @@ -0,0 +1,46 @@ +/* DOC for NET.EXE */ +This is a short description of net.exe which is a simple DOS-client +programm to allow standard NCP network actions, mainly for mars_nwe. +All functions are called as a second parameter. +This programm is very incomplete till now, but some functions +works well with mars_nwe. + +LOGOUT: +Logout from a NCP Server. + +LOGIN: +usage: LOGIN [-u] [user | user password] +-u = use unencrypted password. +With this function you can log into a NCP Server. +Its only make a login, no mappings or something else. + +If you want a login similar to NOVELL's login.exe you should +do it with a batch job. + +example: +[\LOGIN\LOGIN.BAT] +@echo OFF +net logout +net login %1 %2 %3 +if errorlevel 1 goto :end +map h:=HOME: +if not exist h:\profile.bat goto :end +h: +profile.bat +:end + +PASSWD: +usage: PASSWD [user] +With this function you are able to change a users password. +This call uses the old unencryted change password call !! + + +PATH: +usage: PATH sn:[=[path]] + sn = 's1' .. 's16' + +With this function a new path element can be created. +Its only sets the path environment. + + + diff --git a/e.pck b/e.pck new file mode 100755 index 0000000000000000000000000000000000000000..da7271c715cc9feffc1a6f6220a303b6578708fe GIT binary patch literal 1848 zcmd^vJtPeO+s3AziUS<8+mxOf_+jlYLpo8>Ip2^ z8wF*+l1K+*_Nu1 z$Rl+j0?M*@#LH7&;oGM`$t5&@Dd}yh2YQkal(aSN3Hq&#d;ro1tY<_{G;J0dR#+Il zstVLL?GsRMFa(b{2&(mQcv0T^7f9ZjC*-}NP{P<7SczAjvH{6OS<9lVu}`%iz6xmw z$khlYNei>4Vx+}%$oY`^OmCbfy0sz{UGu2#w6!E1gQNh~CM+U3(C~gok8=j;h0QAG z(9zQKXIw vEijASFjG92$zoqD4(OWtgPGz+o-g^qn_qtNjGl2o$k!C?zuhhs^F_V^^%A5) literal 0 HcmV?d00001 diff --git a/kern.asm b/kern.asm new file mode 100755 index 0000000..76dd433 --- /dev/null +++ b/kern.asm @@ -0,0 +1,201 @@ +; kern.asm: 20-Nov-93, 21:52 +IDEAL +P286 +MODEL LARGE +; Fuer Turboc gerettet werden muessen folgende Register: +; BP, SS, SP, DS, CS u. SI, DI + +MACRO P_START + push bp + mov bp, sp +ENDM + +MACRO P_END + pop bp +ENDM + +MACRO PUSH_REGS + push ds + push si + push di +ENDM + +MACRO POP_REGS + pop di + pop si + pop ds +ENDM + +;; EXTRN _esr_routine:FAR + +PUBLIC _IPXinit; +PUBLIC _IPXopen_socket; +PUBLIC _IPXclose_socket; +PUBLIC _IPXlisten; +;; PUBLIC _asm_esr_routine; +PUBLIC _xmemmove; +PUBLIC _Net_Call; + +DATASEG +enterIPX DD FAR + +CODESEG +PROC _IPXinit; + P_START + PUSH_REGS + mov ax, 7A00h + int 2Fh + cmp al, 0FFh + jne @@fertig + mov cx, @data + mov ds, cx + mov [WORD PTR enterIPX], di + mov ax, es + mov [WORD PTR enterIPX+2], ax + mov al, 1 ; OK +@@fertig: + mov ah, 0 + POP_REGS + P_END + ret ; OK = 1 ; nicht ok = 0 +ENDP + +PROC _xmemmove; + ARG z:DATAPTR, q:DATAPTR, nmbr:WORD; Argumente + cli ; Disable Interrupts + push bp + mov bp,sp + mov cx, [nmbr]; + or cx, cx; + jz @@fertig; Anzahl ist 0; + push ds; + push si; + push di; + pushf + lds si, [q] ; Quelle + les di, [z] ; Ziel + cmp di, si ; + jl @@L1 ; Ziel ist kleiner + std ; Richtungsflag setzen + dec cx + add di, cx ; Von oben nach unten kopieren + add si, cx ; + inc cx ; alten Wert wiederherstellen + jmp @@L2; + @@L1: + cld ; Richtungsflag loeschen + @@L2: ; und nun das eigentliche kopieren + REP movsb ; + popf + pop di; + pop si; + pop ds; + @@fertig: + pop bp; + sti ; enable Interrupts + ret +ENDP + +PROC _IPXopen_socket; + ARG sock:WORD, live:WORD + P_START + PUSH_REGS + mov ax, [live] + mov dx, [sock] + mov bx, @data + mov ds, bx + mov bx, 0 + call [enterIPX] + cmp al, 0FFh + jne @@L1 + mov ax, -1 ; Socket already open + jmp @@L3 +@@L1: + cmp al, 0FEh + jne @@L2 + mov ax, -2 ; Socket Table full + jmp @@L3 +@@L2: + mov ax, dx +@@L3: + POP_REGS + P_END + ret +ENDP + +PROC _IPXclose_socket; + ARG sock:WORD + P_START + PUSH_REGS + mov dx, [sock] + mov bx, @data + mov ds, bx + mov bx, 1 + call [enterIPX] + POP_REGS + P_END + ret +ENDP + +PROC _IPXlisten; + ARG ecb:DATAPTR + P_START + PUSH_REGS + les si, [ecb] ; Adresse ecb + mov bx, @data + mov ds, bx + mov bx, 4 + call [enterIPX] + POP_REGS + P_END + mov ah, 0 + ret +ENDP + +;; PROC _asm_esr_routine; +;; push bp; +;; PUSH_REGS; +;; mov ax, @data +;; mov ds, ax ; Fr C PROGRAMM +;; push es; Adressegment vom EBC +;; push si; Adressoffset vom ECB +;; call _esr_routine; C ROUTINE +;; pop si; +;; pop es; +;; POP_REGS; +;; pop bp; +;; cli ; no Interrupt says NOVELL +;; ret +;; ENDP + + +PROC _Net_Call; + ARG func:WORD, req:DATAPTR, repl:DATAPTR; Argumente + push bp + mov bp, sp + mov ax, [func]; + push ds; + push si; + push di; + pushf + lds si, [req] ; Request + les di, [repl] ; Reply + int 21h + popf + pop di; + pop si; + pop ds; + pop bp; + mov ah, 0 + ret +ENDP + +END + + + + + + + + diff --git a/kern.h b/kern.h new file mode 100755 index 0000000..6344225 --- /dev/null +++ b/kern.h @@ -0,0 +1,12 @@ +/* kern.h Assembler Routinen 20-Nov-93 */ +extern int IPXinit(void); +extern int IPXopen_socket(UI sock, int live); +extern void IPXclose_socket(UI sock); +extern int IPXlisten(ECB *ecb); +extern void asm_esr_routine(void); +extern void esr_routine(ECB *ecb); +extern void xmemmove(void *ziel, void *quelle, UI anz); +extern int Net_Call(UI func, void *req, void *repl); + + + diff --git a/kern.lst b/kern.lst new file mode 100755 index 0000000..96fd9cc --- /dev/null +++ b/kern.lst @@ -0,0 +1,317 @@ +Turbo Assembler Version 3.1 28/04/96 13:28:50 Page 1 +kern.asm + + + + 1 ; kern.asm: 20-Nov-93, 21:52 + 2 IDEAL + 3 P286 + 4 0000 MODEL LARGE + 5 ; Fuer Turboc gerettet werden muessen folgende Register: + 6 ; BP, SS, SP, DS, CS u. SI, DI + 7 + 8 MACRO P_START + 9 push bp + 10 mov bp, sp + 11 ENDM + 12 + 13 MACRO P_END + 14 pop bp + 15 ENDM + 16 + 17 MACRO PUSH_REGS + 18 push ds + 19 push si + 20 push di + 21 ENDM + 22 + 23 MACRO POP_REGS + 24 pop di + 25 pop si + 26 pop ds + 27 ENDM + 28 + 29 ;; EXTRN _esr_routine:FAR + 30 + 31 PUBLIC _IPXinit; + 32 PUBLIC _IPXopen_socket; + 33 PUBLIC _IPXclose_socket; + 34 PUBLIC _IPXlisten; + 35 ;; PUBLIC _asm_esr_routine; + 36 PUBLIC _xmemmove; + 37 PUBLIC _Net_Call; + 38 + 39 0000 DATASEG + 40 0000 0000FFFE enterIPX DD FAR + 41 + 42 0004 CODESEG + 43 0000 PROC _IPXinit; + 44 P_START +1 45 0000 55 push bp +1 46 0001 8B EC mov bp, sp + 47 PUSH_REGS +1 48 0003 1E push ds +1 49 0004 56 push si +1 50 0005 57 push di + 51 0006 B8 7A00 mov ax, 7A00h + 52 0009 CD 2F int 2Fh + 53 000B 3C FF cmp al, 0FFh + 54 000D 75 10 jne @@fertig + 55 000F B9 0000s mov cx, @data + 56 0012 8E D9 mov ds, cx + 57 0014 89 3E 0000r mov [WORD PTR enterIPX], di + Turbo Assembler Version 3.1 28/04/96 13:28:50 Page 2 +kern.asm + + + + 58 0018 8C C0 mov ax, es + 59 001A A3 0002r mov [WORD PTR enterIPX+2], ax + 60 001D B0 01 mov al, 1 ; OK + 61 001F @@fertig: + 62 001F B4 00 mov ah, 0 + 63 POP_REGS +1 64 0021 5F pop di +1 65 0022 5E pop si +1 66 0023 1F pop ds + 67 P_END +1 68 0024 5D pop bp + 69 0025 CB ret ; OK = 1 ; nicht ok = 0 + 70 0026 ENDP + 71 + 72 0026 PROC _xmemmove; + 73 ARG z:DATAPTR, q:DATAPTR, nmbr:WORD; Argumente + 74 0026 FA cli ; Disable Interrupts + 75 0027 55 push bp + 76 0028 8B EC mov bp,sp + 77 002A 8B 4E 0E mov cx, [nmbr]; + 78 002D 0B C9 or cx, cx; + 79 002F 74 1F jz @@fertig; Anzahl ist 0; + 80 0031 1E push ds; + 81 0032 56 push si; + 82 0033 57 push di; + 83 0034 9C pushf + 84 0035 C5 76 0A lds si, [q] ; Quelle + 85 0038 C4 7E 06 les di, [z] ; Ziel + 86 003B 3B FE cmp di, si ; + 87 003D 7C 0A jl @@L1 ; Ziel ist kleiner + 88 003F FD std ; Richtungsflag setzen + 89 0040 49 dec cx + 90 0041 03 F9 add di, cx ; Von oben nach unten kopieren + 91 0043 03 F1 add si, cx ; + 92 0045 41 inc cx ; alten Wert wiederherstellen + 93 0046 EB 02 90 jmp @@L2; + 94 0049 @@L1: + 95 0049 FC cld ; Richtungsflag loeschen + 96 004A @@L2: ; und nun das eigentliche kopieren + 97 004A F3> A4 REP movsb ; + 98 004C 9D popf + 99 004D 5F pop di; + 100 004E 5E pop si; + 101 004F 1F pop ds; + 102 0050 @@fertig: + 103 0050 5D pop bp; + 104 0051 FB sti ; enable Interrupts + 105 0052 CB ret + 106 0053 ENDP + 107 + 108 0053 PROC _IPXopen_socket; + 109 ARG sock:WORD, live:WORD + 110 P_START +1 111 0053 55 push bp +1 112 0054 8B EC mov bp, sp + 113 PUSH_REGS +1 114 0056 1E push ds + Turbo Assembler Version 3.1 28/04/96 13:28:50 Page 3 +kern.asm + + + +1 115 0057 56 push si +1 116 0058 57 push di + 117 0059 8B 46 08 mov ax, [live] + 118 005C 8B 56 06 mov dx, [sock] + 119 005F BB 0000s mov bx, @data + 120 0062 8E DB mov ds, bx + 121 0064 BB 0000 mov bx, 0 + 122 0067 FF 1E 0000r call [enterIPX] + 123 006B 3C FF cmp al, 0FFh + 124 006D 75 06 jne @@L1 + 125 006F B8 FFFF mov ax, -1 ; Socket already open + 126 0072 EB 0D 90 jmp @@L3 + 127 0075 @@L1: + 128 0075 3C FE cmp al, 0FEh + 129 0077 75 06 jne @@L2 + 130 0079 B8 FFFE mov ax, -2 ; Socket Table full + 131 007C EB 03 90 jmp @@L3 + 132 007F @@L2: + 133 007F 8B C2 mov ax, dx + 134 0081 @@L3: + 135 POP_REGS +1 136 0081 5F pop di +1 137 0082 5E pop si +1 138 0083 1F pop ds + 139 P_END +1 140 0084 5D pop bp + 141 0085 CB ret + 142 0086 ENDP + 143 + 144 0086 PROC _IPXclose_socket; + 145 ARG sock:WORD + 146 P_START +1 147 0086 55 push bp +1 148 0087 8B EC mov bp, sp + 149 PUSH_REGS +1 150 0089 1E push ds +1 151 008A 56 push si +1 152 008B 57 push di + 153 008C 8B 56 06 mov dx, [sock] + 154 008F BB 0000s mov bx, @data + 155 0092 8E DB mov ds, bx + 156 0094 BB 0001 mov bx, 1 + 157 0097 FF 1E 0000r call [enterIPX] + 158 POP_REGS +1 159 009B 5F pop di +1 160 009C 5E pop si +1 161 009D 1F pop ds + 162 P_END +1 163 009E 5D pop bp + 164 009F CB ret + 165 00A0 ENDP + 166 + 167 00A0 PROC _IPXlisten; + 168 ARG ecb:DATAPTR + 169 P_START +1 170 00A0 55 push bp +1 171 00A1 8B EC mov bp, sp + Turbo Assembler Version 3.1 28/04/96 13:28:50 Page 4 +kern.asm + + + + 172 PUSH_REGS +1 173 00A3 1E push ds +1 174 00A4 56 push si +1 175 00A5 57 push di + 176 00A6 C4 76 06 les si, [ecb] ; Adresse ecb + 177 00A9 BB 0000s mov bx, @data + 178 00AC 8E DB mov ds, bx + 179 00AE BB 0004 mov bx, 4 + 180 00B1 FF 1E 0000r call [enterIPX] + 181 POP_REGS +1 182 00B5 5F pop di +1 183 00B6 5E pop si +1 184 00B7 1F pop ds + 185 P_END +1 186 00B8 5D pop bp + 187 00B9 B4 00 mov ah, 0 + 188 00BB CB ret + 189 00BC ENDP + 190 + 191 ;; PROC _asm_esr_routine; + 192 ;; push bp; + 193 ;; PUSH_REGS; + 194 ;; mov ax, @data + 195 ;; mov ds, ax ; Fr C PROGRAMM + 196 ;; push es; Adressegment vom EBC + 197 ;; push si; Adressoffset vom ECB + 198 ;; call _esr_routine; C ROUTINE + 199 ;; pop si; + 200 ;; pop es; + 201 ;; POP_REGS; + 202 ;; pop bp; + 203 ;; cli ; no Interrupt says NOVELL + 204 ;; ret + 205 ;; ENDP + 206 + 207 + 208 00BC PROC _Net_Call; + 209 ARG func:WORD, req:DATAPTR, repl:DATAPTR; Argumente + 210 00BC 55 push bp + 211 00BD 8B EC mov bp, sp + 212 00BF 8B 46 06 mov ax, [func]; + 213 00C2 1E push ds; + 214 00C3 56 push si; + 215 00C4 57 push di; + 216 00C5 9C pushf + 217 00C6 C5 76 08 lds si, [req] ; Request + 218 00C9 C4 7E 0C les di, [repl] ; Reply + 219 00CC CD 21 int 21h + 220 00CE 9D popf + 221 00CF 5F pop di; + 222 00D0 5E pop si; + 223 00D1 1F pop ds; + 224 00D2 5D pop bp; + 225 00D3 B4 00 mov ah, 0 + 226 00D5 CB ret + 227 00D6 ENDP + 228 + Turbo Assembler Version 3.1 28/04/96 13:28:50 Page 5 +kern.asm + + + + 229 END + Turbo Assembler Version 3.1 28/04/96 13:28:50 Page 6 +Symbol Table + + + + +Symbol Name Type Value + +??DATE Text "28/04/96" +??FILENAME Text "kern " +??TIME Text "13:28:50" +??VERSION Number 030A +@32BIT Text 0 +@@FERTIG Near KERN_TEXT:001F +@@FERTIG Near KERN_TEXT:0050 +@@L1 Near KERN_TEXT:0049 +@@L1 Near KERN_TEXT:0075 +@@L2 Near KERN_TEXT:004A +@@L2 Near KERN_TEXT:007F +@@L3 Near KERN_TEXT:0081 +@CODE Text KERN_TEXT +@CODESIZE Text 1 +@CPU Text 0787H +@CURSEG Text KERN_TEXT +@DATA Text DGROUP +@DATASIZE Text 1 +@FILENAME Text KERN +@INTERFACE Text 00H +@MODEL Text 5 +@STACK Text DGROUP +@WORDSIZE Text 2 +ECB Number [DGROUP:BP+0006] +ENTERIPX Dword DGROUP:0000 +FUNC Number [DGROUP:BP+0006] +LIVE Number [DGROUP:BP+0008] +NMBR Number [DGROUP:BP+000E] +Q Number [DGROUP:BP+000A] +REPL Number [DGROUP:BP+000C] +REQ Number [DGROUP:BP+0008] +SOCK Number [DGROUP:BP+0006] +Z Number [DGROUP:BP+0006] +_IPXCLOSE_SOCKET + Far KERN_TEXT:0086 +(_IPXclose_socket) +_IPXINIT (_IPXinit) Far KERN_TEXT:0000 +_IPXLISTEN (_IPXlisten) Far KERN_TEXT:00A0 +_IPXOPEN_SOCKET + Far KERN_TEXT:0053 +(_IPXopen_socket) +_NET_CALL (_Net_Call) Far KERN_TEXT:00BC +_XMEMMOVE (_xmemmove) Far KERN_TEXT:0026 + +Macro Name + +POP_REGS +PUSH_REGS +P_END +P_START + +Groups & Segments Bit Size Align Combine Class + +DGROUP Group + _DATA 16 0004 Word Public DATA +KERN_TEXT 16 00D6 Word Public CODE + \ No newline at end of file diff --git a/login.bat b/login.bat new file mode 100755 index 0000000..74ee3df --- /dev/null +++ b/login.bat @@ -0,0 +1,4 @@ +c:\net logout +c:\net login %1 %2 %3 +map h:=HOME: + diff --git a/login.c b/login.c new file mode 100755 index 0000000..2ceca64 --- /dev/null +++ b/login.c @@ -0,0 +1,215 @@ +/* login.c 05-Apr-96 */ + +/**************************************************************** + * (C)opyright (C) 1993,1996 Martin Stover, Marburg, Germany * + ****************************************************************/ + +#include "net.h" +#include "nwcrypt.h" + + +static int do_change_object_passwd(char *name, + uint16 objtyp, + char *oldpassword, + char *newpassword) + +{ + uint8 key[8]; + if (0 && !ncp_17_17(key)) { + uint32 objid = ncp_17_35(name, objtyp); + if (objid) { + uint8 buff[128]; + uint8 encrypted[8]; + uint8 newcryptpasswd[16]; + int passwdx=0; + uint8 tmpid[4]; + U32_TO_BE32(objid, tmpid); + shuffle(tmpid, oldpassword, strlen(oldpassword), buff); + nw_encrypt(key, buff, encrypted); + + shuffle(tmpid, newpassword, strlen(newpassword), buff); + + if (!ncp_17_4b(encrypted, name, objtyp, passwdx, newcryptpasswd)) { + ;; + return(0); + } + } + } else { /* now we use old unencrypted algorithmus */ + if (!ncp_17_40(name, objtyp, oldpassword, newpassword)) { + ;; + return(0); + } + } + return(-1); +} + +static int do_object_login(char *name, uint16 objtyp, char *password, int option) +{ + uint8 key[8]; + if (!(option & 1) && !ncp_17_17(key)) { + uint32 objid = ncp_17_35(name, objtyp); + if (objid) { + uint8 buff[128]; + uint8 encrypted[8]; + uint8 tmpid[4]; + U32_TO_BE32(objid, tmpid); + shuffle(tmpid, password, strlen(password), buff); + nw_encrypt(key, buff, encrypted); + if (!ncp_17_18(encrypted, name, objtyp)) { + ;; + return(0); + } + } + } else { /* now we use old unencrypted algorithmus */ + if (!ncp_17_14(name, objtyp, password)) { + return(0); + } + } + return(-1); +} + +static void beep(void) +{ + fprintf(stdout, "\007"); +} + +static int get_raw_str(uint8 *s, int maxlen, int doecho) +/* returns len of readed str */ +{ + int len = 0; + while (len < maxlen){ + int key = getch(); + if (key == '\r' || key == '\n') break; + switch (key) { + case 8 : if (len) { + --len; + --s; + if (doecho) fprintf(stdout, "\010 \010"); + } else beep(); + continue; + + case '\t': beep(); + continue; + + default : *s++=(uint8)key; + len++; + break; + } /* switch */ + if (doecho) fprintf(stdout, "%c", (uint8)key); + } + *s='\0'; + return(len); +} + +static void getstr(char *what, char *str, int rsize, int doecho) +{ + fprintf(stdout, "%s: ", what); + get_raw_str(str, rsize, doecho); + fprintf(stdout, "\n"); +} + +static int login_usage(void) +{ + fprintf(stderr, "usage:\t%s [-u] [user | user password]\n", funcname); + fprintf(stderr, "\t-u : use unecrypted password\n" ); + return(-1); +} + +int func_login(int argc, char *argv[]) +{ + int result=-1; + int option=0; + uint8 uname[200]; + uint8 upasswd[200]; + + if (argc > 1) { + if (argv[1][0] == '-') { + if (argv[1][1] == 'u') option |= 1; + else return(login_usage()); + argc--; + argv++; + } + } + + if (argc > 1) strmaxcpy(uname, argv[1], sizeof(uname) -1); + else uname[0]='\0'; + if (argc > 2) strmaxcpy(upasswd, argv[2], sizeof(upasswd) -1); + else upasswd[0]='\0'; + while (result) { + if (!uname[0]) getstr("login", uname, sizeof(uname)-1, 1); + if (uname[0]) { + upstr(uname); + upstr(upasswd); + if ((result = do_object_login(uname, 0x1, upasswd, option)) < 0 && !*upasswd) { + getstr("Password", upasswd, sizeof(upasswd)-1, 0); + upstr(upasswd); + result = do_object_login(uname, 0x1, upasswd, option); + } + if (result < 0) { + fprintf(stdout, "Login incorrect\n\n"); + uname[0] = '\0'; + upasswd[0] = '\0'; + } + } else break; + } + return(result); +} + +int func_logout(int argc, char *argv[]) +{ + if (logout()) fprintf(stderr, "logout=%d", neterrno); +} + + +int func_passwd(int argc, char *argv[]) +{ + int result=0; + uint8 uname[100]; + uint8 upasswd[130]; + uint32 my_obj_id; + + if (ncp_14_46(&my_obj_id) < 0 || my_obj_id == MAX_U32 || !my_obj_id) { + fprintf(stderr, "Cannot get actual User ID\n"); + result = -1; + } + + if (!result && argc > 1) { + uint32 obj_id; + strmaxcpy(uname, argv[1], sizeof(uname) -1); + upstr(uname); + obj_id = ncp_17_35(uname, 1); + if (!obj_id) { + fprintf(stderr, "Unkwown User: %s\n", uname); + return(-1); + } + } else if (!result) { + uint16 obj_typ; + if (ncp_17_36(my_obj_id, uname, &obj_typ) || obj_typ != 1) { + fprintf(stderr, "Cannot get actual Username\n"); + result=-1; + } + } + if (!result && *uname) { + uint8 newpasswd[130]; + uint8 newpasswd2[130]; + if (my_obj_id == 1L) *upasswd='\0'; + else { + getstr("Old Password", upasswd, sizeof(upasswd)-1, 0); + upstr(upasswd); + } + getstr("New Password", newpasswd, sizeof(newpasswd)-1, 0); + getstr("New Password again", newpasswd2, sizeof(newpasswd2)-1, 0); + if (!strcmp(newpasswd, newpasswd2)) { + upstr(uname); + upstr(newpasswd); + if (do_change_object_passwd(uname, 1, upasswd, newpasswd) < 0) + result = -1; + } else { + result = -1; + fprintf(stderr, "Password misspelled\n"); + } + } + if (result < 0) fprintf(stderr, "Password not changed"); + return(result); +} + diff --git a/makefile b/makefile new file mode 100755 index 0000000..6b0f1ad --- /dev/null +++ b/makefile @@ -0,0 +1,40 @@ +# makefile DOS BCC for simple NET Client for mars_nwe. +# /**************************************************************** +# * (C)opyright (C) 1993,1996 Martin Stover, Marburg, Germany * +# ****************************************************************/ + +O = .obj +E = .exe +A = .lib +S = .asm +C = .c + +INCLUDE=$(BC4)\INCLUDE +LIB=$(BC4)\LIB +CC=bcc -ml -Dmsdos -I$(INCLUDE) +LD=bcc -ml -L$(LIB) +ASFLAGS= -la -mx +AS = tasm +AR = tlib +RM = del + +ASMODS= kern$(O) +CCMODS= tools$(O) netcall$(O) ncpcall$(O) \ + login$(O) map$(O) slist$(O) nwcrypt$(O) \ + nwdebug$(O) nwtests$(O) + +all: net$(E) + +net$(E): net$(O) $(ASMODS) $(CCMODS) + $(LD) net$(O) @&&| +$(ASMODS) +$(CCMODS) +| + +$(C)$(O): + $(CC) -c $*$(C) + +$(S)$(O): + $(AS) $(ASFLAGS) $*$(S) + + diff --git a/map.c b/map.c new file mode 100755 index 0000000..841cb50 --- /dev/null +++ b/map.c @@ -0,0 +1,252 @@ +/* map.c 05-Apr-96 */ + +/**************************************************************** + * (C)opyright (C) 1993,1996 Martin Stover, Marburg, Germany * + ****************************************************************/ + +#include "net.h" + +typedef struct { + uint8 connection; + uint8 volume; + uint8 buff[512]; /* complete path */ + uint8 *path; /* points to path */ +} NWPATH; + +static void show_map(uint8 *drvstr) +{ + int j; + for (j=0; j < 32; j++){ + uint8 connid; + uint8 dhandle; + uint8 flags; + if (*drvstr && (j + 'A' != *drvstr)) continue; + if ((!get_drive_info(j, &connid, &dhandle, &flags)) && flags){ + char servern[52]; + char path[256]; + if (flags & 0x80) { /* lokal DRIVE */ + path[0]= '\\'; + if (j < 2){ + strcpy(path, "DISK LW"); + } else if (getcurdir(j+1, path+1)) { + strcpy(path, "LW !OK"); + } + } else { + if (get_dir_path(dhandle, path)) { + strcpy(path, "DHANDLE !OK"); + } + } + if (connid) { + get_fs_name(connid, servern); + strcat(servern, "\\"); + } else servern[0]='\0'; + printf("MAP %c: = %s%s\n", (char)j+'A', servern, path); + } + } +} +#if 0 +static void do_map(int drive, NWPATH *nwp) +{ + if (drive > -1 && drive < 32) { + uint8 connid; + uint8 dhandle; + uint8 flags; + if ((!get_drive_info(drive, &connid, &dhandle, &flags)) && flags){ + char servern[52]; + char path[256]; + if (flags & 0x80) { /* lokal DRIVE */ + path[0]= '\\'; + if (drive < 2){ + strcpy(path, "DISK LW"); + } else if (getcurdir(drive+1, path+1)) { + strcpy(path, "LW !OK"); + } + } else { + if (get_dir_path(dhandle, path)) { + strcpy(path, "DHANDLE !OK"); + } + } + if (connid) { + get_fs_name(connid, servern); + strcat(servern, "\\"); + } else servern[0]='\0'; + printf("DOMAP %c: = %s%s\n", (char)drive+'A', servern, path); + } + } +} +#endif + +static int do_map(int drive, NWPATH *nwp) +{ + int result = -1; + if (drive > -1 && drive < 32) { + uint8 nmdrive[3]; + nmdrive[0] = drive+'A'; + nmdrive[1] = ':'; + nmdrive[2] = '\0'; + result = redir_device_drive(0x4, nmdrive, nwp->path); + } + return(result); +} + + +static int parse_argv(uint8 *drvstr, NWPATH *nwpath, + int argc, char *argv[], int smode) +{ + int k = 0; + int mode = 0; + uint8 *pd = drvstr; + *drvstr = '\0'; + memset(nwpath, 0, sizeof(NWPATH)); + *(nwpath->buff) = '\0'; + nwpath->path = nwpath->buff; + + while (++k < argc && mode > -1) { + uint8 *p = argv[k]; + while (*p && mode > -1) { + if (!mode) { + if (*p == ':') mode = -1; + else if (smode && *p != 's' && *p != 'S') mode = -1; + } + if (mode < 0) break; + else if (mode < 20) { + if (*p == ':') { + if (!mode || (mode > 1 && (*drvstr != 'S' || !smode))) + mode = -1; + else { + *pd = '\0'; + if (mode > 1) { + *drvstr='s'; + *(drvstr+1)=(uint8) atoi((char*)drvstr+1); + } + mode = 20; + pd = nwpath->buff; + } + } else { + if (++mode == 20) mode = -1; + else { + if (*p > 0x60 && *p < 0x7b) + *pd++ = *p - 0x20; /* upshift */ + else + *pd++ = *p; + } + } + } else if (mode == 20) { + if (*p == '=') mode = 30; + else if (*p != ' ' && *p != '\t') mode = -2; + } else if (mode == 30) { + if (*p != ' ' && *p != '\t') { + mode = 40; + continue; + } + } else if (mode == 40) { + if (*p > 0x60 && *p < 0x7b) + *pd++ = *p - 0x20; /* upshift */ + else + *pd++ = *p; + } + p++; + } /* while *p */ + } /* while k */ + if (mode == 30) { + getcwd((char *)nwpath->buff, sizeof(nwpath->buff)); + mode = 40; + } + if (mode && mode != 20 && mode != 40) { + fprintf(stderr, "Cannot interpret line. errcode=%d\n", mode); + return(mode < 0 ? mode : -3); + } + return(0); +} + +int func_map(int argc, char *argv[]) +{ + uint8 drvstr[22]; + NWPATH nwpath; + if (!ipx_init()) argc = 1; + if (!parse_argv(drvstr, &nwpath, argc, argv, 0)) { + if (*(nwpath.path)) { + if (do_map(*drvstr - 'A', &nwpath)< 0) + fprintf(stderr, "MAP Error\n"); + } + show_map(drvstr); + return(0); + } + return(1); +} +/* ------------------------------------------------- */ +static int show_search(uint8 *drvstr) +{ + SEARCH_VECTOR drives; + SEARCH_VECTOR_ENTRY *p=drives; + int j=0; + get_search_drive_vektor(drives); + while (p->drivenummer != 0xff && j++ < 16) { + char path[256]; + char nwname[256]; + if ( !*drvstr || j == *(drvstr+1)) { + if (p->flags && !(p->flags & 0x80)){ + get_fs_name(p->u.fs.connid, nwname); + if (get_dir_path(p->u.fs.dhandle, path)) { + strcpy(path, "ERROR NW"); + } + (void)xadd_char(nwname, '\\', 20); + } else { + nwname[0] = '\0'; + /* + nwname[0] = '<'; + strcpy(nwname+1, "LOCAL"); + */ + if (p->drivenummer == 0xfe){ + strcpy(path, p->u.d.dospath); + } else if (getcurdir((int)(p->drivenummer)+1, path)) { + strcpy(path, "ERROR DOS"); + } + /* + (void)xadd_char(nwname, '>', 20); + */ + } + strcat(nwname, path); + printf("SEARCH%2d = %c: %s\n", j, (char)(p->drivenummer)+'A', nwname); + } + p++; + } + return(0); +} + +static int set_search(uint8 *drvstr, NWPATH *nwp) +{ + int result=-1; + SEARCH_VECTOR drives; + SEARCH_VECTOR_ENTRY *p=drives; + int j=0; + int entry = (*drvstr=='s') ? *(drvstr+1) : 0; + get_search_drive_vektor(drives); + while (p->drivenummer != 0xff && j++ < 16) { + if (!entry && (p->drivenummer + 'A' == *drvstr)) entry=j; + p++; + } + if (entry > 0) { + if (entry > 16) entry = 16; + if (--entry < j) p = drives+entry; + else (p+1)->drivenummer = 0xff; + p->drivenummer = 0xfe; + strcpy(p->u.d.dospath, nwp->path); + result = set_search_drive_vektor(drives); + } + return(result); +} + +int func_path(int argc, char *argv[]) +{ + uint8 drvstr[22]; + NWPATH nwpath; + if (!parse_argv(drvstr, &nwpath, argc, argv, 1)) { + int result=0; + if (*(nwpath.path)) result=set_search(drvstr, &nwpath); + show_search(drvstr); + return(result); + } + return(1); +} + diff --git a/mk.bat b/mk.bat new file mode 100755 index 0000000..db2def5 --- /dev/null +++ b/mk.bat @@ -0,0 +1,4 @@ +maker %1 %2 %3 %4 > err +type err +copy net.exe c:\ +del net.exe diff --git a/ncpcall.c b/ncpcall.c new file mode 100755 index 0000000..2d5da94 --- /dev/null +++ b/ncpcall.c @@ -0,0 +1,285 @@ +/* ncpcall.c 14-Mar-96 */ + +/**************************************************************** + * (C)opyright (C) 1993,1996 Martin Stover, Marburg, Germany * + ****************************************************************/ + +#include "net.h" + +/* ---------------- 0x16 ----------------------------------- */ +int ncp_16_02(int dirhandle, + uint8 *path, + int *sub_dir, + uint8 *resultpath, + uint32 *creattime, + uint32 *owner_id) + +/* returns max. rights or -1 if failed */ +{ + struct { + uint16 len; + uint8 func; + uint8 dirhandle; + uint8 sub_dir[2]; + uint8 pathlen; + uint8 path[256]; + } req; + struct { + uint16 len; + uint8 sub_dir_name[16]; + uint8 create_date_time[4]; + uint8 owner_id[4]; /* HI LOW */ + uint8 max_right_mask; + uint8 reserved; /* Reserved by Novell */ + uint8 sub_dir_nmbr[2]; /* HI LOW */ + } repl = { sizeof(repl) - sizeof(uint16) }; + req.func = 0x02; + U16_TO_BE16((sub_dir) ? *sub_dir : 1, req.sub_dir); + req.dirhandle = (uint8) dirhandle; + req.pathlen = (uint8) ((path) ? strlen(path) : 0); + req.len = 5 + req.pathlen; + strmaxcpy(req.path, path, req.pathlen); + neterrno = Net_Call(0xE200, &req, &repl); + if (neterrno) return(-1); + if (resultpath) strmaxcpy(resultpath, repl.sub_dir_name, 16); + if (sub_dir) *sub_dir = GET_BE16(repl.sub_dir_nmbr); + if (creattime) *creattime = GET_BE32(repl.create_date_time); + if (owner_id) *owner_id = GET_BE32(repl.owner_id); + return((int) repl.max_right_mask); +} + +/* ---------------- 0x17 ----------------------------------- */ +int ncp_17_02(int module, int debuglevel) +/* debuglevel fuer module setzen */ +{ + struct { + uint16 len; + uint8 func; + uint8 module; + uint8 debug; + } req = { sizeof(req) - sizeof(uint16) }; + struct { + uint16 len; + uint8 olddebug; + } repl = { sizeof(repl) - sizeof(uint16) }; + req.func = 0x2; + req.module = (uint8) module; + req.debug = (uint8) debuglevel; + neterrno = Net_Call(0xE300, &req, &repl); + if (neterrno) return(-1); + return((int) repl.olddebug); +} + +int ncp_17_14(uint8 *objname, uint16 objtyp, uint8 *password) +/* login unencreypted */ +{ + struct { + uint16 len; + uint8 func; + uint8 typ[2]; + uint8 namlen; + uint8 buff[48+1+128]; + } req; + struct { + uint16 len; + } repl= { 0 }; + uint8 *p=req.buff; + req.func = 0x14; + U16_TO_BE16(objtyp, req.typ); + req.namlen = min(47, strlen(objname)); + memcpy(p, objname, req.namlen); + p += req.namlen; + *p = (uint8) min(128, strlen(password)); + req.len = 4 + req.namlen + 1 + *p; + memcpy(p+1, password, (int) *p); + neterrno = Net_Call(0xE300, &req, &repl); + if (neterrno) return(-1); + return(0); +} + +int ncp_17_17(uint8 *key) +/* get crypt key */ +{ + struct { + uint16 len; + uint8 func; + } req; + struct { + uint16 len; + uint8 key[8]; + } repl; + req.len = 1; + req.func = 0x17; + repl.len = 8; + neterrno = Net_Call(0xE300, &req, &repl); + if (neterrno) return(-1); + else { + memcpy(key, repl.key, 8); + return(0); + } +} + +int ncp_17_18(uint8 *cryptkey, uint8 *objname, uint16 objtyp) +/* keyed login */ +{ + struct { + uint16 len; + uint8 func; + uint8 key[8]; + uint8 typ[2]; + uint8 namlen; + uint8 name[48]; + } req; + struct { + uint16 len; + } repl={ 0 }; + req.len = sizeof(req) - sizeof(uint16); + req.func = 0x18; + U16_TO_BE16(objtyp, req.typ); + req.namlen = min(sizeof(req.name), strlen(objname)); + memcpy(req.key, cryptkey, 8); + memcpy(req.name, objname, (int) req.namlen); + neterrno = Net_Call(0xE300, &req, &repl); + if (neterrno) return(-1); + return(0); +} + +uint32 ncp_17_35(uint8 *objname, uint16 objtyp) +/* get bindery object id */ +{ + struct { + uint16 len; + uint8 func; + uint8 typ[2]; + uint8 namlen; + uint8 name[48]; + } req; + struct { + uint16 len; + uint8 object_id[4]; + uint8 object_type[2]; + uint8 object_name[48]; + } repl; + req.len = sizeof(req) - sizeof(uint16); + repl.len = sizeof(repl) - sizeof(uint16); + req.func = 0x35; + U16_TO_BE16(objtyp, req.typ); + req.namlen = min(sizeof(req.name), strlen(objname)); + memcpy(req.name, objname, (int) req.namlen); + neterrno = Net_Call(0xE300, &req, &repl); + if (neterrno) return(0L); + strmaxcpy(objname, repl.object_name, 47); + return(GET_BE32(repl.object_id)); +} + +int ncp_17_36(uint32 obj_id, uint8 *objname, uint16 *objtyp) +/* get bindery object name */ +{ + struct { + uint16 len; + uint8 func; + uint8 id[4]; + } req; + struct { + uint16 len; + uint8 object_id[4]; + uint8 object_type[2]; + uint8 object_name[48]; + } repl; + req.len = sizeof(req) - sizeof(uint16); + repl.len = sizeof(repl) - sizeof(uint16); + req.func = 0x36; + U32_TO_BE32(obj_id, req.id); + neterrno = Net_Call(0xE300, &req, &repl); + if (neterrno) return(-1); + if (objname) strmaxcpy(objname, repl.object_name, 47); + if (objtyp) *objtyp = GET_BE16(repl.object_type); + return(0); +} + + +int ncp_17_40(uint8 *objname, uint16 objtyp, + uint8 *password, uint8 *newpassword) +/* change password unencreypted */ +{ + struct { + uint16 len; + uint8 func; + uint8 typ[2]; + uint8 namlen; + uint8 buff[48+1+128+1+128]; + } req; + struct { + uint16 len; + } repl = { 0 }; + uint8 *p=req.buff; + req.func = 0x40; + U16_TO_BE16(objtyp, req.typ); + req.namlen = min(47, strlen(objname)); + memcpy(p, objname, req.namlen); + p += req.namlen; + *p = (uint8) min(128, strlen(password)); + req.len = 4 + req.namlen + 1 + *p; + memcpy(p+1, password, (int) *p); + p += (1 + *p); + *p = (uint8) min(128, strlen(newpassword)); + req.len += (1 + *p); + memcpy(p+1, newpassword, (int) *p); + neterrno = Net_Call(0xE300, &req, &repl); + if (neterrno) return(-1); + return(0); +} + +int ncp_14_46(uint32 *obj_id) +/* get bindery access level & actual ID */ +{ + struct { + uint16 len; + uint8 func; + } req; + struct { + uint16 len; + uint8 access; + uint8 id[4]; + } repl; + req.len = 1; + req.func = 0x46; + repl.len = 5; + neterrno = Net_Call(0xE300, &req, &repl); + if (neterrno) return(-1); + else { + if (obj_id) *obj_id = GET_BE32(repl.id); + return(repl.access); + } +} + + +int ncp_17_4b(uint8 *cryptkey, uint8 *objname, uint16 objtyp, + int passwx, uint8 *newpassword) +/* keyed change password */ +{ + struct { + uint16 len; + uint8 func; + uint8 key[8]; + uint8 typ[2]; + uint8 namlen; + uint8 buff[48+1+16]; + } req; + struct { + uint16 len; + } repl = { 0 }; + uint8 *p = req.buff; + req.func = 0x4b; + memcpy(req.key, cryptkey, 8); + U16_TO_BE16(objtyp, req.typ); + req.namlen = (uint8) min(48, strlen(objname)); + req.len = 12 + req.namlen + 1 + 16; + memcpy(p, objname, (int) req.namlen); + p += req.namlen; + *p++ = (uint8) passwx; + memcpy(p, newpassword, 16); + neterrno = Net_Call(0xE300, &req, &repl); + if (neterrno) return(-1); + return(0); +} diff --git a/net.c b/net.c new file mode 100755 index 0000000..8ee55cd --- /dev/null +++ b/net.c @@ -0,0 +1,74 @@ +/* net.c 14-Mar-96 */ +/* simple client programm to act with mars_nwe */ + +/**************************************************************** + * (C)opyright (C) 1993,1996 Martin Stover, Marburg, Germany * + ****************************************************************/ + +#include "net.h" +char *funcname=NULL; +typedef int (*NET_FUNC)(int argc, char *argv[]); + +static struct s_net_functions { + char *name; + char *description; + NET_FUNC func; +} net_functions[] = { +{"LOGIN", "login to Server as User" , func_login }, +{"MAP", "list maps and map drives" , func_map }, +{"PATH", "list and set search path" , func_path }, +{"LOGOUT", "logout from Server", func_logout }, +#if 0 +{"SLIST", "list Servers", func_slist }, +#endif +{"PASSWD", "change password", func_passwd }, +#if 1 +{"TESTS", "only testroutines!", func_tests }, +#endif +{"DEBUG", "set debug level, for mars_nwe only !", func_debug } +}; + +#define MAX_FUNCS (sizeof(net_functions) / sizeof(struct s_net_functions)) + +int main(int argc, char *argv[]) +{ + NET_FUNC func = NULL; + int result = -1; + if (argc > 1) { + char funcn[200]; + int k= MAX_FUNCS; + strmaxcpy(funcn, argv[1], sizeof(funcn)-1); + upstr(funcn); + while (k--) { + if (!strcmp(funcn, net_functions[k].name)) { + func=net_functions[k].func; + funcname=net_functions[k].name; + break; + } + } + } + if (func != NULL) { + if (ipx_init() || func == func_map) { + result = (*func) (argc-1, &(argv[1])); + } + } else { + int k= MAX_FUNCS; + char progname[256]; + strmaxcpy(progname, argv[0], sizeof(progname)-1); + upstr(progname); + fprintf(stderr, "\n" + "****************************************************************\n" + "* (C)opyright (C) 1993,1996 Martin Stover, Marburg, Germany *\n" + "****************************************************************\n\n" ); + fprintf(stderr, "Usage:\t%s func ... \nfuncs:", progname); + while (k--) { + if (net_functions[k].func) { + fprintf(stderr, "\t%s\t: %s\n", + net_functions[k].name, net_functions[k].description); + } + } + } + return(result); +} + + diff --git a/net.exe b/net.exe new file mode 100755 index 0000000000000000000000000000000000000000..77dd44adf8d9568ae9cf1fb1a2ac5754382453e8 GIT binary patch literal 51020 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 literal 0 HcmV?d00001 diff --git a/net.h b/net.h new file mode 100755 index 0000000..54cf5f6 --- /dev/null +++ b/net.h @@ -0,0 +1,202 @@ +/* net.h: 01-Feb-96 */ + +/**************************************************************** + * (C)opyright (C) 1993,1996 Martin Stover, Marburg, Germany * + ****************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef unsigned int UI; +typedef unsigned char UC; +typedef unsigned char uint8; +typedef unsigned short int uint16; +typedef unsigned long int uint32; + +typedef union REGS REGS; +typedef struct SREGS SREGS; + +typedef void (*FUNC_VOID)(); +typedef int (*FUNC_INT)(); + + +typedef struct { + uint8 checksum[2]; + uint16 packetlen; + uint8 tcontrol; + uint8 ptype; + uint8 dest_net[4]; + uint8 dest_node[6]; + uint16 dest_sock; /* HI LOW */ + uint8 source_net[4]; + uint8 source_node[6]; + uint16 source_sock; /* HI LOW */ +} IPX_HEADER; + +typedef struct { + uint8 *link_address; + FUNC_VOID esr_routine; + uint8 in_use_flag; + uint8 completition_code; + uint16 socket; /* HI LOW */ + uint8 ipx_workspace[4]; /* interner Gebrauch */ + uint8 drv_workspace[4]; /* interner Gebrauch */ + uint8 immediate_address[6]; /* HI LOW Node Address */ + uint16 fragment_count; /* Anzahl Fragment Buffers */ + uint8 *fragment_1; + uint16 fragment_1_size; + /* K”nnen auch mehr sein */ +} ECB; + +#include "kern.h" + +#define UI2NET(i) ( ( (i) << 8) | ( ((i)>>8) & 0xFF) ) +#define NET2UI(i) ( ( (i) << 8) | ( ((i)>>8) & 0xFF) ) + +#define U16_TO_BE16(u, b) { uint16 a=(u); \ + *( (uint8*) (b) ) = *( ((uint8*) (&a)) +1); \ + *( ((uint8*) (b)) +1) = *( (uint8*) (&a)); } + + +#define U32_TO_BE32(u, ar) { uint32 a= (u); uint8 *b= ((uint8*)(ar))+3; \ + *b-- = (uint8)a; a >>= 8; \ + *b-- = (uint8)a; a >>= 8; \ + *b-- = (uint8)a; a >>= 8; \ + *b = (uint8)a; } + +#define U16_TO_16(u, b) { uint16 a=(u); memcpy(b, &a, 2); } +#define U32_TO_32(u, b) { uint32 a=(u); memcpy(b, &a, 4); } + +#define GET_BE16(b) ( (int) *(((uint8*)(b))+1) \ + | ( ( (int) *( (uint8*)(b) ) << 8) ) ) + +#define GET_BE32(b) ( (uint32) *(((uint8*)(b))+3) \ + | ( ((uint32) *(((uint8*)(b))+2) ) << 8) \ + | ( ((uint32) *(((uint8*)(b))+1) ) << 16) \ + | ( ((uint32) *( (uint8*)(b) ) ) << 24) ) + + +#define GET_16(b) ( (int) *( (uint8*)(b) ) \ + | ( ( (int) *(((uint8*)(b))+1) << 8) ) ) + +#define GET_32(b) ( (uint32) *( (uint8*)(b) ) \ + | ( ((uint32) *(((uint8*)(b))+1) ) << 8) \ + | ( ((uint32) *(((uint8*)(b))+2) ) << 16) \ + | ( ((uint32) *(((uint8*)(b))+3) ) << 24) ) + +#define MAX_U32 ((uint32)0xffffffffL) +#define MAX_U16 ((uint16)0xffff) + +#define NWSERV 1 +#define NCPSERV 2 +#define NWCONN 3 +#define NWCLIENT 4 +#define NWBIND 5 + +/* net.c */ +extern char *funcname; + +/* tools.c */ +extern void clear_kb(void); +extern int key_pressed(void); +extern int ask_user(char *p, ...); +extern int strmaxcpy(char *dest, char *source, int len); +extern char *xadd_char(char *s, int c, int maxlen); +extern uint8 *upstr(uint8 *s); + +#define add_char(s, c) xadd_char((s), (c), -1) + +extern char *getglobenv(char *option); +extern int putglobenv(char *option); + +/* NETCALLS */ +#define DRIVE_ADD 1 +#define DRIVE_INSERT 2 +#define DRIVE_DELETE 3 + +typedef struct { + uint8 drivenummer; /* 0xff, 0xfe fr DOSPATH mit Pfad */ + uint8 flags; + union { + struct { + char dospath[65]; + } d; + struct fs { + uint8 connid; + uint8 dhandle; + } fs; + } u; +} SEARCH_VECTOR_ENTRY; + +typedef SEARCH_VECTOR_ENTRY SEARCH_VECTOR[17]; + +extern int neterrno; + +#define alloc_permanent_dir_handle(dhandle, path, drive, rights) \ + alloc_dir_handle(0x12, (dhandle), (path), (drive), (rights)) + +#define alloc_temp_dir_handle(dhandle, path, drive, rights) \ + alloc_dir_handle(0x13, (dhandle), (path), (drive), (rights)) + +extern int ipx_init(void); + +extern int alloc_dir_handle(int func, int dhandle, char *path, + int driveletter, uint8 *effrights); + +extern int dealloc_dir_handle(int dhandle); + +extern int get_dir_path(uint8 dhandle, char *path); +extern int get_volume_name(uint8 nr, char *name); + +extern int get_search_drive_vektor(SEARCH_VECTOR_ENTRY *vec); +extern int set_search_drive_vektor(SEARCH_VECTOR_ENTRY *vec); + +/********* ncpcall.h ***********/ +extern int ncp_16_02(int dirhandle, + uint8 *path, + int *sub_dir, + uint8 *resultpath, + uint32 *creattime, + uint32 *owner_id); + +extern int ncp_17_02(int module, int debuglevel); +extern int ncp_17_14(uint8 *objname, uint16 objtyp, uint8 *password); +extern int ncp_17_17(uint8 *key); +extern int ncp_17_18(uint8 *cryptkey, uint8 *objname, uint16 objtyp); +extern uint32 ncp_17_35(uint8 *objname, uint16 objtyp); +extern int ncp_17_40(uint8 *objname, uint16 objtyp, uint8 *password, + uint8 *newpassword); + +extern int ncp_17_4b(uint8 *cryptkey, uint8 *objname, uint16 objtyp, + int passwx, uint8 *newpassword); + +/* map.c */ +extern int func_map(int argc, char *argv[]); +extern int func_path(int argc, char *argv[]); + +/* login.c */ +extern int func_login(int argc, char *argv[]); +extern int func_logout(int argc, char *argv[]); +extern int func_passwd(int argc, char *argv[]); + +/* slist.c */ +extern int func_slist(int argc, char *argv[]); + +/* nwdebug.c */ +extern int func_debug(int argc, char *argv[]); + +/* nwtests.c */ +extern int func_tests(int argc, char *argv[]); + + + + diff --git a/netcall.c b/netcall.c new file mode 100755 index 0000000..25fc654 --- /dev/null +++ b/netcall.c @@ -0,0 +1,408 @@ +/* netcall.c: 05-Apr-96 */ + +/**************************************************************** + * (C)opyright (C) 1993,1996 Martin Stover, Marburg, Germany * + ****************************************************************/ + +#include "net.h" + +int neterrno=0; + +int ipx_init(void) +{ +static int ipx_is_init=0; +static int ipx_is_ok =0; + if (!ipx_is_init) { + ipx_is_init++; + ipx_is_ok = IPXinit(); + } + return(ipx_is_ok); +} + +static void *get_shell_ptr(uint16 func) +{ + if (ipx_init()) { + void *p = NULL; + REGS regs; + SREGS sregs; + regs.x.ax = func; + if (!(intdosx(®s, ®s, &sregs) & 0xff)) + p = MK_FP(sregs.es, regs.x.si); + return(p); + } else return(NULL); +} + +int detach(int servernmbr) +{ + REGS regsin, regsout; + regsin.x.ax = 0xf101; + regsin.x.dx = servernmbr; + return(intdos(®sin, ®sout) & 0xff); +} + +int logout(void) +{ + REGS regsin, regsout; + regsin.x.ax = 0xd700; + return(intdos(®sin, ®sout) & 0xff); +} + +int redir_device_drive(int devicetyp, uint8 *devname, uint8 *remotename) +/* if devicetyp == -1, the redir is canceled */ +{ + REGS regs; + SREGS sregs; + int result; + uint8 buff1[16]; + uint8 buff2[128]; + uint8 *ldevname = buff1; + uint8 *lremotename = buff2; + strncpy(ldevname, devname, 16); + regs.x.ax = (devicetyp == -1) ? 0x5f04 : 0x5f03; + regs.h.bl = (uint8)devicetyp; + regs.x.cx = 0x574e; /* user sign 'NW' */ + sregs.ds = FP_SEG(ldevname); + regs.x.si = FP_OFF(ldevname); + if (devicetyp > -1) { + strncpy(lremotename, remotename, 128); + sregs.es = FP_SEG(lremotename); + regs.x.di = FP_OFF(lremotename); + } + result = intdosx(®s, ®s, &sregs); + return(regs.x.cflag ? -result : 0); +} + +int list_redir(int index, int *devicetyp, uint8 *devname, uint8 *remotename) +{ + REGS regs; + SREGS sregs; + int result; + uint8 buff1[16]; + uint8 buff2[128]; + uint8 *ldevname = buff1; + uint8 *lremotename = buff2; + memset(ldevname, 0, sizeof(buff1)); + memset(lremotename, 0, sizeof(buff2)); + regs.x.ax = 0x5f02; + regs.x.bx = index; + regs.x.cx = 0x574e; /* user sign 'NW' */ + sregs.ds = FP_SEG(ldevname); + regs.x.si = FP_OFF(ldevname); + sregs.es = FP_SEG(lremotename); + regs.x.di = FP_OFF(lremotename); + result = intdosx(®s, ®s, &sregs); + if (!regs.x.cflag) { + if (devname) strcpy(devname, ldevname); + if (remotename) strcpy(remotename, lremotename); + if (devicetyp) *devicetyp = (int)regs.h.bl; + return((int)regs.h.bh); + } else return(-result); +} + +int get_drive_info(uint8 drivenumber, uint8 *connid, + uint8 *dhandle, uint8 *statusflags) + +/* drivenumber 0 .. 31 */ +{ + uint8 *drive_handle_table = get_shell_ptr(0xef00); + uint8 *drive_flag_table = get_shell_ptr(0xef01); + uint8 *drive_conn_table = get_shell_ptr(0xef02); + + if ( !drive_handle_table + || !drive_flag_table + || !drive_conn_table + || drivenumber > 31) { + char path[100]; + if (drivenumber < 2 || !getcurdir(drivenumber+1, path)) { + *dhandle = 0; + *connid = 0; + *statusflags = 0x80; + return(0); + } + return(-1); + } + *dhandle = *(drive_handle_table+ drivenumber); + *connid = *(drive_conn_table + drivenumber); + *statusflags = *(drive_flag_table + drivenumber); + return(0); +} + +typedef struct { + char fsname[8][48]; +} SERVER_NAME_TABLE; + +int get_fs_name(int connid, char *name) +/* Connection 1 .. 8 */ +{ + SERVER_NAME_TABLE *sf_t = get_shell_ptr(0xef04); + if (sf_t && connid > 0 && connid-- < 8){ + strmaxcpy(name, sf_t->fsname[connid], 48); + return(0); + } + name[0] = '\0'; + return(-11); +} + +static char *path_env_name="PATH"; + +int get_search_drive_vektor(SEARCH_VECTOR_ENTRY *vec) +/* maximal 16 Entries */ +{ + char *path=getglobenv(path_env_name); + SEARCH_VECTOR_ENTRY *v = vec; + int anz=0; + v->drivenummer = 0xff; + if (path){ + while (*path && anz++ < 16){ + char *p1 = path; + int len = 0; + while (*path && *path++ !=';') len++; + if (*(p1+1) == ':' + && *p1 >= 'A' && *p1 <= 'Z' && + (len==2 || (len == 3 && *(p1+2) == '.'))) { + v->drivenummer = *p1 - 'A'; + get_drive_info(v->drivenummer, &(v->u.fs.connid), + &(v->u.fs.dhandle), &(v->flags)); + } else { + v->flags = 0; + v->drivenummer = 0xfe; /* ergibt ? */ + strmaxcpy(v->u.d.dospath, p1, len); + } + (++v)->drivenummer = 0xff; + if (*path == ';') path++; + } + } + return(0); +} + +int set_search_drive_vektor(SEARCH_VECTOR_ENTRY *vec) +{ + char path[256]; + char *p=path; + SEARCH_VECTOR_ENTRY *v; + int plen=strlen(path_env_name); + strcpy(path, path_env_name); + path[plen] = '='; + path[++plen] = '\0'; + while ((NULL != (v = vec++)) && v->drivenummer != 0xff){ + if (p > path) *p++=';'; + else p+=plen; + if (v->drivenummer < 26) { + *p++ = (char) v->drivenummer + 'A'; + *p++ = ':'; + *p++ = '.'; + *p = '\0'; + } else { + strcpy(p, v->u.d.dospath); + p+= strlen(v->u.d.dospath); + } + } + return(putglobenv(path)); +} + +int alloc_dir_handle(int func, + int dhandle, + char *path, + int driveletter, + uint8 *effrights) +{ + int pathlen = (path == NULL) ? 0 : strlen(path); + struct { + uint16 len; + uint8 func; + uint8 dhandle; + uint8 drive; + uint8 pathlen; + uint8 path[256]; + } req; + struct { + uint16 len; + uint8 newhandle; + uint8 effrights; + } repl; + req.func = (uint8)func; + req.dhandle = (uint8)dhandle; + req.drive = (uint8)driveletter; + req.pathlen = (uint8)pathlen; + xmemmove(req.path, path, pathlen); + req.len = 4 + pathlen; + repl.len = 2; +/* + printf("alloc_dir_handle, path=%s, len=%d, disk=%c\n", path, pathlen, driveletter); +*/ + neterrno = Net_Call(0xE200, &req, &repl); + fprintf(stderr, "neterrno=%d\n", neterrno); + if (neterrno && neterrno != 0xff) return(-1); + + if (effrights) *effrights = repl.effrights; + return((int)repl.newhandle); +} + +int dealloc_dir_handle(int dhandle) +{ + struct { + uint16 len; + uint8 func; + uint8 dhandle; + } req; + struct { + uint16 len; + } repl; + req.len = 2; + req.func = 0x14; + req.dhandle = (uint8)dhandle; + repl.len = 0; + neterrno = Net_Call(0xE200, &req, &repl); + if (neterrno) return(-1); + else return(0); +} + +int set_dir_path(uint8 desthandle, uint8 handle, char *path) +/* Set Directory Handle */ +{ + struct { + uint16 len; + uint8 func; + uint8 desth; + uint8 sourceh; + uint8 pathlen; + uint8 path[256]; + } req; + struct { + uint16 len; + } repl; + req.pathlen = (path) ? strlen(path) : 0; + if (req.pathlen) memcpy(req.path, path, (int)req.pathlen); + req.len = 4+req.pathlen; + req.func = 0; + req.sourceh = handle; + req.desth = desthandle; + repl.len = 0; + neterrno = Net_Call(0xE200, &req, &repl); + return( (neterrno) ? -1 : 0); +} + +int get_dir_path(uint8 dhandle, char *path) +{ + struct { + uint16 len; + uint8 data[2]; + } req; + struct { + uint16 len; + uint8 pathlen; + uint8 path[255]; + } repl; + req.len = 2; + req.data[0] = 0x1; + req.data[1] = dhandle; + repl.len = 256; + neterrno = Net_Call(0xE200, &req, &repl); + if (neterrno) return(-1); + else { + strmaxcpy(path, repl.path, (int)repl.pathlen); + return(0); + } +} + +int get_volume_name(uint8 nr, char *name) +{ + struct { + uint16 len; + uint8 func; + uint8 nr; + } req; + struct { + uint16 len; + uint8 namlen; + uint8 name[16]; + } repl; + req.len = 2; + req.func = 0x6; + req.nr = nr; + repl.len = 17; + neterrno = Net_Call(0xE200, &req, &repl); + if (neterrno) return(-1); + else { + strmaxcpy(name, repl.name, (int)repl.namlen); + return(0); + } +} + + +int save_dir_handle(uint8 dhandle, uint8 *savebuffer) +{ + struct { + uint16 len; + uint8 func; + uint8 dhandle; + } req; + struct { + uint16 len; + uint8 savebuffer[16]; + } repl; + req.len = 2; + req.func = 0x17; + req.dhandle = dhandle; + repl.len = 16; + neterrno = Net_Call(0xE200, &req, &repl); + if (neterrno) return(-1); + else { + xmemmove(savebuffer, repl.savebuffer, 16); + return(0); + } +} + +int restore_dir_handle(uint8 *savebuffer, uint8 *dhandle, uint8 *effrights) +{ + struct { + uint16 len; + uint8 func; + uint8 savebuffer[16]; + } req; + struct { + uint16 len; + uint8 dhandle; + uint8 effrights; + } repl; + req.len = 17; + req.func = 0x18; + repl.len = 2; + xmemmove(req.savebuffer, savebuffer, 16); + neterrno = Net_Call(0xE200, &req, &repl); + if (neterrno) return(-1); + else { + *dhandle = repl.dhandle; + *effrights = repl.effrights; + return(0); + } +} + + + + + + + + + + +int mapdrive(uint8 connection, uint8 dhandle, char *path, + uint8 searchflag, uint8 searchorder, + uint8 *driveletter, uint8 *newdhandle, uint8 *effrights) + +/* Searchorder 0 normal Drive; 1..16 Searchdrives */ +/* searchflag only if Searchdrive : */ +/* DRIVE_ADD, DRIVE_INSERT, DRIVE_DELETE */ +{ + + + return(-1); +} + + + + + + + diff --git a/nwcrypt.c b/nwcrypt.c new file mode 100755 index 0000000..507ce54 --- /dev/null +++ b/nwcrypt.c @@ -0,0 +1,213 @@ +/*$********************************************************* +$* +$* This code has been taken from DDJ 11/93, from an +$* article by Pawel Szczerbina. +$* +$* Password encryption routines follow. +$* Converted to C from Barry Nance's Pascal +$* prog published in the March -93 issue of Byte. +$* +$* Adapted to be useable for ncpfs by +$* Volker Lendecke in +$* October 1995. +$* +$* Stolen to be useable for mars_nwe by +$* Martin Stover in +$* Dezember 1995. +$**********************************************************/ + +/**************************************************************************** + +I read that Novell is not very open when it comes to technical details +of the Netware Core Protocol. This might be especially true for the +encryption stuff. I took the necessary code from Dr. Dobb's Journal +11/93, Undocumented Corner. I asked Jon Erickson about +the legal status of this piece of code: + + +--- +Date: Thu, 12 Oct 1995 13:44:18 +0100 +From: Volker Lendecke +To: jon@ddj.com +Subject: legal status of your source code? + + +Hello! + +I hope that you're the right one to write to, you are the first on your WWW +server. If you are not, could you please forward this message to the right +person? Thanks. + +I'm currently exploring the possibility to write a free (in the GNU GPL +sense) NCP filesystem, which would allow me to access a novell server +transparently. For that I would like to use the encryption functions you +published in DDJ 11/93, Undocumented Corner. I would make some cosmetic +changes, such as other indentations, minor code changes and so on. But I do +not know if that allows me to publish this code under GPL. One alternative +would be to publish a diff against your listing, but that would probably +contain much of your code as well, and it would be very inconvenient for +the average user. + +I think that you have some kind of standard procedure for such a +case. Please tell me what I should do. + +Many thanks in advance, + + Volker + + +=================================================================+ + ! Volker Lendecke Internet: lendecke@namu01.gwdg.de ! + ! D-37081 Goettingen, Germany ! + +=================================================================+ + +-- + + +I got the following answer: + +--- +From: Jon Erickson +X-Mailer: SCO System V Mail (version 3.2) +To: lendecke@namu01.gwdg.de +Subject: Re: legal status of your source code? +Date: Thu, 12 Oct 95 5:42:56 PDT + +Volker, +Code from Dr. Dobb's Journal related articles is provided for +anyone to use. Clearly, the author of the article should be +given credit. +Jon Erickson + +--- + +With this answer in mind, I took the code and made it a bit more +C-like. The original seemed to be translated by a mechanical pascal->c +translator. Jon's answer encouraged me to publish nwcrypt.c under the +GPL. If anybody who knows more about copyright and sees any problems +with this, please tell me. +****************************************************************************/ + +/******************* Data types ***************************/ +typedef unsigned char buf32[32]; +typedef unsigned char buf16[16]; +typedef unsigned char buf8[8]; +typedef unsigned char buf4[4]; +typedef unsigned char u8; + +static u8 encrypttable[256] = +{0x7,0x8,0x0,0x8,0x6,0x4,0xE,0x4,0x5,0xC,0x1,0x7,0xB,0xF,0xA,0x8, + 0xF,0x8,0xC,0xC,0x9,0x4,0x1,0xE,0x4,0x6,0x2,0x4,0x0,0xA,0xB,0x9, + 0x2,0xF,0xB,0x1,0xD,0x2,0x1,0x9,0x5,0xE,0x7,0x0,0x0,0x2,0x6,0x6, + 0x0,0x7,0x3,0x8,0x2,0x9,0x3,0xF,0x7,0xF,0xC,0xF,0x6,0x4,0xA,0x0, + 0x2,0x3,0xA,0xB,0xD,0x8,0x3,0xA,0x1,0x7,0xC,0xF,0x1,0x8,0x9,0xD, + 0x9,0x1,0x9,0x4,0xE,0x4,0xC,0x5,0x5,0xC,0x8,0xB,0x2,0x3,0x9,0xE, + 0x7,0x7,0x6,0x9,0xE,0xF,0xC,0x8,0xD,0x1,0xA,0x6,0xE,0xD,0x0,0x7, + 0x7,0xA,0x0,0x1,0xF,0x5,0x4,0xB,0x7,0xB,0xE,0xC,0x9,0x5,0xD,0x1, + 0xB,0xD,0x1,0x3,0x5,0xD,0xE,0x6,0x3,0x0,0xB,0xB,0xF,0x3,0x6,0x4, + 0x9,0xD,0xA,0x3,0x1,0x4,0x9,0x4,0x8,0x3,0xB,0xE,0x5,0x0,0x5,0x2, + 0xC,0xB,0xD,0x5,0xD,0x5,0xD,0x2,0xD,0x9,0xA,0xC,0xA,0x0,0xB,0x3, + 0x5,0x3,0x6,0x9,0x5,0x1,0xE,0xE,0x0,0xE,0x8,0x2,0xD,0x2,0x2,0x0, + 0x4,0xF,0x8,0x5,0x9,0x6,0x8,0x6,0xB,0xA,0xB,0xF,0x0,0x7,0x2,0x8, + 0xC,0x7,0x3,0xA,0x1,0x4,0x2,0x5,0xF,0x7,0xA,0xC,0xE,0x5,0x9,0x3, + 0xE,0x7,0x1,0x2,0xE,0x1,0xF,0x4,0xA,0x6,0xC,0x6,0xF,0x4,0x3,0x0, + 0xC,0x0,0x3,0x6,0xF,0x8,0x7,0xB,0x2,0xD,0xC,0x6,0xA,0xA,0x8,0xD}; + +static buf32 encryptkeys = +{0x48,0x93,0x46,0x67,0x98,0x3D,0xE6,0x8D, + 0xB7,0x10,0x7A,0x26,0x5A,0xB9,0xB1,0x35, + 0x6B,0x0F,0xD5,0x70,0xAE,0xFB,0xAD,0x11, + 0xF4,0x47,0xDC,0xA7,0xEC,0xCF,0x50,0xC0}; + +#include "nwcrypt.h" +static void +shuffle1(buf32 temp, unsigned char *target) +{ + short b4; + unsigned char b3; + int s, b2, i; + + b4 = 0; + + for (b2 = 0; b2 <= 1; ++b2) + { + for (s = 0; s <= 31; ++s) + { + b3 = (temp[s]+b4) ^ (temp[(s+b4)&31] - encryptkeys[s]); + b4 = b4 + b3; + temp[s] = b3; + } + } + + for (i = 0; i <= 15; ++i) { + target[i] = encrypttable[temp[ 2*i ]] + | (encrypttable[temp[ 2*i + 1]] << 4); + } +} + + +void +shuffle(unsigned char *lon, const unsigned char *buf, int buflen, + unsigned char *target) +{ + int b2, d, s; + buf32 temp; + + while ( (buflen > 0) + && (buf[buflen - 1] == 0)) { + buflen = buflen - 1; + } + + for (s = 0; s < 32; s++) { + temp[s] = 0; + } + + d = 0; + while (buflen >= 32) + { + for (s = 0; s <= 31; ++s) + { + temp[s] = temp[s] ^ buf[d]; + d = d + 1; + } + buflen = buflen - 32; + } + b2 = d; + if (buflen > 0) + { + for (s = 0; s <= 31; ++s) + { + if (d + buflen == b2) + { + b2 = d; + temp[s] = temp[s] ^ encryptkeys[s]; + } else { + temp[s] = temp[s] ^ buf[b2]; + b2 = b2 + 1; + } + } + } + + for (s = 0; s <= 31; ++s) + temp[s] = temp[s] ^ lon[s & 3]; + + shuffle1(temp,target); +} + + +void +nw_encrypt(unsigned char *fra,unsigned char *buf,unsigned char *til) +{ + buf32 k; + int s; + + shuffle(&(fra[0]), buf, 16, &(k[ 0])); + shuffle(&(fra[4]), buf, 16, &(k[16])); + + for (s = 0; s <= 15; ++s) + k[s] = k[s] ^ k[31 - s]; + + for (s = 0; s <= 7; ++s) + til[s] = k[s] ^ k[15 - s]; +} + + diff --git a/nwcrypt.h b/nwcrypt.h new file mode 100755 index 0000000..3876b0b --- /dev/null +++ b/nwcrypt.h @@ -0,0 +1,7 @@ +/* nwcrypt.h */ +extern void shuffle(unsigned char *lon, + const unsigned char *buf, int buflen, + unsigned char *target); + +extern void nw_encrypt(unsigned char *fra, + unsigned char *buf,unsigned char *til); diff --git a/nwdebug.c b/nwdebug.c new file mode 100755 index 0000000..a1f9c56 --- /dev/null +++ b/nwdebug.c @@ -0,0 +1,36 @@ +/* nwdebug.c 04-Apr-96 */ + +/**************************************************************** + * (C)opyright (C) 1993,1996 Martin Stover, Marburg, Germany * + ****************************************************************/ + +#include "net.h" + +static int usage(void) +{ + fprintf(stderr, "usage:\t%s NCPSERV|NWCONN|NWBIND level\n", funcname); + fprintf(stderr, "\tlevel=0 .. 99\n" ); + return(-1); +} + +int func_debug(int argc, char *argv[]) +{ + uint8 s[200]; + int module; + int level; + int result; + if (argc < 3) return(usage()); + strmaxcpy(s, argv[1], sizeof(s) -1); + upstr(s); + if (!strcmp(s, "NCPSERV")) module=NCPSERV; + else if (!strcmp(s, "NWCONN" )) module=NWCONN; + else if (!strcmp(s, "NWBIND" )) module=NWBIND; + else return(usage()); + level = atoi(argv[2]); + if (level < 0 || level > 99) return(usage()); + result = ncp_17_02(module, level); + if (result < 0) fprintf(stderr, "set debug failed\n"); + else fprintf(stdout, "Debug level for %s changed from %d to %d\n", + s, result, level); + return(result < 0 ? result : 0); +} diff --git a/nwtests.c b/nwtests.c new file mode 100755 index 0000000..52c8fed --- /dev/null +++ b/nwtests.c @@ -0,0 +1,46 @@ +/* nwtests.c 14-Mar-96 */ + +/**************************************************************** + * (C)opyright (C) 1993,1996 Martin Stover, Marburg, Germany * + ****************************************************************/ + +#include "net.h" + +static int usage(void) +{ + fprintf(stderr, "usage:\t%s NCPSERV|NWCONN level\n", funcname); + fprintf(stderr, "\tlevel=0 .. 99\n" ); + return(-1); +} + +int func_tests(int argc, char *argv[]) +{ + int level = ncp_17_02(NWCONN, 6); + int dirhandle = alloc_temp_dir_handle(0, "SYS:", 'd', NULL); + int result = -1; + uint8 *path = (argc < 2) ? "SYS:\\TMP" : argv[1]; + if (dirhandle > -1) { + result = ncp_16_02(dirhandle, "SYSTEM/", NULL, NULL, NULL, NULL); + result = ncp_16_02(dirhandle, "SYSTEM", NULL, NULL, NULL, NULL); + } + fprintf(stdout, "dirhandle=%d, result=%d\n", dirhandle, result); + result = redir_device_drive(0x4, "u:", path); + fprintf(stdout, "redir path=%s, result=%d\n", path, result); + + path="Q1"; + result = redir_device_drive(0x3, "LPT1", path); + fprintf(stdout, "redir path=%s, result=%d\n", path, result); + + { + int k =-1; + uint8 devname[20]; + uint8 remotename[130]; + int devicetyp; + while ((result = list_redir(++k, &devicetyp, devname, remotename)) > -1){ + fprintf(stdout, "index=%d, dev=%s(%d), %s result=%d\n", + k, devname, devicetyp, remotename, result); + } + } + if (level > -1) (void) ncp_17_02(NWCONN, level); + return(0); +} diff --git a/slist.c b/slist.c new file mode 100755 index 0000000..d046816 --- /dev/null +++ b/slist.c @@ -0,0 +1,15 @@ +/* map.c 12-Jan-96 */ + +/**************************************************************** + * (C)opyright (C) 1993,1996 Martin Stover, Marburg, Germany * + ****************************************************************/ + +#include "net.h" + +int func_slist(int argc, char *argv[]) +{ + + + + +} diff --git a/teste.c b/teste.c new file mode 100755 index 0000000..7d6711e --- /dev/null +++ b/teste.c @@ -0,0 +1,95 @@ +int main() +{ + char *fn="F.$LN"; + char *string="ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyz"; + int result; + struct stat stbuff; + long offset; + char buff[1024]; + char readbuff[500]; + int j; + int fd=creatnew(fn, S_IREAD |S_IWRITE); + if (fd > -1) { + printf("Konnte Date erzeugen\n"); + close(fd); + } else { + printf("Konnte Datei nicht erzeugen\n"); + } + fd = open(fn, O_RDWR|O_CREAT|O_TRUNC|O_DENYNONE, 0666); + memset(buff, 0, sizeof(buff) ); + strcpy(buff, string); + write(fd, buff, strlen(buff)); + close(fd); + _chmod(fn, 1, _chmod(fn, 0) | 0x80 ); + stat(fn, &stbuff); + printf("Filesize ber stat =%ld\n", stbuff.st_size); + fd = open(fn, O_RDWR | O_BINARY |O_DENYNONE); + + offset = lseek(fd, 0L, SEEK_END); + printf("Filesize ber lseek =%ld\n", offset); + write(fd, buff, strlen(buff)); + + lseek(fd, 0L, SEEK_SET); + for (j=0; j < strlen(buff)*2; j++){ + read(fd, readbuff, 1); + printf("BUFF = %c\n", readbuff[0]); + } + lseek(fd, 1L, SEEK_SET); + for (j = 0; j < 20; j++){ + write(fd, buff+j, 1); + } + + for (j=0; j <60; j++){ + lseek(fd, (long) j, SEEK_SET); + read(fd, readbuff, 2); + printf("BUFF = %c, %c \n", readbuff[0], readbuff[1]); + } + + lseek(fd, 10L, SEEK_SET); + read(fd, buff, 1); + printf("BUFF[10] = %c\n", buff[0]); + result=lock(fd, 100L, 1L); + printf("lock result = %d\n", result); + result=unlock(fd, 100L, 1L); + printf("unlock result = %d\n", result); + close(fd); + + fd = open(fn, O_BINARY|O_RDWR|O_CREAT|O_TRUNC|O_DENYNONE, 0666); + if (fd > -1) { + int bufflen; + strcpy(buff, "d:..\\marlib\\c0l.obj+"); + strcat(buff, "\r\n"); + strcat(buff, "x"); + strcat(buff, "\r\n"); + strcat(buff, "x"); + strcat(buff, "\r\n"); + strcat(buff, "/c/x"); + strcat(buff, "\r\n"); + strcat(buff, "d:..\\marlib\\EMU.LIB+"); + strcat(buff, "\r\n"); + strcat(buff, "d:..\\marlib\\mathl.lib+"); + strcat(buff, "\r\n"); + strcat(buff, "d:..\\marlib\\cl.lib"); + bufflen=strlen(buff); + printf("bufflen = %d, buff=%s\n", bufflen, buff); + write(fd, buff, bufflen); + close(fd); + fd = open(fn, O_TEXT|O_RDONLY); + if (fd > -1) { + char *p=readbuff; + int anz = 0; + memset(readbuff, 0, sizeof(readbuff) ); + while (read(fd, p, 1) == 1){ + anz++; + p++; + } + printf("read = %d, buff=%s\n", anz, readbuff); + close(fd); + } + } + /* + result = detach(1); + printf("Detach result=0x%x", result); + */ + return(0); +} diff --git a/tools.c b/tools.c new file mode 100755 index 0000000..65ca658 --- /dev/null +++ b/tools.c @@ -0,0 +1,201 @@ +/* tools.c: 12-Jan-96 */ +#include "net.h" + +/**************************************************************** + * (C)opyright (C) 1993,1996 Martin Stover, Marburg, Germany * + ****************************************************************/ + +int key_pressed(void) +{ + REGS regsin, regsout; + regsin.h.ah = 0x01; /* read key-press */ + int86(0x16, ®sin, ®sout); + return((regsout.x.flags & 0x40) ? 0 : 1); /* zeroflag != 0 */ +} + +void clear_kb(void) +{ + REGS regsin, regsout; + while (key_pressed()) { /* zeroflag != 0 */ + regsin.h.ah = 0x00; /* read key-press */ + int86(0x16, ®sin, ®sout); + } +} + +int ask_user(char *p, ...) +{ + int key; + int flag = 0; + va_list argptr; + va_start(argptr, p); + vfprintf(stderr, p, argptr); + va_end(argptr); + fprintf(stderr, "\n Please answer: Y)es or N)o!"); + while (1) { + key = getch(); + if (key == 'J' || key == 'j' || key== 'y' || key == 'Y') { + fprintf(stderr, "Y\n\n"); + flag = 1; + break; + } + if (key == 'N' || key == 'n') { + fprintf(stderr, "N\n\n"); + flag = 0; + break; + } + } + clear_kb(); + return(flag); +} + +int strmaxcpy(char *dest, char *source, int len) +/* copied max. len chars + '\0' Byte */ +{ + int slen = (source != (char *)NULL) ? min(len, strlen(source)) : 0; + if (dest == (char *)NULL) return(0); + if (slen) memcpy(dest, source, slen); + dest[slen] = '\0'; + return(slen); +} + +char *xadd_char(char *s, int c, int maxlen) +{ + if (s && maxlen) { + int namlen = strlen(s); + if (maxlen > -1 && namlen >= maxlen) namlen=maxlen-1; + s[namlen++] = c; + s[namlen] = '\0'; + } + return(s); +} + +static uint8 up_char(uint8 ch) +{ + if (ch > 96 && ch < 123) return(ch - 32); + switch(ch) { + case 132: ch = 142; break; + case 148: ch = 153; break; + case 129: ch = 154; break; + default : break; + } + return(ch); +} + +uint8 *upstr(uint8 *s) +{ + if (!s) return((uint8*)NULL); + for (;*s;s++) *s=up_char(*s); + return(s); +} + +typedef struct { + uint16 adr1; + uint16 adr2; + char reserve[6]; + uint32 ladrs[3]; + uint16 father_psp_seg; + char handles[20]; + uint16 environ_seg; +} PROG_PSP; + +typedef struct { + uint8 kennung; + uint16 prozess_seg; + uint16 blocks; +} SPEICH_BLOCK; + +static char *getglobenvironment(uint16 *maxsize, uint16 *aktsize) +{ + static uint16 globmaxenvsize=0; + static char *globenviron=NULL; + if (globenviron == (char *) NULL) { + PROG_PSP *mypsp = MK_FP(_psp, 0); + PROG_PSP *fatherpsp = MK_FP(mypsp->father_psp_seg, 0); + SPEICH_BLOCK *spb = MK_FP(fatherpsp->environ_seg-1, 0); + globenviron = (char *)MK_FP(fatherpsp->environ_seg, 0); + globmaxenvsize = spb->blocks * 16; + } + if (globmaxenvsize){ + char *search = globenviron; + char *maxsearch = search+globmaxenvsize; + while (*search && search < maxsearch) { + int slen=strlen(search); + search+=(slen+1); + } + *aktsize = max(2, (uint16)(search+1 - globenviron)); + } else *aktsize=0; + *maxsize = globmaxenvsize; + /* + printf("globenv=%p maxsize=%d, aktsize=%d\n", globenviron, globmaxenvsize, *aktsize); + */ + return(globenviron); +} + +char *getglobenv(char *option) +{ + uint16 maxenvsize; + uint16 aktenvsize; + char *search = getglobenvironment(&maxenvsize, &aktenvsize); + int length = (option == NULL) ? 0 : strlen(option); + if (aktenvsize && length){ + char *maxsearch=search+aktenvsize; + while (*search && search < maxsearch) { + int slen=strlen(search); + if (slen > length && (*(search + length) == '=') + && (strncmp(search, option, length) == 0)) { + /* + printf("GET GLOB %s=%s\n", option, search+length+1); + */ + return(search + length + 1); + } + search+=(slen+1); + } + } + return(NULL); +} + +int putglobenv(char *option) +{ + uint16 maxenvsize; + uint16 aktenvsize; + char *search = getglobenvironment(&maxenvsize, &aktenvsize); + int optionlen = (option == NULL) ? 0 : strlen(option); + /* + printf("PUT GLOB option=%s\n", option); + */ + if (optionlen && maxenvsize){ + int length; + char *equal; + for (equal = option; *equal && *equal != '='; equal++);; + length = (int) (equal - option); + if (length > 0 && *equal == '='){ + char *maxsearch=search+aktenvsize; + while (*search && search < maxsearch) { + int slen = strlen(search); + char *nextp = search+slen+1; + if (slen > length && (*(search + length) == '=') + && (strncmp(search, option, length) == 0)) { /* gefunden */ + int diffsize = optionlen-slen; + if (diffsize){ + int movesize = (int)(maxsearch - nextp); + if (diffsize > (int)(maxenvsize - aktenvsize)) + return(-1); /* Kein Platz mehr */ + if (!*(equal+1)) diffsize -= (length+2); + xmemmove(nextp+diffsize, nextp, movesize); + } + if (*(equal+1)) strcpy(search, option); + return(0); + } + search=nextp; + } + /* nicht gefunden , nun eintragen, falls m”glich */ + if (*(equal+1) && optionlen < maxenvsize - aktenvsize) { + strcpy(search, option); + *(search+optionlen+1) = '\0'; /* letzter Eintrag '\0' nicht vergessen */ + return(0); + } else return(-1); + } + } + return(-1); +} +