2010-02-04 10:46:47 +01:00
|
|
|
use strict;
|
2009-10-25 03:59:52 +01:00
|
|
|
# this file is commonly used using "require". It is not required to use "use"
|
|
|
|
# (because it doesn't live in a different package)
|
|
|
|
|
|
|
|
# warning: preceding para requires 4th attribute of a programmer after
|
|
|
|
# laziness, impatience, and hubris: sense of humour :-)
|
|
|
|
|
|
|
|
# WARNING
|
|
|
|
# -------
|
|
|
|
# the name of this file will change as soon as its function/feature set
|
|
|
|
# stabilises enough ;-)
|
|
|
|
|
2009-11-26 17:00:59 +01:00
|
|
|
# right now all it does is
|
|
|
|
# - define a function that tells you where to find the rc file
|
|
|
|
# - define a function that creates a new repo and give it our update hook
|
2009-10-25 03:59:52 +01:00
|
|
|
|
2009-12-04 05:21:22 +01:00
|
|
|
# ----------------------------------------------------------------------------
|
|
|
|
# common definitions
|
|
|
|
# ----------------------------------------------------------------------------
|
|
|
|
|
2010-02-04 10:46:47 +01:00
|
|
|
our $ABRT = "\n\t\t***** ABORTING *****\n ";
|
|
|
|
our $WARN = "\n\t\t***** WARNING *****\n ";
|
2009-12-04 05:21:22 +01:00
|
|
|
|
|
|
|
# commands we're expecting
|
2010-02-04 10:46:47 +01:00
|
|
|
our $R_COMMANDS=qr/^(git[ -]upload-pack|git[ -]upload-archive)$/;
|
|
|
|
our $W_COMMANDS=qr/^git[ -]receive-pack$/;
|
2009-12-04 05:21:22 +01:00
|
|
|
|
2009-12-12 05:21:29 +01:00
|
|
|
# note that REPONAME_PATT allows "/", while USERNAME_PATT does not
|
|
|
|
# also, the reason REPONAME_PATT is a superset of USERNAME_PATT is (duh!)
|
|
|
|
# because in this version, a repo can have "CREATER" in the name (see docs)
|
2010-02-05 02:35:27 +01:00
|
|
|
our $REPONAME_PATT=qr(^\@?[0-9a-zA-Z][0-9a-zA-Z._\@/+-]*$); # very simple pattern
|
|
|
|
our $USERNAME_PATT=qr(^\@?[0-9a-zA-Z][0-9a-zA-Z._\@+-]*$); # very simple pattern
|
2009-12-05 14:08:46 +01:00
|
|
|
# same as REPONAME, plus some common regex metas
|
2010-02-05 02:35:27 +01:00
|
|
|
our $REPOPATT_PATT=qr(^\@?[0-9a-zA-Z][\\^.$|()[\]*+?{}0-9a-zA-Z._\@/-]*$);
|
2010-02-04 10:46:47 +01:00
|
|
|
|
|
|
|
our $REPO_UMASK;
|
|
|
|
our %repos;
|
2009-12-04 05:21:22 +01:00
|
|
|
|
|
|
|
# ----------------------------------------------------------------------------
|
|
|
|
# convenience subs
|
|
|
|
# ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
sub wrap_chdir {
|
|
|
|
chdir($_[0]) or die "$ABRT chdir $_[0] failed: $! at ", (caller)[1], " line ", (caller)[2], "\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
sub wrap_open {
|
|
|
|
open (my $fh, $_[0], $_[1]) or die "$ABRT open $_[1] failed: $! at ", (caller)[1], " line ", (caller)[2], "\n" .
|
|
|
|
( $_[2] || '' ); # suffix custom error message if given
|
|
|
|
return $fh;
|
|
|
|
}
|
|
|
|
|
2010-01-31 18:40:12 +01:00
|
|
|
sub log_it {
|
|
|
|
open my $log_fh, ">>", $ENV{GL_LOG} or die "open log failed: $!\n";
|
|
|
|
print $log_fh @_;
|
|
|
|
close $log_fh or die "close log failed: $!\n";
|
|
|
|
}
|
|
|
|
|
2010-01-31 19:26:58 +01:00
|
|
|
# check one ref
|
|
|
|
sub check_ref {
|
|
|
|
|
|
|
|
# normally, the $ref will be whatever ref the commit is trying to update
|
|
|
|
# (like refs/heads/master or whatever). At least one of the refexes that
|
|
|
|
# pertain to this user must match this ref **and** the corresponding
|
|
|
|
# permission must also match the action (W or +) being attempted. If none
|
|
|
|
# of them match, the access is denied.
|
|
|
|
|
|
|
|
# Notice that the function DIES!!! Any future changes that require more
|
|
|
|
# work to be done *after* this, even on failure, can start using return
|
|
|
|
# codes etc., but for now we're happy to just die.
|
|
|
|
|
|
|
|
my ($allowed_refs, $repo, $ref, $perm) = @_;
|
|
|
|
for my $ar (@{$allowed_refs}) {
|
|
|
|
my $refex = (keys %$ar)[0];
|
|
|
|
# refex? sure -- a regex to match a ref against :)
|
|
|
|
next unless $ref =~ /^$refex/;
|
|
|
|
die "$perm $ref $ENV{GL_USER} DENIED by $refex\n" if $ar->{$refex} eq '-';
|
|
|
|
|
|
|
|
# as far as *this* ref is concerned we're ok
|
|
|
|
return $refex if ($ar->{$refex} =~ /\Q$perm/);
|
|
|
|
}
|
|
|
|
die "$perm $ref $repo $ENV{GL_USER} DENIED by fallthru\n";
|
|
|
|
}
|
|
|
|
|
2010-02-05 02:19:07 +01:00
|
|
|
# ln -sf :-)
|
|
|
|
sub ln_sf
|
|
|
|
{
|
|
|
|
my($srcdir, $glob, $dstdir) = @_;
|
|
|
|
for my $hook ( glob("$srcdir/$glob") ) {
|
|
|
|
$hook =~ s/$srcdir\///;
|
|
|
|
unlink "$dstdir/$hook";
|
|
|
|
symlink "$srcdir/$hook", "$dstdir/$hook" or die "could not symlink $hook\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-10-25 03:59:52 +01:00
|
|
|
# ----------------------------------------------------------------------------
|
|
|
|
# where is the rc file hiding?
|
|
|
|
# ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
sub where_is_rc
|
|
|
|
{
|
|
|
|
# till now, the rc file was in one fixed place: .gitolite.rc in $HOME of
|
|
|
|
# the user hosting the gitolite repos. This was fine, because gitolite is
|
|
|
|
# all about empowering non-root users :-)
|
|
|
|
|
|
|
|
# then we wanted to make a debian package out of it (thank you, Rhonda!)
|
|
|
|
# which means (a) it's going to be installed by root anyway and (b) any
|
|
|
|
# config files have to be in /etc/<something>
|
|
|
|
|
|
|
|
# the only way to resolve this in a backward compat way is to look for the
|
|
|
|
# $HOME one, and if you don't find it look for the /etc one
|
|
|
|
|
|
|
|
# this common routine does that, setting an env var for the first one it
|
|
|
|
# finds
|
|
|
|
|
|
|
|
return if $ENV{GL_RC};
|
|
|
|
|
|
|
|
for my $glrc ( $ENV{HOME} . "/.gitolite.rc", "/etc/gitolite/gitolite.rc" ) {
|
|
|
|
if (-f $glrc) {
|
|
|
|
$ENV{GL_RC} = $glrc;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-12-04 05:21:22 +01:00
|
|
|
# ----------------------------------------------------------------------------
|
|
|
|
# create a new repository
|
|
|
|
# ----------------------------------------------------------------------------
|
2009-11-26 17:00:59 +01:00
|
|
|
|
|
|
|
# NOTE: this sub will change your cwd; caller beware!
|
|
|
|
sub new_repo
|
|
|
|
{
|
2009-12-05 18:09:56 +01:00
|
|
|
my ($repo, $hooks_dir, $creater) = @_;
|
2009-11-26 17:00:59 +01:00
|
|
|
|
|
|
|
umask($REPO_UMASK);
|
|
|
|
|
|
|
|
system("mkdir", "-p", "$repo.git") and die "$ABRT mkdir $repo.git failed: $!\n";
|
|
|
|
# erm, note that's "and die" not "or die" as is normal in perl
|
|
|
|
wrap_chdir("$repo.git");
|
|
|
|
system("git --bare init >&2");
|
2010-02-03 18:11:09 +01:00
|
|
|
if ($creater) {
|
|
|
|
system("echo $creater > gl-creater");
|
|
|
|
system("git", "config", "gitweb.owner", $creater);
|
|
|
|
}
|
2009-11-26 17:00:59 +01:00
|
|
|
# propagate our own, plus any local admin-defined, hooks
|
2010-02-05 02:19:07 +01:00
|
|
|
ln_sf($hooks_dir, "*", "hooks");
|
2009-11-26 17:00:59 +01:00
|
|
|
chmod 0755, "hooks/update";
|
|
|
|
}
|
|
|
|
|
2009-12-05 18:09:56 +01:00
|
|
|
# ----------------------------------------------------------------------------
|
|
|
|
# metaphysics (like, "is there a god?", "who created me?", etc)
|
|
|
|
# ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
# "who created this repo", "am I on the R list", and "am I on the RW list"?
|
|
|
|
sub repo_rights
|
|
|
|
{
|
|
|
|
my ($repo_base_abs, $repo, $user) = @_;
|
|
|
|
# creater
|
|
|
|
my $c = '';
|
|
|
|
if ( -f "$repo_base_abs/$repo.git/gl-creater") {
|
|
|
|
my $fh = wrap_open("<", "$repo_base_abs/$repo.git/gl-creater");
|
|
|
|
chomp($c = <$fh>);
|
|
|
|
}
|
|
|
|
# $user's R and W rights
|
|
|
|
my ($r, $w); $r = ''; $w = '';
|
|
|
|
if ($user and -f "$repo_base_abs/$repo.git/gl-perms") {
|
|
|
|
my $fh = wrap_open("<", "$repo_base_abs/$repo.git/gl-perms");
|
|
|
|
my $perms = join ("", <$fh>);
|
|
|
|
if ($perms) {
|
|
|
|
$r = $user if $perms =~ /^\s*R(?=\s).*\s$user(\s|$)/m;
|
|
|
|
$w = $user if $perms =~ /^\s*RW(?=\s).*\s$user(\s|$)/m;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ($c, $r, $w);
|
|
|
|
}
|
|
|
|
|
2009-12-06 10:09:40 +01:00
|
|
|
# ----------------------------------------------------------------------------
|
|
|
|
# getperms and setperms
|
|
|
|
# ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
sub get_set_perms
|
|
|
|
{
|
|
|
|
my($repo_base_abs, $repo, $verb, $user) = @_;
|
|
|
|
my ($creater, $dummy, $dummy2) = &repo_rights($repo_base_abs, $repo, "");
|
|
|
|
die "$repo doesnt exist or is not yours\n" unless $user eq $creater;
|
|
|
|
wrap_chdir("$repo_base_abs");
|
|
|
|
wrap_chdir("$repo.git");
|
|
|
|
if ($verb eq 'getperms') {
|
2010-01-08 13:05:11 +01:00
|
|
|
system("cat", "gl-perms") if -f "gl-perms";
|
2009-12-06 10:09:40 +01:00
|
|
|
} else {
|
|
|
|
system("cat > gl-perms");
|
2010-01-08 13:05:11 +01:00
|
|
|
print "New perms are:\n";
|
|
|
|
system("cat", "gl-perms");
|
2009-12-06 10:09:40 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-02-04 22:40:13 +01:00
|
|
|
# ----------------------------------------------------------------------------
|
|
|
|
# getdesc and setdesc
|
|
|
|
# ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
sub get_set_desc
|
|
|
|
{
|
|
|
|
my($repo_base_abs, $repo, $verb, $user) = @_;
|
|
|
|
my ($creater, $dummy, $dummy2) = &repo_rights($repo_base_abs, $repo, "");
|
|
|
|
die "$repo doesnt exist or is not yours\n" unless $user eq $creater;
|
|
|
|
wrap_chdir("$repo_base_abs");
|
|
|
|
wrap_chdir("$repo.git");
|
|
|
|
if ($verb eq 'getdesc') {
|
|
|
|
system("cat", "description") if -f "description";
|
|
|
|
} else {
|
|
|
|
system("cat > description");
|
|
|
|
print "New description is:\n";
|
|
|
|
system("cat", "description");
|
2009-12-06 10:09:40 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-12-04 05:21:22 +01:00
|
|
|
# ----------------------------------------------------------------------------
|
|
|
|
# parse the compiled acl
|
|
|
|
# ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
sub parse_acl
|
|
|
|
{
|
2009-12-05 18:09:56 +01:00
|
|
|
# IMPLEMENTATION NOTE: a wee bit of this is duplicated in the update hook;
|
|
|
|
# please update that also if the interface or the env vars change
|
|
|
|
|
|
|
|
my ($GL_CONF_COMPILED, $repo, $c, $r, $w) = @_;
|
|
|
|
|
|
|
|
# void $r if same as $w (otherwise "readers" overrides "writers"; this is
|
|
|
|
# the same problem that needed a sort sub for the Dumper in the compile
|
2009-12-06 10:56:53 +01:00
|
|
|
# script, but in this case it's limited to just $readers and $writers)
|
|
|
|
$r = "NOBODY" if $r eq $w;
|
2009-12-05 18:09:56 +01:00
|
|
|
|
|
|
|
# set up the variables for a parse to interpolate stuff from the dumped
|
|
|
|
# hash (remember the selective conversion of single to double quotes?).
|
|
|
|
|
|
|
|
# if they're not passed in, then we look for an env var of that name, else
|
|
|
|
# we default to "NOBODY" (we hope there isn't a real user called NOBODY!)
|
|
|
|
# And in any case, we set those env vars so level 2 can redo the last
|
|
|
|
# parse without any special code
|
|
|
|
|
|
|
|
our $creater = $ENV{GL_CREATER} = $c || $ENV{GL_CREATER} || "NOBODY";
|
|
|
|
our $readers = $ENV{GL_READERS} = $r || $ENV{GL_READERS} || "NOBODY";
|
|
|
|
our $writers = $ENV{GL_WRITERS} = $w || $ENV{GL_WRITERS} || "NOBODY";
|
|
|
|
|
2009-12-04 05:21:22 +01:00
|
|
|
die "parse $GL_CONF_COMPILED failed: " . ($! or $@) unless do $GL_CONF_COMPILED;
|
2009-12-05 18:09:56 +01:00
|
|
|
|
2009-12-21 12:37:31 +01:00
|
|
|
# basic access reporting doesn't send $repo, and doesn't need to; you just
|
|
|
|
# want the config dumped as is, really
|
2009-12-05 18:09:56 +01:00
|
|
|
return unless $repo;
|
|
|
|
|
|
|
|
return $ENV{GL_REPOPATT} = "" if $repos{$repo};
|
2009-12-21 13:19:21 +01:00
|
|
|
|
|
|
|
# didn't find $repo in %repos, so it must be a wildcard-match case
|
2009-12-21 13:03:53 +01:00
|
|
|
my @matched = grep { $repo =~ /^$_$/ } sort keys %repos;
|
2009-12-05 18:09:56 +01:00
|
|
|
die "$repo has no matches\n" unless @matched;
|
|
|
|
die "$repo has multiple matches\n@matched\n" if @matched > 1;
|
|
|
|
# found exactly one pattern that matched, copy its ACL
|
|
|
|
$repos{$repo} = $repos{$matched[0]};
|
|
|
|
# and return the pattern
|
|
|
|
return $ENV{GL_REPOPATT} = $matched[0];
|
2009-12-04 05:21:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
# ----------------------------------------------------------------------------
|
|
|
|
# print a report of $user's basic permissions
|
|
|
|
# ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
# basic means wildcards will be shown as wildcards; this is pretty much what
|
|
|
|
# got parsed by the compile script
|
|
|
|
sub report_basic
|
|
|
|
{
|
|
|
|
my($GL_ADMINDIR, $GL_CONF_COMPILED, $user) = @_;
|
|
|
|
|
2009-12-05 18:09:56 +01:00
|
|
|
&parse_acl($GL_CONF_COMPILED, "", "CREATER", "READERS", "WRITERS");
|
2009-12-04 05:21:22 +01:00
|
|
|
|
|
|
|
# send back some useful info if no command was given
|
|
|
|
print "hello $user, the gitolite version here is ";
|
|
|
|
system("cat", "$GL_ADMINDIR/src/VERSION");
|
|
|
|
print "\ryou have the following permissions:\n\r";
|
|
|
|
for my $r (sort keys %repos) {
|
2009-12-05 18:09:56 +01:00
|
|
|
my $perm .= ( $repos{$r}{C}{'@all'} ? ' @' : ( $repos{$r}{C}{$user} ? ' C' : ' ' ) );
|
|
|
|
$perm .= ( $repos{$r}{R}{'@all'} ? ' @' : ( $repos{$r}{R}{$user} ? ' R' : ' ' ) );
|
|
|
|
$perm .= ( $repos{$r}{W}{'@all'} ? ' @' : ( $repos{$r}{W}{$user} ? ' W' : ' ' ) );
|
|
|
|
print "$perm\t$r\n\r" if $perm =~ /\S/;
|
2009-12-04 05:21:22 +01:00
|
|
|
}
|
|
|
|
}
|
2009-12-05 18:09:56 +01:00
|
|
|
|
2009-12-06 10:56:53 +01:00
|
|
|
# ----------------------------------------------------------------------------
|
|
|
|
# print a report of $user's basic permissions
|
|
|
|
# ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
sub expand_wild
|
|
|
|
{
|
|
|
|
my($GL_CONF_COMPILED, $repo_base_abs, $repo, $user) = @_;
|
|
|
|
|
2009-12-21 12:37:31 +01:00
|
|
|
# this is for convenience; he can copy-paste the output of the basic
|
|
|
|
# access report instead of having to manually change CREATER to his name
|
|
|
|
$repo =~ s/\bCREAT[EO]R\b/$user/g;
|
|
|
|
|
2010-01-29 10:09:03 +01:00
|
|
|
# get the list of repo patterns
|
|
|
|
&parse_acl($GL_CONF_COMPILED, "", "NOBODY", "NOBODY", "NOBODY");
|
2010-01-30 00:18:51 +01:00
|
|
|
my %reponames = map { $_ => 1 } grep { $_ =~ $REPONAME_PATT } sort keys %repos;
|
2010-01-29 10:09:03 +01:00
|
|
|
|
2009-12-06 10:56:53 +01:00
|
|
|
# display matching repos (from *all* the repos in the system) that $user
|
|
|
|
# has at least "R" access to
|
|
|
|
|
|
|
|
chdir("$repo_base_abs") or die "chdir $repo_base_abs failed: $!\n";
|
|
|
|
for my $actual_repo (`find . -type d -name "*.git"|sort`) {
|
|
|
|
chomp ($actual_repo);
|
|
|
|
$actual_repo =~ s/^\.\///;
|
|
|
|
$actual_repo =~ s/\.git$//;
|
2010-01-30 00:18:51 +01:00
|
|
|
# actual_repo should not be present "as is" in the config, because if
|
|
|
|
# it does, those permissions will override anything inherited from a
|
|
|
|
# wildcard that also happens to match, and it would be misleading to
|
|
|
|
# show that here
|
|
|
|
next if $reponames{$actual_repo};
|
2009-12-06 10:56:53 +01:00
|
|
|
# it has to match the pattern being expanded
|
|
|
|
next unless $actual_repo =~ /^$repo$/;
|
|
|
|
|
|
|
|
# find the creater and subsitute in repos
|
|
|
|
my ($creater, $read, $write) = &repo_rights($repo_base_abs, $actual_repo, $user);
|
|
|
|
# get access list with this
|
2010-02-01 18:25:42 +01:00
|
|
|
&parse_acl($GL_CONF_COMPILED, $actual_repo, $creater, $read || "NOBODY", $write || "NOBODY");
|
2009-12-06 10:56:53 +01:00
|
|
|
|
2010-02-01 18:25:42 +01:00
|
|
|
my $perm = " ";
|
|
|
|
$perm .= ($repos{$actual_repo}{R}{'@all'} or $repos{$actual_repo}{R}{$user}) ? " R" : " ";
|
|
|
|
$perm .= ($repos{$actual_repo}{W}{'@all'} or $repos{$actual_repo}{W}{$user}) ? " W" : " ";
|
2010-01-29 10:09:03 +01:00
|
|
|
next if $perm eq " ";
|
|
|
|
print "$perm\t($creater)\t$actual_repo\n";
|
2009-12-06 10:56:53 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-01-31 15:54:36 +01:00
|
|
|
# ----------------------------------------------------------------------------
|
2010-02-01 11:07:35 +01:00
|
|
|
# S P E C I A L C O M M A N D S
|
2010-01-31 15:54:36 +01:00
|
|
|
# ----------------------------------------------------------------------------
|
|
|
|
|
2010-02-01 11:07:35 +01:00
|
|
|
sub special_cmd
|
2010-01-31 15:54:36 +01:00
|
|
|
{
|
2010-02-04 10:46:47 +01:00
|
|
|
my ($GL_ADMINDIR, $GL_CONF_COMPILED, $shell_allowed, $RSYNC_BASE, $HTPASSWD_FILE) = @_;
|
2010-02-01 11:07:35 +01:00
|
|
|
|
|
|
|
my $cmd = $ENV{SSH_ORIGINAL_COMMAND};
|
|
|
|
my $user = $ENV{GL_USER};
|
|
|
|
|
|
|
|
# check each special command we know about and call it if enabled
|
|
|
|
if ($cmd eq 'info') {
|
|
|
|
&report_basic($GL_ADMINDIR, $GL_CONF_COMPILED, $user);
|
|
|
|
print "you also have shell access\n\r" if $shell_allowed;
|
|
|
|
} elsif ($HTPASSWD_FILE and $cmd eq 'htpasswd') {
|
|
|
|
&ext_cmd_htpasswd($HTPASSWD_FILE);
|
|
|
|
} elsif ($RSYNC_BASE and $cmd =~ /^rsync /) {
|
2010-01-31 15:54:36 +01:00
|
|
|
&ext_cmd_rsync($GL_CONF_COMPILED, $RSYNC_BASE, $cmd);
|
|
|
|
} else {
|
2010-02-01 11:07:35 +01:00
|
|
|
# if the user is allowed a shell, just run the command
|
|
|
|
exec $ENV{SHELL}, "-c", $cmd if $shell_allowed;
|
|
|
|
|
2010-01-31 15:54:36 +01:00
|
|
|
die "bad command: $cmd\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
# ----------------------------------------------------------------------------
|
|
|
|
# generic check access routine
|
|
|
|
# ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
sub check_access
|
|
|
|
{
|
|
|
|
my ($GL_CONF_COMPILED, $repo, $path, $perm) = @_;
|
|
|
|
my $ref = "NAME/$path";
|
|
|
|
|
|
|
|
&parse_acl($GL_CONF_COMPILED);
|
|
|
|
|
|
|
|
# until I do some major refactoring (which will bloat the update hook a
|
|
|
|
# bit, sadly), this code duplicates stuff in the current update hook.
|
|
|
|
|
|
|
|
my @allowed_refs;
|
|
|
|
# we want specific perms to override @all, so they come first
|
|
|
|
push @allowed_refs, @ { $repos{$repo}{$ENV{GL_USER}} || [] };
|
|
|
|
push @allowed_refs, @ { $repos{$repo}{'@all'} || [] };
|
|
|
|
|
|
|
|
for my $ar (@allowed_refs) {
|
|
|
|
my $refex = (keys %$ar)[0];
|
|
|
|
next unless $ref =~ /^$refex/;
|
|
|
|
die "$perm $ref $ENV{GL_USER} DENIED by $refex\n" if $ar->{$refex} eq '-';
|
|
|
|
return if ($ar->{$refex} =~ /\Q$perm/);
|
|
|
|
}
|
|
|
|
die "$perm $ref $ENV{GL_REPO} $ENV{GL_USER} DENIED by fallthru\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
# ----------------------------------------------------------------------------
|
|
|
|
# external command helper: rsync
|
|
|
|
# ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
sub ext_cmd_rsync
|
|
|
|
{
|
|
|
|
my ($GL_CONF_COMPILED, $RSYNC_BASE, $cmd) = @_;
|
|
|
|
|
|
|
|
# test the command patterns; reject if they don't fit. Rsync sends
|
|
|
|
# commands that looks like one of these to the server (the first one is
|
|
|
|
# for a read, the second for a write)
|
|
|
|
# rsync --server --sender -some.flags . some/path
|
|
|
|
# rsync --server -some.flags . some/path
|
|
|
|
|
|
|
|
die "bad rsync command: $cmd"
|
2010-01-31 16:39:05 +01:00
|
|
|
unless $cmd =~ /^rsync --server( --sender)? -[\w.]+(?: --(?:delete|partial))* \. (\S+)$/;
|
2010-01-31 15:54:36 +01:00
|
|
|
my $perm = "W";
|
|
|
|
$perm = "R" if $1;
|
|
|
|
my $path = $2;
|
|
|
|
die "I dont like absolute paths in $cmd\n" if $path =~ /^\//;
|
|
|
|
die "I dont like '..' paths in $cmd\n" if $path =~ /\.\./;
|
|
|
|
|
|
|
|
# ok now check if we're permitted to execute a $perm action on $path
|
|
|
|
# (taken as a refex) using rsync.
|
|
|
|
|
|
|
|
&check_access($GL_CONF_COMPILED, 'EXTCMD/rsync', $path, $perm);
|
|
|
|
# that should "die" if there's a problem
|
|
|
|
|
|
|
|
wrap_chdir($RSYNC_BASE);
|
2010-02-01 07:05:35 +01:00
|
|
|
&log_it("$ENV{GL_TS}\t$ENV{SSH_ORIGINAL_COMMAND}\t$ENV{USER}\n");
|
2010-01-31 15:54:36 +01:00
|
|
|
exec $ENV{SHELL}, "-c", $ENV{SSH_ORIGINAL_COMMAND};
|
|
|
|
}
|
|
|
|
|
2010-02-01 11:07:35 +01:00
|
|
|
# ----------------------------------------------------------------------------
|
|
|
|
# external command helper: htpasswd
|
|
|
|
# ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
sub ext_cmd_htpasswd
|
|
|
|
{
|
|
|
|
my $HTPASSWD_FILE = shift;
|
|
|
|
|
|
|
|
die "$HTPASSWD_FILE doesn't exist or is not writable\n" unless -w $HTPASSWD_FILE;
|
|
|
|
$|++;
|
|
|
|
print <<EOFhtp;
|
|
|
|
Please type in your new htpasswd at the prompt. You only have to type it once.
|
|
|
|
|
|
|
|
NOTE THAT THE PASSWORD WILL BE ECHOED, so please make sure no one is
|
|
|
|
shoulder-surfing, and make sure you clear your screen as well as scrollback
|
|
|
|
history after you're done (or close your terminal instance).
|
|
|
|
|
|
|
|
EOFhtp
|
|
|
|
print "new htpasswd:";
|
|
|
|
|
|
|
|
my $password = <>;
|
|
|
|
$password =~ s/[\n\r]*$//;
|
|
|
|
my $rc = system("htpasswd", "-b", $HTPASSWD_FILE, $ENV{GL_USER}, $password);
|
|
|
|
die "htpasswd command seems to have failed with $rc return code...\n" if $rc;
|
|
|
|
}
|
2010-01-31 15:54:36 +01:00
|
|
|
|
2009-12-06 10:56:53 +01:00
|
|
|
1;
|