module Net module NTLM class Message # @private false class Type2 < Message string :sign, {:size => 8, :value => SSP_SIGN} int32LE :type, {:value => 2} security_buffer :target_name, {:size => 0, :value => ""} int32LE :flag, {:value => DEFAULT_FLAGS[:TYPE2]} int64LE :challenge, {:value => 0} int64LE :context, {:value => 0, :active => false} security_buffer :target_info, {:value => "", :active => false} string :padding, {:size => 0, :value => "", :active => false } class << Type2 # Parse a Type 2 packet # @param [String] str A string containing Type 2 data # @return [Type2] def parse(str) t = new t.parse(str) t end end # @!visibility private def parse(str) super(str) if has_flag?(:TARGET_INFO) enable(:context) enable(:target_info) super(str) end if ( (len = data_edge - head_size) > 0) self.padding = "\0" * len super(str) end end # Generates a Type 3 response based on the Type 2 Information # @return [Type3] # @option arg [String] :username The username to authenticate with # @option arg [String] :password The user's password # @option arg [String] :domain ('') The domain to authenticate to # @option opt [String] :workstation (Socket.gethostname) The name of the calling workstation # @option opt [Boolean] :use_default_target (False) Use the domain supplied by the server in the Type 2 packet # @note An empty :domain option authenticates to the local machine. # @note The :use_default_target has presidence over the :domain option def response(arg, opt = {}) usr = arg[:user] pwd = arg[:password] domain = arg[:domain] ? arg[:domain].upcase : "" if usr.nil? or pwd.nil? raise ArgumentError, "user and password have to be supplied" end if opt[:workstation] ws = opt[:workstation] else ws = Socket.gethostname end if opt[:client_challenge] cc = opt[:client_challenge] else cc = rand(MAX64) end cc = NTLM::pack_int64le(cc) if cc.is_a?(Integer) opt[:client_challenge] = cc if has_flag?(:OEM) and opt[:unicode] usr = NTLM::EncodeUtil.decode_utf16le(usr) pwd = NTLM::EncodeUtil.decode_utf16le(pwd) ws = NTLM::EncodeUtil.decode_utf16le(ws) domain = NTLM::EncodeUtil.decode_utf16le(domain) opt[:unicode] = false end if has_flag?(:UNICODE) and !opt[:unicode] usr = NTLM::EncodeUtil.encode_utf16le(usr) pwd = NTLM::EncodeUtil.encode_utf16le(pwd) ws = NTLM::EncodeUtil.encode_utf16le(ws) domain = NTLM::EncodeUtil.encode_utf16le(domain) opt[:unicode] = true end if opt[:use_default_target] domain = self.target_name end ti = self.target_info chal = self[:challenge].serialize if opt[:ntlmv2] ar = {:ntlmv2_hash => NTLM::ntlmv2_hash(usr, pwd, domain, opt), :challenge => chal, :target_info => ti} lm_res = NTLM::lmv2_response(ar, opt) ntlm_res = NTLM::ntlmv2_response(ar, opt) elsif has_flag?(:NTLM2_KEY) ar = {:ntlm_hash => NTLM::ntlm_hash(pwd, opt), :challenge => chal} lm_res, ntlm_res = NTLM::ntlm2_session(ar, opt) else lm_res = NTLM::lm_response(pwd, chal) ntlm_res = NTLM::ntlm_response(pwd, chal) end Type3.create({ :lm_response => lm_res, :ntlm_response => ntlm_res, :domain => domain, :user => usr, :workstation => ws, :flag => self.flag }) end end end end end