1
#!/usr/bin/env ruby
2
3
require "yaml"
4
if File.symlink?(__FILE__)
5
  $:.unshift File.dirname(File.readlink(__FILE__)) + "/../lib/gitorious/ssh"
6
  BASE_DIR = File.dirname(File.readlink(__FILE__)) + "/../"
7
  conf_file = File.join(BASE_DIR, "config/gitorious.yml")
8
else
9
  $:.unshift File.dirname(__FILE__) + "/../lib/gitorious/ssh"
10
  BASE_DIR = File.dirname(__FILE__) + "/../"
11
  conf_file = File.join(BASE_DIR, "config/gitorious.yml")
12
end
13
14
#$DEBUG=true
15
16
RAILS_ENV = ENV['RAILS_ENV'] ||= 'production'
17
18
GitoriousConfig = YAML::load_file(conf_file)[RAILS_ENV]
19
20
ENV["PATH"] = "/usr/local/bin/:/opt/local/bin:#{ENV["PATH"]}"
21
22
require "logger"
23
require "strainer"
24
require "client"
25
26
File.umask(0022)
27
original_command = ENV["SSH_ORIGINAL_COMMAND"]
28
user = ARGV[0]
29
30
logger = Logger.new(File.join(BASE_DIR, "log", "gitorious_auth.log"))
31
logger.formatter = Logger::Formatter.new
32
logger.level = Logger::INFO
33
logger.formatter.datetime_format = "%Y-%m-%d %H:%M:%S"
34
logger.info("Connection from #{ENV['SSH_CLIENT'].inspect} (#{user || nil}): #{original_command || nil}")
35
36
$stderr.puts "original_command: #{original_command.inspect}" if $DEBUG
37
if original_command.nil? || original_command.strip.empty?
38
  logger.info("Need SSH_ORIGINAL_COMMAND")
39
  $stderr.puts "Need SSH_ORIGINAL_COMMAND"
40
  exit!(1)
41
end
42
43
$stderr.puts "user: #{user.inspect}" if $DEBUG
44
if user.nil? || user.strip.empty?
45
  logger.info("Need user arg")
46
  $stderr.puts "Need user arg"
47
  exit!(1)
48
end
49
50
def gitorious_says(msg)
51
  $stderr.puts
52
  $stderr.puts "== Gitorious: " + ("=" * 59)
53
  $stderr.puts msg
54
  $stderr.puts "="*72
55
  $stderr.puts
56
end
57
58
begin
59
  strainer = Gitorious::SSH::Strainer.new(original_command).parse!
60
  client = Gitorious::SSH::Client.new(strainer, user)
61
62
  args = client.to_git_shell_argument
63
  $stderr.puts "git-shell -c #{args.inspect}" if $DEBUG
64
  ENV['GITORIOUS_WRITABLE_BY_URL'] = client.writable_by_query_url
65
  ENV['GITORIOUS_USER'] = user
66
  ENV['GITORIOUS_BASE_DIR'] = BASE_DIR
67
  ENV['GITORIOUS_DENY_FORCE_PUSHES'] = client.force_pushing_denied? ? "true" : "false"
68
69
  logger.info("Accepted #{user.inspect} for #{args.inspect}")
70
  if client.pre_receive_hook_exists?
71
    exec("git-shell", "-c", args)
72
  else
73
    logger.fatal("The pre-receive hook is not executable")
74
    gitorious_says "Fatal error, please contact support"
75
    exit!(1)
76
  end
77
  
78
  unless $?.success?
79
    logger.fatal("Failed to execute git command")
80
    gitorious_says "Failed to execute git command"
81
    exit!(1)
82
  end
83
rescue Gitorious::SSH::AccessDeniedError => e
84
  logger.info("Access denied or bad repository path for #{user.inspect}: #{original_command.inspect}")
85
  gitorious_says "Access denied or wrong repository path"
86
  exit!(1)
87
rescue Gitorious::SSH::BadCommandError => e
88
  logger.info("Access denied or bad command for #{user.inspect}: #{original_command.inspect}")
89
  gitorious_says "Access denied or bad command"
90
  exit!(1)
91
rescue Errno::ECONNREFUSED => e
92
  logger.fatal("Connection refused querying for paths/permissions")
93
  gitorious_says("Temporary error. Please try again shortly")
94
  exit!(1)
95
rescue Object => e
96
  if $DEBUG
97
    $stderr.puts "#{e.class.name} #{e.message}"
98
    $stderr.puts e.backtrace.join("  \n")
99
  end
100
  logger.fatal("#{e.class.name} #{e.message}: #{e.backtrace.join("\n  ")}")
101
  gitorious_says "fatal error"
102
  exit(1)
103
end