# $Id$
# $Revision$

require 'nessus/nessus-xmlrpc'
require 'rex/parser/nessus_xml'

module Msf
	class Plugin::Nessus < Msf::Plugin

		#creates the index of exploit details to make searching for exploits much faster.
		def create_xindex
			start = Time.now
				print_status("Creating Exploit Search Index - (#{@xindex}) - this wont take long.")
				count = 0
				# use Msf::Config.get_config_root as the location.
				File.open("#{@xindex}", "w+") do |f|
					#need to add version line.
					f.puts(Msf::Framework::RepoRevision)
					framework.exploits.sort.each { |refname, mod|
						stuff = ""
						o = nil
						begin
							o = mod.new
						rescue ::Exception
						end
						stuff << "#{refname}|#{o.name}|#{o.platform_to_s}|#{o.arch_to_s}"
						next if not o
						o.references.map do |x|
							if !(x.ctx_id == "URL")
								if (x.ctx_id == "MSB")
									stuff << "|#{x.ctx_val}"
								else
									stuff << "|#{x.ctx_id}-#{x.ctx_val}"
								end
							end
						end
						stuff << "\n"
						f.puts(stuff)
					}
				end
				total = Time.now - start
				print_status("It has taken : #{total} seconds to build the exploits search index")
		end

		def nessus_index
			if File.exist?("#{@xindex}")
				#check if it's version line matches current version.
				File.open("#{@xindex}") {|f|
					line = f.readline
					line.chomp!
					if line.to_i == Msf::Framework::RepoRevision
						print_good("Exploit Index - (#{@xindex}) -  is valid.")
					else
						create_xindex
					end
				}
			else
				create_xindex
			end
		end

		class ConsoleCommandDispatcher
			include Msf::Ui::Console::CommandDispatcher

			def name
				"Nessus"
			end

			def commands
				{
					"nessus_connect" => "Connect to a nessus server: nconnect username:password@hostname:port <ssl ok>.",
					"nessus_admin" => "Checks if user is an admin.",
					"nessus_help" => "Get help on all commands.",
					"nessus_logout" => "Terminate the session.",
					"nessus_server_status" => "Check the status of your Nessus Server.",
					"nessus_server_feed" => "Nessus Feed Type.",
					"nessus_server_prefs" => "Display Server Prefs.",
					"nessus_report_list" => "List all Nessus reports.",
					"nessus_report_get" => "Import a report from the nessus server in Nessus v2 format.",
					"nessus_report_del" => "Delete a report.",
					"nessus_report_vulns" => "Get list of vulns from a report.",
					"nessus_report_hosts" => "Get list of hosts from a report.",
					"nessus_report_host_ports" => "Get list of open ports from a host from a report.",
					"nessus_report_host_detail" => "Detail from a report item on a host.",
					"nessus_scan_status" => "List all currently running Nessus scans.",
					"nessus_scan_new" => "Create new Nessus Scan.",
					"nessus_scan_pause" => "Pause a Nessus Scan.",
					"nessus_scan_pause_all" => "Pause all Nessus Scans.",
					"nessus_scan_stop" => "Stop a Nessus Scan.",
					"nessus_scan_stop_all" => "Stop all Nessus Scans.",
					"nessus_scan_resume" => "Resume a Nessus Scan.",
					"nessus_scan_resume_all" => "Resume all Nessus Scans.",
					"nessus_user_list" => "Show Nessus Users.",
					"nessus_user_add" => "Add a new Nessus User.",
					"nessus_user_del" => "Delete a Nessus User.",
					"nessus_user_passwd" => "Change Nessus Users Password.",
					"nessus_plugin_family" => "List plugins in a family.",
					"nessus_plugin_details" => "List details of a particular plugin.",
					"nessus_plugin_list" => "Displays each plugin family and the number of plugins.",
					"nessus_plugin_prefs" => "Display Plugin Prefs.",
					"nessus_policy_list" => "List all polciies.",
					"nessus_policy_del" => "Delete a policy.",
					"nessus_index" => "Manually generates a search index for exploits.",
					"nessus_template_list" => "List all the templates on the server.",
					"nessus_db_scan" => "Create a scan of all ips in db_hosts.",
					"nessus_save" => "Save username/passowrd/server/port details."
					}
			end

			def cmd_nessus_index
				Msf::Plugin::Nessus.nessus_index
			end

			def cmd_nessus_save(*args)
				#if we are logged in, save session details to nessus.yaml
				@nessus_yaml = "#{Msf::Config.get_config_root}/nessus.yaml"
				if args[0] == "-h"
					print_status("Usage: ")
					print_status("       nessus_save")
					return
				end

				if args[0]
					print_status("Usage: ")
					print_status("       nessus_save")
					return
				end

				group = "default"

				if ((@user and @user.length > 0) and (@host and @host.length > 0) and (@port and @port.length > 0 and @port.to_i > 0) and (@pass and @pass.length > 0))
					config = Hash.new
					config = {"#{group}" => {'username' => @user, 'password' => @pass, 'server' => @host, 'port' => @port}}
					File.open("#{@nessus_yaml}", "w+") do |f|
						f.puts YAML.dump(config)
					end
					print_good("#{@nessus_yaml} created.")

				else
					print_error("Missing username/password/server/port - relogin and then try again.")
					return
				end
			end

			def cmd_nessus_db_scan(*args)
				if args[0] == "-h"
					print_status("Usage: ")
					print_status("       nessus_db_scan <policy id> <scan name>")
					print_status(" Example:> nessus_db_scan 1 \"My Scan\"")
					print_status()
					print_status("Creates a scan based on all the hosts listed in db_hosts.")
					print_status("use nessus_policy_list to list all available policies")
					return
				end

				if ! nessus_verify_token
					return
				end

				case args.length
				when 2
					pid = args[0].to_i
					name = args[1]
				else
					print_status("Usage: ")
					print_status("       nessus_db_scan <policy id> <scan name>")
					print_status("       use nessus_policy_list to list all available policies")
					return
				end

				if check_policy(pid)
					print_error("That policy does not exist.")
					return
				end

				tgts = ""
				framework.db.hosts(framework.db.workspace).each do |host|
					tgts << host.address
					tgts << ","
				end

				tgts.chop!

				print_status("Creating scan from policy number #{pid}, called \"#{name}\" and scanning all hosts in workspace")

				scan = @n.scan_new(pid, name, tgts)

				if scan
					print_status("Scan started.  uid is #{scan}")
				end

			end

			def cmd_nessus_logout
				@token = nil
				print_status("Logged out")
				system("rm #{@nessus_yaml}")
				print_good("#{@nessus_yaml} removed.")
				return
			end

			def cmd_nessus_help(*args)
				tbl = Rex::Ui::Text::Table.new(
					'Columns' => [
						'Command',
						'Help Text'
					]
				)
				tbl << [ "Generic Commands", "" ]
				tbl << [ "-----------------", "-----------------"]
				tbl << [ "nessus_connect", "Connect to a nessus server" ]
				tbl << [ "nessus_save", "Save nessus login info between sessions" ]
				tbl << [ "nessus_logout", "Logout from the nessus server" ]
				tbl << [ "nessus_help", "Listing of available nessus commands" ]
				tbl << [ "nessus_server_status", "Check the status of your Nessus Server" ]
				tbl << [ "nessus_admin", "Checks if user is an admin" ]
				tbl << [ "nessus_server_feed", "Nessus Feed Type" ]
				tbl << [ "nessus_find_targets", "Try to find vulnerable targets from a report" ]
				tbl << [ "nessus_server_prefs", "Display Server Prefs" ]
				tbl << [ "", ""]
				tbl << [ "Reports Commands", "" ]
				tbl << [ "-----------------", "-----------------"]
				tbl << [ "nessus_report_list", "List all Nessus reports" ]
				tbl << [ "nessus_report_get", "Import a report from the nessus server in Nessus v2 format" ]
				tbl << [ "nessus_report_vulns", "Get list of vulns from a report" ]
				tbl << [ "nessus_report_hosts", "Get list of hosts from a report" ]
				tbl << [ "nessus_report_host_ports", "Get list of open ports from a host from a report" ]
				tbl << [ "nessus_report_host_detail", "Detail from a report item on a host" ]
				tbl << [ "", ""]
				tbl << [ "Scan Commands", "" ]
				tbl << [ "-----------------", "-----------------"]
				tbl << [ "nessus_scan_new", "Create new Nessus Scan" ]
				tbl << [ "nessus_scan_status", "List all currently running Nessus scans" ]
				tbl << [ "nessus_scan_pause", "Pause a Nessus Scan" ]
				tbl << [ "nessus_scan_pause_all", "Pause all Nessus Scans" ]
				tbl << [ "nessus_scan_stop", "Stop a Nessus Scan" ]
				tbl << [ "nessus_scan_stop_all", "Stop all Nessus Scans" ]
				tbl << [ "nessus_scan_resume", "Resume a Nessus Scan" ]
				tbl << [ "nessus_scan_resume_all", "Resume all Nessus Scans" ]
				tbl << [ "", ""]
				tbl << [ "Plugin Commands", "" ]
				tbl << [ "-----------------", "-----------------"]
				tbl << [ "nessus_plugin_list", "Displays each plugin family and the number of plugins" ]
				tbl << [ "nessus_plugin_family", "List plugins in a family" ]
				tbl << [ "nessus_plugin_details", "List details of a particular plugin" ]
				tbl << [ "", ""]
				tbl << [ "User Commands", "" ]
				tbl << [ "-----------------", "-----------------"]
				tbl << [ "nessus_user_list", "Show Nessus Users" ]
				tbl << [ "nessus_user_add", "Add a new Nessus User" ]
				tbl << [ "nessus_user_del", "Delete a Nessus User" ]
				tbl << [ "nessus_user_passwd", "Change Nessus Users Password" ]
				tbl << [ "", ""]
				tbl << [ "Policy Commands", "" ]
				tbl << [ "-----------------", "-----------------"]
				tbl << [ "nessus_policy_list", "List all polciies" ]
				tbl << [ "nessus_policy_del", "Delete a policy" ]
				print_status ""
				print_line tbl.to_s
				print_status ""
			end

			def cmd_nessus_server_feed(*args)

				if args[0] == "-h"
					print_status("Usage: ")
					print_status("       nessus_server_feed")
					print_status(" Example:> nessus_server_feed")
					print_status()
					print_status("Returns information about the feed type and server version.")
					return
				end

				if nessus_verify_token
					@feed, @version, @web_version = @n.feed
					tbl = Rex::Ui::Text::Table.new(
						'Columns' => [
							'Feed',
							'Nessus Version',
							'Nessus Web Version'
						])
					tbl << [@feed, @version, @web_version]
					print_good("Nessus Status")
					print_good "\n"
					print_line tbl.to_s
				end
			end

			def nessus_verify_token
				if @token.nil? or @token == ''
					ncusage
					return false
				end
				true
			end

			def nessus_verify_db

				if ! (framework.db and framework.db.active)
					print_error("No database has been configured, please use db_create/db_connect first")
					return false
				end
				true
			end

			def ncusage
				print_status("%redYou must do this before any other commands.%clr")
				print_status("Usage: ")
				print_status("       nessus_connect username:password@hostname:port <ssl ok>")
				print_status(" Example:> nessus_connect msf:msf@192.168.1.10:8834 ok")
				print_status("          OR")
				print_status("       nessus_connect username@hostname:port <ssl ok>")
				print_status(" Example:> nessus_connect msf@192.168.1.10:8834 ok")
				print_status("          OR")
				print_status("       nessus_connect hostname:port <ssl ok>")
				print_status(" Example:> nessus_connect 192.168.1.10:8834 ok")
				print_status("          OR")
				print_status("       nessus_connect")
				print_status(" Example:> nessus_connect")
				print_status("This only works after you have saved creds with nessus_save")
				return
			end

			def cmd_nessus_connect(*args)
				# Check if config file exists and load it
				@nessus_yaml = "#{Msf::Config.get_config_root}/nessus.yaml"
				if ! args[0]
					if File.exist?("#{@nessus_yaml}")
						lconfig = YAML.load_file("#{@nessus_yaml}")
						@user = lconfig['default']['username']
						@pass = lconfig['default']['password']
						@host = lconfig['default']['server']
						@port = lconfig['default']['port']
						nessus_login
						return
					else
						ncusage
						return
					end
				end

				if args[0] == "-h"
					print_status("%redYou must do this before any other commands.%clr")
					print_status("Usage: ")
					print_status("       nessus_connect username:password@hostname:port <ssl ok>")
					print_status(" Example:> nessus_connect msf:msf@192.168.1.10:8834 ok")
					print_status("		OR")
					print_status("       nessus_connect username@hostname:port <ssl ok>")
					print_status(" Example:> nessus_connect msf@192.168.1.10:8834 ok")
					print_status("		OR")
					print_status("       nessus_connect hostname:port <ssl ok>")
					print_status(" Example:> nessus_connect 192.168.1.10:8834 ok")
					print_status("          OR")
					print_status("       nessus_connect")
					print_status(" Example:> nessus_connect")
					print_status("This only works after you have saved creds with nessus_save")
					print_status()
					print_status("%bldusername%clr and %bldpassword%clr are the ones you use to login to the nessus web front end")
					print_status("%bldhostname%clr can be an ip address or a dns name of the web front end.")
					print_status("%bldport%clr is the standard that the nessus web front end runs on : 8834.  This is NOT 1241.")
					print_status("The \"ok\" on the end is important.  It is a way of letting you")
					print_status("know that nessus used a self signed cert and the risk that presents.")
					return
				end

				if ! @token == ''
					print_error("You are already authenticated.  Call nessus_logout before authing again")
					return
				end

				if(args.length == 0 or args[0].empty?)
					ncusage
					return
				end

				@user = @pass = @host = @port = @sslv = nil

				case args.length
				when 1,2
					if args[0].include? "@"
						cred,targ = args[0].split('@', 2)
						@user,@pass = cred.split(':', 2)
						targ ||= '127.0.0.1:8834'
						@host,@port = targ.split(':', 2)
						@port ||= '8834'
						@sslv = args[1]
					else
						@host,@port = args[0].split(':', 2)
						@port ||= '8834'
						@sslv = args[1]
					end

				when 3,4,5
					ncusage
					return
				else
					ncusage
					return
				end

				if /\/\//.match(@host)
					ncusage
					return
				end

				if(@host != "localhost" and @host != "127.0.0.1" and @sslv != "ok")
					print_error("Warning: SSL connections are not verified in this release, it is possible for an attacker")
					print_error("         with the ability to man-in-the-middle the Nessus traffic to capture the Nessus")
					print_error("         credentials. If you are running this on a trusted network, please pass in 'ok'")
					print_error("         as an additional parameter to this command.")
					return
				end

				if ! @user
					print_error("Missing Username")
					ncusage
					return
				end

				if ! @pass
					print_error("Missing Password")
					ncusage
					return
				end

				if ! ((@user and @user.length > 0) and (@host and @host.length > 0) and (@port and @port.length > 0 and @port.to_i > 0) and (@pass and @pass.length > 0))
					ncusage
					return
				end
				nessus_login
			end

			def nessus_login

				if ! ((@user and @user.length > 0) and (@host and @host.length > 0) and (@port and @port.length > 0 and @port.to_i > 0) and (@pass and @pass.length > 0))
					print_status("You need to connect to a server first.")
					ncusage
					return
				end

				@url = "https://#{@host}:#{@port}/"
				print_status("Connecting to #{@url} as #{@user}")
				@n=NessusXMLRPC::NessusXMLRPC.new(@url,@user,@pass)
				@token=@n.login(@user,@pass)
				if @n.logged_in
					print_status("Authenticated")
				else
					print_error("Error connecting/logging to the server!")
					return
				end
			end

			def cmd_nessus_report_list(*args)

				if args[0] == "-h"
					print_status("Usage: ")
					print_status("       nessus_report_list")
					print_status(" Example:> nessus_report_list")
					print_status()
					print_status("Generates a list of all reports visable to your user.")
					return
				end

				if ! nessus_verify_token
					return
				end

				list=@n.report_list_hash

				tbl = Rex::Ui::Text::Table.new(
					'Columns' => [
						'ID',
						'Name',
						'Status',
						'Date'
					])

				list.each {|report|
					t = Time.at(report['timestamp'].to_i)
					tbl << [ report['id'], report['name'], report['status'], t.strftime("%H:%M %b %d %Y") ]
				}
				print_good("Nessus Report List")
				print_good "\n"
				print_line tbl.to_s + "\n"
				print_status("You can:")
				print_status("        Get a list of hosts from the report:          nessus_report_hosts <report id>")
			end

			def check_scan(*args)

				case args.length
				when 1
					rid = args[0]
				else
					print_error("No Report ID Supplied")
					return
				end

				scans = @n.scan_list_hash
				scans.each {|scan|
					if scan['id'] == rid
						return true
					end
				}
				return false
			end

			def cmd_nessus_report_get(*args)

				if args[0] == "-h"
					print_status("Usage: ")
					print_status("       nessus_report_get <report id>")
					print_status(" Example:> nessus_report_get f0eabba3-4065-7d54-5763-f191e98eb0f7f9f33db7e75a06ca")
					print_status()
					print_status("This command pulls the provided report from the nessus server in the nessusv2 format")
					print_status("and parses it the same way db_import_nessus does.  After it is parsed it will be")
					print_status("available to commands such as db_hosts, db_vulns, db_services and db_autopwn.")
					print_status("Use: nessus_report_list to obtain a list of report id's")
					return
				end

				if ! nessus_verify_token
					return
				end

				if ! nessus_verify_db
					return
				end

				if(args.length == 0 or args[0].empty? or args[0] == "-h")
					print_status("Usage: ")
					print_status("       nessus_report_get <report id> ")
					print_status("       use nessus_report_list to list all available reports for importing")
					return
				end

				rid = nil

				case args.length
				when 1
					rid = args[0]
				else
					print_status("Usage: ")
					print_status("       nessus_report_get <report id> ")
					print_status("       use nessus_report_list to list all available reports for importing")
					return
				end

				if check_scan(rid)
					print_error("That scan is still running.")
					return
				end
				content = nil
				content=@n.report_file_download(rid)
				if content.nil?
					print_error("Failed, please reauthenticate")
					return
				end
				print_status("importing " + rid)
				framework.db.import({:data => content}) do |type,data|
					case type
					when :address
						print_line("%bld%blu[*]%clr %bld#{data}%clr")
					end
				end
				print_good("Done")
			end

			def cmd_nessus_scan_status(*args)

				if args[0] == "-h"
					print_status("Usage: ")
					print_status("       nessus_scan_status")
					print_status(" Example:> nessus_scan_status")
					print_status()
					print_status("Returns a list of information about currently running scans.")
					return
				end

				if ! nessus_verify_token
					return
				end

				list=@n.scan_list_hash
				if list.empty?
					print_status("No Scans Running.")
					print_status("You can:")
					print_status("        List of completed scans:     	nessus_report_list")
					print_status("        Create a scan:           		nessus_scan_new <policy id> <scan name> <target(s)>")
					return
				end

				tbl = Rex::Ui::Text::Table.new(
					'Columns' => [
						'Scan ID',
						'Name',
						'Owner',
						'Started',
						'Status',
						'Current Hosts',
						'Total Hosts'
					])

				list.each {|scan|
					t = Time.at(scan['start'].to_i)
					tbl << [ scan['id'], scan['name'], scan['owner'], t.strftime("%H:%M %b %d %Y"), scan['status'], scan['current'], scan['total'] ]
				}
				print_good("Running Scans")
				print_good "\n"
				print_line tbl.to_s
				print_good "\n"
				print_status("You can:")
				print_good("		Import Nessus report to database : 	nessus_report_get <reportid>")
				print_good("		Pause a nessus scan : 			nessus_scan_pause <scanid>")
			end

			def cmd_nessus_template_list(*args)

				if args[0] == "-h"
					print_status("Usage: ")
					print_status("       nessus_template_list")
					print_status(" Example:> nessus_template_list")
					print_status()
					print_status("Returns a list of information about the server templates..")
					return
				end

				if ! nessus_verify_token
					return
				end

				list=@n.template_list_hash

				if list.empty?
					print_status("No Templates Created.")
					print_status("You can:")
					print_status("        List of completed scans:     	nessus_report_list")
					print_status("        Create a template:           		nessus_template_new <policy id> <scan name> <target(s)>")
					return
				end

				tbl = Rex::Ui::Text::Table.new(
					'Columns' => [
						'Template ID',
						'Policy ID',
						'Name',
						'Owner',
						'Target'
					])

				list.each {|template|
					tbl << [ template['name'], template['pid'], template['rname'], template['owner'], template['target'] ]
				}
				print_good("Templates")
				print_good "\n"
				print_line tbl.to_s + "\n"
				print_good "\n"
				print_status("You can:")
				print_good("		Import Nessus report to database : 	nessus_report_get <reportid>")
			end

			def cmd_nessus_user_list(*args)

				if args[0] == "-h"
					print_status("Usage: ")
					print_status("       nessus_user_list")
					print_status(" Example:> nessus_user_list")
					print_status()
					print_status("Returns a list of the users on the Nessus server and their access level.")
					return
				end

				if ! nessus_verify_token
					return
				end

				if ! @n.is_admin
					print_status("Your Nessus user is not an admin")
				end

				list=@n.users_list
				print_good("There are #{list.length} users")
				tbl = Rex::Ui::Text::Table.new(
					'Columns' => [
						'Name',
						'Is Admin?',
						'Last Login'
					])

				list.each {|user|
					t = Time.at(user['lastlogin'].to_i)
					tbl << [ user['name'], user['admin'], t.strftime("%H:%M %b %d %Y") ]
				}
				print_good("Nessus users")
				print_good "\n"
				print_line tbl.to_s
			end

			def cmd_nessus_server_status(*args)

				if args[0] == "-h"
					print_status("Usage: ")
					print_status("       nessus_server_status")
					print_status(" Example:> nessus_server_status")
					print_status()
					print_status("Returns some status items for the server..")
					return
				end
				#Auth
				if ! nessus_verify_token
					return
				end

				#Check if we are an admin
				if ! @n.is_admin
					print_status("You need to be an admin for this.")
					return
				end

				#Versions
				cmd_nessus_server_feed

				tbl = Rex::Ui::Text::Table.new(
					'Columns' => [
						'Users',
						'Policies',
						'Running Scans',
						'Reports',
						'Plugins'
					])
				#Count how many users the server has.
				list=@n.users_list
				users = list.length

				#Count how many policies
				list=@n.policy_list_hash
				policies = list.length

				#Count how many running scans
				list=@n.scan_list_uids
				scans = list.length

				#Count how many reports are available
				list=@n.report_list_hash
				reports = list.length

				#Count how many plugins
				list=@n.plugins_list
				total = Array.new
				list.each {|plugin|
					total.push(plugin['num'].to_i)
				}
				plugins = total.sum
				tbl << [users, policies, scans, reports, plugins]
				print_good "\n"
				print_line tbl.to_s
			end

			def cmd_nessus_plugin_list(*args)

				if args[0] == "-h"
					print_status("Usage: ")
					print_status("       nessus_plugin_list")
					print_status(" Example:> nessus_plugin_list")
					print_status()
					print_status("Returns a list of the plugins on the server per family.")
					return
				end

				if ! nessus_verify_token
					return
				end

				tbl = Rex::Ui::Text::Table.new(
					'Columns' => [
						'Family Name',
						'Total Plugins'
					])
				list=@n.plugins_list
				total = Array.new
				list.each {|plugin|
					total.push(plugin['num'].to_i)
					tbl << [ plugin['name'], plugin['num'] ]
				}
				plugins = total.sum
				tbl << [ '', '']
				tbl << [ 'Total Plugins', plugins ]
				print_good("Plugins By Family")
				print_good "\n"
				print_line tbl.to_s
				print_status("List plugins for a family : nessus_plugin_family <family name>")
			end

			def check_policy(*args)

				case args.length
				when 1
					pid = args[0]
				else
					print_error("No Policy ID supplied.")
					return
				end

				pol = @n.policy_list_hash
				pol.each {|p|
					if p['id'].to_i == pid
						return false
					end
				}
				return true
			end

			def cmd_nessus_scan_new(*args)

				if args[0] == "-h"
					print_status("Usage: ")
					print_status("       nessus_scan_new <policy id> <scan name> <targets>")
					print_status(" Example:> nessus_scan_new 1 \"My Scan\" 192.168.1.250")
					print_status()
					print_status("Creates a scan based on a policy id and targets.")
					print_status("use nessus_policy_list to list all available policies")
					return
				end

				if ! nessus_verify_token
					return
				end

				case args.length
				when 3
					pid = args[0].to_i
					name = args[1]
					tgts = args[2]
				else
					print_status("Usage: ")
					print_status("       nessus_scan_new <policy id> <scan name> <targets>")
					print_status("       use nessus_policy_list to list all available policies")
					return
				end

				if check_policy(pid)
					print_error("That policy does not exist.")
					return
				end

				print_status("Creating scan from policy number #{pid}, called \"#{name}\" and scanning #{tgts}")

				scan = @n.scan_new(pid, name, tgts)

				if scan
					print_status("Scan started.  uid is #{scan}")
				end
			end

			def cmd_nessus_scan_pause(*args)

				if args[0] == "-h"
					print_status("Usage: ")
					print_status("       nessus_scan_pause <scan id>")
					print_status(" Example:> nessus_scan_pause f0eabba3-4065-7d54-5763-f191e98eb0f7f9f33db7e75a06ca")
					print_status()
					print_status("Pauses a running scan")
					print_status("use nessus_scan_status to list all available scans")
					return
				end

				if ! nessus_verify_token
					return
				end

				case args.length
				when 1
					sid = args[0]
				else
					print_status("Usage: ")
					print_status("       nessus_scan_pause <scan id>")
					print_status("       use nessus_scan_status to list all available scans")
					return
				end

				pause = @n.scan_pause(sid)

				print_status("#{sid} has been paused")
			end

			def cmd_nessus_scan_resume(*args)

				if args[0] == "-h"
					print_status("Usage: ")
					print_status("       nessus_scan_resume <scan id>")
					print_status(" Example:> nessus_scan_resume f0eabba3-4065-7d54-5763-f191e98eb0f7f9f33db7e75a06ca")
					print_status()
					print_status("resumes a running scan")
					print_status("use nessus_scan_status to list all available scans")
					return
				end

				if ! nessus_verify_token
					return
				end

				case args.length
				when 1
					sid = args[0]
				else
					print_status("Usage: ")
					print_status("       nessus_scan_resume <scan id>")
					print_status("       use nessus_scan_status to list all available scans")
					return
				end

				resume = @n.scan_resume(sid)

				print_status("#{sid} has been resumed")
			end

			def cmd_nessus_report_hosts(*args)

				if args[0] == "-h"
					print_status("Usage: ")
					print_status("       nessus_report_hosts <report id>")
					print_status(" Example:> nessus_report_hosts f0eabba3-4065-7d54-5763-f191e98eb0f7f9f33db7e75a06ca")
					print_status()
					print_status("Returns all the hosts associated with a scan and details about their vulnerabilities")
					print_status("use nessus_report_list to list all available scans")
					return
				end

				if ! nessus_verify_token
					return
				end

				case args.length
				when 1
					rid = args[0]
				else
					print_status("Usage: ")
					print_status("       nessus_report_hosts <report id>")
					print_status("       use nessus_report_list to list all available reports")
					return
				end

				tbl = Rex::Ui::Text::Table.new(
					'Columns' => [
						'Hostname',
						'Severity',
						'Sev 0',
						'Sev 1',
						'Sev 2',
						'Sev 3',
						'Current Progress',
						'Total Progress'
					])
				hosts=@n.report_hosts(rid)
				hosts.each {|host|
					tbl << [ host['hostname'], host['severity'], host['sev0'], host['sev1'], host['sev2'], host['sev3'], host['current'], host['total'] ]
				}
				print_good("Report Info")
				print_good "\n"
				print_line tbl.to_s
				print_status("You can:")
				print_status("        Get information from a particular host:          nessus_report_host_ports <hostname> <report id>")
			end

			def cmd_nessus_report_vulns(*args)

				if args[0] == "-h"
					print_status("Usage: ")
					print_status("       nessus_report_vulns <report id>")
					print_status(" Example:> nessus_report_vulns f0eabba3-4065-7d54-5763-f191e98eb0f7f9f33db7e75a06ca")
					print_status()
					print_status("Returns all the vulns associated with a scan and details about hosts and their vulnerabilities")
					print_status("use nessus_report_list to list all available scans")
					return
				end

				if ! nessus_verify_token
					return
				end

				case args.length
				when 1
					rid = args[0]
				else
					print_status("Usage: ")
					print_status("       nessus_report_vulns <report id>")
					print_status("       use nessus_report_vulns to list all available reports")
					return
				end

				tbl = Rex::Ui::Text::Table.new(
					'Columns' => [
						'Hostname',
						'Port',
						'Proto',
						'Sev',
						'PluginID',
						'Plugin Name'
					])
				print_status("Grabbing all vulns for report #{rid}")
				hosts=@n.report_hosts(rid)
				hosts.each do |host|
					ports=@n.report_host_ports(rid, host['hostname'])
					ports.each do |port|
						details=@n.report_host_port_details(rid, host['hostname'], port['portnum'], port['protocol'])
						details.each do |detail|
							tbl << [host['hostname'],
							port['portnum'],
							port['protocol'],
							detail['severity'],
							detail['pluginID'],
							detail['pluginName']
							]
						end
					end
				end
				print_good("Report Info")
				print_line
				print_line tbl.to_s
				print_status("You can:")
				print_status("        Get information from a particular host:          nessus_report_host_ports <hostname> <report id>")
			end

			def cmd_nessus_report_host_ports(*args)

				if args[0] == "-h"
					print_status("Usage: ")
					print_status("       nessus_report_host_ports <hostname> <report id>")
					print_status(" Example:> nessus_report_host_ports 192.168.1.250 f0eabba3-4065-7d54-5763-f191e98eb0f7f9f33db7e75a06ca")
					print_status()
					print_status("Returns all the ports associated with a host and details about their vulnerabilities")
					print_status("use nessus_report_hosts to list all available hosts for a report")
				end

				if ! nessus_verify_token
					return
				end

				case args.length
				when 2
					host = args[0]
					rid = args[1]
				else
					print_status("Usage: ")
					print_status("       nessus_report_host_ports <hostname> <report id>")
					print_status("       use nessus_report_list to list all available reports")
					return
				end

				tbl = Rex::Ui::Text::Table.new(
					'Columns' => [
						'Port',
						'Protocol',
						'Severity',
						'Service Name',
						'Sev 0',
						'Sev 1',
						'Sev 2',
						'Sev 3'
					])
				ports=@n.report_host_ports(rid, host)
				ports.each {|port|
					tbl << [ port['portnum'], port['protocol'], port['severity'], port['svcname'], port['sev0'], port['sev1'], port['sev2'], port['sev3'] ]
				}
				print_good("Host Info")
				print_good "\n"
				print_line tbl.to_s
				print_status("You can:")
				print_status("        Get detailed scan infromation about a specfic port: nessus_report_host_detail <hostname> <port> <protocol> <report id>")
			end

			def cmd_nessus_report_host_detail(*args)

				if args[0] == "-h"
					print_status("Usage: ")
					print_status("       nessus_report_host_detail <hostname> <port> <protocol> <report id>")
					print_status(" Example:> nessus_report_host_ports 192.168.1.250 445 tcp f0eabba3-4065-7d54-5763-f191e98eb0f7f9f33db7e75a06ca")
					print_status()
					print_status("Returns all the vulns associated with a port for a specific host")
					print_status("use nessus_report_host_ports to list all available ports for a host")
					return
				end

				if ! nessus_verify_token
					return
				end

				case args.length
				when 4
					host = args[0]
					port = args[1]
					prot = args[2]
					rid = args[3]
				else
					print_status("Usage: ")
					print_status("       nessus_report_host_detail <hostname> <port> <protocol> <report id>")
					print_status("       use nessus_report_host_ports to list all available ports")
					return
				end

				tbl = Rex::Ui::Text::Table.new(
					'Columns' => [
						'Port',
						'Severity',
						'PluginID',
						'Plugin Name',
						'CVSS2',
						'Exploit?',
						'CVE',
						'Risk Factor',
						'CVSS Vector'
					])
				details=@n.report_host_port_details(rid, host, port, prot)
				details.each {|detail|
					tbl << [
						detail['port'],
						detail['severity'],
						detail['pluginID'],
						detail['pluginName'],
						detail['cvss_base_score'] || 'none',
						detail['exploit_available'] || '.',
						detail['cve'] || '.',
						detail['risk_factor'] || '.',
						detail['cvss_vector'] || '.'
					]
				}
				print_good("Port Info")
				print_good "\n"
				print_line tbl.to_s
			end

			def cmd_nessus_scan_pause_all(*args)

				if args[0] == "-h"
					print_status("Usage: ")
					print_status("       nessus_scan_pause_all")
					print_status(" Example:> nessus_scan_pause_all")
					print_status()
					print_status("Pauses all currently running scans")
					print_status("use nessus_scan_list to list all running scans")
					return
				end

				if ! nessus_verify_token
					return
				end

				pause = @n.scan_pause_all

				print_status("All scans have been paused")
			end

			def cmd_nessus_scan_stop(*args)

				if args[0] == "-h"
					print_status("Usage: ")
					print_status("       nessus_scan_stop <scan id>")
					print_status(" Example:> nessus_scan_stop f0eabba3-4065-7d54-5763-f191e98eb0f7f9f33db7e75a06ca")
					print_status()
					print_status("Stops a currently running scans")
					print_status("use nessus_scan_list to list all running scans")
					return
				end

				if ! nessus_verify_token
					return
				end

				case args.length
				when 1
					sid = args[0]
				else
					print_status("Usage: ")
					print_status("       nessus_scan_stop <scan id>")
					print_status("       use nessus_scan_status to list all available scans")
					return
				end

				pause = @n.scan_stop(sid)

				print_status("#{sid} has been stopped")
			end

			def cmd_nessus_scan_stop_all(*args)

				if args[0] == "-h"
					print_status("Usage: ")
					print_status("       nessus_scan_stop_all")
					print_status(" Example:> nessus_scan_stop_all")
					print_status()
					print_status("stops all currently running scans")
					print_status("use nessus_scan_list to list all running scans")
					return
				end

				if ! nessus_verify_token
					return
				end

				pause = @n.scan_stop_all

				print_status("All scans have been stopped")
			end

			def cmd_nessus_scan_resume_all(*args)

				if args[0] == "-h"
					print_status("Usage: ")
					print_status("       nessus_scan_resume_all")
					print_status(" Example:> nessus_scan_resume_all")
					print_status()
					print_status("resumes all currently running scans")
					print_status("use nessus_scan_list to list all running scans")
					return
				end

				if ! nessus_verify_token
					return
				end

				pause = @n.scan_resume_all

				print_status("All scans have been resumed")
			end

			def cmd_nessus_user_add(*args)

				if args[0] == "-h"
					print_status("Usage: ")
					print_status("       nessus_user_add <username> <password>")
					print_status(" Example:> nessus_user_add msf msf")
					print_status()
					print_status("Only adds non admin users. Must be an admin to add users.")
					print_status("use nessus_user_list to list all users")
					return
				end

				if ! nessus_verify_token
					return
				end

				if ! @n.is_admin
					print_error("Your Nessus user is not an admin")
					return
				end

				case args.length
				when 2
					user = args[0]
					pass = args[1]
				else
					print_status("Usage: ")
					print_status("       nessus_user_add <username> <password>")
					print_status("       Only adds non admin users")
					return
				end

				u = @n.users_list
				u.each { |stuff|
					if stuff['name'] == user
						print_error("That user exists")
						return
					end
				}
				add = @n.user_add(user,pass)
				status = add.root.elements['status'].text if add
				if status == "OK"
					print_good("#{user} has been added")
				else
					print_error("#{user} was not added")
				end
			end

			def cmd_nessus_user_del(*args)

				if args[0] == "-h"
					print_status("Usage: ")
					print_status("       nessus_user_del <username>")
					print_status(" Example:> nessus_user_del msf")
					print_status()
					print_status("Only dels non admin users. Must be an admin to del users.")
					print_status("use nessus_user_list to list all users")
					return
				end

				if ! nessus_verify_token
					return
				end

				if ! @n.is_admin
					print_error("Your Nessus user is not an admin")
					return
				end

				case args.length
				when 1
					user = args[0]
				else
					print_status("Usage: ")
					print_status("       nessus_user_del <username>")
					print_status("       Only dels non admin users")
					return
				end

				del = @n.user_del(user)
				status = del.root.elements['status'].text
				if status == "OK"
					print_good("#{user} has been deleted")
				else
					print_error("#{user} was not deleted")
				end
			end

			def cmd_nessus_user_passwd(*args)

				if args[0] == "-h"
					print_status("Usage: ")
					print_status("       nessus_user_passwd <username> <password>")
					print_status(" Example:> nessus_user_passwd msf newpassword")
					print_status()
					print_status("Changes the password of a user. Must be an admin to change passwords.")
					print_status("use nessus_user_list to list all users")
					return
				end

				if ! nessus_verify_token
					return
				end

				if ! @n.is_admin
					print_error("Your Nessus user is not an admin")
					return
				end

				case args.length
				when 2
					user = args[0]
					pass = args[1]
				else
					print_status("Usage: ")
					print_status("       nessus_user_passwd <username> <password>")
					print_status("       User list from nessus_user_list")
					return
				end

				pass = @n.user_pass(user,pass)
				status = pass.root.elements['status'].text
				if status == "OK"
					print_good("#{user}'s password has been changed")
				else
					print_error("#{user}'s password has not been changed")
				end
			end

			def cmd_nessus_admin(*args)

				if args[0] == "-h"
					print_status("Usage: ")
					print_status("       nessus_admin")
					print_status(" Example:> nessus_admin")
					print_status()
					print_status("Checks to see if the current user is an admin")
					print_status("use nessus_user_list to list all users")
					return
				end

				if ! nessus_verify_token
					return
				end

				if ! @n.is_admin
					print_error("Your Nessus user is not an admin")
				else
					print_good("Your Nessus user is an admin")
				end
			end

			def cmd_nessus_plugin_family(*args)

				if args[0] == "-h"
					print_status("Usage: ")
					print_status("       nessus_plugin_family <plugin family name>")
					print_status(" Example:> nessus_plugin_family \"Windows : Microsoft Bulletins\" ")
					print_status()
					print_status("Returns a list of all plugins in that family.")
					print_status("use nessus_plugin_list to list all plugins")
					return
				end

				if ! nessus_verify_token
					return
				end

				case args.length
				when 1
					fam = args[0]
				else
					print_status("Usage: ")
					print_status("       nessus_plugin_family <plugin family name>")
					print_status("       list all plugins from a Family from nessus_plugin_list")
					return
				end

				tbl = Rex::Ui::Text::Table.new(
					'Columns' => [
						'Plugin ID',
						'Plugin Name',
						'Plugin File Name'
					])

				family = @n.plugin_family(fam)

				family.each {|plugin|
					tbl << [ plugin['id'], plugin['name'], plugin['filename'] ]
				}
				print_good("#{fam} Info")
				print_good "\n"
				print_line tbl.to_s
			end

			def cmd_nessus_policy_list(*args)

				if args[0] == "-h"
					print_status("Usage: ")
					print_status("       nessus_policy_list")
					print_status(" Example:> nessus_policy_list")
					print_status()
					print_status("Lists all policies on the server")
					return
				end

				if ! nessus_verify_token
					return
				end

				tbl = Rex::Ui::Text::Table.new(
					'Columns' => [
						'ID',
						'Name',
						'Comments'
					])
				list=@n.policy_list_hash
				list.each {|policy|
					tbl << [ policy['id'], policy['name'], policy['comments'] ]
				}
				print_good("Nessus Policy List")
				print_good "\n"
				print_line tbl.to_s
			end

			def cmd_nessus_policy_del(*args)

				if args[0] == "-h"
					print_status("Usage: ")
					print_status("       nessus_policy_del <policy ID>")
					print_status(" Example:> nessus_policy_del 1")
					print_status()
					print_status("Must be an admin to del policies.")
					print_status("use nessus_policy_list to list all policies")
					return
				end

				if ! nessus_verify_token
					return
				end

				if ! @n.is_admin
					print_error("Your Nessus user is not an admin")
					return
				end

				case args.length
				when 1
					pid = args[0]
				else
					print_status("Usage: ")
					print_status("       nessus_policy_del <policy ID>")
					print_status("       nessus_policy_list to find the id.")
					return
				end


					del = @n.policy_del(pid)
					status = del.root.elements['status'].text
					if status == "OK"
						print_good("Policy number #{pid} has been deleted")
					else
						print_error("Policy number #{pid} was not deleted")
					end

				end

			def cmd_nessus_plugin_details(*args)

				if args[0] == "-h"
					print_status("Usage: ")
					print_status("       nessus_plugin_details <plugin file name>")
					print_status(" Example:> nessus_plugin_details ping_host.nasl ")
					print_status()
					print_status("Returns details on a particular plugin.")
					print_status("use nessus_plugin_list to list all plugins")
					return
				end

				if ! nessus_verify_token
					return
				end

				case args.length
				when 1
					pname = args[0]
				else
					print_status("Usage: ")
					print_status("       nessus_policy_del <plugin file name>")
					print_status("       nessus_plugin_list and then nessus_plugin_family to find the plugin file name.")
					return
				end

				tbl = Rex::Ui::Text::Table.new(
					'Columns' => [
						'',
						''
					])

				entry = @n.plugin_detail(pname)
				print_good("Plugin Details for #{entry['name']}")
				tbl << [ "Plugin ID", entry['id'] ]
				tbl << [ "Plugin Family", entry['family'] ]
				tbl << [ "CVSS Base Score", entry['cvss_base_score'] ]
				tbl << [ "CVSS Vector", entry['cvss_vector'] ]
				tbl << [ "CVSS Temporal Score", entry['cvss_temporal_score'] ]
				tbl << [ "CVSS Temporal Vector", entry['cvss_temporal_vector'] ]
				tbl << [ "Risk Factor", entry['risk_factor'] ]
				tbl << [ "Exploit Available", entry['exploit_available'] ]
				tbl << [ "Exploitability Ease", entry['exploit_ease'] ]
				tbl << [ "Synopsis", entry['synopsis'] ]
				tbl << [ "Description", entry['description'] ]
				tbl << [ "Solution", entry['solution'] ]
				tbl << [ "Plugin Pub Date", entry['plugin_publication_date'] ]
				tbl << [ "Plugin Modification Date", entry['plugin_modification_date'] ]
				print_good "\n"
				print_line tbl.to_s
			end

			def cmd_nessus_report_del(*args)

				if args[0] == "-h"
					print_status("Usage: ")
					print_status("       nessus_report_del <reportname>")
					print_status(" Example:> nessus_report_del f0eabba3-4065-7d54-5763-f191e98eb0f7f9f33db7e75a06ca")
					print_status()
					print_status("Must be an admin to del reports.")
					print_status("use nessus_report_list to list all reports")
					return
				end

				if ! nessus_verify_token
					return
				end

				if ! @n.is_admin
					print_error("Your Nessus user is not an admin")
					return
				end

				case args.length
				when 1
					rid = args[0]
				else
					print_status("Usage: ")
					print_status("       nessus_report_del <report ID>")
					print_status("       nessus_report_list to find the id.")
					return
				end


					del = @n.report_del(rid)
					status = del.root.elements['status'].text
					if status == "OK"
						print_good("Report #{rid} has been deleted")
					else
						print_error("Report #{rid} was not deleted")
					end
				end

			def cmd_nessus_server_prefs(*args)

				if args[0] == "-h"
					print_status("Usage: ")
					print_status("       nessus_server_prefs")
					print_status(" Example:> nessus_server_prefs")
					print_status()
					print_status("Returns a long list of server prefs.")
					return
				end

				if ! nessus_verify_token
					return
				end

				if ! @n.is_admin
					print_error("Your Nessus user is not an admin")
					return
				end

				tbl = Rex::Ui::Text::Table.new(
					'Columns' => [
						'Name',
						'Value'
					])
				prefs = @n.server_prefs
				prefs.each {|pref|
					tbl << [ pref['name'], pref['value'] ]
				}
				print_good("Nessus Server Pref List")
				print_good "\n"
				print_line tbl.to_s + "\n"

			end

			def cmd_nessus_plugin_prefs(*args)

				if args[0] == "-h"
					print_status("Usage: ")
					print_status("       nessus_plugin_prefs")
					print_status(" Example:> nessus_plugin_prefs")
					print_status()
					print_status("Returns a long list of plugin prefs.")
					return
				end

				if ! nessus_verify_token
					return
				end

				if ! @n.is_admin
					print_error("Your Nessus user is not an admin")
					return
				end

				tbl = Rex::Ui::Text::Table.new(
					'Columns' => [
						'Name',
						'Value',
						'Type'
					])
				prefs = @n.plugin_prefs
				prefs.each {|pref|
					tbl << [ pref['prefname'], pref['prefvalues'], pref['preftype'] ]
				}
				print_good("Nessus Plugins Pref List")
				print_good "\n"
				print_line tbl.to_s
			end
		end

		def initialize(framework, opts)
			super

			add_console_dispatcher(ConsoleCommandDispatcher)
			@nbver = "1.1" # Nessus Plugin Version.  Increments each time we commit to msf
			@xindex = "#{Msf::Config.get_config_root}/nessus_index" # location of the exploit index file used to speed up searching for valid exploits.
			@nessus_yaml = "#{Msf::Config.get_config_root}/nessus.yaml" #location of the nessus.yml containing saved nessus creds
			print_status("Nessus Bridge for Metasploit #{@nbver}")
			print_good("Type %bldnessus_help%clr for a command listing")
			#nessus_index
		end

		def cleanup
			remove_console_dispatcher('Nessus')
		end

		def name
			"nessus"
		end

		def desc
			"Nessus Bridge for Metasploit #{@nbver}"
		end
		protected
	end
end
