Files
metasploit-gs/msfupdate
T

256 lines
8.3 KiB
Ruby
Raw Normal View History

2010-10-19 07:32:50 +00:00
#!/usr/bin/env ruby
# -*- coding: binary -*-
2010-10-19 07:32:50 +00:00
2011-10-23 12:04:41 +00:00
# $Id$
# $Revision$
2010-10-19 07:32:50 +00:00
msfbase = __FILE__
2012-10-03 17:06:38 -05:00
while File.symlink?(msfbase)
2010-10-19 07:32:50 +00:00
msfbase = File.expand_path(File.readlink(msfbase), File.dirname(msfbase))
end
2012-11-05 11:48:09 -06:00
@msfbase_dir = File.dirname(msfbase)
2012-11-05 11:44:53 -06:00
@args = ARGV.dup
2010-10-19 07:32:50 +00:00
2012-10-09 16:56:22 -05:00
# May be changed
2012-10-09 16:25:06 -05:00
@configdir = File.expand_path(File.join(File.dirname(msfbase), "data", "svn"))
2012-11-05 11:48:09 -06:00
Dir.chdir(@msfbase_dir)
2010-10-19 07:32:50 +00:00
$stderr.puts "[*]"
$stderr.puts "[*] Attempting to update the Metasploit Framework..."
$stderr.puts "[*]"
2010-10-19 08:22:44 +00:00
$stderr.puts ""
2013-01-14 14:26:42 -08:00
# Bail right away, no waiting around for consoles.
if not (Process.uid == 0 or File.stat(msfbase).owned?)
$stderr.puts "[-] ERROR: User running msfupdate does not own the Metasploit installation"
$stderr.puts "[-] Please run msfupdate as the same user who installed Metasploit."
exit 0x10
2011-10-10 21:08:04 +00:00
end
def is_apt
File.exists?(File.expand_path(File.join(@msfbase_dir, '.apt')))
end
# Are you an installer, or did you get here via a source checkout?
def is_installed
File.exists?(File.expand_path(File.join(@msfbase_dir, "..", "engine", "update.rb"))) && !is_apt
2012-11-21 09:38:05 -06:00
end
2012-11-05 11:44:53 -06:00
2012-11-05 11:48:09 -06:00
def is_git
File.directory?(File.join(@msfbase_dir, ".git"))
2012-11-05 11:44:53 -06:00
end
2012-11-05 11:48:09 -06:00
def is_svn
File.directory?(File.join(@msfbase_dir, ".svn"))
2012-11-05 11:44:53 -06:00
end
# Adding an upstream enables msfupdate to pull updates from
# Rapid7's metasploit-framework repo instead of the repo
# the user originally cloned or forked.
def add_git_upstream
$stdout.puts "[*] Attempting to add remote 'upstream' to your local git repository."
2012-11-27 11:47:59 -06:00
system("git", "remote", "add", "upstream", "git://github.com/rapid7/metasploit-framework.git")
$stdout.puts "[*] Added remote 'upstream' to your local git repository."
end
2012-11-05 12:13:10 -06:00
def print_deprecation_warning
$stdout.puts ""
2013-03-14 15:21:33 -05:00
$stdout.puts "[-] Deprecation Note: Metasploit source checkouts NO LONGER update"
$stdout.puts "[-] over SVN. You will need to reinstall Metasploit using"
$stdout.puts "[-] binary installers (from http://www.metasploit.com/download ),"
$stdout.puts "[-] Debian packages (currently only supported on Kali Linux), or"
$stdout.puts "[-] a development source checkout from GitHub (see http://r-7.co/ZLhA8P )"
$stdout.puts "[-] "
$stdout.puts "[-] For more on msfupdate and migrating off of SVN, see http://r-7.co/MSF-UP"
$stdout.puts ""
2012-11-05 11:44:53 -06:00
end
2013-03-26 14:32:21 -05:00
# This only exits if you actually pass a wait option, otherwise
# just returns nil. This is likely unexpected, revisit this.
2013-01-14 14:26:42 -08:00
def maybe_wait_and_exit(exit_code=0)
if @actually_wait
$stdout.puts ""
$stdout.puts "[*] Please hit enter to exit"
$stdout.puts ""
$stdin.readline
exit exit_code
end
end
def apt_upgrade_available(package)
require 'open3'
installed = nil
upgrade = nil
::Open3.popen3({'LANG'=>'en_US.UTF-8'}, "apt-cache", "policy", package) do |stdin, stdout, stderr|
stdout.each do |line|
installed = $1 if line =~ /Installed: ([\w\-+.:~]+)$/
upgrade = $1 if line =~ /Candidate: ([\w\-+.:~]+)$/
break if installed && upgrade
end
end
if installed && installed != upgrade
upgrade
else
nil
end
end
2012-11-05 11:44:53 -06:00
# Some of these args are meaningful for SVN, some for Git,
# some for both. Fun times.
2012-10-01 12:41:36 -05:00
@args.each_with_index do |arg,i|
2012-10-01 13:07:51 -05:00
case arg
2012-11-05 11:44:53 -06:00
# Handle the old wait/nowait argument behavior
2012-10-10 09:50:30 -05:00
when "wait", "nowait"
2012-10-01 13:10:58 -05:00
@wait_index = i
2012-10-10 09:50:30 -05:00
@actually_wait = (arg == "wait")
2012-11-05 11:44:53 -06:00
# An empty or absent config-dir means a default config-dir
when "--config-dir"
@configdir_index = i
2012-11-05 11:44:53 -06:00
# A defined config dir means a defined config-dir
when /--config-dir=(.*)?/
2012-10-01 13:07:51 -05:00
# Spaces in the directory should be fine since this whole thing is passed
# as a single argument via the multi-arg syntax for system() below.
@configdir = $1
2012-10-01 13:10:58 -05:00
@configdir_index = i
2012-11-05 11:56:05 -06:00
when /--git-remote=([^\s]*)?/
@git_remote = $1
@git_remote_index = i
when /--git-branch=([^\s]*)?/
@git_branch = $1
@git_branch_index = i
2012-10-01 12:41:36 -05:00
end
end
@args[@wait_index] = nil if @wait_index
@args[@configdir_index] = nil if @configdir_index
2012-11-05 11:56:05 -06:00
@args[@git_remote_index] = nil if @git_remote_index
@args[@git_branch_index] = nil if @git_branch_index
@args = @args.compact
2012-11-05 11:44:53 -06:00
####### Since we're SVN, do it all this way #######
if is_svn
2013-03-26 14:32:21 -05:00
# We're fully deprecated now, so just exit.
# Leaving in the commented code in case someone wants to
# get a last-chance at msfupdate before the SVN server goes
# off line, which will be ANY DAY NOW. Seriously.
2012-11-05 12:13:10 -06:00
print_deprecation_warning
2013-03-26 14:32:21 -05:00
$stdin.readline if @actually_wait
exit(0x11) # Comment this to get old functionality back.
2012-11-05 11:44:53 -06:00
@args.push("--config-dir=#{@configdir}")
@args.push("--non-interactive")
res = system("svn", "cleanup")
if res.nil?
$stderr.puts "[-] ERROR: Failed to run svn"
$stderr.puts ""
$stderr.puts "[-] If you used a binary installer, make sure you run the symlink in"
$stderr.puts "[-] /usr/local/bin instead of running this file directly (e.g.: ./msfupdate)"
$stderr.puts "[-] to ensure a proper environment."
2013-01-14 14:26:42 -08:00
maybe_wait_and_exit 1
2012-11-05 11:44:53 -06:00
else
# Cleanup worked, go ahead and update
system("svn", "update", *@args)
end
end
####### Since we're Git, do it all that way #######
if is_git
2012-11-30 15:41:01 -06:00
out = `git remote show upstream` # Actually need the output for this one.
add_git_upstream unless $?.success? and out =~ %r{(https|git|git@github\.com):(//github\.com/)?(rapid7/metasploit-framework\.git)}
remote = @git_remote || "upstream"
2012-11-27 11:47:59 -06:00
branch = @git_branch || "master"
2012-11-05 14:37:32 -06:00
# This will save local changes in a stash, but won't
# attempt to reapply them. If the user wants them back
# they can always git stash pop them, and that presumes
# they know what they're doing when they're editing local
2012-11-21 09:38:05 -06:00
# checkout, which presumes they're not using msfupdate
2012-11-05 14:37:32 -06:00
# to begin with.
#
# Note, this requires at least user.name and user.email
# to be configured in the global git config. Installers should
# take care that this is done. TODO: Enforce this in msfupdate
committed = system("git", "diff", "--quiet", "HEAD")
if committed.nil?
2012-11-05 11:44:53 -06:00
$stderr.puts "[-] ERROR: Failed to run git"
$stderr.puts ""
$stderr.puts "[-] If you used a binary installer, make sure you run the symlink in"
$stderr.puts "[-] /usr/local/bin instead of running this file directly (e.g.: ./msfupdate)"
$stderr.puts "[-] to ensure a proper environment."
2013-01-14 14:26:42 -08:00
maybe_wait_and_exit 1
elsif not committed
system("git", "stash")
$stdout.puts "[*] Stashed local changes to avoid merge conflicts."
$stdout.puts "[*] Run `git stash pop` to reapply local changes."
2012-11-05 11:44:53 -06:00
end
2012-11-05 14:37:32 -06:00
system("git", "reset", "HEAD", "--hard")
2012-11-05 11:56:05 -06:00
system("git", "checkout", branch)
system("git", "fetch", remote)
2012-11-05 11:56:05 -06:00
system("git", "merge", "#{remote}/#{branch}")
$stdout.puts "[*] Updating gems..."
require 'bundler'
Bundler.with_clean_env do
system("bundle", "install")
end
2012-11-05 11:44:53 -06:00
end
if is_installed
2012-11-30 16:50:58 -06:00
update_script = File.expand_path(File.join(@msfbase_dir, "..", "engine", "update.rb"))
product_key = File.expand_path(File.join(@msfbase_dir, "..", "engine", "license", "product.key"))
if File.exists? product_key
if File.readable? product_key
system("ruby", update_script)
else
$stdout.puts "[-] ERROR: Failed to update Metasploit installation"
$stdout.puts ""
$stdout.puts "[-] You must be able to read the product key for the"
$stdout.puts "[-] Metasploit installation in order to run msfupdate."
$stdout.puts "[-] Usually, this means you must be root (EUID 0)."
2013-01-14 14:26:42 -08:00
maybe_wait_and_exit 10
end
else
$stdout.puts "[-] ERROR: Failed to update Metasploit installation"
$stdout.puts ""
$stdout.puts "[-] In order to update your Metasploit installation,"
$stdout.puts "[-] you must first register it through the UI, here:"
$stderr.puts "[-] https://localhost:3790 (note, Metasploit Community"
$stderr.puts "[-] Edition is totally free and takes just a few seconds"
$stderr.puts "[-] to register!)"
2013-01-14 14:26:42 -08:00
maybe_wait_and_exit 11
end
2012-11-21 09:38:05 -06:00
end
if is_apt
$stdout.puts "[*] Checking for updates"
system("apt-get", "-qq", "update")
packages = []
packages << 'metasploit-framework' if framework_version = apt_upgrade_available('metasploit-framework')
packages << 'metasploit' if pro_version = apt_upgrade_available('metasploit')
if packages.empty?
$stdout.puts "[*] No updates available"
else
$stdout.puts "[*] Updating to version #{pro_version || framework_version}"
system("apt-get", "install", "--assume-yes", *packages)
if packages.include?('metasploit')
start_cmd = File.expand_path(File.join(@msfbase_dir, '..', '..', '..', 'scripts', 'start.sh'))
system(start_cmd) if ::File.executable_real? start_cmd
end
end
end
unless is_svn || is_git || is_installed || is_apt
2012-11-05 11:48:09 -06:00
raise RuntimeError, "Cannot determine checkout type: `#{@msfbase_dir}'"
end
2011-05-03 23:58:41 +00:00
2013-01-14 14:26:42 -08:00
maybe_wait_and_exit(0)