(http) auth: handle REQUEST_URI and friends
TODO: if the verb doesn't actually contain "git-receive-pack", I am assuming it is some sort of read. The list in services[] in http-backend.c does not seem to look like any other verb is a "write"; need to check this with someone. For normal git commands: - PATH_INFO gives you the repo name - REQUEST_URI gives you the verb - we construct a fake SSH_ORIGINAL_COMMAND so the rest of the processing does not have to change For our special commands: - PATH_INFO is actually the verb - QUERY_STRING has the parameters - we again fake out the SSH_ORIGINAL_COMMAND - we print the extra HTTP headers in anticipation of the actual output Either way, we also fake out the SSH_CONNECTION so that the IP address can get logged ok And of course REMOTE_USER is now the incoming userid Finally, at the end, we exec GIT_HTTP_BACKEND instead of the normal one
This commit is contained in:
parent
a9e9f98a7e
commit
52e0ed3488
|
@ -92,6 +92,22 @@ sub dbg {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
my $http_headers_printed = 0;
|
||||||
|
sub print_http_headers {
|
||||||
|
my($code, $text) = @_;
|
||||||
|
|
||||||
|
return if $http_headers_printed++;
|
||||||
|
$code ||= 200;
|
||||||
|
$text ||= "OK - gitolite";
|
||||||
|
|
||||||
|
$|++;
|
||||||
|
print "Status: $code $text\r\n";
|
||||||
|
print "Expires: Fri, 01 Jan 1980 00:00:00 GMT\r\n";
|
||||||
|
print "Pragma: no-cache\r\n";
|
||||||
|
print "Cache-Control: no-cache, max-age=0, must-revalidate\r\n";
|
||||||
|
print "\r\n";
|
||||||
|
}
|
||||||
|
|
||||||
sub get_logfilename {
|
sub get_logfilename {
|
||||||
# this sub has a wee little side-effect; it sets $ENV{GL_TS}
|
# this sub has a wee little side-effect; it sets $ENV{GL_TS}
|
||||||
my($template) = shift;
|
my($template) = shift;
|
||||||
|
|
|
@ -3,20 +3,29 @@
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
# === auth-command ===
|
# ----------------------------------------------------------------------------
|
||||||
# the command that GL users actually run
|
# you: what's the invocation?
|
||||||
|
# me: Hail, O Lord Ganesha, destroyer of obsta...
|
||||||
# part of the gitolite (GL) suite
|
# you: err hmm not *that* sort of invocation... I meant how does this program
|
||||||
|
# get invoked?
|
||||||
# how run: via sshd, being listed in "command=" in ssh authkeys
|
# me: oh hehe <hides sheepish grin>, ok here we go...
|
||||||
# when: every login by a GL user
|
#
|
||||||
# input: $1 is GL username, plus $SSH_ORIGINAL_COMMAND
|
# ssh mode
|
||||||
# output:
|
# - started by sshd
|
||||||
# security:
|
# - one argument, the "user" name
|
||||||
|
# - one env var, SSH_ORIGINAL_COMMAND, containing the command
|
||||||
# robustness:
|
# - command typically: git-(receive|upload)-pack 'reponame(.git)?'
|
||||||
|
# - special gitolite commands: info, expand, (get|set)(perms|desc)
|
||||||
# other notes:
|
# - special non-gitolite commands: rsync, svnserve, htpasswd
|
||||||
|
# - other commands: anything in $GL_ADC_PATH if defined (see rc file)
|
||||||
|
#
|
||||||
|
# (smart) http mode
|
||||||
|
# - started by apache (httpd)
|
||||||
|
# - no arguments
|
||||||
|
# - REQUEST_URI contains verb and repo, REMOTE_USER contains username
|
||||||
|
# - REQUEST_URI looks like /path/reponame.git/(info/refs\?service=)?git-(receive|upload)-pack
|
||||||
|
# - no special processing commands currently handled
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
# common definitions
|
# common definitions
|
||||||
|
@ -67,12 +76,43 @@ if (@ARGV and $ARGV[0] eq '-s') {
|
||||||
shift;
|
shift;
|
||||||
}
|
}
|
||||||
|
|
||||||
# no (more) arguments given? default user is $USER (fedorahosted works like
|
# ----------------------------------------------------------------------------
|
||||||
# this, and it is harmless for others)
|
# set up SSH_ORIGINAL_COMMAND and SSH_CONNECTION in http mode
|
||||||
@ARGV = ($ENV{USER}) unless @ARGV;
|
# ----------------------------------------------------------------------------
|
||||||
|
|
||||||
# first, fix the biggest gripe I have with gitosis, a 1-line change
|
# fake out SSH_ORIGINAL_COMMAND and SSH_CONNECTION so the rest of the code
|
||||||
my $user=$ENV{GL_USER}=shift; # there; now that's available everywhere!
|
# stays the same (except the exec at the end).
|
||||||
|
|
||||||
|
my $user;
|
||||||
|
if ($ENV{REQUEST_URI}) {
|
||||||
|
# these patterns indicate normal git usage; see "services[]" in
|
||||||
|
# http-backend.c for how I got that. Also note that "info" is overloaded;
|
||||||
|
# git uses "info/refs...", while gitolite uses "info" or "info?...". So
|
||||||
|
# there's a "/" after info in the list below
|
||||||
|
if ($ENV{PATH_INFO} =~ m(/(HEAD$|info/refs$|objects/|git-(?:upload|receive)-pack$))) {
|
||||||
|
my ($repo) = ($ENV{PATH_INFO} =~ m(^/(.*)\.git(?:/|$)));
|
||||||
|
my ($verb) = ($ENV{REQUEST_URI} =~ m((git-(?:receive|upload)-pack)));
|
||||||
|
print STDERR "(gitolite) no verb found in $ENV{REQUEST_URI}\n" unless $verb;
|
||||||
|
$verb ||= 'git-upload-pack';
|
||||||
|
$ENV{SSH_ORIGINAL_COMMAND} = "$verb '$repo'";
|
||||||
|
} else {
|
||||||
|
# this is one of our custom commands; could be anything really,
|
||||||
|
# because of the adc feature
|
||||||
|
my ($verb) = ($ENV{PATH_INFO} =~ m(^/(\S+)));
|
||||||
|
my $args = $ENV{QUERY_STRING};
|
||||||
|
$args =~ s/\+/ /g;
|
||||||
|
$ENV{SSH_ORIGINAL_COMMAND} = $verb;
|
||||||
|
$ENV{SSH_ORIGINAL_COMMAND} .= " $args" if $args;
|
||||||
|
&print_http_headers(); # in preparation for the eventual output!
|
||||||
|
}
|
||||||
|
$ENV{SSH_CONNECTION} = "$ENV{REMOTE_ADDR} $ENV{REMOTE_PORT} $ENV{SERVER_ADDR} $ENV{SERVER_PORT}";
|
||||||
|
$user = $ENV{GL_USER} = $ENV{REMOTE_USER};
|
||||||
|
} else {
|
||||||
|
# no (more) arguments given in ssh mode? default user is $USER
|
||||||
|
# (fedorahosted works like this, and it is harmless for others)
|
||||||
|
@ARGV = ($ENV{USER}) unless @ARGV;
|
||||||
|
$user=$ENV{GL_USER}=shift;
|
||||||
|
}
|
||||||
|
|
||||||
# if there are any more arguments, they're a list of group names that the user
|
# if there are any more arguments, they're a list of group names that the user
|
||||||
# is a member of
|
# is a member of
|
||||||
|
@ -212,6 +252,13 @@ die "$aa access for $repo DENIED to $user\n" unless $perm =~ /$aa/;
|
||||||
# over to git now
|
# over to git now
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
if ($ENV{REQUEST_URI}) {
|
||||||
|
&log_it($ENV{REQUEST_URI});
|
||||||
|
exec $ENV{GIT_HTTP_BACKEND};
|
||||||
|
# the GIT_HTTP_BACKEND env var should be set either by the rc file, or as
|
||||||
|
# a SetEnv in the apache config somewhere
|
||||||
|
}
|
||||||
|
|
||||||
&log_it();
|
&log_it();
|
||||||
|
|
||||||
$repo = "'$REPO_BASE/$repo.git'";
|
$repo = "'$REPO_BASE/$repo.git'";
|
||||||
|
|
Loading…
Reference in a new issue