{$X+,B-,V-,R-,S-} { essential compiler directives } UNIT NWMISC; { nwMisc unit as of 950301 / NwTP 0.6 API. (c) 1993,1995 R.Spronk } { Includes a bugfix of the EncryptPassword function by Horst Jelonneck } INTERFACE uses nwIntr; { Miscellaneous Functions: Comments: Diagnostic Functions: * IsV3Supported * GetNWversion Novell types comparison functions: * IsLowerNetworkAddress * IsEqualNetworkAddress * IsLaterNovTime * IsEqualNovTime Password Encryption Functions: * EncryptPassword (1) * EncryptPasswordDifference (1) Conversion Functions: * UpString (2) * HexStr * HexDumpStr * PStrCopy * ZStrCopy * LoNibble * HiNibble * Lswap * HiLong * LowLong * MakeLong * NovTime2String * DosTime2NovTime * NovTime2DosTime * NovPath2DosPath DosPath2NovPath . MapV2RightsToV3 . MapV3RightsToV2 Notes: (1)-Encrypt3 and associated tables adapted from a c source (NVPW.C) by Willem Jan Hengeveld, A.K.A. Itsme@Hacktic.nl -Source of the encryption routine: LOGON.PAS by Barry Nance, [1:141/209] BYTE March'93 (2) Fast upcasestring by Bob Swart. } Type TnovTime=record year,month,day,hour,min,sec,DayOfWeek:byte; { 0=sunday } end; TconnectionList=array[1..250] of byte; TencryptionKey=array[0..7] of byte; TencrPWdifference=array[0..15] of byte; TnetworkAddress=array[1..4] of byte; { hi-endian } TnodeAddress =array[1..6] of byte; { Hi-endian } TinterNetworkAddress=record net :TnetworkAddress; {hi-lo} node :Tnodeaddress; {hi-lo} socket:word; {lo-hi} end; Function IsV3Supported:Boolean; Procedure NovTime2String(tim:TnovTime;Var DateStr:string); { Puts the time/date information of a NovTime into a string. output format: 'DOW, dd mmm yyyy hh:mm:ss' DOW= day of the week. } Procedure DosTime2NovTime(dt:Longint;Var nt:TnovTime); { Converts a compact DOS time record (4 bytes) into a Tnovtime record } Procedure NovTime2DosTime(nt:TnovTime;Var dt:Longint); Procedure NovPath2DosPath(np:String;Var dp:string); { Converts Novell type path into a DOS path of type Subdir1\Subdir2\.. \subDirN } {============================level 0 support functions=======================} Procedure UpString(s:string); { Converts s to upperstring. Assembler, so it's realy a Var parameter. } Function HexStr(dw:LongInt;len:byte):string; { Converts dw into a hex-string of length len. } Function HexDumpStr(Var dumpVar;len:Byte):String; { Converts dumpVar into a hex-string of length len. Basically the same as HexStr, but accepts variables only. (Mostly used to dump an array of byte) } procedure PStrCopy(Var dest:String;source:String;len:byte); { if length(source)>len then Copy len bytes from source to dest. else Copy source to dest and fill out with NULLs. Length(Dest) will allways be set to len. } procedure ZStrCopy(dest:String;VAR source;len:byte); { 1. Copies len bytes form an array to a pascal type string. } { 2. Trailing NULLs are removed from the string. } { consequently, the length of dest (dest[0]) will allways be <= len. } { -SOURCE is an array of byte: array[ ] of byte; } Function IsLowerNetworkAddress(Var a, b): Boolean; { Compare two net&node addresses. a and b should be of type TinternetworkAddress } Function IsEqualNetworkAddress(Var a, b): Boolean; { Compare two net&node addresses. a and b should be of type TinternetworkAddress } Function IsLaterNovTime(time1,time2:TnovTime):boolean; Function IsEqualNovTime(time1,time2:TnovTime):boolean; Function MapV2RightsToV3(V2Rights:byte):word; Function MapV3RightsToV2(V3Rights:Word):Byte; Procedure GetNWversion(Var version:word); { determine the version of software installed on the current file server. } { see GetFileServerInformation F217/11 for more information } { Version: MajorVersion * 100 + MinorVersion; e.g. 311 for 3.11 } Procedure EncryptPassword(objId:longint;password:string; {i/o} Var Ekey:TencryptionKey); { called by LoginToFileServer (unit nwConn), and by VerifyBinderyObjectPassword, ChangeBinderyObjectPassword (nwBindry) } { Source of the encryption routine: LOGON.PAS by Barry Nance, [1:141/209] BYTE March'93 } Procedure EncryptPasswordDifference(objId:Longint; OldPassword,NewPassword:string; Var key:TencryptionKey; Var PWdif:TencrPWdifference; Var PWdifChecksum:byte ); Function LoNibble(b:Byte):Byte; { Returns the low nibble of the argument (in low nibble position), with high nibble set to 0000 } Function HiNibble(b:Byte):Byte; { Returns the high nibble of the argument (in low nibble position), with high nibble set to 0000 } Function Lswap(l:Longint):Longint; { swaps bytes in a longInt; ( reverse byte order ) } Inline( $5A/ {pop DX ; low word of long } $58/ {pop AX ; hi word of long } $86/$F2/ {xchg dl,dh ; swap bytes } $86/$E0); {xchg al,ah ; swap bytes } function HiLong(Long : LongInt) : Word; { This inline directive is similar to Turbo's Hi() function, except } { it returns the high word of a LongInt } Inline( $5A/ {pop dx ; low word of long } $58); {pop ax ; hi word of long } function LowLong(Long : LongInt) : Word; { This inline directive is similar to Turbo's Lo() function, except } { it returns the Low word of a LongInt } Inline( $5A/ {pop dx ; low word of long } $58/ {pop ax ; hi word of long } $89/$D0); {mov ax,dx ; return lo word as func. result in Ax } function MakeLong(HiWord,LoWord : Word) : LongInt; { Takes hi and lo words and makes a longint } Inline( $58/ { pop ax ; pop low word into AX } $5A); { pop dx ; pop high word into DX } CONST {** ERRORS DEFINED BY NWxxx UNITS *******} {** STANDARD ERRORS AS USED BY NETWARE **} HARDWARE_FAILURE = 255; INVALID_INITIAL_SEMAPHORE_VALUE = 255; {nwSema} INVALID_SEMAPHORE_HANDLE = 255; {nwSema} BAD_PRINTER_ERROR = 255; QUEUE_FULL_ERROR = 255; NO_FILES_FOUND_ERROR = 255; BAD_RECORD_OFFSET = 255; PATH_NOT_LOCATABLE = 255; SOCKET_ALREADY_OPEN = 255; INVALID_DRIVE_NUMBER = 255; {nwDir} NO_RECORD_FOUND = 255; NO_RESPONSE_FROM_SERVER = 255; REQUEST_NOT_OUTSTANDING = 255; NO_SUCH_OBJECT_OR_BAD_PASSWORD = 255; CLOSE_FCB_ERROR = 255; FILE_EXTENSION_ERROR = 255; FILE_NAME_ERROR = 255; IO_BOUND_ERROR = 255; SPX_IS_INSTALLED = 255; {nwIpx} SPX_SOCKET_NOT_OPENED = 255; {nwIpx} EXPLICIT_TRANSACTION_ACTIVE = 255; {nwTTS} NO_EXPLICIT_TRANSACTION_ACTIVE = 255; {nwTTS} TRANSACTION_NOT_YET_WRITTEN = 255; {nwTTS} NO_MORE_MATCHING_FILES = 255; {nwTTS} BINDERY_FAILURE = 255; OPEN_FILES = 255; {3.x} PRINT_JOB_ALREADY_QUEUED = 255; {3.x} PRINT_JOB_ALREADY_SET = 255; {3.x} SUPERVISOR_HAS_DISABLED_LOGIN = 254; {nwConn} TIMEOUT_FAILURE = 254; BINDERY_LOCKED = 254; {nwBindry} SERVER_BINDERY_LOCKED = 254; INVALID_SEMAPHORE_NAME_LENGTH = 254; {nwSema} PACKET_NOT_DELIVERABLE = 254; SOCKET_TABLE_FULL = 254; DIRECTORY_LOCKED = 254; SPOOL_DIRECTORY_ERROR = 254; IMPLICIT_TRANSACTION_ACTIVE = 254; {nwTTS} TRANSACTION_ENDS_RECORD_LOCK = 254; {nwTTS} IO_FAILURE = 254; {3.x} UNKNOWN_REQUEST = 253; INVALID_PACKET_LENGTH = 253; FIELD_ALREADY_LOCKED = 253; BAD_STATION_NUMBER = 253; SPX_MALFORMED_PACKET = 253; SPX_PACKET_OVERFLOW = 253; TTS_DISABLED = 253; NO_SUCH_OBJECT = 252; UNKNOWN_FILE_SERVER = 252; INTERNET_PACKET_REQT_CANCELED = 252; MESSAGE_QUEUE_FULL = 252; {nwMess} SPX_LISTEN_CANCELED = 252; NO_SUCH_PROPERTY = 251; INVALID_PARAMETERS = 251; {UNKNOWN_REQUEST = 251; ?double see 253} NO_MORE_SERVER_SLOTS = 250; TEMP_REMAP_ERROR = 250; NO_PROPERTY_READ_PRIVILEGE = 249; NO_FREE_CONNECTION_SLOTS = 249; NO_PROPERTY_WRITE_PRIVILEGE = 248; ALREADY_ATTACHED_TO_SERVER = 248; NOT_ATTACHED_TO_SERVER = 248; NO_PROPERTY_CREATE_PRIVILEGE = 247; TARGET_DRIVE_NOT_LOCAL = 247; NO_PROPERTY_DELETE_PRIVILEGE = 246; NOT_SAME_LOCAL_DRIVE = 246; NO_OBJECT_CREATE_PRIVILEGE = 245; NO_OBJECT_DELETE_PRIVILEGE = 244; NO_OBJECT_RENAME_PRIVILEGE = 243; NO_OBJECT_READ_PRIVILEGE = 242; INVALID_BINDERY_SECURITY = 241; WILD_CARD_NOT_ALLOWED = 240; IPX_NOT_INSTALLED = 240; {nwIpx} INVALID_NAME = 239; SPX_CONNECTION_TABLE_FULL = 239; OBJECT_ALREADY_EXISTS = 238; SPX_INVALID_CONNECTION = 238; PROPERTY_ALREADY_EXISTS = 237; SPX_NO_ANSWER_FROM_TARGET = 237; SPX_CONNECTION_FAILED = 237; SPX_CONNECTION_TERMINATED = 237; NO_SUCH_SEGMENT = 236; SPX_TERMINATED_POORLY = 236; NOT_GROUP_PROPERTY = 235; NO_SUCH_MEMBER = 234; MEMBER_ALREADY_EXISTS = 233; NOT_ITEM_PROPERTY = 232; WRITE_PROPERTY_TO_GROUP = 232; PASSWORD_HAS_EXPIRED = 223; PASSWORD_HAS_EXPIRED_NO_GRACE = 222; ACCOUNT_DISABLED = 220; UNAUTHORIZED_LOGIN_STATION = 219; MAX_Q_SERVERS = 219; UNAUTHORIZED_LOGIN_TIME = 218; Q_HALTED = 218; LOGIN_DENIED_NO_CONNECTION = 217; STN_NOT_SERVER = 217; PASSWORD_TOO_SHORT = 216; Q_NOT_ACTIVE = 216; PASSWORD_NOT_UNIQUE = 215; Q_SERVICING = 215; NO_JOB_RIGHTS = 214; NO_Q_JOB = 213; Q_FULL = 212; NO_Q_RIGHTS = 211; NO_Q_SERVER = 210; NO_QUEUE = 209; Q_ERROR = 208; NOT_CONSOLE_OPERATOR = 198; INTRUDER_DETECTION_LOCK = 197; ACCOUNT_TOO_MANY_HOLDS = 195; CREDIT_LIMIT_EXCEEDED = 194; NO_ACCOUNT_BALANCE = 193; NO_ACCOUNT_PRIVILEGES = 192; READ_FILE_WITH_RECORD_LOCKED = 162; DIRECTORY_IO_ERROR = 161; DIRECTORY_NOT_EMPTY = 160; DIRECTORY_ACTIVE = 159; INVALID_FILENAME = 158; NO_MORE_DIRECTORY_HANDLES = 157; NO_MORE_TRUSTEES = 156; INVALID_PATH = 156; BAD_DIRECTORY_HANDLE = 155; RENAMING_ACROSS_VOLUMES = 154; DIRECTORY_FULL = 153; VOLUME_DOES_NOT_EXIST = 152; NO_DISK_SPACE_FOR_SPOOL_FILE = 151; SERVER_OUT_OF_MEMORY = 150; OUT_OF_DYNAMIC_WORKSPACE = 150; FILE_DETACHED = 149; NO_WRITE_PRIVILEGES = 148; READ_ONLY = 148; NO_READ_PRIVILEGES = 147; NO_FILES_RENAMED_NAME_EXISTS = 146; SOME_FILES_RENAMED_NAME_EXISTS = 145; NO_FILES_AFFECTED_READ_ONLY = 144; SOME_FILES_AFFECTED_READ_ONLY = 143; NO_FILES_AFFECTED_IN_USE = 142; SOME_FILES_AFFECTED_IN_USE = 141; NO_MODIFY_PRIVILEGES = 140; NO_RENAME_PRIVILEGES = 139; NO_DELETE_PRIVILEGES = 138; NO_SEARCH_PRIVILEGES = 137; INVALID_FILE_HANDLE = 136; WILD_CARDS_IN_CREATE_FILENAME = 135; CREATE_FILE_EXISTS_READ_ONLY = 134; NO_CREATE_DELETE_PRIVILEGES = 133; NO_CREATE_PRIVILEGES = 132; IO_ERROR_NETWORK_DISK = 131; NO_OPEN_PRIVILEGES = 130; NO_MORE_FILE_HANDLES = 129; FILE_IN_USE_ERROR = 128; DOS_LOCK_VIOLATION = 33; DOS_SHARING_VIOLATION = 32; DOS_NO_MORE_FILES = 31; DOS_NOT_SAME_DEVICE = 30; DOS_ATTEMPT_TO_DEL_CURRENT_DIR = 16; DOS_INVALID_DRIVE = 15; DOS_INVALID_DATA = 13; DOS_INVALID_ACCESS_CODE = 12; DOS_INVALID_FORMAT = 11; DOS_INVALID_ENVIRONMENT = 10; DOS_INVALID_MEMORY_BLOCK_ADDR = 9; DOS_INSUFFICIENT_MEMORY = 8; DOS_MEMORY_BLOCKS_DESTROYED = 7; DOS_INVALID_FILE_HANDLE = 6; DOS_ACCESS_DENIED = 5; DOS_TOO_MANY_OPEN_FILES = 4; DOS_PATH_NOT_FOUND = 3; DOS_FILE_NOT_FOUND = 2; TTS_AVAILABLE = 1; SERVER_IN_USE = 1; SEMAPHORE_OVERFLOW = 1; DOS_INVALID_FUNCTION_NUMBER = 1; TTS_NOT_AVAILABLE = 1; SERVER_NOT_IN_USE = 1; IMPLEMENTATION{=============================================================} {----------------------- Encryption tables and procedures --------------} TYPE Buf32 = ARRAY [0..31] OF Byte; Buf16 = ARRAY [0..15] OF Byte; Buf8 = ARRAY [0..7] OF Byte; Buf4 = ARRAY [0..3] OF Byte; CONST EncryptTable : ARRAY [0..255] OF Byte = ($7,$8,$0,$8,$6,$4,$E,$4,$5,$C,$1,$7,$B,$F,$A,$8, $F,$8,$C,$C,$9,$4,$1,$E,$4,$6,$2,$4,$0,$A,$B,$9, $2,$F,$B,$1,$D,$2,$1,$9,$5,$E,$7,$0,$0,$2,$6,$6, $0,$7,$3,$8,$2,$9,$3,$F,$7,$F,$C,$F,$6,$4,$A,$0, $2,$3,$A,$B,$D,$8,$3,$A,$1,$7,$C,$F,$1,$8,$9,$D, $9,$1,$9,$4,$E,$4,$C,$5,$5,$C,$8,$B,$2,$3,$9,$E, $7,$7,$6,$9,$E,$F,$C,$8,$D,$1,$A,$6,$E,$D,$0,$7, $7,$A,$0,$1,$F,$5,$4,$B,$7,$B,$E,$C,$9,$5,$D,$1, $B,$D,$1,$3,$5,$D,$E,$6,$3,$0,$B,$B,$F,$3,$6,$4, $9,$D,$A,$3,$1,$4,$9,$4,$8,$3,$B,$E,$5,$0,$5,$2, $C,$B,$D,$5,$D,$5,$D,$2,$D,$9,$A,$C,$A,$0,$B,$3, $5,$3,$6,$9,$5,$1,$E,$E,$0,$E,$8,$2,$D,$2,$2,$0, $4,$F,$8,$5,$9,$6,$8,$6,$B,$A,$B,$F,$0,$7,$2,$8, $C,$7,$3,$A,$1,$4,$2,$5,$F,$7,$A,$C,$E,$5,$9,$3, $E,$7,$1,$2,$E,$1,$F,$4,$A,$6,$C,$6,$F,$4,$3,$0, $C,$0,$3,$6,$F,$8,$7,$B,$2,$D,$C,$6,$A,$A,$8,$D); EncryptKeys : Array[0..31] of byte = ($48,$93,$46,$67,$98,$3D,$E6,$8D,$B7,$10,$7A,$26,$5A,$B9,$B1,$35, $6B,$0F,$D5,$70,$AE,$FB,$AD,$11,$F4,$47,$DC,$A7,$EC,$CF,$50,$C0); EncryptTable1:array [0..7,0..1,0..15] OF byte= { used by encrypt3 } { 0 1 2 3 4 5 6 7 8 9 a b c d e f } ((( $F,$8,$5,$7,$C,$2,$E,$9,$0,$1,$6,$D,$3,$4,$B,$A), ( $2,$C,$E,$6,$F,$0,$1,$8,$D,$3,$A,$4,$9,$B,$5,$7)), (( $5,$2,$9,$F,$C,$4,$D,$0,$E,$A,$6,$8,$B,$1,$3,$7), ( $F,$D,$2,$6,$7,$8,$5,$9,$0,$4,$C,$3,$1,$A,$B,$E)), (( $5,$E,$2,$B,$D,$A,$7,$0,$8,$6,$4,$1,$F,$C,$3,$9), ( $8,$2,$F,$A,$5,$9,$6,$C,$0,$B,$1,$D,$7,$3,$4,$E)), (( $E,$8,$0,$9,$4,$B,$2,$7,$C,$3,$A,$5,$D,$1,$6,$F), ( $1,$4,$8,$A,$D,$B,$7,$E,$5,$F,$3,$9,$0,$2,$6,$C)), (( $5,$3,$C,$8,$B,$2,$E,$A,$4,$1,$D,$0,$6,$7,$F,$9), ( $6,$0,$B,$E,$D,$4,$C,$F,$7,$2,$8,$A,$1,$5,$3,$9)), (( $B,$5,$A,$E,$F,$1,$C,$0,$6,$4,$2,$9,$3,$D,$7,$8), ( $7,$2,$A,$0,$E,$8,$F,$4,$C,$B,$9,$1,$5,$D,$3,$6)), (( $7,$4,$F,$9,$5,$1,$C,$B,$0,$3,$8,$E,$2,$A,$6,$D), ( $9,$4,$8,$0,$A,$3,$1,$C,$5,$F,$7,$2,$B,$E,$6,$D)), (( $9,$5,$4,$7,$E,$8,$3,$1,$D,$B,$C,$2,$0,$F,$6,$A), ( $9,$A,$B,$D,$5,$3,$F,$0,$1,$C,$8,$7,$6,$4,$E,$2)) ); EncryptTable3:array[0..15] of byte= { used by encrypt3 } ( $3,$E,$F,$2,$D,$C,$4,$5,$9,$6,$0,$1,$B,$7,$A,$8 ); PROCEDURE Shuffle(VAR ShuffleKey, buf; buflen : Word; VAR target); { UNIT INTERNAL PROCEDURE } { id, password[1.. ],length(passw), OUT: buf } PROCEDURE Shuffle1(VAR temp : Buf32; VAR target); VAR _target : Buf16 ABSOLUTE target; b4 : Word; b3 : Byte; d, k, i : Word; Begin {** Step 4: .. } b4 := 0; FOR k := 0 TO 1 DO Begin FOR i := 0 TO 31 DO Begin b3 := Lo( Lo(temp[i] + b4) XOR Lo(temp[(i + b4) AND 31] - EncryptKeys[i])); b4 := b4 + b3; temp[i] := b3; End; End; {*** Step 5:... } FOR i := 0 TO 15 DO _Target[i] := EncryptTable[temp[i Shl 1]] OR (EncryptTable[temp[i Shl 1 +1]] Shl 4); End; VAR locShuffleKey : Buf4 ABSOLUTE ShuffleKey; localBuf : ARRAY [0..127] OF Byte ABSOLUTE buf; BufBytesUsed : Word; temp : Buf32; t, IndexOfBufBytes : Word; Begin { strip trailing NULLs of the to-be-encoded buf, last element of buf must be a NULL ? } While (buflen > 0) AND (localBuf[buflen-1] = 0) DO buflen := buflen - 1; { clear output of 1st shuffle } FillChar(temp, SizeOf(temp), #0); {*** 1ST Step: XOR folding of first (32*(buflen DIV 32)) bytes. } { temp= buf[0..31] XOR buf[32..63] XOR buf[64..95] XOR etc.. } { IndexOfBufBytes is a multiple of 32, length password= IndexOfBufBytes + buflen } { Temp varuable filled with XOR folding of the first IndexOfBufBytes bytes of the PW. } IndexOfBufBytes := 0; WHILE buflen >= 32 DO Begin FOR t := 0 TO 31 DO Begin temp[t] := temp[t] XOR localBuf[IndexOfBufBytes]; IndexOfBufBytes := IndexOfBufBytes + 1; End; buflen := buflen - 32; End; {*** 2ND step: repetitive XOR folding with (remainder of) password password='hello', (BufBytesUsed=0) or password='12345678901234567890123456789012hello' (BufBytesUsed=32) of which the first 32 bytes were used in the 1st encryption step. temp=temp XOR [hellohellohellohellohellohellohe]; } BufBytesUsed:=IndexOfBufBytes; IF buflen > 0 Then Begin FOR t := 0 TO 31 DO Begin IF IndexOfBufBytes + buflen = BufBytesUsed Then Begin BufBytesUsed := IndexOfBufBytes; temp[t] := temp[t] XOR EncryptKeys[t]; End Else Begin temp[t] := temp[t] XOR localBuf[BufBytesUsed]; BufBytesUsed := BufBytesUsed + 1; End; End; End; {*** 3RD step: XOR-ing with shuffleKey (bytes of a longint)} FOR t := 0 TO 31 DO temp[t] := temp[t] XOR locShuffleKey[t AND 3]; {*** 4&5 TH Step: see Shuffle1 } Shuffle1(temp, target); End; PROCEDURE Encrypt(VAR key, buf, EncrPassword); { The encryptionKey 'key' is encrypted with the aid of the shuffled login name/id within 'buf'. Result: the encrypted Password (of type TencryptionKey). } VAR _Key : TencryptionKey ABSOLUTE Key; _EncrKey : TencryptionKey ABSOLUTE EncrPassword; _LocalBuf : Buf32; i: Byte; Begin Shuffle(_Key[0], buf, 16, _LocalBuf[0]); Shuffle(_Key[4], buf, 16, _LocalBuf[16]); FOR i := 0 TO 15 DO _LocalBuf[i] := _LocalBuf[i] XOR _LocalBuf[31-i]; FOR i := 0 TO 7 DO _EncrKey[i] := _LocalBuf[i] XOR _LocalBuf[15-i]; End; Procedure EncryptPassword(objId:longint;password:string;Var Ekey:TencryptionKey); { Source of the encryption routine: LOGON.PAS by Barry Nance, [1:141/209] BYTE March'93 } { Two bugs fixed by Horst Jelonneck (930323) } Var buf:buf32; TobjId:Longint; Tpassword:string; begin TobjId:=Lswap(objId); Tpassword:=password+#0; Shuffle(TObjId,Tpassword[1],length(password),buf); Encrypt(Ekey,buf,Ekey); end; Procedure EncryptPasswordDifference(objId:Longint; OldPassword,NewPassword:string; Var key:TencryptionKey; Var PWdif:TencrPWdifference; Var PWdifChecksum:byte ); { Used by nwBindry.ChangeEncrBinderyObjectPassword. Encrypt3 and associated tables adapted from a c source (NVPW.C) by Willem Jan Hengeveld, A.K.A. Itsme@Hacktic.nl } Procedure Encrypt3(Var buf1,buf2,buf3); { buf1: (part of) encrypted oldPW buf2: (part of) encrypted newPW buf3: 'change pw' data (result) } Var p1:buf8 absolute buf1; p2:buf8 absolute buf2; p3:buf8 absolute buf3; j,c,i:byte; buf:buf8; begin buf:=p2; for i:=0 to 15 do begin for j:=0 to 7 do begin c:=buf[j] XOR p1[j]; buf[j]:=EncryptTable1[j][0][c AND $0F] OR (EncryptTable1[j][1][c SHR 4] SHL 4); end; c:=p1[7]; for j:=7 downto 1 do p1[j]:=(p1[j] SHL 4) OR (p1[j-1] SHR 4); p1[0]:=(c SHR 4) OR (p1[0] SHL 4); FillChar(p3,8,#$0); for j:=0 to 15 do begin c:=EncryptTable3[j]; If odd(EncryptTable3[j]) then c:=buf[c DIV 2] SHR 4 else c:=buf[c DIV 2] AND $0F; if Odd(j) then p3[j DIV 2]:=p3[j DIV 2] XOR (c SHL 4) else p3[j DIV 2]:=p3[j DIV 2] XOR c; end; buf:=p3; end; end; Var l:byte; OldShuffledPW,NewShuffledPW:array[0..15] of byte; begin objId:=Lswap(objId); Shuffle(objId,OldPassword[1],Length(OldPassword),OldShuffledPW); Shuffle(objId,NewPassword[1],Length(NewPassword),NewShuffledPW); Encrypt(key,OldShuffledPW,key); Encrypt3(OldShuffledPW,NewShuffledPW,PWdif); Encrypt3(OldShuffledPW[8],NewShuffledPW[8],PWdif[8]); if Length(NewPassword)<63 then l:=length(NewPassword) else l:=63; PWdifChecksum:=(((l XOR OldShuffledPW[1] XOR OldShuffledPW[2]) AND $7F) OR $40); end; {-------------- End of encryption procedures ----------------------------} Procedure UpString(s : String); Assembler; { fast upcasestring by Bob Swart } ASM PUSH DS LDS SI, s LES DI, s CLD XOR AH, AH LODSB STOSB XCHG AX, CX { empty string? } JCXZ @2 @1: LODSB SUB AL, 'a' CMP AL, 'z'-'a'+1 SBB AH, AH AND AH, 'a'-'A' SUB AL, AH ADD AL, 'a' STOSB LOOP @1 @2: POP DS end; procedure ZStrCopy(dest:String;Var source;len:byte); assembler; { 1. Copies len bytes from an array to a pascal type string. } { 2. Trailing NULLs are removed from the string. } { consequently, the length of det (dest[0]) will allways be <= len. } asm mov dx,ds les di,dest xor ch,ch mov [es:di],ch { dest[0]:=#0 } mov cl,len jcxz @4 { if len=0 then goto @4 } lds si,source @3: lodsb or al,al jz @2 { determine non-0 length of source } dec cx jnz @3 @2: xor ax,ax mov al,len sub ax,cx { ax:= bytes to copy } les di,dest lds si,source mov es:[di],al { dest[0]:=actual non-0 len } inc di { es:di => dest[1] ; ds:si => source[0] } mov cx,ax cld rep movsb { copy cx bytes from ds:si to es:di } @4: mov ds,dx end; procedure PStrCopy(Var dest:String;source:String;len:byte); Var w:byte; begin w:=1; dest[0]:=chr(len); While w<=ord(source[0]) do begin dest[w]:=source[w]; inc(w) end; While w<=len do begin dest[w]:=#0; inc(w) end; end; Procedure NovTime2String(tim:TnovTime;Var DateStr:string); CONST day:array[0..6] of string[3] =('Sun','Mon','Tue','Wed','Thu','Fri','Sat'); Month:array[1..12] of string[3] =('Jan','Feb','Mar','Apr','May','Jun', 'Jul','Aug','Sep','Oct','Nov','Dec'); Type string4=string[4]; Var sday,syear,shour,smin,ssec:string4; Procedure zstr(n:byte;Var s:string4); begin str(n,s); if s[0]=#1 then s:='0'+s; end; begin if (tim.month>12) or (tim.month<1) or (tim.day<1) or (tim.day>31) or (tim.hour>23) or (tim.min>59) or (tim.sec>59) then DateStr:=' ' else begin zstr(tim.day,sday); if sday[1]='0' then sday[1]:=' '; if tim.year<80 then str(tim.year+2000,syear) else str(tim.year+1900,syear); zstr(tim.hour,shour); zstr(tim.min,smin); zstr(tim.sec,ssec); DateStr:=day[tim.DayOfWeek]+', '+ sday+' '+Month[tim.month]+' '+syear+' '+ shour+':'+smin+':'+ssec; end; end; Procedure DosTime2NovTime(dt:Longint;Var nt:TnovTime); Var k:array[1..2] of word absolute dt; begin with nt do begin year:=(80+byte(k[2] SHR 9)) MOD 100; month:=(byte(k[2] SHR 5) AND 15); day:=byte(k[2] AND 31); hour:=byte (k[1] SHR 11); min:=(byte(k[1] SHR 5) AND 63); sec:=2*byte(k[1] AND 31); end; end; Procedure NovTime2DosTime(nt:TnovTime;Var dt:Longint); Var k:array[1..2] of word absolute dt; begin with nt do begin k[2]:=(((100+year-80) mod 100) SHL 9)+(month SHL 5)+day; k[1]:=(hour SHL 11)+(min SHL 5)+(sec DIV 2); end; end; Procedure NovPath2DosPath(np:String;Var dp:string); { np is a pascal type string with the folowing format: chr(length(subdir1)),subdir1, ... chr(length(subdirN)),subDirN. It will be transformed to a DOS path of type Subdir1\Subdir2\.. \subDirN } Var t:Byte; begin dp:=np; delete(dp,1,1); for t:=1 to ord(dp[1]) do if dp[t]<=#20 then dp[t]:='\'; end; Function LoNibble(b:Byte):Byte; assembler; asm mov al,b and al,$0F end; Function HiNibble(b:Byte):Byte; assembler; asm mov ah,$00 mov al,b shr ax,1 shr ax,1 shr ax,1 shr ax,1 end; Function HexStr(dw:LongInt;len:byte):string; CONST n:array[0..15] of char =('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'); Var t:integer; ldw:LongInt; res:string; begin res:=''; for t:=1 to len do begin ldw:=dw AND $0000000F; res:=n[ldw]+res; dw:=dw SHR 4; end; HexStr:=res; end; Function HexDumpStr(Var dumpVar;len:Byte):String; Var arr:Array[1..256] of Byte ABSOLUTE dumpVar; t:Byte; res:String; begin res:=''; for t:=1 to (1+(len DIV 2)) do res:=res+HexStr(arr[t],2); res[0]:=chr(len); HexDumpStr:=res; end; Function IsLowerNetworkAddress(Var a, b): Boolean; Type TCharNetAddress = Array [1..10] of Char; Var Aaddr : TCharNetAddress ABSOLUTE a; Baddr : TCharNetAddress ABSOLUTE b; Begin IsLowerNetworkAddress := Aaddr < Baddr; End; Function IsEqualNetworkAddress(Var a, b): Boolean; Type TCharNetAddress = Array [1..10] of Char; Var Aaddr : TCharNetAddress ABSOLUTE a; Baddr : TCharNetAddress ABSOLUTE b; Begin IsEqualNetworkAddress := (Aaddr = Baddr); End; Function IsLaterNovTime(time1,time2:TnovTime):boolean; Var bAft:boolean; y1,y2:word; begin if time1.year>=80 then y1:=1900+time1.year else y1:=2000+time1.year; if time2.year>=80 then y2:=1900+time2.year else y2:=2000+time2.year; bAft:=(y1>y2); if y1=y2 then begin bAft:=(time1.month>time2.month); if time1.month=time2.month then begin bAft:=(time1.day>time2.day); if time1.day=time2.day then begin bAft:=(time1.hour>time2.hour); if time1.hour=time2.hour then begin bAft:=(time1.min>time2.min); if time1.min=time2.min then bAft:=(time1.sec>time2.sec); end; end; end; end; IsLaterNovTime:=bAft end; Function IsEqualNovTime(time1,time2:TnovTime):boolean; Var t1:array[1..Sizeof(TnovTime)-1] of char absolute time1; t2:array[1..SizeOf(TnovTime)-1] of char absolute time2; begin IsEqualNovTime:=(t1=t2); end; Function MapV2RightsToV3(V2Rights:byte):word; CONST RightsNotChanged:byte=$08+$10+$40+$80; Var result1:Word; begin if (V2Rights and $FF)>0 then result1:=$1FF else begin result1:=(V2Rights and RightsNotChanged); if (V2Rights and ($01+$04))>0 then result1:=result1 or $01; if (V2Rights and ($02+$04))>0 then result1:=result1 or $02; if (V2Rights and $04)>0 then result1:=result1 or $01; if (V2Rights and $20)>0 then result1:=result1 or $28; end; MapV2RightsToV3:=result1; end; Function MapV3RightsToV2(V3Rights:Word):Byte; CONST RightsNotChanged:word=$10+$20+$40+$80; Var result1:Byte; begin If (V3Rights and $0100)>0 then result1:=$FF else begin result1:=(lo(V3Rights) and RightsNotChanged); If (V3Rights and $01)>0 then result1:=result1 or $05; If (V3Rights and $02)>0 then result1:=result1 or $06; {If (V3Rights and $04)>0 then result:=result or $00;} If (V3Rights and $08)>0 then result1:=result1 or $28; end; MapV3RightsToV2:=result1; end; Procedure GetNWversion(Var version:word); { determine the version of the software installed on the current file server. } { see GetFileServerInformation F217/11 in the nwServ unit for more information } { version : word; contains the versionnumber of the fileserver we're currently connected to. Used by primary functions to determine what type of calls to use to perform a certain function. format: (majorVersion*100)+minorVersion e.g. 311 for 3.11 Range: 215 (advanced netware 2.15) and upwards } { If the version is lower than 2.15, 2.15 is returned. } { note: you don't have to be logged in to call this function. } Type TReq= Record PacketLength : Word; FunctionVal : Byte; End; TRep=array[1..$80] of byte; Tpreq=^Treq; Tprep=^Trep; Var Result:word; Begin With TPreq(GlobalReqBuf)^ Do Begin PacketLength := 1; FunctionVal := $11; End; F2SystemCall($17,sizeof(Treq),Sizeof(Trep),result); If result=0 then version:=(TPrep(GlobalReplyBuf)^[49]*100)+TPrep(GlobalReplyBuf)^[50] else version:=215; End; Function IsV3Supported:boolean; Var version:word; begin GetNWversion(version); IsV3Supported:=(version>=300); end; END.