{ $Project$ $Workfile$ $Revision$ $DateUTC$ $Id$ This file is part of the Indy (Internet Direct) project, and is offered under the dual-licensing agreement described on the Indy website. (http://www.indyproject.org/) Copyright: (c) 1993-2005, Chad Z. Hower and the Indy Pit Crew. All rights reserved. } { $Log$ } { Rev 1.1 6/29/04 12:51:10 PM RLebeau Updatd SetupLanManagerPassword() to check the password length before referencing the password data Rev 1.0 11/13/2002 07:58:08 AM JPMugaas S.G. 12/7/2002: - Rewrote Type 1 and Type 2 structures to be closer to the document referenced in the above URL. (Easier to read and check) - Corrected falgs accouring to bug ID 577895 and own packet traces. This was actually only an adjustment to the new data types when I rewrote the header. - Initialized structures to #0 before using. } { Implementation of the NTLM authentication as specified in http://www.innovation.ch/java/ntlm.html with some fixes Author: Doychin Bondzhev (doychin@dsoft-bg.com) Copyright: (c) Chad Z. Hower and The Winshoes Working Group. } unit IdNTLM; interface {$i IdCompilerDefines.inc} uses IdGlobal, IdStruct; type {$IFDEF DOTNET} ProtocolArray = array [1..8] of AnsiChar; padArray2 = array[0..1] of Byte; padArray3 = Array[0..2] of Byte; padArray7 = Array[0..6] of Byte; padArray8 = Array[0..7] of Byte; nonceArray = Array[1..8] of Byte; ntlm_base = class(TIdStruct) protected fprotocol : ProtocolArray; function GetBytesLen: UInt32; override; public procedure ReadStruct(const ABytes : TIdBytes; var VIndex : UInt32); override; procedure WriteStruct(var VBytes : TIdBytes; var VIndex : UInt32); override; property protocol: ProtocolArray read fprotocol write fprotocol; // array [1..8] of Char; // 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0' {Do not Localize} end; type_1_message_header = class(ntlm_base) protected f_type : UInt8; fpad : padArray3; fflags : UInt16; fpad2 : padArray2; fdom_len1 : UInt16; fdom_len2 : UInt16; fdom_off : UInt32; fhost_len1 : UInt16; fhost_len2 : UInt16; fhost_off : UInt32; function GetBytesLen: UInt32; override; public procedure ReadStruct(const ABytes : TIdBytes; var VIndex : UInt32); override; procedure WriteStruct(var VBytes : TIdBytes; var VIndex : UInt32); override; property _type: UInt8 read f_type write f_type; // 0x01 property pad : padArray3 read fpad write fpad; // 0x0 property flags: UInt16 read fflags write fflags; // 0xb203 property pad2 : padArray2 read fpad2 write fpad2; // 0x0 property dom_len1: UInt16 read fdom_len1 write fdom_len1; // domain string length property dom_len2: UInt16 read fdom_len2 write fdom_len2; // domain string length property dom_off: UInt32 read fdom_off write fdom_off; // domain string offset property host_len1: UInt16 read fhost_len1 write fhost_len1; // host string length property host_len2: UInt16 read fhost_len2 write fhost_len2; // host string length property host_off: UInt32 read fhost_off write fhost_off; // host string offset (always 0x20) end; type_2_message_header = class(ntlm_base) protected f_type : UInt8; fPad: padArray3; fhost_len1: UInt16; fhost_len2: UInt16; fhost_off: UInt32; fflags: UInt16; fPad2: padArray2; fnonce: nonceArray; freserved: padArray8; finfo_len1: UInt16; finfo_len2: UInt16; finfo_off: UInt32; function GetBytesLen: UInt32; override; public procedure ReadStruct(const ABytes : TIdBytes; var VIndex : UInt32); override; procedure WriteStruct(var VBytes : TIdBytes; var VIndex : UInt32); override; property _type: UInt8 read f_type write f_type; // $2 property pad: padArray3 read fPad wrie fPad; property host_len1: UInt16 read fhost_len1 write fhost_len1; property host_len2: UInt16 read fhost_len2 write fhost_len2; property host_off: UInt32 read fhost_off write fhost_off; property flags: UInt16 read fflags write fflags; property pad2: padArray2 read fflags write fflags; property nonce: nonceArray read fnonce write fnonce; property reserved: padArray8 read freserved write freserved; property info_len1: UInt16 read finfo_len1 write finfo_len1; property info_len2: UInt16 read finfo_len2 write finfo_len2; property info_off: UInt32 read finfo_off write finfo_off; end; type_3_message_header = class(ntlm_base) protected f_type: UInt32; flm_resp_len1: UInt16; flm_resp_len2: UInt16; flm_resp_off : UInt32; fnt_resp_len1: UInt16; fnt_resp_len2: UInt16; fnt_resp_off: UInt32; fdom_len1: UInt16; fdom_len2 : UInt16; fdom_off : UInt32; fuser_len1: UInt16; fuser_len2: UInt16; fuser_off: UInt32; fhost_len1: UInt16; fhost_len2: UInt16; fhost_off: UInt32; fkey_len1: UInt16; fkey_len2: UInt16; fkey_off: UInt32; fflags: UInt32; function GetBytesLen: UInt32; override; public procedure ReadStruct(const ABytes : TIdBytes; var VIndex : UInt32); override; procedure WriteStruct(var VBytes : TIdBytes; var VIndex : UInt32); override; property _type: UInt32 read f_type write f_type; // 0x03 property lm_resp_len1: UInt16 read flm_resp_len1 write flm_resp_len1; // LanManager response length (always 0x18) property lm_resp_len2: UInt16 read flm_resp_len2 write flm_resp_len2; // LanManager response length (always 0x18) property lm_resp_off: UInt32 read flm_resp_off write flm_resp_off; // LanManager response offset property nt_resp_len1: UInt16 read fnt_resp_len1 write fnt_resp_len1; // NT response length (always 0x18) property nt_resp_len2: UInt16 read fnt_resp_len2 write fnt_resp_len2; // NT response length (always 0x18) property nt_resp_off: UInt32 read fnt_resp_off write fnt_resp_off; // NT response offset property dom_len1: UInt16 read fdom_len1 write fdom_len1; // domain string length property dom_len2: UInt16 read fdom_len2 write fdom_len2; // domain string length property dom_off: UInt32 read fdom_off write fdom_off; // domain string offset (always 0x40) property user_len1: UInt16 read fuser_len1 write fuser_len1; // username string length property user_len2: UInt16 read fuser_len2 write fuser_len2; // username string length property user_off: UInt32 read fuser_off write fuser_off; // username string offset property host_len1: UInt16 read fhost_len1 write fhost_len1; // host string length property host_len2: UInt16 read fhost_len2 write fhost_len2; // host string length property host_off: UInt32 read fhost_off write fhost_off; // host string offset property key_len1: UInt16 read fkey_len1 write fkey_len1; // session key length property key_len2: UInt16 read fkey_len2 write fkey_len2; // session key length property key_off: UInt32 read fkey_off write fkey_off; // session key offset property flags: UInt32 read fflags write fflags; // 0xA0808205 end; {$ELSE} type_1_message_header = packed record protocol: array [1..8] of UInt8; // 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0' {Do not Localize} _type: UInt8; // 0x01 pad : packed Array[1..3] of UInt8; // 0x0 flags: UInt16; // 0xb203 pad2 : packed Array[1..2] of UInt8; // 0x0 dom_len1: UInt16; // domain string length dom_len2: UInt16; // domain string length dom_off: UInt32; // domain string offset host_len1: UInt16; // host string length host_len2: UInt16; // host string length host_off: UInt32; // host string offset (always 0x20) end; type_2_message_header = packed record protocol: packed array [1..8] of UInt8; // 'N', 'T', 'L', 'M', 'S', 'S', 'P', #0 {Do not Localize} _type: UInt8; // $2 Pad: packed Array[1..3] of UInt8; host_len1: UInt16; host_len2: UInt16; host_off: UInt32; flags: UInt16; Pad2: packed Array[1..2] of UInt8; nonce: packed Array[1..8] of UInt8; reserved: packed Array[1..8] of UInt8; info_len1: UInt16; info_len2: UInt16; info_off: UInt32; end; type_3_message_header = packed record protocol: array [1..8] of UInt8; // 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0' {Do not Localize} _type: UInt32; // 0x03 lm_resp_len1: UInt16; // LanManager response length (always 0x18) lm_resp_len2: UInt16; // LanManager response length (always 0x18) lm_resp_off: UInt32; // LanManager response offset nt_resp_len1: UInt16; // NT response length (always 0x18) nt_resp_len2: UInt16; // NT response length (always 0x18) nt_resp_off: UInt32; // NT response offset dom_len1: UInt16; // domain string length dom_len2: UInt16; // domain string length dom_off: UInt32; // domain string offset (always 0x40) user_len1: UInt16; // username string length user_len2: UInt16; // username string length user_off: UInt32; // username string offset host_len1: UInt16; // host string length host_len2: UInt16; // host string length host_off: UInt32; // host string offset key_len1: UInt16; // session key length key_len2: UInt16; // session key length key_off: UInt32; // session key offset flags: UInt32; // 0xA0808205 end; function BuildType1Message(const ADomain, AHost: String): String; function BuildType3Message(const ADomain, AHost, AUsername: TIdUnicodeString; const APassword: String; const ANonce: TIdBytes): String; {$ENDIF} function NTLMFunctionsLoaded : Boolean; procedure GetDomain(const AUserName : String; var VUserName, VDomain : String); //IMPORTANT!!! // //NTLM is a funny protocol because it was designed for little endian machines. //Some record values must be in little endian byte-orders. const // S.G. 12/7/2002: Changed the flag to $B207 (from BugID 577895 and packet trace) //was $A000B207; //b203; //JPM - note that this value has to be little endian. We precalculate //this for big endian machines. MSG1_FLAGS : UInt16 = $b207; // S.G. 12/7/2002: was: flags := $A0808205; (from BugID 577895 and packet trace) MSG3_FLAGS : UInt32 = $018205; implementation uses {$IFDEF HAS_UNIT_AnsiStrings} AnsiStrings, {$ENDIF} SysUtils, {$IFDEF DOTNET} System.Text, {$ENDIF} IdFIPS, IdGlobalProtocols, IdHash, IdHashMessageDigest, IdCoderMIME {$IFNDEF DOTNET}, IdSSLOpenSSLHeaders{$ENDIF} {$IFDEF HAS_GENERICS_TArray_Copy} {$IFDEF HAS_UNIT_Generics_Collections} , System.Generics.Collections {$ENDIF} {$ENDIF} ; type Pdes_key_schedule = ^des_key_schedule; const cProtocolStr: array[1..8] of Byte = (Ord('N'),Ord('T'),Ord('L'),Ord('M'),Ord('S'),Ord('S'),Ord('P'),$0); {Do not Localize} procedure GetDomain(const AUserName : String; var VUserName, VDomain : String); {$IFDEF USE_INLINE} inline; {$ENDIF} var i: Integer; begin i := Pos('\', AUsername); if i > -1 then begin VDomain := Copy(AUsername, 1, i - 1); VUserName := Copy(AUsername, i + 1, Length(AUserName)); end else begin VDomain := ' '; {do not localize} VUserName := AUserName; end; end; {$IFDEF DOTNET} function NTLMFunctionsLoaded : Boolean; {$IFDEF USE_INLINE} inline; {$ENDIF} begin Result := True; end; {$ELSE} function NTLMFunctionsLoaded : Boolean; begin Result := IdSSLOpenSSLHeaders.Load; if Result then begin Result := Assigned(DES_set_odd_parity) and Assigned(DES_set_key) and Assigned(DES_ecb_encrypt); end; end; {$ENDIF} {$IFNDEF DOTNET} {/* * turns a 56 bit key into the 64 bit, odd parity key and sets the key. * The key schedule ks is also set. */} procedure setup_des_key(key_56: des_cblock; Var ks: des_key_schedule); Var key: des_cblock; begin key[0] := key_56[0]; key[1] := ((key_56[0] SHL 7) and $FF) or (key_56[1] SHR 1); key[2] := ((key_56[1] SHL 6) and $FF) or (key_56[2] SHR 2); key[3] := ((key_56[2] SHL 5) and $FF) or (key_56[3] SHR 3); key[4] := ((key_56[3] SHL 4) and $FF) or (key_56[4] SHR 4); key[5] := ((key_56[4] SHL 3) and $FF) or (key_56[5] SHR 5); key[6] := ((key_56[5] SHL 2) and $FF) or (key_56[6] SHR 6); key[7] := (key_56[6] SHL 1) and $FF; DES_set_odd_parity(@key); DES_set_key(@key, ks); end; {/* * takes a 21 byte array and treats it as 3 56-bit DES keys. The * 8 byte plaintext is encrypted with each key and the resulting 24 * bytes are stored in the results array. */} procedure calc_resp(keys: PDES_cblock; const ANonce: TIdBytes; results: Pdes_key_schedule); Var ks: des_key_schedule; nonce: des_cblock; begin setup_des_key(keys^, ks); Move(ANonce[0], nonce, 8); des_ecb_encrypt(@nonce, Pconst_DES_cblock(results), ks, DES_ENCRYPT); setup_des_key(PDES_cblock(PtrUInt(keys) + 7)^, ks); des_ecb_encrypt(@nonce, Pconst_DES_cblock(PtrUInt(results) + 8), ks, DES_ENCRYPT); setup_des_key(PDES_cblock(PtrUInt(keys) + 14)^, ks); des_ecb_encrypt(@nonce, Pconst_DES_cblock(PtrUInt(results) + 16), ks, DES_ENCRYPT); end; Const Magic: des_cblock = ($4B, $47, $53, $21, $40, $23, $24, $25 ); //* setup LanManager password */ function SetupLanManagerPassword(const APassword: String; const ANonce: TIdBytes): TIdBytes; var lm_hpw: array[0..20] of Byte; lm_pw: array[0..13] of Byte; idx, len: Integer; ks: des_key_schedule; lm_resp: array [0..23] of Byte; lPassword: {$IFDEF STRING_IS_UNICODE}TIdBytes{$ELSE}AnsiString{$ENDIF}; begin {$IFDEF STRING_IS_UNICODE} lPassword := IndyTextEncoding_OSDefault.GetBytes(UpperCase(APassword)); {$ELSE} lPassword := UpperCase(APassword); {$ENDIF} len := IndyMin(Length(lPassword), 14); if len > 0 then begin Move(lPassword[{$IFDEF STRING_IS_UNICODE}0{$ELSE}1{$ENDIF}], lm_pw[0], len); end; if len < 14 then begin for idx := len to 13 do begin lm_pw[idx] := $0; end; end; //* create LanManager hashed password */ setup_des_key(pdes_cblock(@lm_pw[0])^, ks); des_ecb_encrypt(@magic, Pconst_DES_cblock(@lm_hpw[0]), ks, DES_ENCRYPT); setup_des_key(pdes_cblock(PtrUInt(@lm_pw[0]) + 7)^, ks); des_ecb_encrypt(@magic, Pconst_DES_cblock(PtrUInt(@lm_hpw[0]) + 8), ks, DES_ENCRYPT); FillChar(lm_hpw[16], 5, 0); calc_resp(PDes_cblock(@lm_hpw[0]), ANonce, Pdes_key_schedule(@lm_resp[0])); SetLength(Result, SizeOf(lm_resp)); Move(lm_resp[0], Result[0], SizeOf(lm_resp)); end; function BuildUnicode(const S: String): TIdBytes; {$IFDEF STRING_IS_UNICODE} {$IFDEF USE_INLINE}inline;{$ENDIF} {$ELSE} var i: integer; {$ENDIF} begin {$IFDEF STRING_IS_UNICODE} Result := IndyTextEncoding_UTF16LE.GetBytes(S); {$ELSE} // RLebeau: TODO - should this use encUTF16LE as well? This logic will // not produce a valid Unicode string if non-ASCII characters are present! SetLength(Result, Length(S) * SizeOf(WideChar)); for i := 0 to Length(S)-1 do begin Result[i*2] := Byte(S[i+1]); Result[(i*2)+1] := Byte(#0); end; {$ENDIF} end; //* create NT hashed password */ function CreateNTPassword(const APassword: String; const ANonce: TIdBytes): TIdBytes; var nt_hpw: array [1..21] of Byte; nt_hpw128: TIdBytes; nt_resp: array [1..24] of Byte; LMD4: TIdHashMessageDigest4; begin CheckMD4Permitted; LMD4 := TIdHashMessageDigest4.Create; try {$IFDEF STRING_IS_UNICODE} nt_hpw128 := LMD4.HashString(APassword, IndyTextEncoding_UTF16LE); {$ELSE} nt_hpw128 := LMD4.HashBytes(BuildUnicode(APassword)); {$ENDIF} finally LMD4.Free; end; Move(nt_hpw128[0], nt_hpw[1], 16); FillChar(nt_hpw[17], 5, 0); calc_resp(pdes_cblock(@nt_hpw[1]), ANonce, Pdes_key_schedule(@nt_resp[1])); SetLength(Result, SizeOf(nt_resp)); Move(nt_resp[1], Result[0], SizeOf(nt_resp)); end; function BuildType1Message(const ADomain, AHost: String): String; var LEncoding: IIdTextEncoding; Type_1_Message: type_1_message_header; lDomain: TIdBytes; lHost: TIdBytes; buf: TIdBytes; begin LEncoding := IndyTextEncoding_ASCII; lDomain := ToBytes(UpperCase(ADomain), LEncoding); lHost := ToBytes(UpperCase(AHost), LEncoding); LEncoding := nil; FillChar(Type_1_Message, SizeOf(Type_1_Message), #0); {$IFDEF HAS_GENERICS_TArray_Copy} TArray.Copy(cProtocolStr, Type_1_Message.protocol, 8); {$ELSE} {$IFDEF USE_MARSHALLED_PTRS} buf := cProtocolStr; TMarshal.Copy(TBytesPtr(@buf)^, 0, TPtrWrapper.Create(@Type_1_Message.protocol[1]), 8); {$ELSE} Move(cProtocolStr[1], Type_1_Message.protocol[1], 8); {$ENDIF} {$ENDIF} Type_1_Message._type := 1; // S.G. 12/7/2002: Changed the flag to $B207 (from BugID 577895 and packet trace) Type_1_Message.flags := MSG1_FLAGS; //was $A000B207; //b203; Type_1_Message.dom_len1 := UInt16(Length(lDomain)); // dom_off := 0; Type_1_Message.dom_off := 32; Type_1_Message.host_len1 := UInt16(Length(lHost)); Type_1_Message.host_off := UInt32(Type_1_Message.dom_off + Type_1_Message.dom_len1); Type_1_Message._type := HostToLittleEndian(Type_1_Message._type); Type_1_Message.flags := HostToLittleEndian(Type_1_Message.flags); Type_1_Message.dom_len1 := HostToLittleEndian(Type_1_Message.dom_len1); Type_1_Message.dom_len2 := Type_1_Message.dom_len1; Type_1_Message.dom_off := HostToLittleEndian(Type_1_Message.dom_off); Type_1_Message.host_len1 := HostToLittleEndian(Type_1_Message.host_len1); Type_1_Message.host_len2 := Type_1_Message.host_len1; Type_1_Message.host_off := HostToLittleEndian(Type_1_Message.host_off); buf := RawToBytes(Type_1_Message, SizeOf(Type_1_Message)); AppendBytes(buf, lDomain); AppendBytes(buf, lHost); Result := TIdEncoderMIME.EncodeBytes(buf); end; function BuildType3Message(const ADomain, AHost, AUsername: TIdUnicodeString; const APassword: String; const ANonce: TIdBytes): String; var type3: type_3_message_header; buf: TIdBytes; lm_password: TIdBytes; nt_password: TIdBytes; lDomain: TIdBytes; lHost: TIdBytes; lUsername: TIdBytes; begin lm_password := SetupLanManagerPassword(APassword, ANonce); nt_password := CreateNTPassword(APassword, ANonce); lDomain := BuildUnicode(UpperCase(ADomain)); lHost := BuildUnicode(UpperCase(AHost)); lUsername := BuildUnicode(AUsername); {$IFDEF HAS_GENERICS_TArray_Copy} TArray.Copy(cProtocolStr, Type3.protocol, 8); {$ELSE} {$IFDEF USE_MARSHALLED_PTRS} buf := cProtocolStr; TMarshal.Copy(TBytesPtr(@buf)^, 0, TPtrWrapper.Create(@Type3.protocol[1]), 8); {$ELSE} Move(cProtocolStr[1], Type3.protocol[1], 8); {$ENDIF} {$ENDIF} Type3._type := 3; Type3.lm_resp_len1 := UInt16(Length(lm_password)); Type3.lm_resp_off := $40; Type3.nt_resp_len1 := UInt16(Length(nt_password)); Type3.nt_resp_off := UInt32(Type3.lm_resp_off + Type3.lm_resp_len1); Type3.dom_len1 := UInt16(Length(lDomain)); Type3.dom_off := UInt32(Type3.nt_resp_off + Type3.nt_resp_len1); Type3.user_len1 := UInt16(Length(lUsername)); Type3.user_off := UInt32(Type3.dom_off + Type3.dom_len1); Type3.host_len1 := UInt16(Length(lHost)); Type3.host_off := UInt32(Type3.user_off + Type3.user_len1); Type3.key_len1 := 0; Type3.key_off := UInt32(Type3.user_len1 + Type3.host_len1); Type3.flags := MSG3_FLAGS; Type3._type := HostToLittleEndian(Type3._type); Type3.lm_resp_len1 := HostToLittleEndian(Type3.lm_resp_len1); Type3.lm_resp_len2 := Type3.lm_resp_len1; Type3.lm_resp_off := HostToLittleEndian(Type3.lm_resp_off); Type3.nt_resp_len1 := HostToLittleEndian(Type3.nt_resp_len1); Type3.nt_resp_len2 := Type3.nt_resp_len1; Type3.nt_resp_off := HostToLittleEndian(Type3.nt_resp_off); Type3.dom_len1 := HostToLittleEndian(Type3.dom_len1); Type3.dom_len2 := Type3.dom_len1; Type3.dom_off := HostToLittleEndian(Type3.dom_off); Type3.user_len1 := HostToLittleEndian(Type3.user_len1); Type3.user_len2 := Type3.user_len1; Type3.user_off := HostToLittleEndian(Type3.user_off); Type3.host_len1 := HostToLittleEndian(Type3.host_len1); Type3.host_len2 := Type3.host_len1; Type3.host_off := HostToLittleEndian(Type3.host_off); Type3.key_len1 := HostToLittleEndian(Type3.key_len1); Type3.key_len2 := Type3.key_len1; Type3.key_off := HostToLittleEndian(Type3.key_off); Type3.flags := HostToLittleEndian(Type3.flags); buf := RawToBytes(Type3, SizeOf(Type3)); AppendBytes(buf, lm_password); AppendBytes(buf, nt_password); AppendBytes(buf, lDomain); AppendBytes(buf, lUsername); AppendBytes(buf, lHost); Result := TIdEncoderMIME.EncodeBytes(buf); end; {$ELSE} procedure BytesToCharArray(const ABytes : TIdBytes; var VArray : Array of Char; const AIndex : Integer = 0); var i, ll, lh : Integer; begin ll := Low(VArray); lh := High(Varray); for i := ll to lh do begin VArray[i] := Char(ABytes[ (i - ll)+ AIndex]); end; end; procedure BytesToByteArray(const ABytes : TIdBytes; var VArray : Array of Byte; const AIndex : Integer = 0); var i, ll, lh : Integer; begin ll := Low(VArray); lh := High(Varray); for i := ll to lh do begin VArray[i] := ABytes[ (i - ll)+ AIndex]; end; end; procedure ByteArrayToBytes(const VArray : array of Byte; const ABytes : TIdBytes; const AIndex : Integer = 0); var i, ll, lh : Integer; begin ll := Low(VArray); lh := High(Varray); for i := ll to lh do begin ABytes[ (i - ll)+ AIndex] := VArray[i]; end; end; function ntlm_base.GetBytesLen: UInt32; begin Result := 8; end; procedure ntlm_base.ReadStruct(const ABytes : TIdBytes; var VIndex : UInt32); var i : Integer; begin inherited ReadStruct(ABytes,VIndex); for i := 1 to Length(fprotocol) do begin fprotocol[i] := Char(ABytes[i+VIndex]); end; Inc(VIndex, Length(fprotocol)); end; procedure ntlm_base.WriteStruct(var VBytes : TIdBytes; var VIndex : UInt32); var LLen : Integer; LBytes : TIdBytes; begin inherited WriteStruct(VBytes,VIndex); LBytes := System.Text.ASCIIEncoding.GetBytes(fprotocol); LLen := Length(fprotocol); CopyTIdBytes(LBytes, VIndex, VBytes, VIndex, LLen); Inc(VIndex, LLen); end; function type_1_message_header.GetBytesLen: UInt32; begin Result := inherited GetByesLen() + 24; end; procedure type_1_message_header.ReadStruct(const ABytes : TIdBytes; var VIndex : UInt32); begin inherited ReadStruct(ABytes, VIndex); f_type := ABytes[VIndex]; Inc(VIndex); BytesToByteArray(ABytes, fpad, VIndex); Inc(VIndex, Length(fpad)); fflags := BytesToUInt16(ABytes, VIndex); Inc(VIndex, 2); BytesToByteArray(ABytes, fpad2, VIndex); Inc(VIndex, Length(fpad2)); fdom_len1 := BytesToUInt16(ABytes, VIndex); Inc(VIndex, 2); fdom_len2 := BytesToUInt16(ABytes, VIndex); Inc(VIndex, 2); fdom_off := BytesToUInt32(ABytes, VIndex); Inc(VIndex, 4); fhost_len1 := BytesToUInt16(ABytes, VIndex); Inc(VIndex, 2); fhost_len2 := BytesToUInt16(ABytes, VIndex); Inc(VIndex, 2); fhost_off := BytesToUInt32(ABytes, VIndex); Inc(VIndex, 4); end; procedure type_1_message_header.WriteStruct(var VBytes : TIdBytes; var VIndex : UInt32); begin inherited WriteStruct(VBytes, VIndex); VBytes[VIndex] := f_type; Inc(VIndex); ByteArrayToBytes(fpad, VBytes, VIndex); Inc(VIndex, Length(fpad)); CopyTIdUInt16(fflags, VBytes, VIndex); Inc(VIndex, 2); ByteArrayToBytes(fpad2, VBytes, VIndex); Inc(VIndex, Length(fpad2)); CopyTIdUInt16(fdom_len1, VBytes, VIndex); Inc(VIndex, 2); CopyTIdUInt16(fdom_len2, VBytes, VIndex); Inc(VIndex, 2); CopyTIdUInt32(fdom_off, VBytes, VIndex); Inc(VIndex, 4); CopyTIdUInt16(fhost_len1, VBytes, VIndex); Inc(VIndex, 2); CopyTIdUInt16(fhost_len2, VBytes, VIndex); Inc(VIndex, 2); CopyTIdUInt32(fhost_off, VBytes, VIndex); Inc(VIndex, 4); end; function type_2_message_header.GetBytesLen: UInt32; begin Result := inherited GetBytesLen() + 40; end; procedure type_2_message_header.ReadStruct(const ABytes : TIdBytes; var VIndex : UInt32); begin inherited ReadStruct(ABytes, VIndex); f_type := ABytes[VIndex]; Inc(VIndex); BytesToByteArray(ABytes, fpad, VIndex); Inc(VIndex, Length(fpad)); fhost_len1 := BytesToUInt16(ABytes, VIndex); Inc(VIndex, 2); fhost_len2 := BytesToUInt16(ABytes, VIndex); Inc(VIndex, 2); fhost_off := BytesToUInt32(ABytes, VIndex); Inc(VIndex, 4); fflags := BytesToUInt16(ABytes, VIndex); Inc(VIndex, 2); BytesToByteArray(ABytes, fPad2, VIndex); Inc(VIndex, Length(fpad2)); BytesToByteArray(ABytes, fnonce, VIndex); Inc(VIndex, Length(fnonce)); BytesToByteArray(ABytes, freserved, VIndex); Inc(VIndex, Length(freserved)); finfo_len1 := BytesToUInt16(ABytes, VIndex); Inc(VIndex, 2); finfo_len2 := BytesToUInt16(ABytes, VIndex); Inc(VIndex, 2); finfo_off := BytesToUInt32(ABytes, VIndex); Inc(VIndex, 4); end; procedure type_2_message_header.WriteStruct(var VBytes : TIdBytes; var VIndex : UInt32); begin inherited WriteStruct(VBytes, VIndex); VBytes[VIndex] := f_type; Inc(VIndex); ByteArrayToBytes(fPad, VBytes, VIndex); Inc(VIndex, Length(fpad)); CopyTIdUInt16(fhost_len1, VBytes, VIndex); Inc(VIndex, 2); CopyTIdUInt16(fhost_len2, VBytes, VIndex); Inc(VIndex, 2); CopyTIdUInt32(fhost_off, VBytes, VIndex); Inc(VIndex, 4); CopyTIdUInt16(fflags, VBytes, VIndex); Inc(VIndex, 2); ByteArrayToBytes(fPad2, VBytes, VIndex); Inc(VIndex, Length(fPad2)); ByteArrayToBytes(fnonce, VBytes, VIndex); Inc(VIndex, Length(fnonce)); ByteArrayToBytes(freserved, VBytes, VIndex); Inc(VIndex, Length(freserved)); CopyTIdUInt16(finfo_len1, VBytes, VIndex); Inc(VIndex, 2); CopyTIdUInt16(finfo_len2, VBytes, VIndex); Inc(VIndex, 2); CopyTIdUInt32(finfo_off, VBytes, VIndex); Inc(VIndex, 4); end; function type_3_message_header.GetBytesLen: UInt32; begin Result := inherited GetByteLen() + ? ; end; procedure type_3_message_header.ReadStruct(const ABytes : TIdBytes; var VIndex : UInt32); begin { _type: UInt32; // 0x03 lm_resp_len1: UInt16; // LanManager response length (always 0x18) lm_resp_len2: UInt16; // LanManager response length (always 0x18) lm_resp_off: UInt32; // LanManager response offset nt_resp_len1: UInt16; // NT response length (always 0x18) nt_resp_len2: UInt16; // NT response length (always 0x18) nt_resp_off: UInt32; // NT response offset dom_len1: UInt16; // domain string length dom_len2: UInt16; // domain string length dom_off: UInt32; // domain string offset (always 0x40) user_len1: UInt16; // username string length user_len2: UInt16; // username string length user_off: UInt32; // username string offset host_len1: UInt16; // host string length host_len2: UInt16; // host string length host_off: UInt32; // host string offset zero: UInt32; msg_len: UInt32; // message length flags: UInt32; // 0xA0808205 } end; procedure type_3_message_header.WriteStruct(var VBytes : TIdBytes; var VIndex : UInt32); begin { _type: UInt32; // 0x03 lm_resp_len1: UInt16; // LanManager response length (always 0x18) lm_resp_len2: UInt16; // LanManager response length (always 0x18) lm_resp_off: UInt32; // LanManager response offset nt_resp_len1: UInt16; // NT response length (always 0x18) nt_resp_len2: UInt16; // NT response length (always 0x18) nt_resp_off: UInt32; // NT response offset dom_len1: UInt16; // domain string length dom_len2: UInt16; // domain string length dom_off: UInt32; // domain string offset (always 0x40) user_len1: UInt16; // username string length user_len2: UInt16; // username string length user_off: UInt32; // username string offset host_len1: UInt16; // host string length host_len2: UInt16; // host string length host_off: UInt32; // host string offset zero: UInt32; msg_len: UInt32; // message length flags: UInt32; // 0xA0808205 } end; {$ENDIF} end.