2009-08-25 05:14:46 +02:00
|
|
|
#!/usr/bin/perl
|
2009-08-23 14:54:37 +02:00
|
|
|
|
|
|
|
use strict;
|
2009-08-25 05:14:46 +02:00
|
|
|
use warnings;
|
2009-08-23 14:54:37 +02:00
|
|
|
|
|
|
|
# === auth-command ===
|
|
|
|
# the command that GL users actually run
|
|
|
|
|
2009-08-26 02:47:27 +02:00
|
|
|
# part of the gitolite (GL) suite
|
2009-08-23 14:54:37 +02:00
|
|
|
|
|
|
|
# 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:
|
|
|
|
|
|
|
|
# robustness:
|
|
|
|
|
|
|
|
# other notes:
|
|
|
|
|
|
|
|
# ----------------------------------------------------------------------------
|
|
|
|
# common definitions
|
|
|
|
# ----------------------------------------------------------------------------
|
|
|
|
|
2009-12-04 05:21:22 +01:00
|
|
|
# these are set by the "rc" file
|
gitweb/daemon now work for wild repos also
(thanks to Kevin Fleming for the need/use case)
TODO: tests
TODO: proper documentation; meanwhile, just read this:
- you can give gitweb and daemon read rights to wild card repos also,
and it'll all just work -- when a new repo is 'C'reated, it'll pick
up those rights etc
- you can assign descriptions (and owners) to individual repos as
before, except now you can assign them to repos that actually were
created from wild card patterns. So for example, you can define
rules for
repo foo/..*
and then assign descriptions like
foo/repo1 = "repo one"
foo/repo2 = "repo two"
foo/dil "scott" = "scott's dilbert repo"
However, this only works for repos that already exist, and only when
you push the admin repo.
Thumb rule: have the user create his wild repo, *then* add and push
the admin config file with the description. Not the other way
around.
implementation notes:
- wildcard support for git config revamped, refactored...
it's not just git config that needs wildcard support. daemon and
gitweb access also will be needing it soon, so we start by factoring
out the part that finds the "pattern" given a "real" repo name.
- GL_NO_DAEMON_NO_GITWEB now gates more than just those two things;
see doc/big-config.mkd for details
- we trawl through $GL_REPO_BASE_ABS *once* only, collecting repo
names and tying them to either the same name or to a wild pattern
that the repo name was created from
- nice little subs to setup gitweb, daemon, and git config
- god bless $GL_REPOPATT and the day I decided to set that env var
whenever a user hits a wild repo in any way :-)
- the code in gl-compile-conf is very simple now. Much nicer than
before
2010-07-16 19:31:34 +02:00
|
|
|
our ($GL_LOGT, $GL_CONF_COMPILED, $REPO_BASE, $GIT_PATH, $REPO_UMASK, $GL_ADMINDIR, $RSYNC_BASE, $HTPASSWD_FILE, $GL_WILDREPOS, $GL_WILDREPOS_DEFPERMS, $GL_ADC_PATH, $SVNSERVE, $PROJECTS_LIST, $GL_SLAVE_MODE);
|
2009-12-04 05:21:22 +01:00
|
|
|
# and these are set by gitolite.pm
|
2010-01-29 10:09:03 +01:00
|
|
|
our ($R_COMMANDS, $W_COMMANDS, $REPONAME_PATT, $REPOPATT_PATT);
|
2009-08-23 14:54:37 +02:00
|
|
|
our %repos;
|
2010-05-10 08:16:47 +02:00
|
|
|
our %groups;
|
2010-06-26 01:51:57 +02:00
|
|
|
our %repo_config;
|
2009-08-23 14:54:37 +02:00
|
|
|
|
2009-10-25 03:59:52 +01:00
|
|
|
# the common setup module is in the same directory as this running program is
|
|
|
|
my $bindir = $0;
|
|
|
|
$bindir =~ s/\/[^\/]+$//;
|
2010-02-09 12:30:01 +01:00
|
|
|
$bindir = "$ENV{PWD}/$bindir" unless $bindir =~ /^\//;
|
2009-10-25 03:59:52 +01:00
|
|
|
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};
|
2009-08-23 14:54:37 +02:00
|
|
|
|
2010-01-31 18:40:12 +01:00
|
|
|
# we need to pass GL_ADMINDIR and the bindir to the child hooks
|
2009-12-15 08:05:48 +01:00
|
|
|
$ENV{GL_ADMINDIR} = $GL_ADMINDIR;
|
|
|
|
$ENV{GL_BINDIR} = $bindir;
|
|
|
|
|
2009-10-13 06:32:45 +02:00
|
|
|
# add a custom path for git binaries, if specified
|
|
|
|
$ENV{PATH} .= ":$GIT_PATH" if $GIT_PATH;
|
|
|
|
|
2010-06-22 13:30:48 +02:00
|
|
|
# set default permission of wildcard repositories
|
|
|
|
$ENV{GL_WILDREPOS_DEFPERMS} = $GL_WILDREPOS_DEFPERMS if $GL_WILDREPOS_DEFPERMS;
|
|
|
|
|
2009-12-15 11:41:21 +01:00
|
|
|
# set the umask before creating any files
|
|
|
|
umask($REPO_UMASK);
|
|
|
|
|
2010-06-29 07:25:36 +02:00
|
|
|
$ENV{GL_REPO_BASE_ABS} = ( $REPO_BASE =~ m(^/) ? $REPO_BASE : "$ENV{HOME}/$REPO_BASE" );
|
2010-02-04 10:12:10 +01:00
|
|
|
|
2009-08-23 14:54:37 +02:00
|
|
|
# ----------------------------------------------------------------------------
|
|
|
|
# start...
|
|
|
|
# ----------------------------------------------------------------------------
|
|
|
|
|
2009-12-19 16:22:30 +01:00
|
|
|
# if the first argument is a "-s", this user is allowed to get a shell using
|
|
|
|
# this key
|
|
|
|
my $shell_allowed = 0;
|
2010-07-21 02:57:43 +02:00
|
|
|
if (@ARGV and $ARGV[0] eq '-s') {
|
2009-12-19 16:22:30 +01:00
|
|
|
$shell_allowed = 1;
|
|
|
|
shift;
|
|
|
|
}
|
|
|
|
|
2010-07-21 02:57:43 +02:00
|
|
|
# no (more) arguments given? default user is $USER (fedorahosted works like
|
|
|
|
# this, and it is harmless for others)
|
|
|
|
@ARGV = ($ENV{USER}) unless @ARGV;
|
|
|
|
|
2009-08-23 14:54:37 +02:00
|
|
|
# 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!
|
|
|
|
|
2010-05-14 13:05:37 +02:00
|
|
|
# if there are any more arguments, they're a list of group names that the user
|
|
|
|
# is a member of
|
|
|
|
$ENV{GL_GROUP_LIST} = join(" ", @ARGV) if @ARGV;
|
|
|
|
|
2010-02-01 12:24:39 +01:00
|
|
|
# ----------------------------------------------------------------------------
|
|
|
|
# logging, timestamp env vars
|
|
|
|
# ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
# 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;
|
|
|
|
|
2009-08-23 14:54:37 +02:00
|
|
|
# ----------------------------------------------------------------------------
|
|
|
|
# sanity checks on SSH_ORIGINAL_COMMAND
|
|
|
|
# ----------------------------------------------------------------------------
|
|
|
|
|
2010-02-01 07:06:24 +01:00
|
|
|
# no SSH_ORIGINAL_COMMAND given...
|
2009-10-28 09:03:24 +01:00
|
|
|
unless ($ENV{SSH_ORIGINAL_COMMAND}) {
|
2010-02-01 07:06:24 +01:00
|
|
|
# if the user is allowed to use a shell, give him one
|
2009-12-19 16:22:30 +01:00
|
|
|
if ($shell_allowed) {
|
|
|
|
my $shell = $ENV{SHELL};
|
|
|
|
$shell =~ s/.*\//-/; # change "/bin/bash" to "-bash"
|
2010-06-16 03:50:12 +02:00
|
|
|
&log_it($shell);
|
2009-12-19 16:22:30 +01:00
|
|
|
exec { $ENV{SHELL} } $shell;
|
|
|
|
}
|
2010-02-01 07:06:24 +01:00
|
|
|
# otherwise, pretend he typed in "info" and carry on...
|
|
|
|
$ENV{SSH_ORIGINAL_COMMAND} = 'info';
|
2009-10-28 09:03:24 +01:00
|
|
|
}
|
|
|
|
|
2010-08-10 10:12:52 +02:00
|
|
|
# ----------------------------------------------------------------------------
|
|
|
|
# slave mode should not do much
|
|
|
|
# ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
die "server is in slave mode; you can only fetch\n"
|
|
|
|
if ($GL_SLAVE_MODE and $ENV{SSH_ORIGINAL_COMMAND} !~ /^(info|expand|get|git-upload-)/);
|
|
|
|
|
2010-04-24 14:46:13 +02:00
|
|
|
# ----------------------------------------------------------------------------
|
|
|
|
# admin defined commands
|
|
|
|
# ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
# please see doc/admin-defined-commands.mkd for details
|
|
|
|
if ($GL_ADC_PATH and -d $GL_ADC_PATH) {
|
|
|
|
my ($cmd, @args) = split ' ', $ENV{SSH_ORIGINAL_COMMAND};
|
|
|
|
if (-x "$GL_ADC_PATH/$cmd") {
|
|
|
|
# yes this is rather strict, sorry.
|
|
|
|
do { die "I don't like $_\n" unless $_ =~ $REPOPATT_PATT } for ($cmd, @args);
|
2010-06-16 03:50:12 +02:00
|
|
|
&log_it("$GL_ADC_PATH/$ENV{SSH_ORIGINAL_COMMAND}");
|
2010-04-24 14:46:13 +02:00
|
|
|
exec("$GL_ADC_PATH/$cmd", @args);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-12-06 10:09:40 +01:00
|
|
|
# ----------------------------------------------------------------------------
|
|
|
|
# get and set perms for actual repo created by wildcard-autoviv
|
|
|
|
# ----------------------------------------------------------------------------
|
|
|
|
|
2010-02-18 14:50:46 +01:00
|
|
|
my $CUSTOM_COMMANDS=qr/^\s*(expand|(get|set)(perms|desc))\b/;
|
2009-12-06 10:09:40 +01:00
|
|
|
|
|
|
|
# note that all the subs called here chdir somewhere else and do not come
|
|
|
|
# back; they all blithely take advantage of the fact that processing custom
|
|
|
|
# commands is sort of a dead end for normal (git) processing
|
|
|
|
|
2010-02-04 10:12:10 +01:00
|
|
|
if ($ENV{SSH_ORIGINAL_COMMAND} =~ $CUSTOM_COMMANDS) {
|
2010-02-05 11:30:47 +01:00
|
|
|
die "wildrepos disabled, sorry\n" unless $GL_WILDREPOS;
|
2010-02-04 10:12:10 +01:00
|
|
|
my $cmd = $ENV{SSH_ORIGINAL_COMMAND};
|
2010-03-01 16:02:54 +01:00
|
|
|
my ($verb, $repo) = ($cmd =~ /^\s*(\S+)(?:\s+'?\/?(.*?)(?:\.git)?'?)?$/);
|
2010-02-18 14:50:46 +01:00
|
|
|
# deal with "no argument" cases
|
2010-02-26 15:55:28 +01:00
|
|
|
$verb eq 'expand' ? $repo = '^' : die "$verb needs an argument\n" unless $repo;
|
2009-12-06 10:09:40 +01:00
|
|
|
if ($repo =~ $REPONAME_PATT and $verb =~ /getperms|setperms/) {
|
|
|
|
# with an actual reponame, you can "getperms" or "setperms"
|
2010-06-29 07:25:36 +02:00
|
|
|
get_set_perms($repo, $verb, $user);
|
2009-12-06 10:09:40 +01:00
|
|
|
}
|
2010-02-04 22:40:13 +01:00
|
|
|
elsif ($repo =~ $REPONAME_PATT and $verb =~ /(get|set)desc/) {
|
|
|
|
# with an actual reponame, you can "getdesc" or "setdesc"
|
2010-06-29 07:25:36 +02:00
|
|
|
get_set_desc($repo, $verb, $user);
|
2009-12-06 10:09:40 +01:00
|
|
|
}
|
2009-12-21 13:19:21 +01:00
|
|
|
elsif ($verb eq 'expand') {
|
2009-12-06 10:09:40 +01:00
|
|
|
# with a wildcard, you can "expand" it to see what repos actually match
|
2010-01-29 10:09:03 +01:00
|
|
|
die "$repo has invalid characters" unless "x$repo" =~ $REPOPATT_PATT;
|
2010-06-29 07:25:36 +02:00
|
|
|
expand_wild($GL_ADMINDIR, $GL_CONF_COMPILED, $repo, $user);
|
2009-12-06 10:09:40 +01:00
|
|
|
} else {
|
|
|
|
die "$cmd doesn't make sense to me\n";
|
|
|
|
}
|
2010-01-08 13:05:11 +01:00
|
|
|
exit 0;
|
2009-12-06 10:09:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
# ----------------------------------------------------------------------------
|
2010-02-01 11:07:35 +01:00
|
|
|
# non-git commands
|
2009-12-06 10:09:40 +01:00
|
|
|
# ----------------------------------------------------------------------------
|
2009-08-23 14:54:37 +02:00
|
|
|
|
2010-02-01 11:07:35 +01:00
|
|
|
# if the command does NOT fit the pattern of a normal git command, send it off
|
|
|
|
# somewhere else...
|
2009-08-23 14:54:37 +02:00
|
|
|
|
2010-02-01 11:07:35 +01:00
|
|
|
# side notes on detecting a normal git command: the pattern we check allows
|
|
|
|
# old style as well as new style ("git-subcommand arg" or "git subcommand
|
2010-05-21 18:02:33 +02:00
|
|
|
# arg"). Currently, this is how git sends across the command (including the
|
|
|
|
# single quotes):
|
2010-02-01 11:07:35 +01:00
|
|
|
# git-receive-pack 'reponame.git'
|
2009-08-23 14:54:37 +02:00
|
|
|
|
2010-02-01 11:07:35 +01:00
|
|
|
my ($verb, $repo) = ($ENV{SSH_ORIGINAL_COMMAND} =~ /^\s*(git\s+\S+|\S+)\s+'\/?(.*?)(?:\.git)?'/);
|
2010-04-25 01:25:43 +02:00
|
|
|
unless ( $verb and ( $verb eq 'git-init' or $verb =~ $R_COMMANDS or $verb =~ $W_COMMANDS ) and $repo and $repo =~ $REPONAME_PATT ) {
|
2010-02-01 11:07:35 +01:00
|
|
|
# ok, it's not a normal git command; call the special command helper
|
2010-05-09 17:04:55 +02:00
|
|
|
&special_cmd ($GL_ADMINDIR, $GL_CONF_COMPILED, $shell_allowed, $RSYNC_BASE, $HTPASSWD_FILE, $SVNSERVE);
|
2010-02-01 11:07:35 +01:00
|
|
|
exit;
|
2009-12-19 16:22:30 +01:00
|
|
|
}
|
2009-12-11 17:07:33 +01:00
|
|
|
die "$repo ends with a slash; I don't like that\n" if $repo =~ /\/$/;
|
2009-12-13 08:13:44 +01:00
|
|
|
die "$repo has two consecutive periods; I don't like that\n" if $repo =~ /\.\./;
|
2009-08-23 14:54:37 +02:00
|
|
|
|
2010-02-04 10:12:10 +01:00
|
|
|
# reponame
|
|
|
|
$ENV{GL_REPO}=$repo;
|
2009-08-23 14:54:37 +02:00
|
|
|
|
2010-02-01 11:07:35 +01:00
|
|
|
# ----------------------------------------------------------------------------
|
|
|
|
# the real git commands (git-receive-pack, etc...)
|
|
|
|
# ----------------------------------------------------------------------------
|
|
|
|
|
2009-08-23 14:54:37 +02:00
|
|
|
# ----------------------------------------------------------------------------
|
|
|
|
# first level permissions check
|
|
|
|
# ----------------------------------------------------------------------------
|
|
|
|
|
2010-05-10 08:16:47 +02:00
|
|
|
my ($perm, $creator, $wild) = &repo_rights($repo);
|
2010-04-24 09:44:16 +02:00
|
|
|
if ($perm =~ /C/) {
|
|
|
|
# it was missing, and you have create perms
|
2010-06-29 07:25:36 +02:00
|
|
|
wrap_chdir("$ENV{GL_REPO_BASE_ABS}");
|
2010-04-24 09:44:16 +02:00
|
|
|
new_repo($repo, "$GL_ADMINDIR/hooks/common", $user);
|
gitweb/daemon now work for wild repos also
(thanks to Kevin Fleming for the need/use case)
TODO: tests
TODO: proper documentation; meanwhile, just read this:
- you can give gitweb and daemon read rights to wild card repos also,
and it'll all just work -- when a new repo is 'C'reated, it'll pick
up those rights etc
- you can assign descriptions (and owners) to individual repos as
before, except now you can assign them to repos that actually were
created from wild card patterns. So for example, you can define
rules for
repo foo/..*
and then assign descriptions like
foo/repo1 = "repo one"
foo/repo2 = "repo two"
foo/dil "scott" = "scott's dilbert repo"
However, this only works for repos that already exist, and only when
you push the admin repo.
Thumb rule: have the user create his wild repo, *then* add and push
the admin config file with the description. Not the other way
around.
implementation notes:
- wildcard support for git config revamped, refactored...
it's not just git config that needs wildcard support. daemon and
gitweb access also will be needing it soon, so we start by factoring
out the part that finds the "pattern" given a "real" repo name.
- GL_NO_DAEMON_NO_GITWEB now gates more than just those two things;
see doc/big-config.mkd for details
- we trawl through $GL_REPO_BASE_ABS *once* only, collecting repo
names and tying them to either the same name or to a wild pattern
that the repo name was created from
- nice little subs to setup gitweb, daemon, and git config
- god bless $GL_REPOPATT and the day I decided to set that env var
whenever a user hits a wild repo in any way :-)
- the code in gl-compile-conf is very simple now. Much nicer than
before
2010-07-16 19:31:34 +02:00
|
|
|
&setup_repo_configs($repo, $ENV{GL_REPOPATT}, \%repo_config);
|
|
|
|
&setup_daemon_access($repo, $repos{$ENV{GL_REPOPATT}}{'R'}{'daemon'} || '');
|
|
|
|
&setup_gitweb_access($repo, $repos{$ENV{GL_REPOPATT}}{'R'}{'gitweb'} || '', '', '');
|
|
|
|
system("echo $repo.git >> $PROJECTS_LIST");
|
2010-04-24 09:44:16 +02:00
|
|
|
wrap_chdir($ENV{HOME});
|
2009-12-05 18:09:56 +01:00
|
|
|
}
|
2009-12-04 05:21:22 +01:00
|
|
|
|
2009-08-25 05:51:07 +02:00
|
|
|
# we know the user and repo; we just need to know what perm he's trying
|
2010-04-24 09:44:16 +02:00
|
|
|
# aa == attempted access
|
|
|
|
my $aa = ($verb =~ $R_COMMANDS ? 'R' : 'W');
|
|
|
|
die "$aa access for $repo DENIED to $user\n" unless $perm =~ /$aa/;
|
2009-08-23 14:54:37 +02:00
|
|
|
|
|
|
|
# ----------------------------------------------------------------------------
|
2010-02-01 12:24:39 +01:00
|
|
|
# over to git now
|
2009-08-23 14:54:37 +02:00
|
|
|
# ----------------------------------------------------------------------------
|
|
|
|
|
2010-06-16 03:50:12 +02:00
|
|
|
&log_it();
|
2009-08-23 14:54:37 +02:00
|
|
|
|
|
|
|
$repo = "'$REPO_BASE/$repo.git'";
|
2010-04-25 01:25:43 +02:00
|
|
|
exec("git", "shell", "-c", "$verb $repo") unless $verb eq 'git-init';
|