gitolite v2.0rc1 -- please see new developer-notes doc
This commit is contained in:
parent
d022d90031
commit
692552d146
|
@ -1,5 +1,8 @@
|
|||
<a name="start"></a>
|
||||
|
||||
***IMPORTANT NOTE: v2.0rc1 is out; all development will be on that now.
|
||||
Please see new doc/developer-notes.mkd***
|
||||
|
||||
# gitolite
|
||||
|
||||
Gitolite is an access control layer on top of git, which allows access control
|
||||
|
|
|
@ -3,19 +3,21 @@
|
|||
# PLEASE READ THE DOCUMENTATION BEFORE EDITING OR ASKING QUESTIONS
|
||||
# ( http://github.com/sitaramc/gitolite/blob/pu/doc/gitolite.rc.mkd )
|
||||
|
||||
# this file is meant to be pulled into a perl program using "do" or "require".
|
||||
# You do NOT need to know perl to edit the paths; it should be fairly
|
||||
# self-explanatory and easy to maintain perl syntax :-)
|
||||
# this file is in perl syntax. However, you do NOT need to know perl to edit
|
||||
# it; it should be fairly self-explanatory and easy to maintain
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# VARIABLES THAT SHOULD NOT BE TOUCHED AT ALL. EVER.
|
||||
# DO NOT TOUCH THIS SECTION!
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
$GL_ADMINDIR=$ENV{HOME} . "/.gitolite";
|
||||
$GL_CONF="$GL_ADMINDIR/conf/gitolite.conf";
|
||||
$GL_KEYDIR="$GL_ADMINDIR/keydir";
|
||||
$GL_CONF_COMPILED="$GL_ADMINDIR/conf/gitolite.conf-compiled.pm";
|
||||
# DO NOT CHANGE THE NEXT TWO LINES UNLESS YOU REALLY KNOW WHAT YOU'RE DOING.
|
||||
|
||||
# DO NOT CHANGE THE NEXT FOUR LINES UNLESS YOU REALLY KNOW WHAT YOU'RE DOING.
|
||||
# These variables are set automatically by the install method you choose.
|
||||
# (PACKAGE MAINTAINERS: PLEASE READ doc/packaging.mkd)
|
||||
# $GL_PACKAGE_CONF = "";
|
||||
# $GL_PACKAGE_HOOKS = "";
|
||||
|
||||
|
@ -27,13 +29,14 @@ $PROJECTS_LIST = $ENV{HOME} . "/projects.list";
|
|||
$REPO_UMASK = 0077;
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# variables with an efficiency impact
|
||||
# variables with an efficiency/performance impact
|
||||
# ------------------------------------------------------------------------------
|
||||
$GL_BIG_CONFIG = 0;
|
||||
$GL_NO_DAEMON_NO_GITWEB = 0;
|
||||
# $GL_NICE_VALUE = 0;
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# VARIABLES WITH A SECURITY IMPACT. READ DOC WELL BEFORE CHANGING THESE.
|
||||
# VARIABLES WITH A SECURITY IMPACT. READ DOCS BEFORE CHANGING THESE!
|
||||
# http://github.com/sitaramc/gitolite/blob/pu/doc/gitolite.rc.mkd#_variables_with_a_security_impact
|
||||
# ------------------------------------------------------------------------------
|
||||
# $GL_ALL_READ_ALL = 0;
|
||||
|
@ -59,19 +62,23 @@ $SVNSERVE = "";
|
|||
# $ENV{GL_SLAVES} = 'gitolite@server2 gitolite@server3';
|
||||
# PLEASE USE SINGLE QUOTES ABOVE, NOT DOUBLE QUOTES
|
||||
$GL_WILDREPOS_PERM_CATS = "READERS WRITERS";
|
||||
# $GL_SITE_INFO = "XYZ.COM DEVELOPERS: PLEASE SEE http://xyz.com/gitolite/help first";
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# rarely changed variables
|
||||
# ------------------------------------------------------------------------------
|
||||
$GL_LOGT="$GL_ADMINDIR/logs/gitolite-%y-%m.log";
|
||||
# $GL_PERFLOGT="$GL_ADMINDIR/logs/perf-gitolite-%y-%m.log";
|
||||
# $GL_SITE_INFO = "XYZ.COM DEVELOPERS: PLEASE SEE http://xyz.com/gitolite/help first";
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# variables that should NOT be changed after the install step completes
|
||||
# ------------------------------------------------------------------------------
|
||||
$REPO_BASE="repositories";
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# DO NOT TOUCH ANY THING AFTER THIS LINE
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# per perl rules, this should be the last line in such a file:
|
||||
1;
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
. $(dirname $0)/adc.common-functions
|
||||
|
||||
[ -z "$GL_RC" ] && die "ENV GL_RC not set"
|
||||
|
||||
# get_rights_and_owner now also sets $repo; see comments in common functions
|
||||
get_rights_and_owner $1; from=$repo
|
||||
[ -z "$perm_read" ] && die "no read permissions on $from"
|
||||
|
@ -17,7 +19,7 @@ git clone --bare -l $GL_REPO_BASE_ABS/$from.git $GL_REPO_BASE_ABS/$to.git
|
|||
cd $GL_REPO_BASE_ABS/$to.git
|
||||
echo $GL_USER > gl-creater
|
||||
git config gitweb.owner "$GL_USER"
|
||||
( cd $HOME;perl -le 'do ".gitolite.rc"; print $GL_WILDREPOS_DEFPERMS' ) |
|
||||
( $GL_BINDIR/gl-query-rc GL_WILDREPOS_DEFPERMS ) |
|
||||
SSH_ORIGINAL_COMMAND="setperms $to" $GL_BINDIR/gl-auth-command $GL_USER
|
||||
cp -R $GL_REPO_BASE_ABS/$from.git/hooks/* $GL_REPO_BASE_ABS/$to.git/hooks
|
||||
|
||||
|
|
|
@ -3,8 +3,12 @@
|
|||
use strict;
|
||||
use warnings;
|
||||
|
||||
die "ENV GL_RC not set\n" unless $ENV{GL_RC};
|
||||
die "ENV GL_BINDIR not set\n" unless $ENV{GL_BINDIR};
|
||||
|
||||
unshift @INC, $ENV{GL_BINDIR};
|
||||
require gitolite or die "parse gitolite.pm failed\n";
|
||||
gitolite->import;
|
||||
|
||||
# get the repo name
|
||||
my $repo = shift;
|
||||
|
@ -15,7 +19,7 @@ $repo =~ s/\.git$//;
|
|||
|
||||
|
||||
# to do a "level 1" check (repo level -- not branch level), do this:
|
||||
my ($perm, $creator) = &check_access($repo);
|
||||
my ($perm, $creator) = check_access($repo);
|
||||
# you can pass in any repo name you wish instead of the active repo
|
||||
|
||||
# the first return value looks like one of these, so you can just check for
|
||||
|
@ -30,7 +34,7 @@ my ($perm, $creator) = &check_access($repo);
|
|||
|
||||
|
||||
# to do a "level 2" check (branches), do something like this
|
||||
my $ret = &check_access($repo, 'refs/heads/foo', 'W', 1);
|
||||
my $ret = check_access($repo, 'refs/heads/foo', 'W', 1);
|
||||
# the 2nd argument must be a *full* refname (i.e., not "master", but
|
||||
# "refs/heads/master"). The 3rd argument is one of W, +, C, or D. The 4th
|
||||
# argument should be any non-false perl value, like 1.
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
use strict;
|
||||
use warnings;
|
||||
|
||||
die "ENV GL_RC not set\n" unless $ENV{GL_RC};
|
||||
die "ENV GL_BINDIR not set\n" unless $ENV{GL_BINDIR};
|
||||
|
||||
# - show fake "reflog" from gitolite server
|
||||
# - recover deleted branches
|
||||
# - recover from bad force pushes
|
||||
|
@ -42,8 +45,9 @@ $limit ||= 10;
|
|||
|
||||
unshift @INC, $ENV{GL_BINDIR};
|
||||
require gitolite or die "parse gitolite.pm failed\n";
|
||||
gitolite->import;
|
||||
|
||||
my ($perm, $creator, $wild) = &repo_rights($repo);
|
||||
my ($perm, $creator, $wild) = repo_rights($repo);
|
||||
die "you don't have read access to $repo\n" unless $perm =~ /R/;
|
||||
|
||||
my @logfiles = sort glob("$ENV{GL_ADMINDIR}/logs/*");
|
||||
|
@ -93,5 +97,5 @@ if ( $cmd eq 'recover' ) {
|
|||
$newsha2 = '' if $newsha =~ /^0+$/;
|
||||
system("git", "update-ref", $ref, $oldsha, $newsha2) and
|
||||
die "repo $repo, update-ref $ref $oldsha $newsha failed...\n";
|
||||
&log_it("", "+\t$newsha\t$oldsha\t$repo\t$ref");
|
||||
log_it("", "+\t$newsha\t$oldsha\t$repo\t$ref");
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
. $(dirname $0)/adc.common-functions
|
||||
|
||||
[ -z "$GL_RC" ] && die "ENV GL_RC not set"
|
||||
|
||||
# options settable in adc.common-functions are
|
||||
# ARE_YOU_SURE -- prompts "are you sure?"
|
||||
# USE_LOCK_UNLOCK -- allows delete only if repo is "unlock"ed
|
||||
|
@ -32,6 +34,6 @@ rm -rf $repo.git
|
|||
echo "$repo is now GONE!"
|
||||
|
||||
cd $HOME
|
||||
PROJECTS_LIST=$(perl -e 'do ".gitolite.rc"; print $PROJECTS_LIST')
|
||||
PROJECTS_LIST=$($GL_BINDIR/gl-query-rc PROJECTS_LIST)
|
||||
export repo
|
||||
perl -ni -e 'print unless /^\Q$ENV{repo}.git\E$/' $PROJECTS_LIST
|
||||
|
|
|
@ -20,10 +20,10 @@ $doc =~ s/^<a name="_.*"><\/a>\n\n//mg;
|
|||
$doc =~ s/^<a name="AUTO_.*"><\/a>\n\n//mg;
|
||||
|
||||
my @toc = $doc =~ /^###+ .*/mg;
|
||||
$doc =~ s/^(###+) (.*)/"<a name=\"_" . &make_anchor($2) . "\"><\/a>\n\n$1 $2"/mge;
|
||||
$doc =~ s/^(###+) (.*)/"<a name=\"_" . make_anchor($2) . "\"><\/a>\n\n$1 $2"/mge;
|
||||
|
||||
for (@toc) {
|
||||
s/^(###+) (.*)/' ' x (length($1)-3) . ' * <a href="#_' . &make_anchor($2) . "\">$2<\/a>"/e;
|
||||
s/^(###+) (.*)/' ' x (length($1)-3) . ' * <a href="#_' . make_anchor($2) . "\">$2<\/a>"/e;
|
||||
}
|
||||
|
||||
my $toc = "In this document:\n\n";
|
||||
|
|
|
@ -6,29 +6,36 @@
|
|||
# HOME of the gitolite user
|
||||
my $gl_home = "/home/git";
|
||||
|
||||
# environment variables needed by gitolite.pm
|
||||
# the following variables are needed by gitolite; please edit before using
|
||||
|
||||
# this should normally not be anything else
|
||||
$ENV{GL_RC} = "$gl_home/.gitolite.rc";
|
||||
# this can have different values depending on how you installed.
|
||||
|
||||
# If you installed using the 'from-client' method it will be this:
|
||||
$ENV{GL_BINDIR} = "$gl_home/.gitolite/src";
|
||||
# if you used RPM/DEB or "root" methods it **might** be this:
|
||||
$ENV{GL_BINDIR} = "/usr/local/bin";
|
||||
# if you used the "non-root" method it **might** be this:
|
||||
$ENV{GL_BINDIR} = "$gl_home/bin";
|
||||
# If in doubt take a look at ~/.ssh/authorized_keys; at least one of the lines
|
||||
# might contain something like:
|
||||
# command="/home/git/.gitolite/src/gl-auth-command
|
||||
# and you should use whatever directory the gl-auth-command is in (in this
|
||||
# example /home/git/.gitolite.src)
|
||||
|
||||
# finally the user name
|
||||
$ENV{GL_USER} = $cgi->remote_user || "gitweb";
|
||||
|
||||
# variables from the RC file
|
||||
our ($REPO_BASE, $GL_ADMINDIR);
|
||||
|
||||
# set HOME temporarily for RC parsing
|
||||
my $orig_home = $ENV{HOME};
|
||||
$ENV{HOME} = $gl_home;
|
||||
do $ENV{GL_RC}
|
||||
or die_error(500, "Failed to parse $ENV{GL_RC}: " . ($! or $@));
|
||||
$ENV{HOME} = $orig_home;
|
||||
# now get gitolite stuff in...
|
||||
use lib $ENV{GL_BINDIR};
|
||||
use gitolite_rc;
|
||||
use gitolite;
|
||||
|
||||
# set project root etc. absolute paths
|
||||
$ENV{GL_REPO_BASE_ABS} = ( $REPO_BASE =~ m(^/) ? $REPO_BASE : "$gl_home/$REPO_BASE" );
|
||||
$projects_list = $projectroot = $ENV{GL_REPO_BASE_ABS};
|
||||
|
||||
# load gitolite helper routines
|
||||
unshift @INC, "$GL_ADMINDIR/src";
|
||||
require gitolite
|
||||
or die_error(500, "Failed to parse gitolite.pm: " . ($! or $@));
|
||||
|
||||
$export_auth_hook = sub {
|
||||
my $repo = shift;
|
||||
# gitweb passes us the full repo path; so we strip the beginning
|
||||
|
|
|
@ -119,7 +119,7 @@ Finally, you can call gitolite to query ownership and permissions for the
|
|||
current user (which may not necessarily be the owner). This is done loosely
|
||||
as follows (don't use this exact code yet though):
|
||||
|
||||
perl -I$HOME/.gitolite/src -Mgitolite -e "cli_repo_rights('reponame')"
|
||||
perl -I$GL_BINDIR -Mgitolite -e "cli_repo_rights('reponame')"
|
||||
|
||||
which will print two space-separated words, something like `_____R__W u1` or
|
||||
maybe `____@R_@W <gitolite>`. (The former is the response for a wildcard repo
|
||||
|
|
213
doc/developer-notes.mkd
Normal file
213
doc/developer-notes.mkd
Normal file
|
@ -0,0 +1,213 @@
|
|||
# developer/patch maintainer notes
|
||||
|
||||
In this document:
|
||||
|
||||
* <a href="#_current_development_version">current development version</a>
|
||||
* <a href="#_testing_status_of_gitolite_v2_0rc1">testing status of gitolite v2.0rc1</a>
|
||||
* <a href="#_migration_to_gitolite_v2_x">migration to gitolite v2.x</a>
|
||||
* <a href="#_general_stuff">general stuff</a>
|
||||
* <a href="#_the_rc_file">the rc file</a>
|
||||
* <a href="#_modules">modules</a>
|
||||
* <a href="#_that_bindir_thing">that 'bindir' thing</a>
|
||||
* <a href="#_from_perl">from perl</a>
|
||||
* <a href="#_from_shell">from shell</a>
|
||||
* <a href="#_OUTLIER_">OUTLIER!</a>
|
||||
* <a href="#_special_types_of_setups">special types of setups</a>
|
||||
* <a href="#_Fedora">Fedora</a>
|
||||
|
||||
----
|
||||
|
||||
<a name="_current_development_version"></a>
|
||||
|
||||
### current development version
|
||||
|
||||
The current gitolite development version is v2.0rc1. Unless there is a
|
||||
serious security problem, *or* one of my large users [i.e., anyone whose name
|
||||
is in doc/who-uses-it.mkd (grin!)] needs it, all future changes will now
|
||||
happen here.
|
||||
|
||||
The commit looks *huge*, but it's mostly just large chunks of code moving
|
||||
around; there's not a whole lot of new code. However, I do apologise if
|
||||
anyone has their local changes conflicted when merging or rebasing against
|
||||
this version, and I promise to help as much as I can.
|
||||
|
||||
<a name="_testing_status_of_gitolite_v2_0rc1"></a>
|
||||
|
||||
#### testing status of gitolite v2.0rc1
|
||||
|
||||
Pretty much all the major features have been properly tested using the test
|
||||
suite. The following exceptions exist:
|
||||
|
||||
* basic, manual, testing only
|
||||
* most admin defined commands
|
||||
* not yet tested
|
||||
* smart http
|
||||
* mirroring
|
||||
* mob branches
|
||||
* things which I have no easy way to test
|
||||
* controlling gitweb authentication using gitolite (as described [here][gw])
|
||||
* SVN passthru
|
||||
|
||||
<a name="_migration_to_gitolite_v2_x"></a>
|
||||
|
||||
### migration to gitolite v2.x
|
||||
|
||||
In general, the procedure for migrating described in the install document
|
||||
should suffice. Even the rc file hasn't really changed much from the latest
|
||||
versions in v1.x, except that if you add a new variable to it you must also
|
||||
add it to the @EXPORT list in `src/gitolite_rc.pm`.
|
||||
|
||||
<a name="_general_stuff"></a>
|
||||
|
||||
### general stuff
|
||||
|
||||
* all scripts and libraries must be in the same directory. However, RPM/DEB
|
||||
packagers can put the libraries where they want, as long as they can be
|
||||
found in perl's default `@INC`.
|
||||
|
||||
* gl-auth-command **requires** an actual `~/.gitolite.rc` (except if your
|
||||
initials are "JK" or "DG", in which case `/etc/gitolite/gitolite.rc` also
|
||||
works!) It knows how to look around and set env vars etc correctly
|
||||
|
||||
* all programs except gl-auth-command **require** the environment variables
|
||||
`GL_RC` and `GL_BINDIR` set properly. Your best bet is to run them *via*
|
||||
gl-auth-command, like so:
|
||||
|
||||
path/to/gl-auth-command -e other_program other_program_arguments
|
||||
|
||||
In any case none of these programs are meant to be run manually -- pretty
|
||||
much all of them are run via gl-auth-command or from something that was
|
||||
forked from it so the variables *will* exist during normal operation.
|
||||
|
||||
<a name="_the_rc_file"></a>
|
||||
|
||||
### the rc file
|
||||
|
||||
The 'rc' file has one major change from v1: any new values in the rc file need
|
||||
to be added to the @EXPORT list in `src/gitolite_rc.pm`.
|
||||
|
||||
<a name="_modules"></a>
|
||||
|
||||
### modules
|
||||
|
||||
There are 3 "modules" (`gitolite_rc`, `gitolite_env`, and `gitolite` itself).
|
||||
Their purposes should be fairly obvious.
|
||||
|
||||
<a name="_that_bindir_thing"></a>
|
||||
|
||||
### that 'bindir' thing
|
||||
|
||||
The importance of `GL_BINDIR` is that the command= argument in
|
||||
`~/.ssh/authorized_keys` must be a full path, ideally, and the compile script
|
||||
gets this from `GL_BINDIR`.
|
||||
|
||||
<a name="_from_perl"></a>
|
||||
|
||||
#### from perl
|
||||
|
||||
* for frequently run perl programs, I prefer my method
|
||||
|
||||
* gl-auth-command -- this is invoked with a full path
|
||||
* gl-time -- same as above
|
||||
|
||||
* "their" ideal is "FindBin". I will use it only on manually or
|
||||
infrequently run programs
|
||||
|
||||
* gl-setup-authkeys (external shim to compile keys separately from PTA)
|
||||
|
||||
<a name="_from_shell"></a>
|
||||
|
||||
#### from shell
|
||||
|
||||
* a perl program called gl-query-rc finds its own BINDIR (using my perl
|
||||
method, not FindBin). This is suitable for calling from shell scripts
|
||||
as `${0%/*}/gl-query-rc GL_BINDIR`
|
||||
|
||||
* gl-mirror-shell (frequent use)
|
||||
* gl-setup
|
||||
* gl-tool
|
||||
|
||||
<a name="_OUTLIER_"></a>
|
||||
|
||||
#### OUTLIER!
|
||||
|
||||
* gl-dont-panic is an outlier. For some silly reason I have the notion that
|
||||
even if it runs from /tmp it should get the right values, so it is the
|
||||
only one that interrogates `~/.ssh/authorized_keys` to get the actual
|
||||
BINDIR in use!
|
||||
|
||||
<a name="_special_types_of_setups"></a>
|
||||
|
||||
### special types of setups
|
||||
|
||||
<a name="_Fedora"></a>
|
||||
|
||||
#### Fedora
|
||||
|
||||
Fedora has a very special setup, as follows:
|
||||
|
||||
* each user has his own userid and login
|
||||
* his/her ~/.ssh/authkeys file (containing only his/her key) has a
|
||||
"command=" clause invoking gl-auth-command
|
||||
* trusted users have "gl-auth-command -s" meaning they can get a shell if
|
||||
they want to
|
||||
|
||||
* actual git repos are under "git" (or some such), and include the chmod g+s
|
||||
(git init --shared) unix perms tricks for shared access
|
||||
|
||||
* but since they're coming through gl-auth, branch-level acls are in effect
|
||||
|
||||
* the gitolite config file is generated from some database and compiled (all
|
||||
via cron)
|
||||
|
||||
* the keydir/ is empty; in fact they probably don't use the admin repo at
|
||||
all, AFAIK
|
||||
|
||||
The most important implication of this setup is that **the RC file is no
|
||||
longer is `$HOME` of the 'git' user**. They keep it in
|
||||
`/etc/gitolite/gitolite.rc`. This means that a properly setup rc file must
|
||||
already be present in `/etc/gitolite/gitolite.rc` before doing any such
|
||||
installs.
|
||||
|
||||
----
|
||||
|
||||
# **Why v2?**
|
||||
|
||||
I went onto `#perl` to ask some question about setpriority() and got yelled at
|
||||
for writing "horrible code". And that was one of the kinder comments; my
|
||||
rather fragile ego is trying to forget the rest ;-)
|
||||
|
||||
They also gave me a link to a PDF book, "Modern Perl" by 'chromatic'. Nice
|
||||
book; one of the first things you learn from it is that you should not go to
|
||||
`#perl` for general help.
|
||||
|
||||
Anyway, the summary of the collective angst of `#perl` (well 2 people anyway)
|
||||
was: use Getopt::Long, FindBin, 'use lib', a library for HTTP stuff, stop
|
||||
prefixing subs with '&', and get rid of the huge number of 'our' declarations.
|
||||
|
||||
That last item is the only one I totally agree with, because it was on my long
|
||||
term todo list anyway. And 'use lib' sorta goes with it, so that's fine too.
|
||||
And as soon as I found that vim colors the sub names differently if you take
|
||||
out the '&' I decided I'd do that too :-) [But honestly, if `&sub` is so bad
|
||||
shouldn't "man perlsub" at least say something negative about it, other than
|
||||
"disables prototype checking", which doesn't matter here since I'm not using
|
||||
prototypes?]
|
||||
|
||||
As for the rest, FindBin brings in a good 1000+ lines for something that I do
|
||||
in a line or two (since I don't care about all the pathological edge cases).
|
||||
Getopt::Long is 2649 lines to replace the code below [note that there *is*
|
||||
only one possible option to this command, and it is *never* run manually
|
||||
either, so I don't need any fancy features]:
|
||||
|
||||
my $shell_allowed = 0;
|
||||
if (@ARGV and $ARGV[0] eq '-s') {
|
||||
$shell_allowed = 1;
|
||||
shift;
|
||||
}
|
||||
|
||||
Apparently TMTOWTDI has given way to TOOWTDI.
|
||||
|
||||
Anyway, I spent a few hours refactoring it. And I do thank them for pushing
|
||||
me to stop being lazy on the "our" business.
|
||||
|
||||
[gw]: https://github.com/sitaramc/gitolite/blob/pu/doc/3-faq-tips-etc.mkd#_easier_to_link_gitweb_authorisation_with_gitolite
|
|
@ -61,7 +61,7 @@ things happen if you change them.
|
|||
|
||||
<a name="_variables_with_an_efficiency_impact"></a>
|
||||
|
||||
### variables with an efficiency impact
|
||||
### variables with an efficiency/performance impact
|
||||
|
||||
* `$GL_BIG_CONFIG`, boolean, default 0
|
||||
|
||||
|
@ -79,6 +79,12 @@ things happen if you change them.
|
|||
blocks repo config settings. Please read [doc/big-config.mkd][bc] for
|
||||
more details.
|
||||
|
||||
* `$GL_NICE_VALUE`, boolean, default undef
|
||||
|
||||
The nice value to run under. Applicable only if it is greater than 0.
|
||||
Please do NOT set it if your bits/resource.h does not define PRIO_PROCESS
|
||||
is 0. For Linux this is true...
|
||||
|
||||
<a name="_variables_with_a_security_impact"></a>
|
||||
|
||||
### variables with a security impact
|
||||
|
|
|
@ -113,17 +113,21 @@ bar.pub and baz.pub, etc.
|
|||
|
||||
#### setup the mirror-shell on each server
|
||||
|
||||
XXX review this document after testing mirroring...
|
||||
|
||||
If you installed gitolite using the from client method, run the following:
|
||||
|
||||
# on foo
|
||||
export GL_ADMINDIR=` cd $HOME;perl -e 'do ".gitolite.rc"; print $GL_ADMINDIR'`
|
||||
export GL_BINDIR=$HOME/.gitolite/src
|
||||
cat bar.pub baz.pub |
|
||||
sed -e 's,^,command="'$GL_ADMINDIR'/src/gl-mirror-shell" ,' >> ~/.ssh/authorized_keys
|
||||
sed -e 's,^,command="'$GL_BINDIR'/gl-mirror-shell" ,' >> ~/.ssh/authorized_keys
|
||||
|
||||
If you installed using any of the other 3 methods do this:
|
||||
|
||||
# on foo
|
||||
export GL_BINDIR=`gl-query-rc GL_BINDIR`
|
||||
cat bar.pub baz.pub |
|
||||
sed -e 's,^,command="'$(which gl-mirror-shell)'" ,' >> ~/.ssh/authorized_keys
|
||||
sed -e 's,^,command="'$GL_BINDIR'/gl-mirror-shell" ,' >> ~/.ssh/authorized_keys
|
||||
|
||||
Also do the same thing on the other machines.
|
||||
|
||||
|
|
|
@ -36,7 +36,9 @@ clone's `hooks/common` directory, containing the following code:
|
|||
|
||||
#!/bin/bash
|
||||
|
||||
GL_ADMINDIR=` cd;perl -e 'do ".gitolite.rc"; print $GL_ADMINDIR'`
|
||||
[ -z "$GL_RC" ] && { echo "ENV GL_RC not set"; exit 1; }
|
||||
|
||||
GL_ADMINDIR=`$GL_BINDIR/gl-query-rc GL_ADMINDIR`
|
||||
|
||||
cp $GL_ADMINDIR/local/gitolite.rc $HOME/.gitolite.rc
|
||||
cp -a $GL_ADMINDIR/local/hooks/* $GL_ADMINDIR/hooks/common
|
||||
|
|
|
@ -6,50 +6,32 @@ use warnings;
|
|||
# === update ===
|
||||
# this is gitolite's update hook
|
||||
|
||||
# part of the gitolite (GL) suite
|
||||
|
||||
# how run: via git, being copied as .git/hooks/update in every repo
|
||||
# when: every push
|
||||
# input:
|
||||
# - see man githooks for STDIN
|
||||
# - uses the compiled config file to get permissions info
|
||||
# output: based on permissions etc., exit 0 or 1
|
||||
# security:
|
||||
# - none
|
||||
|
||||
# robustness:
|
||||
|
||||
# other notes:
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# common definitions
|
||||
# find the rc file, then pull the libraries
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
our ($GL_CONF_COMPILED, $UPDATE_CHAINS_TO, $GL_PERFLOGT);
|
||||
our %repos;
|
||||
BEGIN {
|
||||
die "ENV GL_RC not set\n" unless $ENV{GL_RC};
|
||||
die "ENV GL_BINDIR not set\n" unless $ENV{GL_BINDIR};
|
||||
}
|
||||
|
||||
# people with shell access should be allowed to bypass the update hook, simply
|
||||
# by setting an env var that the ssh "front door" will never set
|
||||
exit 0 if exists $ENV{GL_BYPASS_UPDATE_HOOK};
|
||||
|
||||
# we should already have the GL_RC env var set when we enter this hook
|
||||
die "parse $ENV{GL_RC} failed: " . ($! or $@) unless do $ENV{GL_RC};
|
||||
|
||||
unshift @INC, $ENV{GL_BINDIR};
|
||||
require gitolite or die "parse gitolite.pm failed\n";
|
||||
|
||||
my ($perm, $creator, $wild) = &repo_rights($ENV{GL_REPO});
|
||||
my $reported_repo = $ENV{GL_REPO} . ( $ENV{GL_REPOPATT} ? " ($ENV{GL_REPOPATT})" : "" );
|
||||
use lib $ENV{GL_BINDIR};
|
||||
use gitolite_rc;
|
||||
use gitolite qw(:DEFAULT %repos);
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# start...
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
my @saved_ARGV = @ARGV; # for chaining to another update hook at the end
|
||||
# people with shell access should be allowed to bypass the update hook, simply
|
||||
# by setting an env var that the ssh "front door" will never set
|
||||
exit 0 if exists $ENV{GL_BYPASS_UPDATE_HOOK};
|
||||
|
||||
my $ref = shift;
|
||||
my $oldsha = shift;
|
||||
my $newsha = shift;
|
||||
my ($perm, $creator, $wild) = repo_rights($ENV{GL_REPO});
|
||||
my $reported_repo = $ENV{GL_REPO} . ( $wild ? " ($wild)" : "" );
|
||||
|
||||
# arguments are as supplied to an update hook by git; man githooks
|
||||
my ($ref, $oldsha, $newsha) = @ARGV;
|
||||
my $merge_base = '0' x 40;
|
||||
# compute a merge-base if both SHAs are non-0, else leave it as '0'x40
|
||||
# (i.e., for branch create or delete, merge_base == '0'x40)
|
||||
|
@ -97,21 +79,21 @@ if (exists $repos{$ENV{GL_REPO}}{NAME_LIMITS}) {
|
|||
push @refs, map { chomp; s/^/NAME\//; $_; } `git diff --name-only $oldtree $newtree`;
|
||||
}
|
||||
|
||||
# and in this version, we have many "refs" to check. The one we print in the
|
||||
# log is the *first* one (which is a *real* ref, like refs/heads/master),
|
||||
# while all the rest (if they exist) are like NAME/something. So we do the
|
||||
# first one separately to capture it, then run the rest (if any)
|
||||
# we potentially have many "refs" to check. The one we print in the log is
|
||||
# the *first* one (which is a *real* ref, like refs/heads/master), while all
|
||||
# the rest (if they exist) are like NAME/something. So we do the first one
|
||||
# separately to capture it, then run the rest (if any)
|
||||
my $log_refex = check_ref(\@allowed_refs, $ENV{GL_REPO}, (shift @refs), $att_acc);
|
||||
&check_ref (\@allowed_refs, $ENV{GL_REPO}, $_ , $att_acc) for @refs;
|
||||
check_ref (\@allowed_refs, $ENV{GL_REPO}, $_ , $att_acc) for @refs;
|
||||
|
||||
# if we returned at all, all the checks succeeded, so we log the action and exit 0
|
||||
|
||||
&log_it("", "$att_acc\t" . substr($oldsha, 0, 14) . "\t" . substr($newsha, 0, 14) .
|
||||
log_it("", "$att_acc\t" . substr($oldsha, 0, 14) . "\t" . substr($newsha, 0, 14) .
|
||||
"\t$reported_repo\t$ref\t$log_refex");
|
||||
|
||||
# now chain to the local admin defined update hook, if present
|
||||
$UPDATE_CHAINS_TO ||= 'hooks/update.secondary';
|
||||
exec $UPDATE_CHAINS_TO, @saved_ARGV
|
||||
exec $UPDATE_CHAINS_TO, @ARGV
|
||||
if -f $UPDATE_CHAINS_TO or -l $UPDATE_CHAINS_TO;
|
||||
|
||||
exit 0;
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
#!/bin/sh
|
||||
|
||||
[ -z "$GL_RC" ] && die "ENV GL_RC not set"
|
||||
[ -z "$GL_BINDIR" ] && die "ENV GL_BINDIR not set"
|
||||
[ -z "$GL_ADMINDIR" ] && die "ENV GL_ADMINDIR not set"
|
||||
|
||||
# ensure that the admin is not sneaking in src/ and hooks/ :)
|
||||
GIT_WORK_TREE=$GL_ADMINDIR git ls-tree --name-only master |
|
||||
perl -lne 'exit 1 if /^(src|hooks)$/' || {
|
||||
|
@ -19,7 +23,7 @@ $GL_BINDIR/gl-compile-conf
|
|||
|
||||
cd $od
|
||||
|
||||
ADMIN_POST_UPDATE_CHAINS_TO=` cd $HOME;perl -e 'do ".gitolite.rc"; print $ADMIN_POST_UPDATE_CHAINS_TO'`
|
||||
ADMIN_POST_UPDATE_CHAINS_TO=`$GL_BINDIR/gl-query-rc ADMIN_POST_UPDATE_CHAINS_TO`
|
||||
[ -n "$ADMIN_POST_UPDATE_CHAINS_TO" ] || ADMIN_POST_UPDATE_CHAINS_TO=hooks/post-update.secondary
|
||||
|
||||
if [ -f $ADMIN_POST_UPDATE_CHAINS_TO ] || [ -L $ADMIN_POST_UPDATE_CHAINS_TO ]
|
||||
|
|
760
src/gitolite.pm
760
src/gitolite.pm
|
@ -1,56 +1,71 @@
|
|||
# lots of common routines
|
||||
|
||||
package gitolite;
|
||||
use Exporter 'import';
|
||||
@EXPORT = qw(
|
||||
can_read
|
||||
check_access
|
||||
check_ref
|
||||
check_repo_write_enabled
|
||||
cli_repo_rights
|
||||
dbg
|
||||
list_phy_repos
|
||||
ln_sf
|
||||
log_it
|
||||
new_repo
|
||||
new_wild_repo
|
||||
repo_rights
|
||||
run_custom_command
|
||||
setup_authkeys
|
||||
setup_daemon_access
|
||||
setup_git_configs
|
||||
setup_gitweb_access
|
||||
shell_out
|
||||
special_cmd
|
||||
try_adc
|
||||
wrap_chdir
|
||||
wrap_open
|
||||
wrap_print
|
||||
);
|
||||
@EXPORT_OK = qw(
|
||||
%repos
|
||||
%groups
|
||||
%git_configs
|
||||
%split_conf
|
||||
);
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Data::Dumper;
|
||||
$Data::Dumper::Deepcopy = 1;
|
||||
$|++;
|
||||
|
||||
# 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 ;-)
|
||||
|
||||
# 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
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# common definitions
|
||||
# find the rc file, then pull the libraries
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
our $ABRT = "\n\t\t***** ABORTING *****\n ";
|
||||
our $WARN = "\n\t\t***** WARNING *****\n ";
|
||||
BEGIN {
|
||||
die "ENV GL_RC not set\n" unless $ENV{GL_RC};
|
||||
die "ENV GL_BINDIR not set\n" unless $ENV{GL_BINDIR};
|
||||
}
|
||||
|
||||
# commands we're expecting
|
||||
our $R_COMMANDS=qr/^(git[ -]upload-pack|git[ -]upload-archive)$/;
|
||||
our $W_COMMANDS=qr/^git[ -]receive-pack$/;
|
||||
use lib $ENV{GL_BINDIR};
|
||||
use gitolite_rc;
|
||||
|
||||
# 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 "CREATOR" in the name (see docs)
|
||||
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
|
||||
# same as REPONAME, but used for wildcard repos, allows some common regex metas
|
||||
our $REPOPATT_PATT=qr(^\@?[0-9a-zA-Z[][\\^.$|()[\]*+?{}0-9a-zA-Z._\@/-]*$);
|
||||
# ADC commands and arguments must match this pattern
|
||||
our $ADC_CMD_ARGS_PATT=qr(^[0-9a-zA-Z._\@/+:-]*$);
|
||||
# ----------------------------------------------------------------------------
|
||||
# the big data structures we care about
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# these come from the RC file
|
||||
our ($REPO_UMASK, $GL_WILDREPOS, $GL_PACKAGE_CONF, $GL_PACKAGE_HOOKS, $REPO_BASE, $GL_CONF_COMPILED, $GL_BIG_CONFIG, $GL_PERFLOGT, $PROJECTS_LIST, $GL_ALL_INCLUDES_SPECIAL, $GL_SITE_INFO, $GL_GET_MEMBERSHIPS_PGM, $GL_WILDREPOS_PERM_CATS);
|
||||
our %repos;
|
||||
our %groups;
|
||||
our %git_configs;
|
||||
our %split_conf;;
|
||||
our %split_conf;
|
||||
our $data_version;
|
||||
our $current_data_version = '1.7';
|
||||
|
||||
# the following are read in from individual repo's gl-conf files, if present
|
||||
our %one_repo;
|
||||
our %one_git_config;
|
||||
our %one_repo; # corresponds to what goes into %repos
|
||||
our %one_git_config; # ditto for %git_configs
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# convenience subs
|
||||
|
@ -94,45 +109,12 @@ sub add_del_line {
|
|||
}
|
||||
|
||||
sub dbg {
|
||||
use Data::Dumper;
|
||||
for my $i (@_) {
|
||||
print STDERR "DBG: $i\n";
|
||||
print STDERR "DBG: " . Dumper($i);
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
# this sub has a wee little side-effect; it sets $ENV{GL_TS}
|
||||
my($template) = shift;
|
||||
|
||||
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
|
||||
$template =~ s/%y/$y/g;
|
||||
$template =~ s/%m/$m/g;
|
||||
$template =~ s/%d/$d/g;
|
||||
return ($template);
|
||||
}
|
||||
|
||||
sub log_it {
|
||||
my ($ip, $logmsg);
|
||||
open my $log_fh, ">>", $ENV{GL_LOG} or die "open log failed: $!\n";
|
||||
|
@ -147,33 +129,6 @@ sub log_it {
|
|||
close $log_fh or die "close log failed: $!\n";
|
||||
}
|
||||
|
||||
# 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 unless a non-false 5th argument is present
|
||||
|
||||
my ($allowed_refs, $repo, $ref, $perm, $dry_run) = @_;
|
||||
my @allowed_refs = sort { $a->[0] <=> $b->[0] } @{$allowed_refs};
|
||||
for my $ar (@allowed_refs) {
|
||||
my $refex = $ar->[1];
|
||||
# refex? sure -- a regex to match a ref against :)
|
||||
next unless $ref =~ /^$refex/;
|
||||
return "DENIED by $refex" if $ar->[2] eq '-' and $dry_run;
|
||||
die "$perm $ref $ENV{GL_USER} DENIED by $refex\n" if $ar->[2] eq '-';
|
||||
|
||||
# as far as *this* ref is concerned we're ok
|
||||
return $refex if ($ar->[2] =~ /\Q$perm/);
|
||||
}
|
||||
return "DENIED by fallthru" if $dry_run;
|
||||
die "$perm $ref $repo $ENV{GL_USER} DENIED by fallthru\n";
|
||||
}
|
||||
|
||||
# ln -sf :-)
|
||||
sub ln_sf
|
||||
{
|
||||
|
@ -200,71 +155,35 @@ sub list_phy_repos
|
|||
return @phy_repos;
|
||||
}
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# birth and death registration ;-)
|
||||
# serious logic subs (as opposed to just "convenience" subs)
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# background
|
||||
# check one ref
|
||||
sub check_ref {
|
||||
|
||||
# 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 :-)
|
||||
# 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 C/D if used) being
|
||||
# attempted. If none of them match, the access is denied.
|
||||
|
||||
# but in smart http mode, running under "apache", you should actually use
|
||||
# $GITOLITE_HTTP_HOME instead of $HOME (in fact $HOME may not even be
|
||||
# defined). However, the dependency on $HOME is so pervasive that we'd best
|
||||
# just set it here and be done. We also set $ENV{GL_RC} to point to the rc
|
||||
# file
|
||||
# NOTE: the function DIES when access is denied, unless arg 5 is true
|
||||
|
||||
# every gitolite program ends up calling this anyway, so that's birth
|
||||
my ($allowed_refs, $repo, $ref, $perm, $dry_run) = @_;
|
||||
my @allowed_refs = sort { $a->[0] <=> $b->[0] } @{$allowed_refs};
|
||||
for my $ar (@allowed_refs) {
|
||||
my $refex = $ar->[1];
|
||||
# refex? sure -- a regex to match a ref against :)
|
||||
next unless $ref =~ /^$refex/;
|
||||
return "DENIED by $refex" if $ar->[2] eq '-' and $dry_run;
|
||||
die "$perm $ref $ENV{GL_USER} DENIED by $refex\n" if $ar->[2] eq '-';
|
||||
|
||||
# the second thing we need to do is handle death a little better. A plain
|
||||
# "die" was fine for ssh but http has all that extra gunk it needs. So we
|
||||
# need to, in effect, create a "death handler".
|
||||
|
||||
# the name of the sub, however, is a holdover from when that was the sole
|
||||
# purpose. I suck at function names anyway...
|
||||
|
||||
sub where_is_rc
|
||||
{
|
||||
die "I need either HOME or GITOLITE_HTTP_HOME env vars set\n" unless $ENV{GITOLITE_HTTP_HOME} or $ENV{HOME};
|
||||
if ($ENV{GITOLITE_HTTP_HOME}) {
|
||||
# smart http mode; GITOLITE_HTTP_HOME becomes our HOME
|
||||
$ENV{HOME} = $ENV{GITOLITE_HTTP_HOME};
|
||||
|
||||
$SIG{__DIE__} = sub {
|
||||
my $service = ($ENV{SSH_ORIGINAL_COMMAND} =~ /git-receive-pack/ ? 'git-receive-pack' : 'git-upload-pack');
|
||||
my $message = shift; chomp($message);
|
||||
print STDERR "$message\n";
|
||||
|
||||
# format the service response, then the message. With initial
|
||||
# help from Ilari and then a more detailed email from Shawn...
|
||||
$service = "# service=$service\n"; $message = "ERR $message\n";
|
||||
$service = sprintf("%04X", length($service)+4) . "$service"; # no CRLF on this one
|
||||
$message = sprintf("%04X", length($message)+4) . "$message";
|
||||
|
||||
&print_http_headers();
|
||||
print $service;
|
||||
print "0000"; # flush-pkt, apparently
|
||||
print $message;
|
||||
print STDERR $service;
|
||||
print STDERR $message;
|
||||
exit 0; # if it's ok for die_webcgi in git.git/http-backend.c, it's ok for me ;-)
|
||||
}
|
||||
}
|
||||
|
||||
return if $ENV{GL_RC};
|
||||
|
||||
# Fedora doesn't actually have a "hosting user" at all (yeah -- bet you
|
||||
# didn't know gitolite was *that* flexible!), so there's no fixed $HOME,
|
||||
# and they prefer to keep their RC file in /etc/gitolite.
|
||||
for my $glrc ( $ENV{HOME} . "/.gitolite.rc", "/etc/gitolite/gitolite.rc" ) {
|
||||
if (-f $glrc) {
|
||||
$ENV{GL_RC} = $glrc;
|
||||
last;
|
||||
}
|
||||
# as far as *this* ref is concerned we're ok
|
||||
return $refex if ($ar->[2] =~ /\Q$perm/);
|
||||
}
|
||||
return "DENIED by fallthru" if $dry_run;
|
||||
die "$perm $ref $repo $ENV{GL_USER} DENIED by fallthru\n";
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
@ -302,8 +221,21 @@ sub new_repo
|
|||
system("env GL_REPO='$repo' hooks/gl-post-init") if -x "hooks/gl-post-init";
|
||||
}
|
||||
|
||||
sub new_wild_repo {
|
||||
my ($repo, $user) = @_;
|
||||
|
||||
wrap_chdir("$ENV{GL_REPO_BASE_ABS}");
|
||||
new_repo($repo, "$GL_ADMINDIR/hooks/common", $user);
|
||||
# note pwd is now the bare "repo.git"; new_repo does that...
|
||||
wrap_print("gl-perms", "$GL_WILDREPOS_DEFPERMS\n") if $GL_WILDREPOS_DEFPERMS;
|
||||
setup_git_configs($repo, \%git_configs);
|
||||
setup_daemon_access($repo);
|
||||
add_del_line ("$repo.git", $PROJECTS_LIST, setup_gitweb_access($repo, '', ''));
|
||||
wrap_chdir($ENV{HOME});
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# metaphysics (like, "is there a god?", "who created me?", etc)
|
||||
# wild_repo_rights
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
{
|
||||
|
@ -393,7 +325,7 @@ sub get_set_perms
|
|||
my($repo, $verb, $user) = @_;
|
||||
# set default categories
|
||||
$GL_WILDREPOS_PERM_CATS ||= "READERS WRITERS";
|
||||
my ($creator, $dummy, $dummy2) = &wild_repo_rights($repo, "");
|
||||
my ($creator, $dummy, $dummy2) = wild_repo_rights($repo, "");
|
||||
die "$repo doesnt exist or is not yours\n" unless $user eq $creator;
|
||||
wrap_chdir("$ENV{GL_REPO_BASE_ABS}");
|
||||
wrap_chdir("$repo.git");
|
||||
|
@ -419,7 +351,7 @@ sub get_set_perms
|
|||
# gitweb and daemon
|
||||
setup_daemon_access($repo);
|
||||
# add or delete line (arg1) from file (arg2) depending on arg3
|
||||
&add_del_line ("$repo.git", $PROJECTS_LIST, &setup_gitweb_access($repo, '', ''));
|
||||
add_del_line ("$repo.git", $PROJECTS_LIST, setup_gitweb_access($repo, '', ''));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -430,7 +362,7 @@ sub get_set_perms
|
|||
sub get_set_desc
|
||||
{
|
||||
my($repo, $verb, $user) = @_;
|
||||
my ($creator, $dummy, $dummy2) = &wild_repo_rights($repo, "");
|
||||
my ($creator, $dummy, $dummy2) = wild_repo_rights($repo, "");
|
||||
die "$repo doesnt exist or is not yours\n" unless $user eq $creator;
|
||||
wrap_chdir("$ENV{GL_REPO_BASE_ABS}");
|
||||
wrap_chdir("$repo.git");
|
||||
|
@ -475,7 +407,7 @@ sub setup_daemon_access
|
|||
{
|
||||
my $repo = shift;
|
||||
|
||||
if (&can_read($repo, 'daemon')) {
|
||||
if (can_read($repo, 'daemon')) {
|
||||
system("touch $export_ok");
|
||||
} else {
|
||||
unlink($export_ok);
|
||||
|
@ -517,10 +449,111 @@ sub setup_gitweb_access
|
|||
system("git config --remove-section gitweb 2>/dev/null");
|
||||
}
|
||||
|
||||
return ($desc or &can_read($repo, 'gitweb'));
|
||||
return ($desc or can_read($repo, 'gitweb'));
|
||||
# this return value is used by the caller to write to projects.list
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# print a report of $user's basic permissions
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
sub report_version {
|
||||
my($user) = @_;
|
||||
print "hello $user, the gitolite version here is ";
|
||||
system("cat", ($GL_PACKAGE_CONF || "$GL_ADMINDIR/conf") . "/VERSION");
|
||||
}
|
||||
|
||||
sub perm_code {
|
||||
# print the permission code
|
||||
my($all, $super, $user, $x) = @_;
|
||||
return " " unless $all or $super or $user;
|
||||
return " $x " unless $all or $super; # only $user (explicit access) was given
|
||||
my $ret;
|
||||
$ret = " \@$x" if $all; # prefix @ if repo allows access for @all users
|
||||
$ret = " \#$x" if $super; # prefix # if user has access to @all repos (sort of like a super user)
|
||||
$ret = " \&$x" if $all and $super; # prefix & if both the above
|
||||
$ret .= ($user ? " " : "_" ); # suffix _ if no explicit access else <space>
|
||||
return $ret;
|
||||
}
|
||||
|
||||
# basic means wildcards will be shown as wildcards; this is pretty much what
|
||||
# got parsed by the compile script
|
||||
sub report_basic
|
||||
{
|
||||
my($repo, $user) = @_;
|
||||
|
||||
# XXX The correct way is actually to give parse_acl another argument
|
||||
# (defaulting to $ENV{GL_USER}, the value being used now). But for now
|
||||
# this will do, even though it's a bit of a kludge to get the basic access
|
||||
# rights for some other user this way
|
||||
local $ENV{GL_USER} = $user;
|
||||
|
||||
parse_acl("", "CREATOR");
|
||||
# all we need is for 'keys %repos' to come up with all the names, so:
|
||||
@repos{ keys %split_conf } = values %split_conf if %split_conf;
|
||||
|
||||
# send back some useful info if no command was given
|
||||
report_version($user);
|
||||
print "\rthe gitolite config gives you the following access:\r\n";
|
||||
my $count = 0;
|
||||
for my $r (sort keys %repos) {
|
||||
next unless $r =~ /$repo/i;
|
||||
# if $GL_BIG_CONFIG is on, limit the number of output lines to 20
|
||||
next if $GL_BIG_CONFIG and $count++ >= 20;
|
||||
if ($r =~ $REPONAME_PATT and $r !~ /\bCREAT[EO]R\b/) {
|
||||
parse_acl($r, "NOBODY");
|
||||
} else {
|
||||
$r =~ s/\bCREAT[EO]R\b/$user/g;
|
||||
parse_acl($r, $ENV{GL_USER});
|
||||
}
|
||||
# @all repos; meaning of read/write flags:
|
||||
# @R => @all users are allowed access to this repo
|
||||
# #R => you're a super user and can see @all repos
|
||||
# R => normal access
|
||||
my $perm .= ( $repos{$r}{C}{'@all'} ? ' @C' : ( $repos{$r}{C}{$user} ? ' C' : ' ' ) );
|
||||
$perm .= perm_code( $repos{$r}{R}{'@all'}, $repos{'@all'}{R}{$user}, $repos{$r}{R}{$user}, 'R');
|
||||
$perm .= perm_code( $repos{$r}{W}{'@all'}, $repos{'@all'}{W}{$user}, $repos{$r}{W}{$user}, 'W');
|
||||
print "$perm\t$r\r\n" if $perm =~ /\S/;
|
||||
}
|
||||
print "only 20 out of $count candidate repos examined\r\nplease use a partial reponame or regex pattern to limit output\r\n" if $GL_BIG_CONFIG and $count > 20;
|
||||
print "$GL_SITE_INFO\n" if $GL_SITE_INFO;
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# print a report of $user's expanded permissions
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
sub expand_wild
|
||||
{
|
||||
my($repo, $user) = @_;
|
||||
|
||||
report_version($user);
|
||||
print "\ryou have access to the following repos on the server:\r\n";
|
||||
# this is for convenience; he can copy-paste the output of the basic
|
||||
# access report instead of having to manually change CREATOR to his name
|
||||
$repo =~ s/\bCREAT[EO]R\b/$user/g;
|
||||
|
||||
# display matching repos (from *all* the repos in the system) that $user
|
||||
# has at least "R" access to
|
||||
|
||||
chdir("$ENV{GL_REPO_BASE_ABS}") or die "chdir $ENV{GL_REPO_BASE_ABS} failed: $!\n";
|
||||
my $count = 0;
|
||||
for my $actual_repo (`find . -type d -name "*.git"|sort`) {
|
||||
chomp ($actual_repo);
|
||||
$actual_repo =~ s/^\.\///;
|
||||
$actual_repo =~ s/\.git$//;
|
||||
# actual_repo has to match the pattern being expanded
|
||||
next unless $actual_repo =~ /$repo/i;
|
||||
next if $GL_BIG_CONFIG and $count++ >= 20;
|
||||
|
||||
my($perm, $creator, $wild) = repo_rights($actual_repo);
|
||||
next unless $perm =~ /\S/;
|
||||
print "$perm\t$creator\t$actual_repo\n";
|
||||
}
|
||||
print "only 20 out of $count candidate repos examined\nplease use a partial reponame or regex pattern to limit output\n" if $GL_BIG_CONFIG and $count > 20;
|
||||
print "$GL_SITE_INFO\n" if $GL_SITE_INFO;
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# parse the compiled acl
|
||||
# ----------------------------------------------------------------------------
|
||||
|
@ -530,8 +563,8 @@ sub parse_acl
|
|||
# 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, %perm_cats) = @_;
|
||||
my $perm_cats_sig = '';
|
||||
my ($repo, $c, %perm_cats) = @_;
|
||||
my $perm_cats_sig = ''; # a "signature" of the perm_cats hash
|
||||
map { $perm_cats_sig .= "$_.$perm_cats{$_}," } sort keys %perm_cats;
|
||||
$c = "NOBODY" unless $GL_WILDREPOS;
|
||||
|
||||
|
@ -572,8 +605,8 @@ sub parse_acl
|
|||
|
||||
my ($wild, @repo_plus, @user_plus);
|
||||
# expand $repo and $gl_user into all possible matching values
|
||||
($wild, @repo_plus) = &get_memberships($repo, 1);
|
||||
( @user_plus) = &get_memberships($gl_user, 0);
|
||||
($wild, @repo_plus) = get_memberships($repo, 1);
|
||||
( @user_plus) = get_memberships($gl_user, 0);
|
||||
|
||||
# the old "convenience copy" thing. Now on steroids :)
|
||||
|
||||
|
@ -598,8 +631,6 @@ sub parse_acl
|
|||
}
|
||||
}
|
||||
|
||||
$ENV{GL_REPOPATT} = "";
|
||||
$ENV{GL_REPOPATT} = $wild if $wild and $GL_WILDREPOS;
|
||||
return ($wild);
|
||||
}
|
||||
|
||||
|
@ -613,108 +644,10 @@ sub add_repo_conf
|
|||
$git_configs{$repo} = $one_git_config{$repo};
|
||||
}
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# print a report of $user's basic permissions
|
||||
# repo_rights
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
sub report_version {
|
||||
my($GL_ADMINDIR, $user) = @_;
|
||||
print "hello $user, the gitolite version here is ";
|
||||
system("cat", ($GL_PACKAGE_CONF || "$GL_ADMINDIR/conf") . "/VERSION");
|
||||
}
|
||||
|
||||
sub perm_code {
|
||||
# print the permission code
|
||||
my($all, $super, $user, $x) = @_;
|
||||
return " " unless $all or $super or $user;
|
||||
return " $x " unless $all or $super; # only $user (explicit access) was given
|
||||
my $ret;
|
||||
$ret = " \@$x" if $all; # prefix @ if repo allows access for @all users
|
||||
$ret = " \#$x" if $super; # prefix # if user has access to @all repos (sort of like a super user)
|
||||
$ret = " \&$x" if $all and $super; # prefix & if both the above
|
||||
$ret .= ($user ? " " : "_" ); # suffix _ if no explicit access else <space>
|
||||
return $ret;
|
||||
}
|
||||
|
||||
# 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, $repo, $user) = @_;
|
||||
|
||||
# XXX The correct way is actually to give parse_acl another argument
|
||||
# (defaulting to $ENV{GL_USER}, the value being used now). But for now
|
||||
# this will do, even though it's a bit of a kludge to get the basic access
|
||||
# rights for some other user this way
|
||||
local $ENV{GL_USER} = $user;
|
||||
|
||||
&parse_acl($GL_CONF_COMPILED, "", "CREATOR");
|
||||
# all we need is for 'keys %repos' to come up with all the names, so:
|
||||
@repos{ keys %split_conf } = values %split_conf if %split_conf;
|
||||
|
||||
# send back some useful info if no command was given
|
||||
&report_version($GL_ADMINDIR, $user);
|
||||
print "\rthe gitolite config gives you the following access:\r\n";
|
||||
my $count = 0;
|
||||
for my $r (sort keys %repos) {
|
||||
next unless $r =~ /$repo/i;
|
||||
# if $GL_BIG_CONFIG is on, limit the number of output lines to 20
|
||||
next if $GL_BIG_CONFIG and $count++ >= 20;
|
||||
if ($r =~ $REPONAME_PATT and $r !~ /\bCREAT[EO]R\b/) {
|
||||
&parse_acl($GL_CONF_COMPILED, $r, "NOBODY");
|
||||
} else {
|
||||
$r =~ s/\bCREAT[EO]R\b/$user/g;
|
||||
&parse_acl($GL_CONF_COMPILED, $r, $ENV{GL_USER});
|
||||
}
|
||||
# @all repos; meaning of read/write flags:
|
||||
# @R => @all users are allowed access to this repo
|
||||
# #R => you're a super user and can see @all repos
|
||||
# R => normal access
|
||||
my $perm .= ( $repos{$r}{C}{'@all'} ? ' @C' : ( $repos{$r}{C}{$user} ? ' C' : ' ' ) );
|
||||
$perm .= &perm_code( $repos{$r}{R}{'@all'}, $repos{'@all'}{R}{$user}, $repos{$r}{R}{$user}, 'R');
|
||||
$perm .= &perm_code( $repos{$r}{W}{'@all'}, $repos{'@all'}{W}{$user}, $repos{$r}{W}{$user}, 'W');
|
||||
print "$perm\t$r\r\n" if $perm =~ /\S/;
|
||||
}
|
||||
print "only 20 out of $count candidate repos examined\r\nplease use a partial reponame or regex pattern to limit output\r\n" if $GL_BIG_CONFIG and $count > 20;
|
||||
print "$GL_SITE_INFO\n" if $GL_SITE_INFO;
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# print a report of $user's basic permissions
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
sub expand_wild
|
||||
{
|
||||
my($GL_ADMINDIR, $GL_CONF_COMPILED, $repo, $user) = @_;
|
||||
|
||||
&report_version($GL_ADMINDIR, $user);
|
||||
print "\ryou have access to the following repos on the server:\r\n";
|
||||
# this is for convenience; he can copy-paste the output of the basic
|
||||
# access report instead of having to manually change CREATOR to his name
|
||||
$repo =~ s/\bCREAT[EO]R\b/$user/g;
|
||||
|
||||
# display matching repos (from *all* the repos in the system) that $user
|
||||
# has at least "R" access to
|
||||
|
||||
chdir("$ENV{GL_REPO_BASE_ABS}") or die "chdir $ENV{GL_REPO_BASE_ABS} failed: $!\n";
|
||||
my $count = 0;
|
||||
for my $actual_repo (`find . -type d -name "*.git"|sort`) {
|
||||
chomp ($actual_repo);
|
||||
$actual_repo =~ s/^\.\///;
|
||||
$actual_repo =~ s/\.git$//;
|
||||
# actual_repo has to match the pattern being expanded
|
||||
next unless $actual_repo =~ /$repo/i;
|
||||
next if $GL_BIG_CONFIG and $count++ >= 20;
|
||||
|
||||
my($perm, $creator, $wild) = &repo_rights($actual_repo);
|
||||
next unless $perm =~ /\S/;
|
||||
print "$perm\t$creator\t$actual_repo\n";
|
||||
}
|
||||
print "only 20 out of $count candidate repos examined\nplease use a partial reponame or regex pattern to limit output\n" if $GL_BIG_CONFIG and $count > 20;
|
||||
print "$GL_SITE_INFO\n" if $GL_SITE_INFO;
|
||||
}
|
||||
|
||||
# there will be multiple calls to repo_rights; better to use a closure. We
|
||||
# might even be called from outside (see the admin-defined-commands docs for
|
||||
# how/why). Regardless of how we're called, we assume $ENV{GL_USER} is
|
||||
|
@ -733,7 +666,7 @@ sub expand_wild
|
|||
|
||||
unless ($REPO_BASE) {
|
||||
# means we've been called from outside; see doc/admin-defined-commands.mkd
|
||||
&where_is_rc();
|
||||
where_is_rc();
|
||||
die "parse $ENV{GL_RC} failed: " . ($! or $@) unless do $ENV{GL_RC};
|
||||
}
|
||||
|
||||
|
@ -749,11 +682,11 @@ sub expand_wild
|
|||
# "wild_repo_rights" sub for nuances.
|
||||
my (%perm_cats);
|
||||
# these will be empty if it's not a wildcard repo anyway
|
||||
($creator, %perm_cats) = &wild_repo_rights($repo, $ENV{GL_USER});
|
||||
($creator, %perm_cats) = wild_repo_rights($repo, $ENV{GL_USER});
|
||||
# get access list with these substitutions
|
||||
$wild = &parse_acl($GL_CONF_COMPILED, $repo, $creator || "NOBODY", %perm_cats);
|
||||
$wild = parse_acl($repo, $creator || "NOBODY", %perm_cats);
|
||||
} else {
|
||||
$wild = &parse_acl($GL_CONF_COMPILED, $repo, $ENV{GL_USER});
|
||||
$wild = parse_acl($repo, $ENV{GL_USER});
|
||||
}
|
||||
|
||||
if ($exists) {
|
||||
|
@ -774,8 +707,8 @@ sub expand_wild
|
|||
delete $repos{$repo} if $perm !~ /C/ and $wild;
|
||||
$creator = "<notfound>";
|
||||
}
|
||||
$perm .= &perm_code( $repos{$repo}{R}{'@all'}, $repos{'@all'}{R}{$ENV{GL_USER}}, $repos{$repo}{R}{$ENV{GL_USER}}, 'R' );
|
||||
$perm .= &perm_code( $repos{$repo}{W}{'@all'}, $repos{'@all'}{W}{$ENV{GL_USER}}, $repos{$repo}{W}{$ENV{GL_USER}}, 'W' );
|
||||
$perm .= perm_code( $repos{$repo}{R}{'@all'}, $repos{'@all'}{R}{$ENV{GL_USER}}, $repos{$repo}{R}{$ENV{GL_USER}}, 'R' );
|
||||
$perm .= perm_code( $repos{$repo}{W}{'@all'}, $repos{'@all'}{W}{$ENV{GL_USER}}, $repos{$repo}{W}{$ENV{GL_USER}}, 'W' );
|
||||
|
||||
# set up for caching %repos
|
||||
$last_repo = $repo;
|
||||
|
@ -784,18 +717,22 @@ sub expand_wild
|
|||
}
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# helpers...
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# helper/convenience routine to get rights and ownership from a shell command
|
||||
sub cli_repo_rights {
|
||||
# check_access does a lot more, so just call it. Since it returns perms
|
||||
# and creator separately, just space-join them and print it.
|
||||
print join(" ", &check_access($_[0])), "\n";
|
||||
print join(" ", check_access($_[0])), "\n";
|
||||
}
|
||||
|
||||
sub can_read {
|
||||
my $repo = shift;
|
||||
my $user = shift || $ENV{GL_USER};
|
||||
local $ENV{GL_USER} = $user;
|
||||
my ($perm, $creator, $wild) = &repo_rights($repo);
|
||||
my ($perm, $creator, $wild) = repo_rights($repo);
|
||||
return ( ($GL_ALL_INCLUDES_SPECIAL || $user !~ /^(gitweb|daemon)$/)
|
||||
? $perm =~ /R/
|
||||
: $perm =~ /R /
|
||||
|
@ -812,6 +749,117 @@ sub check_repo_write_enabled {
|
|||
}
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# get memberships
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# given a plain reponame or username, return:
|
||||
# - the name itself if it's a user
|
||||
# - the name itself if it's a repo and the repo exists in the config
|
||||
# plus, if $GL_BIG_CONFIG is set:
|
||||
# - all the groups the name belongs to
|
||||
# plus, for repos:
|
||||
# - all the wildcards matching it
|
||||
# plus, if $GL_BIG_CONFIG is set:
|
||||
# - all the groups those wildcards belong to
|
||||
|
||||
# A name can normally appear (repo example) (user example)
|
||||
# - directly (repo foo) (RW = bob)
|
||||
# - (only for repos) as a direct wildcard (repo foo/.*)
|
||||
# but if $GL_BIG_CONFIG is set, it can also appear:
|
||||
# - indirectly (@g = foo; repo @g) (@ug = bob; RW = @ug))
|
||||
# - (only for repos) as an indirect wildcard (@g = foo/.*; repo @g).
|
||||
# note: the wildcard stuff does not apply to username memberships
|
||||
|
||||
our %extgroups_cache;
|
||||
sub get_memberships {
|
||||
my $base = shift; # reponame or username
|
||||
my $is_repo = shift; # some true value means a repo name has been passed
|
||||
|
||||
my $wild = ''; # will be a space-sep list of matching patterns
|
||||
my @ret; # list of matching groups/patterns
|
||||
|
||||
# direct
|
||||
push @ret, $base if not $is_repo or exists $repos{$base};
|
||||
if ($is_repo and $GL_WILDREPOS) {
|
||||
for my $i (sort keys %repos) {
|
||||
next if $i eq $base; # "direct" name already done; skip
|
||||
# direct wildcard
|
||||
if ($base =~ /^$i$/) {
|
||||
push @ret, $i;
|
||||
$wild = ($wild ? "$wild $i" : $i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($GL_BIG_CONFIG) {
|
||||
for my $g (sort keys %groups) {
|
||||
for my $i (sort keys %{ $groups{$g} }) {
|
||||
if ($base eq $i) {
|
||||
# indirect
|
||||
push @ret, $g;
|
||||
} elsif ($is_repo and $GL_WILDREPOS and $base =~ /^$i$/) {
|
||||
# indirect wildcard
|
||||
push @ret, $g;
|
||||
$wild = ($wild ? "$wild $i" : $i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# deal with returning user info first
|
||||
unless ($is_repo) {
|
||||
# bring in group membership info stored externally, by running
|
||||
# $GL_GET_MEMBERSHIPS_PGM if it is defined
|
||||
|
||||
if ($extgroups_cache{$base}) {
|
||||
push @ret, @{ $extgroups_cache{$base} };
|
||||
} elsif ($GL_GET_MEMBERSHIPS_PGM) {
|
||||
my @extgroups = map { s/^/@/; $_; } split ' ', `$GL_GET_MEMBERSHIPS_PGM $base`;
|
||||
$extgroups_cache{$base} = \@extgroups;
|
||||
push @ret, @extgroups;
|
||||
}
|
||||
|
||||
return (@ret);
|
||||
}
|
||||
|
||||
# note that there is an extra return value when called for repos (as
|
||||
# opposed to being called for usernames)
|
||||
return ($wild, @ret);
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# generic check access routine
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
sub check_access
|
||||
{
|
||||
my ($repo, $ref, $aa, $dry_run) = @_;
|
||||
# aa = attempted access
|
||||
|
||||
my ($perm, $creator, $wild) = repo_rights($repo);
|
||||
$perm =~ s/ /_/g;
|
||||
$creator =~ s/^\(|\)$//g;
|
||||
return ($perm, $creator) unless $ref;
|
||||
|
||||
# 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;
|
||||
# user+repo specific perms override everything else, so they come first.
|
||||
# Then perms given to specific user for @all repos, and finally perms
|
||||
# given to @all users for specific repo
|
||||
push @allowed_refs, @ { $repos{$repo}{$ENV{GL_USER}} || [] };
|
||||
push @allowed_refs, @ { $repos{'@all'}{$ENV{GL_USER}} || [] };
|
||||
push @allowed_refs, @ { $repos{$repo}{'@all'} || [] };
|
||||
|
||||
if ($dry_run) {
|
||||
return check_ref(\@allowed_refs, $repo, $ref, $aa, $dry_run);
|
||||
} else {
|
||||
check_ref(\@allowed_refs, $repo, $ref, $aa);
|
||||
}
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# setup the ~/.ssh/authorized_keys file
|
||||
# ----------------------------------------------------------------------------
|
||||
|
@ -820,16 +868,16 @@ sub setup_authkeys
|
|||
{
|
||||
# ARGUMENTS
|
||||
|
||||
my($bindir, $GL_KEYDIR, $user_list_p) = @_;
|
||||
my($GL_KEYDIR, $user_list_p) = @_;
|
||||
# calling from outside the normal compile script may mean that argument 2
|
||||
# may not be passed; so make sure it's a valid hashref, even if empty
|
||||
$user_list_p = {} unless $user_list_p;
|
||||
|
||||
# CONSTANTS
|
||||
# LOCAL CONSTANTS
|
||||
|
||||
# command and options for authorized_keys
|
||||
my $AUTH_COMMAND="$bindir/gl-auth-command";
|
||||
$AUTH_COMMAND="$bindir/gl-time $bindir/gl-auth-command" if $GL_PERFLOGT;
|
||||
my $AUTH_COMMAND="$ENV{GL_BINDIR}/gl-auth-command";
|
||||
$AUTH_COMMAND="$ENV{GL_BINDIR}/gl-time $ENV{GL_BINDIR}/gl-auth-command" if $GL_PERFLOGT;
|
||||
my $AUTH_OPTIONS="no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty";
|
||||
|
||||
# START
|
||||
|
@ -931,14 +979,14 @@ sub setup_authkeys
|
|||
|
||||
sub special_cmd
|
||||
{
|
||||
my ($GL_ADMINDIR, $GL_CONF_COMPILED, $shell_allowed, $RSYNC_BASE, $HTPASSWD_FILE, $SVNSERVE) = @_;
|
||||
my ($shell_allowed) = @_;
|
||||
|
||||
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);
|
||||
report_basic('^', $user);
|
||||
print "you also have shell access\r\n" if $shell_allowed;
|
||||
} elsif ($cmd =~ /^info\s+(.+)$/) {
|
||||
my @otherusers = split ' ', $1;
|
||||
|
@ -951,139 +999,69 @@ sub special_cmd
|
|||
# set up the list of users being queried; it's either a list passed in
|
||||
# (allowed only for admin pushers) or just $user
|
||||
if (@otherusers) {
|
||||
my($perm, $creator, $wild) = &repo_rights('gitolite-admin');
|
||||
my($perm, $creator, $wild) = repo_rights('gitolite-admin');
|
||||
die "you can't ask for others' permissions\n" unless $perm =~ /W/;
|
||||
}
|
||||
push @otherusers, $user unless @otherusers;
|
||||
|
||||
&parse_acl($GL_CONF_COMPILED);
|
||||
parse_acl();
|
||||
for my $otheruser (@otherusers) {
|
||||
warn("ignoring illegal username $otheruser\n"), next unless $otheruser =~ $USERNAME_PATT;
|
||||
&report_basic($GL_ADMINDIR, $GL_CONF_COMPILED, $repo, $otheruser);
|
||||
report_basic($repo, $otheruser);
|
||||
}
|
||||
} elsif ($HTPASSWD_FILE and $cmd eq 'htpasswd') {
|
||||
&ext_cmd_htpasswd($HTPASSWD_FILE);
|
||||
ext_cmd_htpasswd($HTPASSWD_FILE);
|
||||
} elsif ($RSYNC_BASE and $cmd =~ /^rsync /) {
|
||||
&ext_cmd_rsync($GL_CONF_COMPILED, $RSYNC_BASE, $cmd);
|
||||
ext_cmd_rsync($GL_CONF_COMPILED, $RSYNC_BASE, $cmd);
|
||||
} elsif ($SVNSERVE and $cmd eq 'svnserve -t') {
|
||||
&ext_cmd_svnserve($SVNSERVE);
|
||||
ext_cmd_svnserve($SVNSERVE);
|
||||
} else {
|
||||
# if the user is allowed a shell, just run the command
|
||||
&log_it();
|
||||
log_it();
|
||||
exec $ENV{SHELL}, "-c", $cmd if $shell_allowed;
|
||||
|
||||
die "bad command: $cmd\n";
|
||||
}
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# get memberships
|
||||
# ----------------------------------------------------------------------------
|
||||
sub run_custom_command {
|
||||
my $user = shift;
|
||||
|
||||
# given a plain reponame or username, return:
|
||||
# - the name itself if it's a user
|
||||
# - the name itself if it's a repo and the repo exists in the config
|
||||
# plus, if $GL_BIG_CONFIG is set:
|
||||
# - all the groups the name belongs to
|
||||
# plus, for repos:
|
||||
# - all the wildcards matching it
|
||||
# plus, if $GL_BIG_CONFIG is set:
|
||||
# - all the groups those wildcards belong to
|
||||
|
||||
# A name can normally appear (repo example) (user example)
|
||||
# - directly (repo foo) (RW = bob)
|
||||
# - (only for repos) as a direct wildcard (repo foo/.*)
|
||||
# but if $GL_BIG_CONFIG is set, it can also appear:
|
||||
# - indirectly (@g = foo; repo @g) (@ug = bob; RW = @ug))
|
||||
# - (only for repos) as an indirect wildcard (@g = foo/.*; repo @g).
|
||||
# note: the wildcard stuff does not apply to username memberships
|
||||
|
||||
our %extgroups_cache;
|
||||
sub get_memberships {
|
||||
my $base = shift; # reponame or username
|
||||
my $is_repo = shift; # some true value means a repo name has been passed
|
||||
|
||||
my $wild = ''; # will be a space-sep list of matching patterns
|
||||
my @ret; # list of matching groups/patterns
|
||||
|
||||
# direct
|
||||
push @ret, $base if not $is_repo or exists $repos{$base};
|
||||
if ($is_repo and $GL_WILDREPOS) {
|
||||
for my $i (sort keys %repos) {
|
||||
next if $i eq $base; # "direct" name already done; skip
|
||||
# direct wildcard
|
||||
if ($base =~ /^$i$/) {
|
||||
push @ret, $i;
|
||||
$wild = ($wild ? "$wild $i" : $i);
|
||||
my $cmd = $ENV{SSH_ORIGINAL_COMMAND};
|
||||
my ($verb, $repo) = ($cmd =~ /^\s*(\S+)(?:\s+'?\/?(.*?)(?:\.git)?'?)?$/);
|
||||
# deal with "no argument" cases
|
||||
$verb eq 'expand' ? $repo = '^' : die "$verb needs an argument\n" unless $repo;
|
||||
if ($repo =~ $REPONAME_PATT and $verb =~ /getperms|setperms/) {
|
||||
# with an actual reponame, you can "getperms" or "setperms"
|
||||
get_set_perms($repo, $verb, $user);
|
||||
}
|
||||
elsif ($repo =~ $REPONAME_PATT and $verb =~ /(get|set)desc/) {
|
||||
# with an actual reponame, you can "getdesc" or "setdesc"
|
||||
get_set_desc($repo, $verb, $user);
|
||||
}
|
||||
elsif ($verb eq 'expand') {
|
||||
# with a wildcard, you can "expand" it to see what repos actually match
|
||||
die "$repo has invalid characters" unless "x$repo" =~ $REPOPATT_PATT;
|
||||
expand_wild($repo, $user);
|
||||
} else {
|
||||
die "$cmd doesn't make sense to me\n";
|
||||
}
|
||||
|
||||
if ($GL_BIG_CONFIG) {
|
||||
for my $g (sort keys %groups) {
|
||||
for my $i (sort keys %{ $groups{$g} }) {
|
||||
if ($base eq $i) {
|
||||
# indirect
|
||||
push @ret, $g;
|
||||
} elsif ($is_repo and $GL_WILDREPOS and $base =~ /^$i$/) {
|
||||
# indirect wildcard
|
||||
push @ret, $g;
|
||||
$wild = ($wild ? "$wild $i" : $i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# deal with returning user info first
|
||||
unless ($is_repo) {
|
||||
# bring in group membership info stored externally, by running
|
||||
# $GL_GET_MEMBERSHIPS_PGM if it is defined
|
||||
|
||||
if ($extgroups_cache{$base}) {
|
||||
push @ret, @{ $extgroups_cache{$base} };
|
||||
} elsif ($GL_GET_MEMBERSHIPS_PGM) {
|
||||
my @extgroups = map { s/^/@/; $_; } split ' ', `$GL_GET_MEMBERSHIPS_PGM $base`;
|
||||
$extgroups_cache{$base} = \@extgroups;
|
||||
push @ret, @extgroups;
|
||||
}
|
||||
|
||||
return (@ret);
|
||||
}
|
||||
|
||||
# note that there is an extra return value when called for repos (as
|
||||
# opposed to being called for usernames)
|
||||
return ($wild, @ret);
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# generic check access routine
|
||||
# ----------------------------------------------------------------------------
|
||||
sub shell_out {
|
||||
my $shell = $ENV{SHELL};
|
||||
$shell =~ s/.*\//-/; # change "/bin/bash" to "-bash"
|
||||
log_it($shell);
|
||||
exec { $ENV{SHELL} } $shell;
|
||||
}
|
||||
|
||||
sub check_access
|
||||
{
|
||||
my ($repo, $ref, $aa, $dry_run) = @_;
|
||||
# aa = attempted access
|
||||
|
||||
my ($perm, $creator, $wild) = &repo_rights($repo);
|
||||
$perm =~ s/ /_/g;
|
||||
$creator =~ s/^\(|\)$//g;
|
||||
return ($perm, $creator) unless $ref;
|
||||
|
||||
# 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;
|
||||
# user+repo specific perms override everything else, so they come first.
|
||||
# Then perms given to specific user for @all repos, and finally perms
|
||||
# given to @all users for specific repo
|
||||
push @allowed_refs, @ { $repos{$repo}{$ENV{GL_USER}} || [] };
|
||||
push @allowed_refs, @ { $repos{'@all'}{$ENV{GL_USER}} || [] };
|
||||
push @allowed_refs, @ { $repos{$repo}{'@all'} || [] };
|
||||
|
||||
if ($dry_run) {
|
||||
return &check_ref(\@allowed_refs, $repo, $ref, $aa, $dry_run);
|
||||
} else {
|
||||
&check_ref(\@allowed_refs, $repo, $ref, $aa);
|
||||
sub try_adc {
|
||||
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 $_ =~ $ADC_CMD_ARGS_PATT } for ($cmd, @args);
|
||||
log_it("$GL_ADC_PATH/$ENV{SSH_ORIGINAL_COMMAND}");
|
||||
exec("$GL_ADC_PATH/$cmd", @args);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1114,11 +1092,11 @@ sub ext_cmd_rsync
|
|||
# ok now check if we're permitted to execute a $perm action on $path
|
||||
# (taken as a refex) using rsync.
|
||||
|
||||
&check_access('EXTCMD/rsync', "NAME/$path", $perm);
|
||||
check_access('EXTCMD/rsync', "NAME/$path", $perm);
|
||||
# that should "die" if there's a problem
|
||||
|
||||
wrap_chdir($RSYNC_BASE);
|
||||
&log_it();
|
||||
log_it();
|
||||
exec $ENV{SHELL}, "-c", $ENV{SSH_ORIGINAL_COMMAND};
|
||||
}
|
||||
|
||||
|
@ -1162,4 +1140,6 @@ sub ext_cmd_svnserve
|
|||
die "svnserve exec failed\n";
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# per perl rules, this should be the last line in such a file:
|
||||
1;
|
||||
|
|
157
src/gitolite_env.pm
Normal file
157
src/gitolite_env.pm
Normal file
|
@ -0,0 +1,157 @@
|
|||
# stuff that detects or sets up the runtime environment
|
||||
|
||||
package gitolite_env;
|
||||
use Exporter 'import';
|
||||
@EXPORT = qw(
|
||||
setup_environment
|
||||
simulate_ssh_connection
|
||||
get_logfilename
|
||||
);
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# find the rc file, then pull the libraries
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
BEGIN {
|
||||
die "ENV GL_RC not set\n" unless $ENV{GL_RC};
|
||||
die "ENV GL_BINDIR not set\n" unless $ENV{GL_BINDIR};
|
||||
}
|
||||
|
||||
use lib $ENV{GL_BINDIR};
|
||||
use gitolite_rc;
|
||||
use gitolite;
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# start
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# firstly, the following function, 'setup_environment', is not only about env
|
||||
# vars; it does other stuff too (like umask, nice...)
|
||||
|
||||
# a lot of stuff gets carried around in env vars primarily for 2 reasons. One
|
||||
# is that git calls the hooks, so they're not in the same 'process' as the
|
||||
# 'gl-auth-command' that probably started things off.
|
||||
|
||||
# Granted; we could write the same 'discovery' within the hook code, but
|
||||
# that's needless code duplication, plus in some cases a good amount of
|
||||
# inefficiency.
|
||||
|
||||
# Even more important, we do *not* want to burden the ADCs (admin defined
|
||||
# commands) with all this discovery, because those are written by the users
|
||||
# themselves (my 'user' == some gitolite 'admin' somewhere; I don't mean
|
||||
# 'gitolite user')
|
||||
|
||||
# think of it OS-supported memo-ization :-)
|
||||
sub setup_environment {
|
||||
$ENV{GL_ADMINDIR} = $GL_ADMINDIR;
|
||||
$ENV{GL_LOG} = get_logfilename($GL_LOGT);
|
||||
$ENV{PATH} = "$GIT_PATH:$ENV{PATH}" if $GIT_PATH;
|
||||
# set default permission of wildcard repositories
|
||||
$ENV{GL_WILDREPOS_DEFPERMS} = $GL_WILDREPOS_DEFPERMS if $GL_WILDREPOS_DEFPERMS;
|
||||
# this is used in so many places, inside and outside gitolite by external
|
||||
# hooks and ADCs, it isn't even funny...
|
||||
$ENV{GL_REPO_BASE_ABS} = ( $REPO_BASE =~ m(^/) ? $REPO_BASE : "$ENV{HOME}/$REPO_BASE" );
|
||||
|
||||
# be nice if asked. If you want me to pull in BSD::Resource to get rid of
|
||||
# the first '0', feel free to send me a patch that does everything needed
|
||||
# from within my own installer, does not require internet access (don't
|
||||
# ask!), and doesn't require a C compiler or the perl-devel (or eqvt
|
||||
# named) packages. Heck in some cases it's not even Linux...
|
||||
setpriority(0, 0, $GL_NICE_VALUE) if $GL_NICE_VALUE and $GL_NICE_VALUE > 0;
|
||||
|
||||
umask($REPO_UMASK);
|
||||
|
||||
set_up_http_death() if $ENV{GITOLITE_HTTP_HOME};
|
||||
}
|
||||
|
||||
sub simulate_ssh_connection {
|
||||
# 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 = $1;
|
||||
my $verb = ($ENV{REQUEST_URI} =~ /git-receive-pack/) ? 'git-receive-pack' : '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}";
|
||||
}
|
||||
|
||||
# a plain "die" was fine for ssh but http has all that extra gunk it needs.
|
||||
# So we need to, in effect, create a "death handler".
|
||||
sub set_up_http_death
|
||||
{
|
||||
$SIG{__DIE__} = sub {
|
||||
my $service = ($ENV{SSH_ORIGINAL_COMMAND} =~ /git-receive-pack/ ? 'git-receive-pack' : 'git-upload-pack');
|
||||
my $message = shift; chomp($message);
|
||||
print STDERR "$message\n";
|
||||
|
||||
# format the service response, then the message. With initial
|
||||
# help from Ilari and then a more detailed email from Shawn...
|
||||
$service = "# service=$service\n"; $message = "ERR $message\n";
|
||||
$service = sprintf("%04X", length($service)+4) . "$service"; # no CRLF on this one
|
||||
$message = sprintf("%04X", length($message)+4) . "$message";
|
||||
|
||||
print_http_headers();
|
||||
print $service;
|
||||
print "0000"; # flush-pkt, apparently
|
||||
print $message;
|
||||
print STDERR $service;
|
||||
print STDERR $message;
|
||||
exit 0; # if it's ok for die_webcgi in git.git/http-backend.c, it's ok for me ;-)
|
||||
}
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# helpers
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
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 {
|
||||
# this sub has a wee little side-effect; it sets $ENV{GL_TS}
|
||||
my($template) = shift;
|
||||
|
||||
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
|
||||
$template =~ s/%y/$y/g;
|
||||
$template =~ s/%m/$m/g;
|
||||
$template =~ s/%d/$d/g;
|
||||
return ($template);
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# per perl rules, this should be the last line in such a file:
|
||||
1;
|
68
src/gitolite_rc.pm
Normal file
68
src/gitolite_rc.pm
Normal file
|
@ -0,0 +1,68 @@
|
|||
# stuff to help pull in the rc file, plus various constants
|
||||
|
||||
package gitolite_rc;
|
||||
use Exporter 'import';
|
||||
|
||||
# the first set (before the blank line) are constants defined right here in
|
||||
# this program. The second set are from the 'rc'; We're clubbing all in
|
||||
# because they're all "constants" in a programmatic sense
|
||||
@EXPORT = qw(
|
||||
$ABRT $WARN
|
||||
$R_COMMANDS $W_COMMANDS
|
||||
$REPONAME_PATT $USERNAME_PATT $REPOPATT_PATT
|
||||
$ADC_CMD_ARGS_PATT
|
||||
$current_data_version
|
||||
|
||||
$ADMIN_POST_UPDATE_CHAINS_TO $ENV $GITOLITE_BASE $GITOLITE_PATH $GIT_PATH
|
||||
$GL_ADC_PATH $GL_ADMINDIR $GL_ALL_INCLUDES_SPECIAL $GL_ALL_READ_ALL
|
||||
$GL_BIG_CONFIG $GL_CONF $GL_CONF_COMPILED $GL_GET_MEMBERSHIPS_PGM
|
||||
$GL_GITCONFIG_KEYS $GL_GITCONFIG_WILD $GL_KEYDIR $GL_LOGT $GL_NICE_VALUE
|
||||
$GL_NO_CREATE_REPOS $GL_NO_DAEMON_NO_GITWEB $GL_NO_SETUP_AUTHKEYS
|
||||
$GL_PACKAGE_CONF $GL_PACKAGE_HOOKS $GL_PERFLOGT $GL_SITE_INFO
|
||||
$GL_SLAVE_MODE $GL_WILDREPOS $GL_WILDREPOS_DEFPERMS
|
||||
$GL_WILDREPOS_PERM_CATS $HTPASSWD_FILE $PROJECTS_LIST $REPO_BASE
|
||||
$REPO_UMASK $RSYNC_BASE $SVNSERVE $UPDATE_CHAINS_TO
|
||||
);
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# bring in the rc vars and allow querying them
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# in case we're running under Apache using smart http
|
||||
$ENV{HOME} = $ENV{GITOLITE_HTTP_HOME} if $ENV{GITOLITE_HTTP_HOME};
|
||||
|
||||
# we also need to "bring in" the rc variables. The rc can only be in one of
|
||||
# these two places; the first one we find, wins
|
||||
for ("$ENV{HOME}/.gitolite.rc", "/etc/gitolite/gitolite.rc") {
|
||||
$ENV{GL_RC} ||= $_ if -f;
|
||||
}
|
||||
die "no rc file found\n" unless $ENV{GL_RC};
|
||||
do $ENV{GL_RC} or die "error parsing $ENV{GL_RC}\n";
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# real constants
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
$current_data_version = '1.7';
|
||||
|
||||
$ABRT = "\n\t\t***** ABORTING *****\n ";
|
||||
$WARN = "\n\t\t***** WARNING *****\n ";
|
||||
|
||||
# commands we're expecting
|
||||
$R_COMMANDS=qr/^(git[ -]upload-pack|git[ -]upload-archive)$/;
|
||||
$W_COMMANDS=qr/^git[ -]receive-pack$/;
|
||||
|
||||
# note that REPONAME_PATT allows "/", while USERNAME_PATT does not
|
||||
# also, the reason REPONAME_PATT is a superset of USERNAME_PATT is (duh!)
|
||||
# because a repo can have "CREATOR" in the name
|
||||
$REPONAME_PATT=qr(^\@?[0-9a-zA-Z][0-9a-zA-Z._\@/+-]*$);
|
||||
$USERNAME_PATT=qr(^\@?[0-9a-zA-Z][0-9a-zA-Z._\@+-]*$);
|
||||
# same as REPONAME, but used for wildcard repos, allows some common regex metas
|
||||
$REPOPATT_PATT=qr(^\@?[0-9a-zA-Z[][\\^.$|()[\]*+?{}0-9a-zA-Z._\@/-]*$);
|
||||
|
||||
# ADC commands and arguments must match this pattern
|
||||
$ADC_CMD_ARGS_PATT=qr(^[0-9a-zA-Z._\@/+:-]*$);
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# per perl rules, this should be the last line in such a file:
|
||||
1;
|
|
@ -1,17 +1,9 @@
|
|||
#!/usr/bin/perl
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# you: what's the invocation?
|
||||
# me: Hail, O Lord Ganesha, destroyer of obsta...
|
||||
# you: err hmm not *that* sort of invocation... I meant how does this program
|
||||
# get invoked?
|
||||
# me: oh hehe <hides sheepish grin>, ok here we go...
|
||||
#
|
||||
# ssh mode
|
||||
# - started by sshd
|
||||
# - one optional flag, "-s", for "shell allowed" people
|
||||
# - one argument, the "user" name
|
||||
# - one env var, SSH_ORIGINAL_COMMAND, containing the command
|
||||
# - command typically: git-(receive|upload)-pack 'reponame(.git)?'
|
||||
|
@ -27,180 +19,101 @@ use warnings;
|
|||
# - no special processing commands currently handled
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# common definitions
|
||||
# find the rc file, then pull the libraries in
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# these are set by the "rc" file
|
||||
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, $GL_PERFLOGT, $GL_ALL_READ_ALL);
|
||||
# and these are set by gitolite.pm
|
||||
our ($R_COMMANDS, $W_COMMANDS, $REPONAME_PATT, $REPOPATT_PATT, $ADC_CMD_ARGS_PATT);
|
||||
our %repos;
|
||||
our %groups;
|
||||
our %git_configs;
|
||||
our %split_conf;;
|
||||
# this (gl-auth-command) is one of the two valid starting points for all of
|
||||
# gitolite for normal operations (the other being gl-time). All other
|
||||
# programs are invoked either from this, or from something else (typically
|
||||
# git-*-pack) in between). They thus get the benefit of the environment
|
||||
# variables that this code sets up.
|
||||
BEGIN {
|
||||
# find and set bin dir
|
||||
$0 =~ m|^(/)?(.*)/| and $ENV{GL_BINDIR} = ($1 || "$ENV{PWD}/") . $2;
|
||||
}
|
||||
|
||||
# the common setup module is in the same directory as this running program is
|
||||
my $bindir = $0;
|
||||
$bindir =~ s/\/[^\/]+$//;
|
||||
$bindir = "$ENV{PWD}/$bindir" unless $bindir =~ /^\//;
|
||||
unshift @INC, $bindir;
|
||||
require gitolite or die "parse gitolite.pm failed\n";
|
||||
# our libraries are either in the same place the scripts are, or, as with
|
||||
# RPM/DEB install, in some 'system' location that is already in perl's @INC
|
||||
# anyway
|
||||
use lib $ENV{GL_BINDIR};
|
||||
|
||||
# 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
|
||||
$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 default permission of wildcard repositories
|
||||
$ENV{GL_WILDREPOS_DEFPERMS} = $GL_WILDREPOS_DEFPERMS if $GL_WILDREPOS_DEFPERMS;
|
||||
|
||||
# set the umask before creating any files
|
||||
umask($REPO_UMASK);
|
||||
|
||||
$ENV{GL_REPO_BASE_ABS} = ( $REPO_BASE =~ m(^/) ? $REPO_BASE : "$ENV{HOME}/$REPO_BASE" );
|
||||
use gitolite_rc; # this does a "do" of the rc file
|
||||
use gitolite_env;
|
||||
use gitolite;
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# 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 and $ARGV[0] eq '-s') {
|
||||
$shell_allowed = 1;
|
||||
shift;
|
||||
}
|
||||
# these two options are mutually exclusive. And this program is not supposed
|
||||
# to be called manually anyway
|
||||
my $shell_allowed = (@ARGV and $ARGV[0] eq '-s' and shift);
|
||||
my $program = (@ARGV and $ARGV[0] eq '-e' and shift);
|
||||
|
||||
# setup the environment for the kids so they don't need to embark on the
|
||||
# voyage of self-discovery above ;-) [environment also means things like
|
||||
# nice, umask, etc., not just the environment *variables*]
|
||||
setup_environment();
|
||||
|
||||
# if one of the other programs is being invoked (see doc/hacking.mkd), exec it
|
||||
exec(@ARGV) if $program;
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# set up SSH_ORIGINAL_COMMAND and SSH_CONNECTION in http mode
|
||||
# set up GL_USER and (if reqd) SSH_ORIGINAL_COMMAND and SSH_CONNECTION
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# fake out SSH_ORIGINAL_COMMAND and SSH_CONNECTION so the rest of the code
|
||||
# stays the same (except the exec at the end).
|
||||
|
||||
my $user;
|
||||
if ($ENV{REQUEST_URI}) {
|
||||
die "fallback to DAV not supported\n" if $ENV{REQUEST_METHOD} eq 'PROPFIND';
|
||||
|
||||
# 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 = $1;
|
||||
my $verb = ($ENV{REQUEST_URI} =~ /git-receive-pack/) ? 'git-receive-pack' : '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}";
|
||||
# fake out SSH_ORIGINAL_COMMAND and SSH_CONNECTION when called via http,
|
||||
# so the rest of the code stays the same (except the exec at the end).
|
||||
simulate_ssh_connection();
|
||||
|
||||
$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;
|
||||
$user = $ENV{GL_USER} = shift;
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# logging, timestamp env vars
|
||||
# SSH_ORIGINAL_COMMAND
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
$ENV{GL_LOG} = &get_logfilename($GL_LOGT);
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# sanity checks on SSH_ORIGINAL_COMMAND
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# no SSH_ORIGINAL_COMMAND given...
|
||||
# no SSH_ORIGINAL_COMMAND given: shell out or default to 'info'
|
||||
unless ($ENV{SSH_ORIGINAL_COMMAND}) {
|
||||
# if the user is allowed to use a shell, give him one
|
||||
if ($shell_allowed) {
|
||||
my $shell = $ENV{SHELL};
|
||||
$shell =~ s/.*\//-/; # change "/bin/bash" to "-bash"
|
||||
&log_it($shell);
|
||||
exec { $ENV{SHELL} } $shell;
|
||||
}
|
||||
# otherwise, pretend he typed in "info" and carry on...
|
||||
shell_out() if $shell_allowed; # doesn't return ('exec's out)
|
||||
$ENV{SSH_ORIGINAL_COMMAND} = 'info';
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# 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-)/);
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# admin defined commands
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# please see doc/admin-defined-commands.mkd for details
|
||||
# admin defined commands; please see doc/admin-defined-commands.mkd
|
||||
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 $_ =~ $ADC_CMD_ARGS_PATT } for ($cmd, @args);
|
||||
&log_it("$GL_ADC_PATH/$ENV{SSH_ORIGINAL_COMMAND}");
|
||||
exec("$GL_ADC_PATH/$cmd", @args);
|
||||
}
|
||||
try_adc(); # if it succeeds, this also 'exec's out
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# get and set perms for actual repo created by wildcard-autoviv
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# get/set perms/desc for wild repos; also the 'expand' command
|
||||
my $CUSTOM_COMMANDS=qr/^\s*(expand|(get|set)(perms|desc))\b/;
|
||||
|
||||
# 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
|
||||
|
||||
if ($ENV{SSH_ORIGINAL_COMMAND} =~ $CUSTOM_COMMANDS) {
|
||||
die "wildrepos disabled, sorry\n" unless $GL_WILDREPOS;
|
||||
my $cmd = $ENV{SSH_ORIGINAL_COMMAND};
|
||||
my ($verb, $repo) = ($cmd =~ /^\s*(\S+)(?:\s+'?\/?(.*?)(?:\.git)?'?)?$/);
|
||||
# deal with "no argument" cases
|
||||
$verb eq 'expand' ? $repo = '^' : die "$verb needs an argument\n" unless $repo;
|
||||
if ($repo =~ $REPONAME_PATT and $verb =~ /getperms|setperms/) {
|
||||
# with an actual reponame, you can "getperms" or "setperms"
|
||||
get_set_perms($repo, $verb, $user);
|
||||
}
|
||||
elsif ($repo =~ $REPONAME_PATT and $verb =~ /(get|set)desc/) {
|
||||
# with an actual reponame, you can "getdesc" or "setdesc"
|
||||
get_set_desc($repo, $verb, $user);
|
||||
}
|
||||
elsif ($verb eq 'expand') {
|
||||
# with a wildcard, you can "expand" it to see what repos actually match
|
||||
die "$repo has invalid characters" unless "x$repo" =~ $REPOPATT_PATT;
|
||||
expand_wild($GL_ADMINDIR, $GL_CONF_COMPILED, $repo, $user);
|
||||
} else {
|
||||
die "$cmd doesn't make sense to me\n";
|
||||
}
|
||||
run_custom_command($user);
|
||||
exit 0;
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# non-git commands
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# if the command does NOT fit the pattern of a normal git command, send it off
|
||||
# somewhere else...
|
||||
# non-git commands: if the command does NOT fit the pattern of a normal git
|
||||
# command, send it off somewhere else...
|
||||
|
||||
# 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
|
||||
|
@ -210,63 +123,53 @@ if ($ENV{SSH_ORIGINAL_COMMAND} =~ $CUSTOM_COMMANDS) {
|
|||
|
||||
my ($verb, $repo) = ($ENV{SSH_ORIGINAL_COMMAND} =~ /^\s*(git\s+\S+|\S+)\s+'\/?(.*?)(?:\.git)?'/);
|
||||
unless ( $verb and ( $verb eq 'git-init' or $verb =~ $R_COMMANDS or $verb =~ $W_COMMANDS ) and $repo and $repo =~ $REPONAME_PATT ) {
|
||||
# ok, it's not a normal git command; call the special command helper
|
||||
&special_cmd ($GL_ADMINDIR, $GL_CONF_COMPILED, $shell_allowed, $RSYNC_BASE, $HTPASSWD_FILE, $SVNSERVE);
|
||||
exit;
|
||||
special_cmd ($shell_allowed);
|
||||
exit 0;
|
||||
}
|
||||
|
||||
# some final sanity checks
|
||||
die "$repo ends with a slash; I don't like that\n" if $repo =~ /\/$/;
|
||||
die "$repo has two consecutive periods; I don't like that\n" if $repo =~ /\.\./;
|
||||
|
||||
# reponame
|
||||
# save the reponame; too many things need this
|
||||
$ENV{GL_REPO}=$repo;
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# the real git commands (git-receive-pack, etc...)
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# first level permissions check
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
my ($perm, $creator, $wild);
|
||||
if ( $GL_ALL_READ_ALL and $verb =~ $R_COMMANDS and -d "$ENV{GL_REPO_BASE_ABS}/$repo.git") {
|
||||
$perm = 'R';
|
||||
} else {
|
||||
($perm, $creator, $wild) = &repo_rights($repo);
|
||||
}
|
||||
if ($perm =~ /C/) {
|
||||
# it was missing, and you have create perms
|
||||
wrap_chdir("$ENV{GL_REPO_BASE_ABS}");
|
||||
new_repo($repo, "$GL_ADMINDIR/hooks/common", $user);
|
||||
# note pwd is now the bare "repo.git"; new_repo does that...
|
||||
wrap_print("gl-perms", "$GL_WILDREPOS_DEFPERMS\n") if $GL_WILDREPOS_DEFPERMS;
|
||||
&setup_git_configs($repo, \%git_configs);
|
||||
&setup_daemon_access($repo);
|
||||
&add_del_line ("$repo.git", $PROJECTS_LIST, &setup_gitweb_access($repo, '', ''));
|
||||
wrap_chdir($ENV{HOME});
|
||||
($perm, $creator, $wild) = repo_rights($repo);
|
||||
}
|
||||
# it was missing, and you have create perms, so create it
|
||||
new_wild_repo($repo, $user) if ($perm =~ /C/);
|
||||
|
||||
# we know the user and repo; we just need to know what perm he's trying
|
||||
# aa == attempted access
|
||||
# we know the user and repo; we just need to know what perm he's trying for
|
||||
# (aa == attempted access)
|
||||
my $aa = ($verb =~ $R_COMMANDS ? 'R' : 'W');
|
||||
die "$aa access for $repo DENIED to $user
|
||||
(Or there may be no repository at the given path. Did you spell it correctly?)\n" unless $perm =~ /$aa/;
|
||||
|
||||
# check if repo is write-enabled
|
||||
&check_repo_write_enabled($repo) if $aa eq 'W';
|
||||
check_repo_write_enabled($repo) if $aa eq 'W';
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# over to git now
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
if ($ENV{REQUEST_URI}) {
|
||||
&log_it($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'";
|
||||
exec("git", "shell", "-c", "$verb $repo") unless $verb eq 'git-init';
|
||||
|
|
|
@ -6,70 +6,24 @@ use Data::Dumper;
|
|||
$Data::Dumper::Indent = 1;
|
||||
$Data::Dumper::Sortkeys = 1;
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# find the rc file, then pull the libraries
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
BEGIN {
|
||||
die "ENV GL_RC not set\n" unless $ENV{GL_RC};
|
||||
die "ENV GL_BINDIR not set\n" unless $ENV{GL_BINDIR};
|
||||
}
|
||||
|
||||
use lib $ENV{GL_BINDIR};
|
||||
use gitolite_rc;
|
||||
use gitolite qw(:DEFAULT %repos %groups %git_configs %split_conf);
|
||||
|
||||
# === add-auth-keys ===
|
||||
|
||||
# part of the gitolite (GL) suite
|
||||
|
||||
# (1) - "compiles" ~/.ssh/authorized_keys from the list of pub-keys
|
||||
# (2) - also "compiles" the user-friendly GL conf file into something easier
|
||||
# to parse. We're doing this because both the gl-auth-command and the
|
||||
# (gl-)update hook need this, and it seems easier to do this than
|
||||
# replicate the parsing code in both those places. As a bonus, it's
|
||||
# probably more efficient.
|
||||
# (3) - finally does what I have resisted doing all along -- handle gitweb and
|
||||
# git-daemon access. It won't *setup* gitweb/daemon for you -- you have
|
||||
# to that yourself. What this does is make sure that "repo.git"
|
||||
# contains the file "git-daemon-export-ok" (for daemon case) and the
|
||||
# line "repo.git" exists in the "projects.list" file (for gitweb case).
|
||||
|
||||
# how run: manual, by GL admin
|
||||
# when:
|
||||
# - anytime a pubkey is added/deleted
|
||||
# - anytime gitolite.conf is changed
|
||||
# input:
|
||||
# - GL_CONF (default: ~/.gitolite/conf/gitolite.conf)
|
||||
# - GL_KEYDIR (default: ~/.gitolite/keydir)
|
||||
# output:
|
||||
# - ~/.ssh/authorized_keys (dictated by sshd)
|
||||
# - GL_CONF_COMPILED (default: ~/.gitolite/conf/gitolite.conf-compiled.pm)
|
||||
# security:
|
||||
# - touches a very critical system file that manages the restrictions on
|
||||
# incoming users. Be sure to audit AUTH_COMMAND and AUTH_OPTIONS (see
|
||||
# below) on any change to this script
|
||||
# - no security checks within program. The GL admin runs this manually
|
||||
|
||||
# warnings:
|
||||
# - if the "start" line exists, but the "end" line does not, you lose the
|
||||
# rest of the existing authkey file. In general, "don't do that (TM)",
|
||||
# but we do have a "vim -d" popping up so you can see the changes being
|
||||
# made, just in case...
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# common definitions
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# setup quiet mode if asked; please do not use this when running manually
|
||||
open STDOUT, ">", "/dev/null" if (@ARGV and shift eq '-q');
|
||||
|
||||
# these are set by the "rc" file
|
||||
our ($GL_ADMINDIR, $GL_CONF, $GL_KEYDIR, $GL_CONF_COMPILED, $REPO_BASE, $REPO_UMASK, $PROJECTS_LIST, $GIT_PATH, $GL_WILDREPOS, $GL_GITCONFIG_KEYS, $GL_GITCONFIG_WILD, $GL_PACKAGE_HOOKS, $GL_BIG_CONFIG, $GL_NO_DAEMON_NO_GITWEB, $GL_NO_CREATE_REPOS, $GL_NO_SETUP_AUTHKEYS, $GL_PERFLOGT);
|
||||
# and these are set by gitolite.pm
|
||||
our ($REPONAME_PATT, $REPOPATT_PATT, $USERNAME_PATT, $ABRT, $WARN);
|
||||
|
||||
# the common setup module is in the same directory as this running program is
|
||||
my $bindir = $0;
|
||||
$bindir =~ s/\/[^\/]+$//;
|
||||
$bindir = "$ENV{PWD}/$bindir" unless $bindir =~ /^\//;
|
||||
unshift @INC, $bindir;
|
||||
require gitolite or die "parse gitolite.pm failed\n";
|
||||
|
||||
# ask where the rc file is, get it, and "do" it
|
||||
&where_is_rc();
|
||||
die "$ABRT parse $ENV{GL_RC} failed: " . ($! or $@) unless do $ENV{GL_RC};
|
||||
|
||||
# add a custom path for git binaries, if specified
|
||||
$ENV{PATH} .= ":$GIT_PATH" if $GIT_PATH;
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# definitions specific to this program
|
||||
# ----------------------------------------------------------------------------
|
||||
|
@ -78,7 +32,7 @@ $ENV{PATH} .= ":$GIT_PATH" if $GIT_PATH;
|
|||
|
||||
# $groups{group}{member} = "master" (or name of fragment file in which the
|
||||
# group is defined).
|
||||
our %groups = ();
|
||||
# our %groups = (); # moved to gitolite.pm now
|
||||
|
||||
# %repos has two functions.
|
||||
|
||||
|
@ -90,10 +44,10 @@ our %groups = ();
|
|||
# level 2 check. In order to allow "exclude" rules, the order of rules now
|
||||
# matters, so what used to be entirely "hash of hash of hash" now has a list
|
||||
# in between :)
|
||||
my %repos = ();
|
||||
# copy above desc to lite.pm -- my %repos = ();
|
||||
|
||||
# repos whose ACLs don't make it into the main compiled config file
|
||||
my %split_conf = ();
|
||||
# names of repos whose ACLs don't make it into the main compiled config file
|
||||
# copy above desc to lite.pm -- my %split_conf = ();
|
||||
|
||||
# rule sequence number
|
||||
my $rule_seq = 0;
|
||||
|
@ -103,21 +57,16 @@ my $rule_seq = 0;
|
|||
# multiple times for the same repo+user. So...
|
||||
my %rurp_seen = ();
|
||||
|
||||
our $current_data_version; # this comes from gitolite.pm
|
||||
|
||||
# catch usernames<->pubkeys mismatches; search for "lint" below
|
||||
my %user_list = ();
|
||||
|
||||
# repo specific 'git config' stuff
|
||||
our %git_configs = ();
|
||||
# our %git_configs = (); # moved to gitolite.pm now
|
||||
|
||||
# gitweb descriptions and owners; plain text, keyed by "$repo.git"
|
||||
my %desc = ();
|
||||
my %owner = ();
|
||||
|
||||
# set the umask before creating any files
|
||||
umask($REPO_UMASK);
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# subroutines
|
||||
# ----------------------------------------------------------------------------
|
||||
|
@ -401,28 +350,6 @@ for my $fragment_file (glob("conf/fragments/*.conf"))
|
|||
parse_conf_file($fragment_file, $fragment);
|
||||
}
|
||||
|
||||
sub write_compiled_conf
|
||||
{
|
||||
my $compiled_fh = wrap_open( ">", "$GL_CONF_COMPILED.new" );
|
||||
my $data_version = $current_data_version;
|
||||
print $compiled_fh Data::Dumper->Dump([$data_version], [qw(*data_version)]);
|
||||
my $dumped_data = Data::Dumper->Dump([\%repos], [qw(*repos)]);
|
||||
$dumped_data .= Data::Dumper->Dump([\%git_configs], [qw(*git_configs)]) if %git_configs;
|
||||
# the dump uses single quotes, but we convert any strings containing $creator
|
||||
# and $gl_user to double quoted strings. A bit sneaky, but not too much...
|
||||
$dumped_data =~ s/'(?=[^']*\$(?:creator|gl_user))~?(.*?)'/"$1"/g;
|
||||
print $compiled_fh $dumped_data;
|
||||
if (%groups) {
|
||||
$dumped_data = Data::Dumper->Dump([\%groups], [qw(*groups)]);
|
||||
$dumped_data =~ s/\bCREAT[EO]R\b/\$creator/g;
|
||||
$dumped_data =~ s/'(?=[^']*\$(?:creator|gl_user))~?(.*?)'/"$1"/g;
|
||||
print $compiled_fh $dumped_data;
|
||||
}
|
||||
print $compiled_fh Data::Dumper->Dump([\%split_conf], [qw(*split_conf)]) if %split_conf;
|
||||
close $compiled_fh or die "$ABRT close compiled-conf failed: $!\n";
|
||||
rename "$GL_CONF_COMPILED.new", "$GL_CONF_COMPILED";
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# (that ends the config file compiler, though we postpone the writing
|
||||
# for now to deal with the latest GL_BIG_CONFIG innovation!)
|
||||
|
@ -539,12 +466,34 @@ sub write_1_compiled_conf
|
|||
$split_conf{$repo} = 1;
|
||||
}
|
||||
|
||||
sub write_compiled_conf
|
||||
{
|
||||
my $compiled_fh = wrap_open( ">", "$GL_CONF_COMPILED.new" );
|
||||
my $data_version = $current_data_version;
|
||||
print $compiled_fh Data::Dumper->Dump([$data_version], [qw(*data_version)]);
|
||||
my $dumped_data = Data::Dumper->Dump([\%repos], [qw(*repos)]);
|
||||
$dumped_data .= Data::Dumper->Dump([\%git_configs], [qw(*git_configs)]) if %git_configs;
|
||||
# the dump uses single quotes, but we convert any strings containing $creator
|
||||
# and $gl_user to double quoted strings. A bit sneaky, but not too much...
|
||||
$dumped_data =~ s/'(?=[^']*\$(?:creator|gl_user))~?(.*?)'/"$1"/g;
|
||||
print $compiled_fh $dumped_data;
|
||||
if (%groups) {
|
||||
$dumped_data = Data::Dumper->Dump([\%groups], [qw(*groups)]);
|
||||
$dumped_data =~ s/\bCREAT[EO]R\b/\$creator/g;
|
||||
$dumped_data =~ s/'(?=[^']*\$(?:creator|gl_user))~?(.*?)'/"$1"/g;
|
||||
print $compiled_fh $dumped_data;
|
||||
}
|
||||
print $compiled_fh Data::Dumper->Dump([\%split_conf], [qw(*split_conf)]) if %split_conf;
|
||||
close $compiled_fh or die "$ABRT close compiled-conf failed: $!\n";
|
||||
rename "$GL_CONF_COMPILED.new", "$GL_CONF_COMPILED";
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# get a list of physical repos for later
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
my @phy_repos = ();
|
||||
@phy_repos = &list_phy_repos() unless $GL_NO_DAEMON_NO_GITWEB;
|
||||
@phy_repos = list_phy_repos() unless $GL_NO_DAEMON_NO_GITWEB;
|
||||
|
||||
# NOTE: we're overloading GL_NO_DAEMON_NO_GITWEB to mean "no git config" also.
|
||||
# In fact anything that requires trawling through the existing repos doing
|
||||
|
@ -573,7 +522,7 @@ my %projlist = ();
|
|||
for my $repo (@phy_repos) {
|
||||
wrap_chdir("$ENV{GL_REPO_BASE_ABS}/$repo.git");
|
||||
# daemon is easy
|
||||
&setup_daemon_access($repo);
|
||||
setup_daemon_access($repo);
|
||||
}
|
||||
|
||||
for my $repo (@phy_repos) {
|
||||
|
@ -588,7 +537,7 @@ for my $repo (@phy_repos) {
|
|||
# into the "repo foo" section; they're essentialy independent.
|
||||
# Anyway, I believe it doesn't make sense to have all wild repos
|
||||
# (for some pattern) to have the same description and owner.
|
||||
$projlist{"$repo.git"} = 1 if &setup_gitweb_access($repo, $desc{"$repo.git"} || '', $owner{"$repo.git"} || '');
|
||||
$projlist{"$repo.git"} = 1 if setup_gitweb_access($repo, $desc{"$repo.git"} || '', $owner{"$repo.git"} || '');
|
||||
|
||||
# git config
|
||||
# implementation note: this must happen *after* one of the previous 2
|
||||
|
@ -597,7 +546,7 @@ for my $repo (@phy_repos) {
|
|||
# set for the *current* repo, which in turn stores translated values for
|
||||
# $creator in the git_configs hash, which, (phew!) is needed for a match
|
||||
# that eventually gets you a valid $git_configs{} below
|
||||
&setup_git_configs($repo, \%git_configs) if $git_configs{$repo};
|
||||
setup_git_configs($repo, \%git_configs) if $git_configs{$repo};
|
||||
}
|
||||
|
||||
# write out the project list
|
||||
|
@ -612,5 +561,5 @@ close $projlist_fh;
|
|||
# ----------------------------------------------------------------------------
|
||||
|
||||
unless ($GL_NO_SETUP_AUTHKEYS) {
|
||||
&setup_authkeys($bindir, $GL_KEYDIR, \%user_list);
|
||||
setup_authkeys($GL_KEYDIR, \%user_list);
|
||||
}
|
||||
|
|
|
@ -62,10 +62,19 @@ else
|
|||
fi
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
# setup stuff
|
||||
REPO_BASE=$( cd $HOME; perl -e 'do ".gitolite.rc"; print $REPO_BASE' )
|
||||
GL_BINDIR=$( cd $HOME; perl -ne 'print($1), exit if /^command="(.*?)\/gl-auth-command /' < $HOME/.ssh/authorized_keys)
|
||||
GL_ADMINDIR=$(cd $HOME; perl -e 'do ".gitolite.rc"; print $GL_ADMINDIR')
|
||||
# setup stuff. Note that for *this* program, we don't want to rely on $0
|
||||
# telling us bindir; the user should be allowed to run it from anywhere and
|
||||
# still have it work. Luckily, by the time you feel the need to run this
|
||||
# program, authkeys is already populated, and anyway that's the only
|
||||
# *reliable* place to get this info. However, when running in HTTP mode or
|
||||
# Fedora mode, you have *no* keys in the authkeys file. In those cases you
|
||||
# have to manually set GL_BINDIR externally before running this program
|
||||
[ -z "$GL_BINDIR" ] &&
|
||||
GL_BINDIR=$( perl -ne 'print($1), exit if /^command="(.+?)\/gl-(time|auth-command) /' < $HOME/.ssh/authorized_keys)
|
||||
GL_RC=$( $GL_BINDIR/gl-query-rc GL_RC)
|
||||
REPO_BASE=$( $GL_BINDIR/gl-query-rc REPO_BASE)
|
||||
GL_ADMINDIR=$($GL_BINDIR/gl-query-rc GL_ADMINDIR)
|
||||
export GL_RC
|
||||
export REPO_BASE
|
||||
export GL_BINDIR
|
||||
export GL_ADMINDIR
|
||||
|
|
|
@ -48,7 +48,7 @@ main() {
|
|||
[[ $upgrade == 0 ]] && initial_conf_key
|
||||
|
||||
# MANUAL: cd to $GL_ADMINDIR and run "src/gl-compile-conf"
|
||||
ssh $p_port $user@$host "cd $GL_ADMINDIR; \$PWD/src/gl-compile-conf $quiet"
|
||||
ssh $p_port $user@$host "cd $GL_ADMINDIR; src/gl-auth-command -e src/gl-compile-conf $quiet"
|
||||
|
||||
setup_pta
|
||||
|
||||
|
@ -361,9 +361,9 @@ run_install() {
|
|||
prompt "installing/upgrading..." "$v_ignore_stuff"
|
||||
|
||||
# extract the GL_ADMINDIR, REPO_BASE and GIT_PATH locations
|
||||
GL_ADMINDIR=$(ssh $p_port $user@$host "perl -e 'do \".gitolite.rc\"; print \$GL_ADMINDIR'")
|
||||
REPO_BASE=$( ssh $p_port $user@$host "perl -e 'do \".gitolite.rc\"; print \$REPO_BASE'")
|
||||
GIT_PATH=$( ssh $p_port $user@$host "perl -e 'do \".gitolite.rc\"; print \$GIT_PATH'")
|
||||
GL_ADMINDIR=$(ssh $p_port $user@$host gitolite-install/src/gl-query-rc GL_ADMINDIR)
|
||||
REPO_BASE=$( ssh $p_port $user@$host gitolite-install/src/gl-query-rc REPO_BASE)
|
||||
GIT_PATH=$( ssh $p_port $user@$host gitolite-install/src/gl-query-rc GIT_PATH)
|
||||
|
||||
# determine if this is an upgrade; we decide based on whether a file
|
||||
# called $GL_ADMINDIR/conf/gitolite.conf exists on the remote side. We
|
||||
|
@ -382,7 +382,7 @@ run_install() {
|
|||
# MANUAL: still in the "gitolite-install" directory? Good. Run
|
||||
# "src/gl-install"
|
||||
|
||||
ssh $p_port $user@$host "cd gitolite-install; src/gl-install $quiet"
|
||||
ssh $p_port $user@$host "cd gitolite-install; src/gl-auth-command -e src/gl-install $quiet"
|
||||
|
||||
# MANUAL: if you're upgrading, run "src/gl-compile-conf" and you're done!
|
||||
# -- ignore the rest of this file for the purposes of an upgrade
|
||||
|
@ -443,7 +443,7 @@ GIT_WORK_TREE=$GL_ADMINDIR git diff --cached --quiet 2>/dev/null || GIT_WORK_TRE
|
|||
# properly. The install program does this. So cd back to the
|
||||
# "gitolite-install" directory and run "src/gl-install"
|
||||
|
||||
ssh $p_port $user@$host "cd gitolite-install; src/gl-install $quiet"
|
||||
ssh $p_port $user@$host "cd gitolite-install; src/gl-auth-command -e src/gl-install $quiet"
|
||||
|
||||
# MANUAL: you're done! Log out of the server, come back to your
|
||||
# workstation, and clone the admin repo using "git clone
|
||||
|
|
|
@ -5,7 +5,22 @@
|
|||
use strict;
|
||||
use warnings;
|
||||
|
||||
our ($REPO_BASE, $GL_ADMINDIR, $GL_CONF, $GIT_PATH, $GL_PACKAGE_CONF, $GL_PACKAGE_HOOKS, $GL_PERFLOGT, $REPO_UMASK);
|
||||
# ----------------------------------------------------------------------------
|
||||
# find the rc file, then pull the libraries
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
BEGIN {
|
||||
die "ENV GL_RC not set\n" unless $ENV{GL_RC};
|
||||
die "ENV GL_BINDIR not set\n" unless $ENV{GL_BINDIR};
|
||||
}
|
||||
|
||||
use lib $ENV{GL_BINDIR};
|
||||
use gitolite_rc;
|
||||
use gitolite;
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# start...
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# setup quiet mode if asked; please do not use this when running manually
|
||||
open STDOUT, ">", "/dev/null" if (@ARGV and shift eq '-q');
|
||||
|
@ -25,21 +40,13 @@ sub wrap_mkdir
|
|||
print "created $dir\n";
|
||||
}
|
||||
|
||||
# the common setup module is in the same directory as this running program is
|
||||
my $bindir = $0;
|
||||
$bindir =~ s/\/[^\/]+$//;
|
||||
unshift @INC, $bindir;
|
||||
require gitolite or die "parse gitolite.pm failed\n";
|
||||
|
||||
# ask where the rc file is, get it, and "do" it
|
||||
&where_is_rc();
|
||||
unless ($ENV{GL_RC}) {
|
||||
# doesn't exist. Copy it across, tell user to edit it and come back
|
||||
my $glrc = $ENV{HOME} . "/.gitolite.rc";
|
||||
if ($GL_PACKAGE_CONF) {
|
||||
system("cp $GL_PACKAGE_CONF/example.gitolite.rc $glrc");
|
||||
} else {
|
||||
system("cp $bindir/../conf/example.gitolite.rc $glrc");
|
||||
system("cp $ENV{GL_BINDIR}/../conf/example.gitolite.rc $glrc");
|
||||
}
|
||||
print "created $glrc\n";
|
||||
print "please edit it, change the paths if you wish to, and RERUN THIS SCRIPT\n";
|
||||
|
@ -69,8 +76,8 @@ for my $dir qw(conf doc keydir logs src hooks hooks/common hooks/gitolite-admin)
|
|||
if ($GL_PACKAGE_HOOKS) {
|
||||
system("cp -R -p $GL_PACKAGE_HOOKS $GL_ADMINDIR");
|
||||
} else {
|
||||
system("cp -R -p $bindir/../src $bindir/../doc $bindir/../hooks $GL_ADMINDIR");
|
||||
system("cp $bindir/../conf/VERSION $GL_ADMINDIR/conf");
|
||||
system("cp -R -p $ENV{GL_BINDIR}/../src $ENV{GL_BINDIR}/../doc $ENV{GL_BINDIR}/../hooks $GL_ADMINDIR");
|
||||
system("cp $ENV{GL_BINDIR}/../conf/VERSION $GL_ADMINDIR/conf");
|
||||
}
|
||||
|
||||
unless (-f $GL_CONF or $GL_PACKAGE_CONF) {
|
||||
|
|
|
@ -3,8 +3,13 @@
|
|||
export GL_BYPASS_UPDATE_HOOK
|
||||
GL_BYPASS_UPDATE_HOOK=1
|
||||
|
||||
export REPO_BASE=`cd $HOME;perl -e 'do ".gitolite.rc"; print $REPO_BASE' `
|
||||
export REPO_UMASK=`cd $HOME;perl -e 'do ".gitolite.rc"; print $REPO_UMASK' `
|
||||
get_rc_val() {
|
||||
${0%/*}/gl-query-rc $1
|
||||
}
|
||||
|
||||
REPO_BASE=$( get_rc_val REPO_BASE)
|
||||
REPO_UMASK=$(get_rc_val REPO_UMASK)
|
||||
|
||||
umask $REPO_UMASK
|
||||
|
||||
if echo $SSH_ORIGINAL_COMMAND | egrep git-upload\|git-receive >/dev/null
|
||||
|
@ -13,8 +18,8 @@ then
|
|||
# the (special) admin post-update hook needs these, so we cheat
|
||||
export GL_ADMINDIR
|
||||
export GL_BINDIR
|
||||
GL_ADMINDIR=` cd $HOME;perl -e 'do ".gitolite.rc"; print $GL_ADMINDIR'`
|
||||
GL_BINDIR=`echo $0 | perl -lpe 's/^/$ENV{PWD}\// unless /^\//; s/\/[^\/]+$//;'`
|
||||
GL_ADMINDIR=$(get_rc_val GL_ADMINDIR)
|
||||
GL_BINDIR=$( get_rc_val GL_BINDIR)
|
||||
|
||||
SSH_ORIGINAL_COMMAND=`echo $SSH_ORIGINAL_COMMAND | sed -e "s:':'$REPO_BASE/:"`
|
||||
exec git shell -c "$SSH_ORIGINAL_COMMAND"
|
||||
|
|
|
@ -6,7 +6,7 @@ ssh -o PasswordAuthentication=no $mirror echo hello-there | grep hello-there >/d
|
|||
{ echo I cant ssh to $mirror; exit 1; }
|
||||
|
||||
cd $HOME
|
||||
REPO_BASE=` cd $HOME;perl -e 'do ".gitolite.rc"; print $REPO_BASE'`
|
||||
REPO_BASE=`${0%/*}/gl-query-rc REPO_BASE`
|
||||
cd $REPO_BASE
|
||||
|
||||
ssh $mirror cat \$HOME/.gitolite.rc | expand | egrep '^ *\$GL_SLAVE_MODE *= *1; *$' >/dev/null || {
|
||||
|
|
23
src/gl-query-rc
Executable file
23
src/gl-query-rc
Executable file
|
@ -0,0 +1,23 @@
|
|||
#!/usr/bin/perl
|
||||
|
||||
# let shell scripts query rc values
|
||||
# prints out a tab delimited list of all queried values
|
||||
# just run "gl-query-rc REPO_BASE GL_ADMINDIR" (for example)
|
||||
|
||||
use strict;
|
||||
no strict 'refs';
|
||||
use warnings;
|
||||
|
||||
# find the rc file, then pull the libraries
|
||||
BEGIN {
|
||||
# find and set bin dir; same code as in gl-auth-command
|
||||
$0 =~ m|^(/)?(.*)/| and $ENV{GL_BINDIR} = ($1 || "$ENV{PWD}/") . $2;
|
||||
}
|
||||
use lib $ENV{GL_BINDIR};
|
||||
require gitolite_rc;
|
||||
gitolite_rc->import;
|
||||
|
||||
our $GL_RC=$ENV{GL_RC};
|
||||
our $GL_BINDIR=$ENV{GL_BINDIR};
|
||||
|
||||
print join("\t", map { $$_ } grep { $$_ } @ARGV) . "\n" if @ARGV;
|
33
src/gl-setup
33
src/gl-setup
|
@ -20,6 +20,10 @@ GL_PACKAGE_CONF=/tmp/share/gitolite/conf
|
|||
|
||||
die() { echo "$@"; exit 1; } >&2
|
||||
|
||||
get_rc_val() {
|
||||
${0%/*}/gl-query-rc $1
|
||||
}
|
||||
|
||||
TEMPDIR=$(mktemp -d -t tmp.XXXXXXXXXX)
|
||||
export TEMPDIR
|
||||
trap "/bin/rm -rf $TEMPDIR" 0
|
||||
|
@ -40,20 +44,24 @@ else
|
|||
fi
|
||||
fi
|
||||
|
||||
if [ -f $HOME/.gitolite.rc ]
|
||||
export GL_RC
|
||||
GL_RC=$(get_rc_val GL_RC 2>/dev/null)
|
||||
[ -z "$GL_RC" ] && GL_RC=$HOME/.gitolite.rc
|
||||
|
||||
if [ -f $GL_RC ]
|
||||
then
|
||||
print_rc_vars() {
|
||||
perl -ne 's/^\s+//; s/[\s=].*//; print if /^\$/;' < $1 | sort
|
||||
}
|
||||
print_rc_vars $GL_PACKAGE_CONF/example.gitolite.rc > $TEMPDIR/.newvars
|
||||
print_rc_vars $HOME/.gitolite.rc > $TEMPDIR/.oldvars
|
||||
print_rc_vars $GL_RC > $TEMPDIR/.oldvars
|
||||
comm -23 $TEMPDIR/.newvars $TEMPDIR/.oldvars > $TEMPDIR/.diffvars
|
||||
if [ -s $TEMPDIR/.diffvars ]
|
||||
then
|
||||
cp $GL_PACKAGE_CONF/example.gitolite.rc $HOME/.gitolite.rc.new
|
||||
echo new version of the rc file saved in $HOME/.gitolite.rc.new
|
||||
echo
|
||||
echo please update $HOME/.gitolite.rc manually if you need features
|
||||
echo please update $GL_RC manually if you need features
|
||||
echo controlled by any of the following variables:
|
||||
echo ----
|
||||
sed -e 's/^/ /' < $TEMPDIR/.diffvars
|
||||
|
@ -63,11 +71,11 @@ else
|
|||
[ -n "$GITOLITE_HTTP_HOME" ] || [ -n "$pubkey_file" ] || die "looks like first run -- I need a pubkey file"
|
||||
[ -z "$GITOLITE_HTTP_HOME" ] || [ -n "$admin_name" ] || die "looks like first run -- I need an admin name"
|
||||
|
||||
cp $GL_PACKAGE_CONF/example.gitolite.rc $HOME/.gitolite.rc
|
||||
printf "The default settings in the "rc" file ($HOME/.gitolite.rc) are fine for most\n"
|
||||
cp $GL_PACKAGE_CONF/example.gitolite.rc $GL_RC
|
||||
printf "The default settings in the "rc" file ($GL_RC) are fine for most\n"
|
||||
printf "people but if you wish to make any changes, you can do so now.\n\nhit enter..."
|
||||
read i
|
||||
${EDITOR:-vi} $HOME/.gitolite.rc
|
||||
${EDITOR:-vi} $GL_RC
|
||||
fi
|
||||
|
||||
# setup ssh stuff. We break our normal rule that we will not fiddle with
|
||||
|
@ -80,16 +88,17 @@ fi
|
|||
chmod go-w . .ssh .ssh/authorized_keys
|
||||
)
|
||||
|
||||
export GL_BINDIR
|
||||
export REPO_BASE
|
||||
export GL_ADMINDIR
|
||||
GL_BINDIR=$( get_rc_val GL_BINDIR )
|
||||
REPO_BASE=$( get_rc_val REPO_BASE )
|
||||
GL_ADMINDIR=$(get_rc_val GL_ADMINDIR)
|
||||
|
||||
# now we get to gitolite itself
|
||||
|
||||
gl-install -q
|
||||
|
||||
get_rc_val() {
|
||||
perl -e "do '$HOME/.gitolite.rc'; print $1"
|
||||
}
|
||||
GL_ADMINDIR=$(get_rc_val '$GL_ADMINDIR')
|
||||
REPO_BASE=$( get_rc_val '$REPO_BASE' )
|
||||
|
||||
[ -f $GL_ADMINDIR/conf/gitolite.conf ] || {
|
||||
cat <<EOF | cut -c9- > $GL_ADMINDIR/conf/gitolite.conf
|
||||
repo gitolite-admin
|
||||
|
|
|
@ -1,43 +1,51 @@
|
|||
#!/usr/bin/perl -w
|
||||
|
||||
# shim program
|
||||
# documentation for this program is right here, please read
|
||||
|
||||
# arg-1: keydir
|
||||
# IMPORTANT NOTES:
|
||||
|
||||
# - this program MUST be placed in the same directory as the rest of the
|
||||
# programs that come with gitolite
|
||||
|
||||
# - this program MUST be run by supplying its full path!
|
||||
|
||||
# BACKGROUND/PURPOSE:
|
||||
|
||||
# - an external program populates "keydir" with *all* keys and then
|
||||
# calls us, giving "keydir" as arg-1
|
||||
# calls this program, giving "keydir" as arg-1
|
||||
# - we then call gitolite.pm's "setup_authkeys" function to do its thing
|
||||
|
||||
# IMPLEMENTATION NOTE: make sure this is in the same directory as
|
||||
# "gitolite.pm" and all the rest of "src/".
|
||||
# arg-1: keydir
|
||||
|
||||
# DISCUSSION:
|
||||
#
|
||||
# For now, we will assume *all* the keys are in the keydir passed. The
|
||||
# setup_authkeys routine factored out from the old gl-compile-conf is
|
||||
# not setup to take a partial set of keys and create the
|
||||
# ~/.ssh/authorized_keys file.
|
||||
# setup_authkeys routine factored out from the old gl-compile-conf is not
|
||||
# setup to take a partial set of keys and create the ~/.ssh/authorized_keys
|
||||
# file.
|
||||
#
|
||||
# Also, there are issues to do with *deleted* keys that need to be taken
|
||||
# care of.
|
||||
# Also, there are issues to do with *deleted* keys that need to be taken care
|
||||
# of.
|
||||
#
|
||||
# All in all, unless it is shown to be quite inefficient, I'd much
|
||||
# prefer processing *all* keys each time there is a change.
|
||||
# All in all, unless it is shown to be quite inefficient, I'd much prefer
|
||||
# processing *all* keys each time there is a change.
|
||||
|
||||
our ($GL_PERFLOGT);
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
# setup
|
||||
my $bindir = $0;
|
||||
$bindir =~ s/\/[^\/]+$//;
|
||||
$bindir = "$ENV{PWD}/$bindir" unless $bindir =~ /^\//;
|
||||
unshift @INC, $bindir;
|
||||
require gitolite or die "parse gitolite.pm failed\n";
|
||||
use FindBin;
|
||||
BEGIN { $ENV{GL_BINDIR} = $FindBin::Bin; }
|
||||
|
||||
# prevent newbie from running it accidentally and clobbering his authkeys
|
||||
# file!
|
||||
if (@ARGV and $ARGV[0] eq '-batch') {
|
||||
shift;
|
||||
} else {
|
||||
use lib $ENV{GL_BINDIR};
|
||||
use gitolite_rc;
|
||||
use gitolite;
|
||||
|
||||
use Getopt::Long;
|
||||
my $batch = 0;
|
||||
GetOptions('batch' => \$batch);
|
||||
|
||||
# prevent newbie from running it accidentally and clobbering his authkeys file!
|
||||
unless ($batch) {
|
||||
print STDERR "
|
||||
This is a cronnable, batchable, program to rewrite ~/.ssh/authorized_keys
|
||||
using public keys in a given directory.
|
||||
|
@ -54,4 +62,4 @@ if (@ARGV and $ARGV[0] eq '-batch') {
|
|||
my $keydir = shift or die "I need a directory name\n";
|
||||
-d $keydir or die "$keydir should be a directory\n";
|
||||
|
||||
&setup_authkeys($bindir, $keydir);
|
||||
setup_authkeys($keydir);
|
||||
|
|
30
src/gl-time
30
src/gl-time
|
@ -9,22 +9,32 @@
|
|||
use strict;
|
||||
use warnings;
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# find the rc file, then pull the libraries
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# see notes on this code in gl-auth-command
|
||||
BEGIN {
|
||||
# find and set bin dir
|
||||
$0 =~ m|^(/)?(.*)/| and $ENV{GL_BINDIR} = ($1 || "$ENV{PWD}/") . $2;
|
||||
}
|
||||
|
||||
use lib $ENV{GL_BINDIR};
|
||||
use gitolite_rc;
|
||||
use gitolite_env;
|
||||
use gitolite qw(log_it);
|
||||
|
||||
use Time::HiRes qw(gettimeofday tv_interval);
|
||||
|
||||
our ($GL_PERFLOGT);
|
||||
# ----------------------------------------------------------------------------
|
||||
# start...
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# rc file
|
||||
do "$ENV{HOME}/.gitolite.rc";
|
||||
# this file is always in a fixed place; code in the main gitolite that
|
||||
# seems to indicate it is not, is obsolete and needs to be fixed.
|
||||
|
||||
# the common setup module is in the same directory as this running program is
|
||||
my $bindir = $0;
|
||||
$bindir =~ s/\/[^\/]+$//;
|
||||
$bindir = "$ENV{PWD}/$bindir" unless $bindir =~ /^\//;
|
||||
unshift @INC, $bindir;
|
||||
require gitolite or die "parse gitolite.pm failed\n";
|
||||
|
||||
# ---------------------------------------------------------------
|
||||
|
||||
my $starttime = [gettimeofday];
|
||||
|
@ -36,6 +46,6 @@ $ENV{GL_USER} = shift;
|
|||
|
||||
my $elapsedtime = tv_interval($starttime);
|
||||
|
||||
$ENV{GL_LOG} = &get_logfilename($GL_PERFLOGT);
|
||||
$ENV{GL_LOG} = get_logfilename($GL_PERFLOGT);
|
||||
# log_it logs to $ENV{GL_LOG}
|
||||
&log_it("", "$elapsedtime\trc=$returncode");
|
||||
log_it("", "$elapsedtime\trc=$returncode");
|
||||
|
|
|
@ -14,8 +14,9 @@
|
|||
# current sub-commands:
|
||||
|
||||
# (1) REPLACE THE OLD $SHELL_USERS MECHANISM
|
||||
|
||||
#
|
||||
# $0 shell-add foo.pub
|
||||
#
|
||||
# adds the pubkey in foo.pub into the authkeys file with "-s" argument (shell
|
||||
# access) and user "foo". The line will be added *before* the "# gitolite
|
||||
# start" section, so that a gitolite-admin push will not affect it.
|
||||
|
@ -45,12 +46,12 @@ then
|
|||
# side, it's not likely to change anytime soon!
|
||||
AUTH_OPTIONS="no-port-forwarding,no-X11-forwarding,no-agent-forwarding"
|
||||
|
||||
bindir=`echo $0 | perl -lpe 's/^/$ENV{PWD}\// unless /^\//; s/\/[^\/]+$//;'`
|
||||
GL_BINDIR=`${0%/*}/gl-query-rc GL_BINDIR`
|
||||
|
||||
pubkey_file=$2
|
||||
user=`basename $pubkey_file .pub`
|
||||
|
||||
authline="command=\"$bindir/gl-auth-command -s $user\",$AUTH_OPTIONS `cat $pubkey_file`";
|
||||
authline="command=\"$GL_BINDIR/gl-auth-command -s $user\",$AUTH_OPTIONS `cat $pubkey_file`";
|
||||
|
||||
authkeys=$HOME/.ssh/authorized_keys
|
||||
|
||||
|
|
|
@ -6,8 +6,8 @@ our (%users, %linenos);
|
|||
my $thisbin = $0;
|
||||
$thisbin = "$ENV{PWD}/$thisbin" unless $thisbin =~ /^\//;
|
||||
|
||||
&usage unless $ARGV[0] and -f $ARGV[0];
|
||||
my @authlines = &filelines($ARGV[0]);
|
||||
usage() unless $ARGV[0] and -f $ARGV[0];
|
||||
my @authlines = filelines($ARGV[0]);
|
||||
my $lineno = 0;
|
||||
for (@authlines)
|
||||
{
|
||||
|
@ -36,7 +36,7 @@ print "\n";
|
|||
my @pubkeys = glob("*.pub");
|
||||
die "no *.pub files here\n" unless @pubkeys;
|
||||
for my $pub (@pubkeys) {
|
||||
my @lines = &filelines($pub);
|
||||
my @lines = filelines($pub);
|
||||
die "$pub has more than one line\n" if @lines > 1;
|
||||
die "$pub does not start with ssh-rsa or ssh-dss\n" unless $lines[0] =~ /^(?:ssh-rsa|ssh-dss) (\S+)/;
|
||||
my $key = $1;
|
||||
|
|
|
@ -71,6 +71,15 @@ In this document:
|
|||
# or
|
||||
./test-driver.sh t51
|
||||
|
||||
* you can also run them through "prove", although to make it work easier
|
||||
with prove, I ended up making the "subtest" numbers be the actual test
|
||||
numbers, making it look like I have over 2000 tests, when in reality I
|
||||
have about 600:
|
||||
|
||||
prove ./test-driver.sh
|
||||
# or
|
||||
prove ./test-driver.sh :: t51
|
||||
|
||||
<a name="instructions_for_adding_new_tests"></a>
|
||||
|
||||
### instructions for adding new tests
|
||||
|
|
20
t/t65-rsync
20
t/t65-rsync
|
@ -26,8 +26,8 @@ name "u1 rsync to frob"
|
|||
cd ~/gitolite-admin
|
||||
runlocal rsync -avP conf u1:frob
|
||||
expect conf/gitolite.conf
|
||||
expect 386.*100%
|
||||
expect "total size is 386"
|
||||
expect 100%
|
||||
expect "total size is"
|
||||
runlocal find /tmp/rsyncbase -type f
|
||||
expect /tmp/rsyncbase/frob/conf/gitolite.conf
|
||||
|
||||
|
@ -42,8 +42,8 @@ name "u2 rsync to nitz"
|
|||
cd ~/gitolite-admin
|
||||
runlocal rsync -avP conf u2:nitz
|
||||
expect conf/gitolite.conf
|
||||
expect 386.*100%
|
||||
expect "total size is 386"
|
||||
expect 100%
|
||||
expect "total size is"
|
||||
runlocal find /tmp/rsyncbase -type f
|
||||
expect /tmp/rsyncbase/nitz/conf/gitolite.conf
|
||||
|
||||
|
@ -55,8 +55,8 @@ expect "W NAME/spl u2 DENIED by NAME/spl"
|
|||
name "u1 rsync to spl"
|
||||
cd ~/gitolite-admin
|
||||
runlocal rsync -avP conf u1:spl
|
||||
expect 386.*100%
|
||||
expect "total size is 386"
|
||||
expect 100%
|
||||
expect "total size is"
|
||||
|
||||
name "u2 rsync from spl"
|
||||
cd ~/td
|
||||
|
@ -66,14 +66,14 @@ expect "R NAME/spl u2 DENIED by NAME/spl"
|
|||
name "u1 rsync from spl"
|
||||
cd ~/td
|
||||
runlocal rsync -avP u1:spl splhere
|
||||
expect 386.*100%
|
||||
expect "total size is 386"
|
||||
expect 100%
|
||||
expect "total size is"
|
||||
|
||||
name "u3 rsync to foo"
|
||||
cd ~/gitolite-admin
|
||||
runlocal rsync -avP conf u3:foo/
|
||||
expect 386.*100%
|
||||
expect "total size is 386"
|
||||
expect 100%
|
||||
expect "total size is"
|
||||
|
||||
name "u3 rsync to bar"
|
||||
cd ~/gitolite-admin
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
# documentation
|
||||
|
||||
testnum=0
|
||||
subtests=0
|
||||
|
||||
# remote local command
|
||||
runlocal() { "$@" > ~/1 2> ~/2; }
|
||||
|
@ -28,22 +27,22 @@ taillog() { ssh gitolite-test@localhost tail $1 .gitolite/logs/gitolite-????-??.
|
|||
hl() { # highlight function
|
||||
normal=`tput sgr0`
|
||||
red=`tput sgr0; tput setaf 1; tput bold`
|
||||
echo >&2
|
||||
if [[ -n $1 ]]
|
||||
then
|
||||
echo $red"$@"$normal
|
||||
echo $red"$@"$normal >&2
|
||||
else
|
||||
echo $red
|
||||
echo $red >&2
|
||||
cat
|
||||
echo $normal
|
||||
echo $normal >&2
|
||||
fi
|
||||
}
|
||||
pause() { echo pausing, "$@"\; hit enter or ctrl-c...; read; }
|
||||
|
||||
capture() { cf=$1; shift; "$@" >& $TESTDIR/$cf; }
|
||||
|
||||
editrc() {
|
||||
scp gitolite-test@localhost:.gitolite.rc ~/junk >/dev/null
|
||||
perl -pi -e "print STDERR if not /^#/ and /$1\b/ and s/=.*/= $2;/" ~/junk
|
||||
perl -pi -e "print STDERR if not /^#/ and /$1\b/ and s/=.*/= $2;/" ~/junk 2> >(sed -e 's/^/# /')
|
||||
scp ~/junk gitolite-test@localhost:.gitolite.rc >/dev/null
|
||||
}
|
||||
|
||||
|
@ -80,80 +79,64 @@ mdc()
|
|||
) >~/1 2>~/2
|
||||
}
|
||||
|
||||
# flush result of last test when next one comes along
|
||||
testdone() {
|
||||
[[ $subtests > 1 ]] && TESTNAME="($subtests) $TESTNAME"
|
||||
echo -e $testnum\\t$TESTNAME
|
||||
}
|
||||
|
||||
# set test name/desc
|
||||
name() {
|
||||
if [[ -n $TESTNAME ]]
|
||||
then
|
||||
export TESTNAME="$*"
|
||||
if [[ $TESTNAME != INTERNAL ]]
|
||||
then
|
||||
(( testnum++ ))
|
||||
testdone
|
||||
echo '#' "$*"
|
||||
fi
|
||||
subtests=0
|
||||
fi
|
||||
export TESTNAME="$*"
|
||||
}
|
||||
|
||||
ok() {
|
||||
(( testnum++ ))
|
||||
echo 'ok' "($testnum) $*"
|
||||
}
|
||||
|
||||
|
||||
notok() {
|
||||
echo ----------
|
||||
head -999 ~/1 ~/2 | sed -e 's/^/ /'
|
||||
(( testnum++ ))
|
||||
echo 'not ok' "($testnum) $*"
|
||||
}
|
||||
|
||||
expect_filesame() {
|
||||
if cmp ~/1 "$1"
|
||||
then
|
||||
(( subtests++ ))
|
||||
ok
|
||||
else
|
||||
echo files ~/1 and "$1" are different
|
||||
echo '*** ABORTING ***'
|
||||
exit 1
|
||||
notok files ~/1 and "$1" are different
|
||||
fi
|
||||
}
|
||||
|
||||
die() {
|
||||
echo '***** AAAAARRRGGH! *****'
|
||||
echo ${BASH_LINENO[1]} ${BASH_SOURCE[2]}
|
||||
read
|
||||
cd $TESTDIR
|
||||
vim +${BASH_LINENO[1]} '+r !head ~/1 ~/2 /dev/null' ${BASH_SOURCE[2]}
|
||||
echo '***** AAAAARRRGGH! *****' >&2
|
||||
echo ${BASH_LINENO[1]} ${BASH_SOURCE[2]} >&2
|
||||
echo "vim +${BASH_LINENO[1]} \'+r !head ~/1 ~/2 /dev/null\' ${BASH_SOURCE[2]}" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
expect() {
|
||||
if cat ~/1 ~/2 | grep "$1" >/dev/null
|
||||
then
|
||||
(( subtests++ ))
|
||||
ok
|
||||
else
|
||||
notok
|
||||
echo ----------
|
||||
echo " expecting: $1"
|
||||
echo ----------
|
||||
die $TESTNAME
|
||||
exit 1
|
||||
notok "expecting: $1, got:"
|
||||
cat ~/1 ~/2|sed -e 's/^/# /'
|
||||
fi
|
||||
}
|
||||
|
||||
notexpect() {
|
||||
if cat ~/1 ~/2 | grep "$1" >/dev/null
|
||||
then
|
||||
notok
|
||||
echo "NOT expecting: $1"
|
||||
echo ----------
|
||||
die $TESTNAME
|
||||
exit 1
|
||||
notok "NOT expecting: $1, got:"
|
||||
cat ~/1 ~/2|sed -e 's/^/# /'
|
||||
else
|
||||
(( subtests++ ))
|
||||
ok
|
||||
fi
|
||||
}
|
||||
|
||||
print_summary() {
|
||||
echo -e "==========\n$testnum tests succeeded"
|
||||
echo 1..$testnum
|
||||
}
|
||||
|
||||
expect_push_ok() {
|
||||
|
|
Loading…
Reference in a new issue