require 'msf/base'

module Msf
module Simple

###
#
# A simplified exploit wrapper.
#
###
module Exploit

	include Module

	#
	# Wraps the exploitation process in a simple single method.  The options
	# hash can have the following values passed in it:
	#
	# Encoder
	#
	# 	The encoder module that should be used.
	#
	# Payload
	#
	# 	The payload module name that should be used.
	#
	# Target
	#
	# 	The selected target index.
	#
	# Nop
	#
	# 	The NOP generator that should be used in preference.
	#
	# OptionStr
	#
	# 	A string of comma separated option values that should be imported into
	# 	the datastore.
	#
	# Options
	#
	# 	A hash of values to be imported directly into the datastore.
	#
	# LocalInput
	#
	# 	The local input handle that data can be read in from.
	#
	# LocalOutput
	#
	# 	The local output through which data can be displayed.
	#
	# RunAsJob
	#
	# 	Whether or not the exploit should be run in the context of a background
	# 	job.
	#
	def self.exploit_simple(exploit, opts)
		# Trap and print errors here (makes them UI-independent)
		begin

			# Import options from the OptionStr or Option hash.
			exploit._import_extra_options(opts)

			# Make sure parameters are valid.
			if (opts['Payload'] == nil)
				raise MissingPayloadError,
					"You must specify a payload.", caller
			end

			# Start it up
			driver = ExploitDriver.new(exploit.framework)

			# Initialize the driver instance
			driver.exploit    = exploit
			driver.payload    = exploit.framework.modules.create(opts['Payload'])

			# Set the force wait for session flag if the caller requested force
			# blocking.  This is so that passive exploits can be blocked on from
			# things like the cli.
			driver.force_wait_for_session = true if (opts['ForceBlocking'] == true)

			# Was the payload valid?
			if (driver.payload == nil)
				raise MissingPayloadError,
					"You specified an invalid payload: #{opts['Payload']}", caller
			end

			# Use the supplied encoder, if any.  If one was not specified, then
			# nil will be assigned causing the exploit to default to picking the
			# best encoder.
			exploit.datastore['ENCODER'] = opts['Encoder'] if opts['Encoder']

			# Force the payload to share the exploit's datastore
			driver.payload.share_datastore(driver.exploit.datastore)

			# If we still have no target index, try to use the datastore's index
			target_idx = opts['Target'] || exploit.default_target

			# Convert it to an integer if it's valid
			if (target_idx)
				target_idx = target_idx.to_i
			end

			if (target_idx == nil or target_idx < 0)
				raise MissingTargetError,
					"You must select a target.", caller
			end

			driver.target_idx = target_idx

			# Set the payload and exploit's subscriber values
			if ! opts['Quiet']
				driver.exploit.init_ui(opts['LocalInput'] || exploit.user_input, opts['LocalOutput'] || exploit.user_output)
				driver.payload.init_ui(opts['LocalInput'] || exploit.user_input, opts['LocalOutput'] || exploit.user_output)
			else
				driver.exploit.init_ui(nil, nil)
				driver.payload.init_ui(nil, nil)
			end

			if (opts['RunAsJob'])
				driver.use_job = true
			end

			# Let's rock this party
			driver.run

			# Save the job identifier this exploit is running as
			exploit.job_id = driver.job_id
		rescue ::Interrupt
			exploit.error = $!
			raise $!
		rescue ::Exception => e
			exploit.error = e
			exploit.print_error("Exploit failed: #{e}")
			elog("Exploit failed (#{exploit.refname}): #{e}", 'core', LEV_0)
			dlog("Call stack:\n#{e.backtrace.join("\n")}", 'core', LEV_3)
		end

		return driver.session if driver
		nil
	end

	#
	# Calls the class method.
	#
	def exploit_simple(opts)
		Msf::Simple::Exploit.exploit_simple(self, opts)
	end

	#
	# Initiates a check, setting up the exploit to be used.  The following
	# options can be specified:
	#
	# LocalInput
	#
	# 	The local input handle that data can be read in from.
	#
	# LocalOutput
	#
	# 	The local output through which data can be displayed.
	#
	def self.check_simple(mod, opts)
		if opts['LocalInput']
			mod.init_ui(opts['LocalInput'], opts['LocalOutput'])
		end

		# Validate the option container state so that options will
		# be normalized
		mod.validate

		# Run check
		mod.check
	end

	#
	# Calls the class method.
	#
	def check_simple(opts)
		Msf::Simple::Exploit.check_simple(self, opts)
	end

end

end
end

