Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

executable file 165 lines (131 sloc) 5.627 kb
#!/usr/bin/perl
use strict;
use warnings;
# === auth-command ===
# the command that GL users actually run
# part of the gitolite (GL) suite
# how run: via sshd, being listed in "command=" in ssh authkeys
# when: every login by a GL user
# input: $1 is GL username, plus $SSH_ORIGINAL_COMMAND
# output:
# security:
# - currently, we just make some basic checks, copied from gitosis
# robustness:
# other notes:
# ----------------------------------------------------------------------------
# common definitions
# ----------------------------------------------------------------------------
# these are set by the "rc" file
our ($GL_LOGT, $GL_CONF_COMPILED, $REPO_BASE, $GIT_PATH, $REPO_UMASK, $GL_ADMINDIR);
# and these are set by gitolite.pm
our ($R_COMMANDS, $W_COMMANDS, $REPONAME_PATT);
our %repos;
# the common setup module is in the same directory as this running program is
my $bindir = $0;
$bindir =~ s/\/[^\/]+$//;
require "$bindir/gitolite.pm";
# ask where the rc file is, get it, and "do" it
&where_is_rc();
die "parse $ENV{GL_RC} failed: " . ($! or $@) unless do $ENV{GL_RC};
# we need to pass GL_ADMINDIR and the bindir to the child hooks (well only the
# admin repo's post-update hook but still...)
$ENV{GL_ADMINDIR} = $GL_ADMINDIR;
$ENV{GL_BINDIR} = $bindir;
# add a custom path for git binaries, if specified
$ENV{PATH} .= ":$GIT_PATH" if $GIT_PATH;
# set the umask before creating any files
umask($REPO_UMASK);
# ----------------------------------------------------------------------------
# start...
# ----------------------------------------------------------------------------
# if the first argument is a "-s", this user is allowed to get a shell using
# this key
my $shell_allowed = 0;
if ($ARGV[0] eq '-s') {
$shell_allowed = 1;
shift;
}
# first, fix the biggest gripe I have with gitosis, a 1-line change
my $user=$ENV{GL_USER}=shift; # there; now that's available everywhere!
# ----------------------------------------------------------------------------
# sanity checks on SSH_ORIGINAL_COMMAND
# ----------------------------------------------------------------------------
# print basic access info if SSH_ORIGINAL_COMMAND does not exist
unless ($ENV{SSH_ORIGINAL_COMMAND}) {
# unless the user is allowed to use a shell
if ($shell_allowed) {
my $shell = $ENV{SHELL};
$shell =~ s/.*\//-/; # change "/bin/bash" to "-bash"
exec { $ENV{SHELL} } $shell;
}
&report_basic($GL_ADMINDIR, $GL_CONF_COMPILED, $user);
exit 1;
}
my $cmd = $ENV{SSH_ORIGINAL_COMMAND};
# people allowed to get a shell can get basic access info by asking nicely
if ($cmd eq 'info') {
&report_basic($GL_ADMINDIR, $GL_CONF_COMPILED, $user);
print "you also have shell access\n\r" if $shell_allowed;
exit 1;
}
# split into command and arguments; the pattern allows old style as well as
# new style: "git-subcommand arg" or "git subcommand arg", just like gitosis
# does, although I'm not sure how necessary that is
#
# keep in mind this is how git sends across the command:
# git-receive-pack 'reponame.git'
# including the single quotes
my ($verb, $repo) = ($cmd =~ /^\s*(git\s+\S+|\S+)\s+'\/?(.*?)(?:\.git)?'/);
unless ( $verb and ( $verb =~ $R_COMMANDS or $verb =~ $W_COMMANDS ) and $repo and $repo =~ $REPONAME_PATT ) {
# if the user is allowed a shell, just run the command
exec $ENV{SHELL}, "-c", $ENV{SSH_ORIGINAL_COMMAND} if $shell_allowed;
# otherwise, whine
die "bad command: $cmd\n";
}
# ----------------------------------------------------------------------------
# first level permissions check
# ----------------------------------------------------------------------------
# parse the compiled acl; goes into %repos (global)
&parse_acl($GL_CONF_COMPILED);
# we know the user and repo; we just need to know what perm he's trying
my $perm = ($verb =~ $R_COMMANDS ? 'R' : 'W');
die "$perm access for $repo DENIED to $user\n"
unless $repos{$repo}{$perm}{$user}
or $repos{$repo}{$perm}{'@all'};
# create the repo if it doesn't already exist and the user has "W" access
my $repo_base_abs = ( $REPO_BASE =~ m(^/) ? $REPO_BASE : "$ENV{HOME}/$REPO_BASE" );
if ( not -d "$repo_base_abs/$repo.git" ) {
if ( $repos{$repo}{W}{$user} or $repos{$repo}{W}{'@all'} ) {
wrap_chdir("$repo_base_abs");
new_repo($repo, "$GL_ADMINDIR/src/hooks");
wrap_chdir($ENV{HOME});
}
}
# ----------------------------------------------------------------------------
# logging, timestamp. also setup env vars for later
# ----------------------------------------------------------------------------
# reponame
$ENV{GL_REPO}=$repo;
# timestamp
my ($s, $min, $h, $d, $m, $y) = (localtime)[0..5];
$y += 1900; $m++; # usual adjustments
for ($s, $min, $h, $d, $m) {
$_ = "0$_" if $_ < 10;
}
$ENV{GL_TS} = "$y-$m-$d.$h:$min:$s";
# substitute template parameters and set the logfile name
$GL_LOGT =~ s/%y/$y/g;
$GL_LOGT =~ s/%m/$m/g;
$GL_LOGT =~ s/%d/$d/g;
$ENV{GL_LOG} = $GL_LOGT;
# if log failure isn't important enough to block access, get rid of all the
# error checking
open my $log_fh, ">>", $ENV{GL_LOG}
or die "open log failed: $!\n";
print $log_fh "$ENV{GL_TS}\t$ENV{SSH_ORIGINAL_COMMAND}\t$user\n";
close $log_fh or die "close log failed: $!\n";
# ----------------------------------------------------------------------------
# over to git now
# ----------------------------------------------------------------------------
$repo = "'$REPO_BASE/$repo.git'";
exec("git", "shell", "-c", "$verb $repo");
Jump to Line
Something went wrong with that request. Please try again.