require 'msf/core'

module Msf

###
#
# This module exposes methods for accessing NDMP services
#
###
module Exploit::Remote::NDMP
	
	include Exploit::Remote::Tcp
	
	#
	# Creates an instance of a NDMP exploit module.
	#
	def initialize(info = {})
		super

		# Register the options that all NDMP exploits may make use of.
		register_options(
			[
				Opt::RHOST,
				Opt::RPORT(10000),
			], Msf::Exploit::Remote::NDMP)

		self.recv_buff = ''
	end
	
	#
	# Flush the receive buffer on a new connection
	#
	def connect
		super
		self.recv_buff = ''
	end
		
	#
	# This method dumps ndmp version information
	#
	def ndmp_info
		connect
		req = [
				1,               # Sequence number
				Time.now.to_i,   # Current time
				0,               # Message type (request)
				0x108,           # Message name (version)
				0,               # Reply sequence number
				0,               # Error status
			].pack('NNNNNN')
		
		resp = ndmp_recv()
		ndmp_send(req)
		resp = ndmp_recv()
		disconnect
		
		if !(resp and resp.length > 28)
			return false
		end
		
		info = { }
		
		i = 32
		
		vend_len = resp[i, 4].unpack('N')[0]
		vend     = resp[i + 4, vend_len]
		i += vend_len + 4 + 1
		
		prod_len = resp[i, 4].unpack('N')[0]
		prod     = resp[i + 4, prod_len]
		i += prod_len + 4 + 1
		
		vers_len = resp[i, 4].unpack('N')[0]
		vers     = resp[i + 4, vers_len]
		i += vers_len + 4 + 1

		info['Version'] = vers
		info['Product'] = prod
		info['Vendor']  = vend
		
		return info
	end
	
	#
	# This method reads from the socket and parses out a single
	# NDMP response, buffering the rest
	#
	def ndmp_recv(nsock = self.sock)
		if (self.recv_buff.length < 4)
			self.recv_buff << (sock.get_once || '')
		end

		if (self.recv_buff.length < 4)
			return false
		end
				
		# Read the length header out of the message
		dlen = self.recv_buff[0, 4].unpack('N')[0] & 0x7fffffff
		
		# Do we have the entire response message?
		if (self.recv_buff.length >= dlen + 4)
			return self.recv_buff.slice!(0, dlen + 4)
		end
		
		return false
	end
	
	#
	# This method tacks a length header on a packet then sends
	# it out the socket
	#
	def ndmp_send(data, nsock = self.sock)		
		nsock.put( [ data.length + 0x80000000 ].pack('N') + data )
	end	
	
	attr_accessor	:recv_buff
end
end