some nice ADC changes... (warning: minor backward compat breakage)
- support for ADCs with unchecked arguments - rsync, htpasswd, and svnserve gone from core; turned into ADCs Backward compat breakage and fix: Please see documentation for details, but if you're using gitolite to control rsync you will now need to setup ADCs (admin defined commands), and install at least the new "rsync" ADC. ---- Thanks to Joey Hess (see commit prior to this) for forcing me to stop being lazy and get this out of my long term todo list.
This commit is contained in:
parent
955edcc5ec
commit
85da5572b2
|
@ -45,28 +45,3 @@ repo foo
|
||||||
# rules. So, lead_dev can push changes to any files, dev1/2 can push
|
# rules. So, lead_dev can push changes to any files, dev1/2 can push
|
||||||
# changes to files in "doc/" and "src/" (but not the top level README), and
|
# changes to files in "doc/" and "src/" (but not the top level README), and
|
||||||
# dev3/4 can only push changes to files in "src/".
|
# dev3/4 can only push changes to files in "src/".
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# (2) rsync helper: this is an oddball feature that only the person who asked
|
|
||||||
# me for is apparently using, created long ago, before I learned the value of
|
|
||||||
# saying "no" :-) These items just don't seem to fit in any of the existing
|
|
||||||
# documents.
|
|
||||||
|
|
||||||
# EXTERNAL COMMAND HELPERS -- RSYNC
|
|
||||||
# ---------------------------------
|
|
||||||
|
|
||||||
# If $RSYNC_BASE is non-empty, the following config entries come into play
|
|
||||||
# (otherwise they are ignored):
|
|
||||||
|
|
||||||
# a "fake" git repository to collect rsync rules. Gitolite does not
|
|
||||||
# auto-create any repo whose name starts with EXTCMD/
|
|
||||||
repo EXTCMD/rsync
|
|
||||||
# grant permissions to files/dirs within the $RSYNC_BASE tree. A leading
|
|
||||||
# NAME/ is required as a prefix; the actual path starts after that. Matching
|
|
||||||
# follows the same rules as given in "FILE/DIR NAME BASED RESTRICTIONS" above
|
|
||||||
RW NAME/ = sitaram
|
|
||||||
RW NAME/foo/ = user1
|
|
||||||
R NAME/bar/ = user2
|
|
||||||
# just to remind you that these are perl regexes, not shell globs
|
|
||||||
RW NAME/baz/.*/*.c = user3
|
|
||||||
|
|
30
contrib/adc/htpasswd
Normal file
30
contrib/adc/htpasswd
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
#!/usr/bin/perl
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
BEGIN {
|
||||||
|
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};
|
||||||
|
}
|
||||||
|
use gitolite_rc;
|
||||||
|
use gitolite;
|
||||||
|
|
||||||
|
die "$HTPASSWD_FILE doesn't exist or is not writable\n" unless -w $HTPASSWD_FILE;
|
||||||
|
$|++;
|
||||||
|
print <<EOFhtp;
|
||||||
|
Please type in your new htpasswd at the prompt. You only have to type it once.
|
||||||
|
|
||||||
|
NOTE THAT THE PASSWORD WILL BE ECHOED, so please make sure no one is
|
||||||
|
shoulder-surfing, and make sure you clear your screen as well as scrollback
|
||||||
|
history after you're done (or close your terminal instance).
|
||||||
|
|
||||||
|
EOFhtp
|
||||||
|
print "new htpasswd:";
|
||||||
|
|
||||||
|
my $password = <>;
|
||||||
|
$password =~ s/[\n\r]*$//;
|
||||||
|
die "empty passwords are not allowed\n" unless $password;
|
||||||
|
my $rc = system("htpasswd", "-mb", $HTPASSWD_FILE, $ENV{GL_USER}, $password);
|
||||||
|
die "htpasswd command seems to have failed with $rc return code...\n" if $rc;
|
63
contrib/adc/rsync
Executable file
63
contrib/adc/rsync
Executable file
|
@ -0,0 +1,63 @@
|
||||||
|
#!/usr/bin/perl
|
||||||
|
|
||||||
|
# 'rsync' helper ADC. See bottom of this file for more info
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
BEGIN {
|
||||||
|
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};
|
||||||
|
}
|
||||||
|
use gitolite_rc;
|
||||||
|
use gitolite;
|
||||||
|
|
||||||
|
my $cmd = $ENV{SSH_ORIGINAL_COMMAND};
|
||||||
|
|
||||||
|
# test the command patterns; reject if they don't fit. Rsync sends
|
||||||
|
# commands that looks like one of these to the server (the first one is
|
||||||
|
# for a read, the second for a write)
|
||||||
|
# rsync --server --sender -some.flags . some/path
|
||||||
|
# rsync --server -some.flags . some/path
|
||||||
|
|
||||||
|
die "bad rsync command: $cmd"
|
||||||
|
unless $cmd =~ /^rsync --server( --sender)? -[\w.]+(?: --(?:delete|partial))* \. (\S+)$/;
|
||||||
|
my $perm = "W";
|
||||||
|
$perm = "R" if $1;
|
||||||
|
my $path = $2;
|
||||||
|
die "I dont like some of the characters in $path\n" unless $path =~ $REPONAME_PATT;
|
||||||
|
# XXX make a better pattern for this if people complain ;-)
|
||||||
|
die "I dont like absolute paths in $cmd\n" if $path =~ /^\//;
|
||||||
|
die "I dont like '..' paths in $cmd\n" if $path =~ /\.\./;
|
||||||
|
|
||||||
|
# ok now check if we're permitted to execute a $perm action on $path
|
||||||
|
# (taken as a refex) using rsync.
|
||||||
|
|
||||||
|
check_access('EXTCMD/rsync', "NAME/$path", $perm);
|
||||||
|
# that should "die" if there's a problem
|
||||||
|
|
||||||
|
wrap_chdir($RSYNC_BASE);
|
||||||
|
log_it();
|
||||||
|
exec $ENV{SHELL}, "-c", $ENV{SSH_ORIGINAL_COMMAND};
|
||||||
|
|
||||||
|
__END__
|
||||||
|
|
||||||
|
This is an rsync helper ADC. It is an example of using gitolite's config
|
||||||
|
language, combined with the 'check_access()' function, to implement access
|
||||||
|
control for non-git software using a "fake" repo. For historical reasons,
|
||||||
|
fake repos start with "EXTCMD/". Gitolite does not auto-create fake repos, so
|
||||||
|
you can use those as namespaces to hold collections of rules for various
|
||||||
|
purposes.
|
||||||
|
|
||||||
|
So here's a fake git repository to collect rsync rules in one place. It grant
|
||||||
|
permissions to files/dirs within the $RSYNC_BASE tree. A leading NAME/ is
|
||||||
|
required as a prefix; the actual path starts after that. Matching follows the
|
||||||
|
same rules as given in "FILE/DIR NAME BASED RESTRICTIONS" elsewhere in the
|
||||||
|
gitolite documentation.
|
||||||
|
|
||||||
|
repo EXTCMD/rsync
|
||||||
|
RW NAME/ = sitaram
|
||||||
|
RW NAME/foo/ = user1
|
||||||
|
R NAME/bar/ = user2
|
||||||
|
RW NAME/baz/.*/.*\.c$ = user3
|
20
contrib/adc/svnserve
Normal file
20
contrib/adc/svnserve
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
#!/usr/bin/perl
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
BEGIN {
|
||||||
|
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};
|
||||||
|
}
|
||||||
|
use gitolite_rc;
|
||||||
|
use gitolite;
|
||||||
|
|
||||||
|
my $cmd = $ENV{SSH_ORIGINAL_COMMAND};
|
||||||
|
|
||||||
|
die "expecting 'svnserve -t', got '$cmd'\n" unless $cmd eq 'svnserve -t';
|
||||||
|
|
||||||
|
$SVNSERVE =~ s/%u/$ENV{GL_USER}/g;
|
||||||
|
exec $SVNSERVE;
|
||||||
|
die "svnserve exec failed\n";
|
|
@ -1,25 +1,22 @@
|
||||||
## admin defined commands
|
## admin defined commands
|
||||||
|
|
||||||
Summary: this document describes a mechanism to allow users controlled access
|
|
||||||
to specific programs or scripts, without giving them full shell access.
|
|
||||||
|
|
||||||
**WARNING**: careless use of this feature, including inadequate review of
|
|
||||||
allowed commands or scripts, could compromise this security and allow users to
|
|
||||||
grant themselves full shell access, accidentally or otherwise.
|
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
In this document:
|
In this document:
|
||||||
|
|
||||||
* <a href="#_background">background</a>
|
* <a href="#_background">background</a>
|
||||||
* <a href="#_setting_it_up">setting it up</a>
|
* <a href="#_details">details</a>
|
||||||
* <a href="#_configuring_ADCs">configuring ADCs</a>
|
* <a href="#_installing_ADCs">installing ADCs</a>
|
||||||
|
* <a href="#_user_invocation">user invocation</a>
|
||||||
|
* <a href="#_checking_authorisation">checking authorisation</a>
|
||||||
|
* <a href="#_checking_arguments">checking arguments</a>
|
||||||
|
* <a href="#_passing_unchecked_arguments">passing unchecked arguments</a>
|
||||||
|
* <a href="#_fake_repos_and_access_control_for_non_git_programs">"fake" repos and access control for non-git programs</a>
|
||||||
* <a href="#_anatomy_of_a_command">anatomy of a command</a>
|
* <a href="#_anatomy_of_a_command">anatomy of a command</a>
|
||||||
* <a href="#_example_uses_and_sample_commands_in_contrib">example uses and sample commands in contrib</a>
|
* <a href="#_example_uses_and_sample_commands_in_contrib_adc_">example uses and sample commands in `contrib/adc`</a>
|
||||||
* <a href="#_fork">fork</a>
|
* <a href="#_fork">fork</a>
|
||||||
* <a href="#_deleting_trashing_repos">deleting/trashing repos</a>
|
* <a href="#_deleting_trashing_repos">deleting/trashing repos</a>
|
||||||
* <a href="#_enable_disable_push_access_temporarily">enable/disable push access temporarily</a>
|
* <a href="#_enable_disable_push_access_temporarily">enable/disable push access temporarily</a>
|
||||||
* <a href="#_bonus_restricted_admin">(bonus) restricted admin</a>
|
|
||||||
* <a href="#_how_this_feature_came_about">how this feature came about</a>
|
* <a href="#_how_this_feature_came_about">how this feature came about</a>
|
||||||
|
|
||||||
----
|
----
|
||||||
|
@ -28,66 +25,115 @@ In this document:
|
||||||
|
|
||||||
### background
|
### background
|
||||||
|
|
||||||
Allowing users to get a shell is a no-no if you're using gitolite, but there
|
The admin-defined commands (ADCs) feature allows controlled access to
|
||||||
are times when you want them to be able to run specific commands or custom
|
specific, "safe", programs or scripts, without giving users full shell access.
|
||||||
scripts that you (the admin) have pre-approved to be "safe". Here's how to
|
|
||||||
enable such commands.
|
|
||||||
|
|
||||||
However, as the warning at the top says, careless use could allow users to
|
**WARNING**: regardless of what you read below, the security of the code in
|
||||||
defeat this security and get a shell. Every command you approve must be
|
the commands or scripts you install as ADCs is **your responsibility**. The
|
||||||
checked to be sure it cannot be compromised.
|
sample ADCs shipped with gitolite (in `contrib/adc`) should be safe enough,
|
||||||
|
but an extra pair of eyes never hurt, so please review before use.
|
||||||
|
|
||||||
To help you with this, gitolite restricts ADCs arguments to only some very
|
<font color="gray">Although this is a generic way to allow pretty much any
|
||||||
safe characters (see `$ADC_CMD_ARGS_PATT` in `src/gitolite_rc.pm`). The code
|
command to be run, most of the examples and sample ADCs pertain to allowing
|
||||||
inside the ADC, however, is *your* responsibility. The sample ADCs shipped
|
users to manage their "own" repos. If that's your use case, please read
|
||||||
with gitolite (in `contrib/adc`) should be OK, but an extra pair of eyes never
|
[doc/wildcard-repositories.mkd][wild] before you continue here.</font>
|
||||||
hurt :-) so please review before installing them.
|
|
||||||
|
|
||||||
<font color="gray">
|
[wild]: http://sitaramc.github.com/gitolite/doc/wildcard-repositories.html
|
||||||
|
|
||||||
Finally, although this is a generic way to allow specific commands to be run,
|
<a name="_details"></a>
|
||||||
most of the examples and sample ADCs pertain to allowing users to manage their
|
|
||||||
"own" repos. If that's your use case, please read
|
|
||||||
[doc/wildcard-repositories.mkd][wild] before you continue here.
|
|
||||||
|
|
||||||
</font>
|
### details
|
||||||
|
|
||||||
<a name="_setting_it_up"></a>
|
<a name="_installing_ADCs"></a>
|
||||||
|
|
||||||
### setting it up
|
#### installing ADCs
|
||||||
|
|
||||||
This can only be setup by someone who has shell access to the server. Edit
|
ADCs can only be installed by someone with shell access to the server; merely
|
||||||
the rc file and update the `$GL_ADC_PATH` variable to point to, say,
|
having push rights to the admin repo is not enough.
|
||||||
`/home/git/bin/adc`. *Nothing happens unless this variable is set and
|
|
||||||
pointing to a directory*. Then put in whatever such commands you create into
|
* edit `~/.gitolite.rc` and set `$GL_ADC_PATH` to a directory that is *not*
|
||||||
that directory. If you have a command called "foo" in that directory, then a
|
in `$PATH`.
|
||||||
user can invoke it by saying:
|
|
||||||
|
* add your "safe" executables to this directory.
|
||||||
|
|
||||||
|
**Warning**: An ADC can hide (or override) gitolite's built-in commands like
|
||||||
|
'info', 'expand', 'setperms', or even 'git-receive-pack' or 'git-upload-pack'!
|
||||||
|
This is by design. So be careful what you name your scripts.
|
||||||
|
|
||||||
|
However, it is perfectly ok, and may even be necessary in some cases, to name
|
||||||
|
them after system executables (like 'rsync').
|
||||||
|
|
||||||
|
<a name="_user_invocation"></a>
|
||||||
|
|
||||||
|
#### user invocation
|
||||||
|
|
||||||
|
If you have a command called "foo" in that directory, then a user can invoke
|
||||||
|
it by saying:
|
||||||
|
|
||||||
ssh git@server foo argument list
|
ssh git@server foo argument list
|
||||||
|
|
||||||
**WARNING: When gitolite takes control, this directory is checked first, and
|
<a name="_checking_authorisation"></a>
|
||||||
if the requested command exists, it is executed. It is therefore quite easy
|
|
||||||
to inadvertently *hide* some of the "official" commands (like "info",
|
|
||||||
"expand", "setperms", etc., or worse, say "git-upload-pack"!) by creating
|
|
||||||
executable files with those names in this directory. So don't do that -- you
|
|
||||||
have been warned!**
|
|
||||||
|
|
||||||
<a name="_configuring_ADCs"></a>
|
#### checking authorisation
|
||||||
|
|
||||||
#### configuring ADCs
|
Once an ADC is installed, *all* users can run it. But sometimes you want only
|
||||||
|
some people to be able to do so.
|
||||||
|
|
||||||
I didn't want to put configuration variables for ADCs also into the main 'rc'
|
While you cannot prevent the ADC from running at all, you can *start* the ADC
|
||||||
file, so I chose to put them in the `adc.common-functions` file instead. Take
|
with code that checks the user's access to *any* arbitrary repo. For example,
|
||||||
a look at it sometime.
|
you can bail out if the user does not have "W" access to the "gitolite-admin"
|
||||||
|
repo, which is an easy way of making sure an ADC is only run by admins.
|
||||||
|
|
||||||
|
See the section on "the anatomy of a command" later for this and many more
|
||||||
|
details.
|
||||||
|
|
||||||
|
<a name="_checking_arguments"></a>
|
||||||
|
|
||||||
|
#### checking arguments
|
||||||
|
|
||||||
|
Gitolite will call an ADC only if the arguments passed to it match a very
|
||||||
|
strict pattern (see `$ADC_CMD_ARGS_PATT` in `src/gitolite_rc.pm`). This
|
||||||
|
reduces the risk of various kinds of shell-meta related compromises.
|
||||||
|
|
||||||
|
<a name="_passing_unchecked_arguments"></a>
|
||||||
|
|
||||||
|
#### passing unchecked arguments
|
||||||
|
|
||||||
|
Some commands need arguments with a broader range of characters than
|
||||||
|
`$ADC_CMD_ARGS_PATT` will allow. As long as you are sure those commands are
|
||||||
|
doing their own argument checking and sanitisation, you can place such
|
||||||
|
commands in `$GL_ADC_PATH/ua` and they will be run with **no checks on the
|
||||||
|
arguments**.
|
||||||
|
|
||||||
|
The "ua" stand for "unchecked arguments". Consider this your last warning ;-)
|
||||||
|
|
||||||
|
<a name="_fake_repos_and_access_control_for_non_git_programs"></a>
|
||||||
|
|
||||||
|
### "fake" repos and access control for non-git programs
|
||||||
|
|
||||||
|
A "fake" repo is a repo that exists in the config file but is specially named
|
||||||
|
(starts with "EXTCMD/") so that gitolite will not create an actual repo on
|
||||||
|
disk for it. It serves as a place holder for different sets of rules.
|
||||||
|
|
||||||
|
If you install the 'rsync' ADC, you can use a fake repo called 'EXTCMD/rsync'
|
||||||
|
to collect a set of rules that specify what user is allowed to read/write what
|
||||||
|
files using the rsync command on his workstation. See `contrib/adc/rsync` for
|
||||||
|
more on this.
|
||||||
|
|
||||||
|
<font color="gray">*Any* non-git program can be similarly access controlled,
|
||||||
|
as long as the *command line* that the client attempts to execute on the
|
||||||
|
server has sufficient information to decide. Protocols where the command line
|
||||||
|
is just one word and everything else happens in the conversation later cannot
|
||||||
|
be helped by this mechanism.</font>
|
||||||
|
|
||||||
<a name="_anatomy_of_a_command"></a>
|
<a name="_anatomy_of_a_command"></a>
|
||||||
|
|
||||||
### anatomy of a command
|
### anatomy of a command
|
||||||
|
|
||||||
You can basically do whatever you want in such a command -- go wild! It's
|
You can do whatever you want in an ADC! It's upto you to check the
|
||||||
upto you to check the permissions of *each* repo that the user is manipulating
|
permissions of *each* repo that the user is manipulating using your ADC --
|
||||||
using your command -- you can `rm -rf $GL_REPO_BASE_ABS` if you like and
|
your code can `rm -rf $GL_REPO_BASE_ABS` if you like and gitolite wouldn't
|
||||||
gitolite wouldn't stop you.
|
stop you.
|
||||||
|
|
||||||
The current directory (`$PWD`) will be set to the `$HOME` of `git@server` (or
|
The current directory (`$PWD`) will be set to the `$HOME` of `git@server` (or
|
||||||
whatever id you're using). It won't be any specific repo, it won't even be
|
whatever id you're using). It won't be any specific repo, it won't even be
|
||||||
|
@ -112,15 +158,9 @@ internal/undocumented/subject to change.
|
||||||
`GL_BINDIR`. I have not tested this in those scenarios, but they probably put
|
`GL_BINDIR`. I have not tested this in those scenarios, but they probably put
|
||||||
`gitolite.pm` somewhere in perl's lib path anyway, so it ought to work].
|
`gitolite.pm` somewhere in perl's lib path anyway, so it ought to work].
|
||||||
|
|
||||||
In addition, all the arguments of the command are also available to you, so
|
You can query ownership and permissions for the current user (which may not
|
||||||
you can define your own command syntaxes. Gitolite checks these arguments to
|
necessarily be the owner). This is done loosely as follows (don't use this
|
||||||
make sure they fit a very conservative pattern (see `$ADC_CMD_ARGS_PATT` in
|
exact code yet though):
|
||||||
`src/gitolite.pm`), so take that into consideration when designing your
|
|
||||||
commands and usage.
|
|
||||||
|
|
||||||
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$GL_BINDIR -Mgitolite -e "cli_repo_rights('reponame')"
|
perl -I$GL_BINDIR -Mgitolite -e "cli_repo_rights('reponame')"
|
||||||
|
|
||||||
|
@ -133,12 +173,12 @@ But that's cumbersome. There's a bash shell function called
|
||||||
`get_rights_and_owner` in `contrib/adc/adc.common-functions` that is much more
|
`get_rights_and_owner` in `contrib/adc/adc.common-functions` that is much more
|
||||||
convenient. See any of the other samples for how to use it.
|
convenient. See any of the other samples for how to use it.
|
||||||
|
|
||||||
If you don't like this, roll your own. If you don't like bash, do the eqvt in
|
If you prefer perl, there is a nicely commented example in
|
||||||
your language of choice.
|
`contrib/adc/get-rights-and-owner.in-perl`.
|
||||||
|
|
||||||
<a name="_example_uses_and_sample_commands_in_contrib"></a>
|
<a name="_example_uses_and_sample_commands_in_contrib_adc_"></a>
|
||||||
|
|
||||||
### example uses and sample commands in contrib
|
### example uses and sample commands in `contrib/adc`
|
||||||
|
|
||||||
<a name="_fork"></a>
|
<a name="_fork"></a>
|
||||||
|
|
||||||
|
@ -197,33 +237,6 @@ Note: please see [this][diswr] for more on this.
|
||||||
|
|
||||||
[diswr]: http://sitaramc.github.com/gitolite/doc/3-faq-tips-etc.html#_disabling_write_access_to_take_backups
|
[diswr]: http://sitaramc.github.com/gitolite/doc/3-faq-tips-etc.html#_disabling_write_access_to_take_backups
|
||||||
|
|
||||||
<a name="_bonus_restricted_admin"></a>
|
|
||||||
|
|
||||||
#### (bonus) restricted admin
|
|
||||||
|
|
||||||
It's rather important to me (and presumably others in the "corporate" world)
|
|
||||||
to separate permission to push to the "gitolite-admin" repo from unrestricted
|
|
||||||
shell access to the server. This issue has been visited often in the past.
|
|
||||||
|
|
||||||
Until now, though, this was binary -- you either had full shell access or none
|
|
||||||
at all. If there were tasks that legitimately needed to be done from the
|
|
||||||
shell on the server, it often meant you had to break that separation or load
|
|
||||||
the few people who did have shell access already.
|
|
||||||
|
|
||||||
Now, however, it is possible to provide scripts to do what you want, and put
|
|
||||||
them in `$GL_ADC_PATH`. `contrib/adc/restrict-admin` is a commented sample --
|
|
||||||
as you can see, it cleverly makes use of the fact that you can now check for
|
|
||||||
the invoking uses access to any repo in the system. In this case it checks if
|
|
||||||
he has "W" access to the gitolite-admin repo, and if he does, allows the
|
|
||||||
script to proceed.
|
|
||||||
|
|
||||||
[Note that this particular use does not require `$GL_WILDREPOS` to be enabled,
|
|
||||||
because it's not using any wildcard repos].
|
|
||||||
|
|
||||||
[xkcd224]: http://xkcd.com/224/
|
|
||||||
[lazy]: http://c2.com/cgi/wiki?LazinessImpatienceHubris
|
|
||||||
[wild]: http://sitaramc.github.com/gitolite/doc/wildcard-repositories.html
|
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
<a name="_how_this_feature_came_about"></a>
|
<a name="_how_this_feature_came_about"></a>
|
||||||
|
@ -242,6 +255,9 @@ resisted the urge to point him to [this][xkcd224], told him that's a great
|
||||||
idea and he should go for it, mentally blessing him for letting me off the
|
idea and he should go for it, mentally blessing him for letting me off the
|
||||||
hook on coding it ;-) [Laziness][lazy] *is* the first virtue you know!
|
hook on coding it ;-) [Laziness][lazy] *is* the first virtue you know!
|
||||||
|
|
||||||
|
[xkcd224]: http://xkcd.com/224/
|
||||||
|
[lazy]: http://c2.com/cgi/wiki?LazinessImpatienceHubris
|
||||||
|
|
||||||
And that was that. For a couple of days.
|
And that was that. For a couple of days.
|
||||||
|
|
||||||
Soon, though, I realised that there could be a pretty big bonus in this for
|
Soon, though, I realised that there could be a pretty big bonus in this for
|
||||||
|
@ -249,4 +265,3 @@ tightly controlled setups, so I went and coded it all anyway. See the section
|
||||||
on "restricted admin" for what's really exciting about this for *me*.
|
on "restricted admin" for what's really exciting about this for *me*.
|
||||||
|
|
||||||
</font>
|
</font>
|
||||||
|
|
||||||
|
|
|
@ -1160,12 +1160,6 @@ sub special_cmd
|
||||||
warn("ignoring illegal username $otheruser\n"), next unless $otheruser =~ $USERNAME_PATT;
|
warn("ignoring illegal username $otheruser\n"), next unless $otheruser =~ $USERNAME_PATT;
|
||||||
report_basic($repo, $otheruser);
|
report_basic($repo, $otheruser);
|
||||||
}
|
}
|
||||||
} elsif ($HTPASSWD_FILE and $cmd eq 'htpasswd') {
|
|
||||||
ext_cmd_htpasswd($HTPASSWD_FILE);
|
|
||||||
} elsif ($RSYNC_BASE and $cmd =~ /^rsync /) {
|
|
||||||
ext_cmd_rsync($GL_CONF_COMPILED, $RSYNC_BASE, $cmd);
|
|
||||||
} elsif ($SVNSERVE and $cmd eq 'svnserve -t') {
|
|
||||||
ext_cmd_svnserve($SVNSERVE);
|
|
||||||
} else {
|
} else {
|
||||||
# if the user is allowed a shell, just run the command
|
# if the user is allowed a shell, just run the command
|
||||||
log_it();
|
log_it();
|
||||||
|
@ -1208,88 +1202,21 @@ sub shell_out {
|
||||||
|
|
||||||
sub try_adc {
|
sub try_adc {
|
||||||
my ($cmd, @args) = split ' ', $ENV{SSH_ORIGINAL_COMMAND};
|
my ($cmd, @args) = split ' ', $ENV{SSH_ORIGINAL_COMMAND};
|
||||||
|
die "I don't like $cmd\n" if $cmd =~ /\.\./;
|
||||||
|
|
||||||
|
# try the default (strict arguments) version first
|
||||||
if (-x "$GL_ADC_PATH/$cmd") {
|
if (-x "$GL_ADC_PATH/$cmd") {
|
||||||
die "I don't like $cmd\n" if $cmd =~ /\.\./;
|
|
||||||
# yes this is rather strict, sorry.
|
# yes this is rather strict, sorry.
|
||||||
do { die "I don't like $_\n" unless $_ =~ $ADC_CMD_ARGS_PATT and $_ !~ m(\.\./) } for ($cmd, @args);
|
do { die "I don't like $_\n" unless $_ =~ $ADC_CMD_ARGS_PATT and $_ !~ m(\.\./) } for ($cmd, @args);
|
||||||
log_it("$GL_ADC_PATH/$ENV{SSH_ORIGINAL_COMMAND}");
|
log_it("$GL_ADC_PATH/$ENV{SSH_ORIGINAL_COMMAND}");
|
||||||
exec("$GL_ADC_PATH/$cmd", @args);
|
exec("$GL_ADC_PATH/$cmd", @args);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
# ----------------------------------------------------------------------------
|
# now the "ua" (unrestricted/unchecked arguments) version
|
||||||
# external command helper: rsync
|
if (-x "$GL_ADC_PATH/ua/$cmd") {
|
||||||
# ----------------------------------------------------------------------------
|
log_it("$GL_ADC_PATH/ua/$ENV{SSH_ORIGINAL_COMMAND}");
|
||||||
|
exec("$GL_ADC_PATH/ua/$cmd", @args);
|
||||||
sub ext_cmd_rsync
|
}
|
||||||
{
|
|
||||||
my ($GL_CONF_COMPILED, $RSYNC_BASE, $cmd) = @_;
|
|
||||||
|
|
||||||
# test the command patterns; reject if they don't fit. Rsync sends
|
|
||||||
# commands that looks like one of these to the server (the first one is
|
|
||||||
# for a read, the second for a write)
|
|
||||||
# rsync --server --sender -some.flags . some/path
|
|
||||||
# rsync --server -some.flags . some/path
|
|
||||||
|
|
||||||
die "bad rsync command: $cmd"
|
|
||||||
unless $cmd =~ /^rsync --server( --sender)? -[\w.]+(?: --(?:delete|partial))* \. (\S+)$/;
|
|
||||||
my $perm = "W";
|
|
||||||
$perm = "R" if $1;
|
|
||||||
my $path = $2;
|
|
||||||
die "I dont like some of the characters in $path\n" unless $path =~ $REPONAME_PATT;
|
|
||||||
# XXX make a better pattern for this if people complain ;-)
|
|
||||||
die "I dont like absolute paths in $cmd\n" if $path =~ /^\//;
|
|
||||||
die "I dont like '..' paths in $cmd\n" if $path =~ /\.\./;
|
|
||||||
|
|
||||||
# ok now check if we're permitted to execute a $perm action on $path
|
|
||||||
# (taken as a refex) using rsync.
|
|
||||||
|
|
||||||
check_access('EXTCMD/rsync', "NAME/$path", $perm);
|
|
||||||
# that should "die" if there's a problem
|
|
||||||
|
|
||||||
wrap_chdir($RSYNC_BASE);
|
|
||||||
log_it();
|
|
||||||
exec $ENV{SHELL}, "-c", $ENV{SSH_ORIGINAL_COMMAND};
|
|
||||||
}
|
|
||||||
|
|
||||||
# ----------------------------------------------------------------------------
|
|
||||||
# external command helper: htpasswd
|
|
||||||
# ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
sub ext_cmd_htpasswd
|
|
||||||
{
|
|
||||||
my $HTPASSWD_FILE = shift;
|
|
||||||
|
|
||||||
die "$HTPASSWD_FILE doesn't exist or is not writable\n" unless -w $HTPASSWD_FILE;
|
|
||||||
$|++;
|
|
||||||
print <<EOFhtp;
|
|
||||||
Please type in your new htpasswd at the prompt. You only have to type it once.
|
|
||||||
|
|
||||||
NOTE THAT THE PASSWORD WILL BE ECHOED, so please make sure no one is
|
|
||||||
shoulder-surfing, and make sure you clear your screen as well as scrollback
|
|
||||||
history after you're done (or close your terminal instance).
|
|
||||||
|
|
||||||
EOFhtp
|
|
||||||
print "new htpasswd:";
|
|
||||||
|
|
||||||
my $password = <>;
|
|
||||||
$password =~ s/[\n\r]*$//;
|
|
||||||
die "empty passwords are not allowed\n" unless $password;
|
|
||||||
my $rc = system("htpasswd", "-mb", $HTPASSWD_FILE, $ENV{GL_USER}, $password);
|
|
||||||
die "htpasswd command seems to have failed with $rc return code...\n" if $rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
# ----------------------------------------------------------------------------
|
|
||||||
# external command helper: svnserve
|
|
||||||
# ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
sub ext_cmd_svnserve
|
|
||||||
{
|
|
||||||
my $SVNSERVE = shift;
|
|
||||||
|
|
||||||
$SVNSERVE =~ s/%u/$ENV{GL_USER}/g;
|
|
||||||
exec $SVNSERVE;
|
|
||||||
die "svnserve exec failed\n";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
# - one env var, SSH_ORIGINAL_COMMAND, containing the command
|
# - one env var, SSH_ORIGINAL_COMMAND, containing the command
|
||||||
# - command typically: git-(receive|upload)-pack 'reponame(.git)?'
|
# - command typically: git-(receive|upload)-pack 'reponame(.git)?'
|
||||||
# - special gitolite commands: info, expand, (get|set)(perms|desc)
|
# - special gitolite commands: info, expand, (get|set)(perms|desc)
|
||||||
# - special non-gitolite commands: rsync, svnserve, htpasswd
|
|
||||||
# - other commands: anything in $GL_ADC_PATH if defined (see rc file)
|
# - other commands: anything in $GL_ADC_PATH if defined (see rc file)
|
||||||
#
|
#
|
||||||
# (smart) http mode
|
# (smart) http mode
|
||||||
|
|
|
@ -2,6 +2,11 @@
|
||||||
cd $TESTDIR
|
cd $TESTDIR
|
||||||
$TESTDIR/rollback || die "rollback failed"
|
$TESTDIR/rollback || die "rollback failed"
|
||||||
|
|
||||||
|
rm -rf $ADC_PATH
|
||||||
|
mkdir $ADC_PATH || die "mkdir $ADC_PATH failed"
|
||||||
|
cp ../contrib/adc/* $ADC_PATH
|
||||||
|
echo "\$GL_ADC_PATH = '$ADC_PATH';" | addrc
|
||||||
|
|
||||||
runremote rm -rf /tmp/rsyncbase
|
runremote rm -rf /tmp/rsyncbase
|
||||||
runremote mkdir /tmp/rsyncbase
|
runremote mkdir /tmp/rsyncbase
|
||||||
editrc REPO_UMASK 0022
|
editrc REPO_UMASK 0022
|
||||||
|
|
Loading…
Reference in a new issue