metasploit-framework/msfupdate

143 lines
4.2 KiB
Ruby
Executable File

#!/usr/bin/env ruby
# -*- coding: binary -*-
# $Id$
# $Revision$
msfbase = __FILE__
while File.symlink?(msfbase)
msfbase = File.expand_path(File.readlink(msfbase), File.dirname(msfbase))
end
@msfbase_dir = File.dirname(msfbase)
@args = ARGV.dup
# May be changed
@configdir = File.expand_path(File.join(File.dirname(msfbase), "data", "svn"))
Dir.chdir(@msfbase_dir)
$stderr.puts "[*]"
$stderr.puts "[*] Attempting to update the Metasploit Framework..."
$stderr.puts "[*]"
$stderr.puts ""
if not (Process.uid == 0 or File.stat(msfbase).owned?)
$stderr.puts "[-] ERROR: User running msfupdate does not own the metasploit install"
$stderr.puts "Please run msfupdate as the same user who installed metasploit."
end
def is_git
File.directory?(File.join(@msfbase_dir, ".git"))
end
def is_svn
File.directory?(File.join(@msfbase_dir, ".svn"))
end
def print_deprecation_warning
$stdout.puts "[*] Deprecation Note: The next version of Metasploit will"
$stdout.puts "[*] update over the git protocol, which requires outbound"
$stdout.puts "[*] access to github.com:9418/TCP."
$stdout.puts "[*] Please adjust your egress firewall rules accordingly."
end
# Some of these args are meaningful for SVN, some for Git,
# some for both. Fun times.
@args.each_with_index do |arg,i|
case arg
# Handle the old wait/nowait argument behavior
when "wait", "nowait"
@wait_index = i
@actually_wait = (arg == "wait")
# An empty or absent config-dir means a default config-dir
when "--config-dir"
@configdir_index = i
# A defined config dir means a defined config-dir
when /--config-dir=(.*)?/
# 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
@configdir_index = i
when /--git-remote=([^\s]*)?/
@git_remote = $1
@git_remote_index = i
when /--git-branch=([^\s]*)?/
@git_branch = $1
@git_branch_index = i
end
end
@args[@wait_index] = nil if @wait_index
@args[@configdir_index] = nil if @configdir_index
@args[@git_remote_index] = nil if @git_remote_index
@args[@git_branch_index] = nil if @git_branch_index
@args = @args.compact
####### Since we're SVN, do it all this way #######
if is_svn
print_deprecation_warning
@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."
exit 1
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
remote = @git_remote || "origin"
branch = @git_branch || "master"
# 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
# checkout, which presumes they're not using msfupdate
# 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
res = system("git", "stash")
if res.nil?
$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."
exit 1
else
$stdout.puts "[*] Stashed local changes (if any) to avoid merge conflicts."
$stdout.puts "[*] Run 'git stash pop' to reapply local changes."
end
system("git", "reset", "HEAD", "--hard")
system("git", "checkout", branch)
system("git", "fetch")
system("git", "merge", "#{remote}/#{branch}")
end
unless is_svn || is_git
raise RuntimeError, "Cannot determine checkout type: `#{@msfbase_dir}'"
end
if @actually_wait
$stderr.puts ""
$stderr.puts "[*] Please hit enter to exit"
$stderr.puts ""
$stdin.readline
end