(IMPORTANT; read this in full) no more "wildrepos"

The wildrepos branch has been merged into master, and deleted.  It will no
longer exist as a separate branch.  Instead, a new variable
called $GL_WILDREPOS has been added which acts as a switch; when
off (which is the default), many wildrepos features are disabled.
(the "C" permissions, and the getperms (etc.) commands mainly).

Important: if you are using wildrepos, please set "$GL_WILDREPOS = 1;" in
the RC file when you upgrade to this version (or just before you do the
upgrade).
This commit is contained in:
Sitaram Chamarty 2010-02-05 16:00:47 +05:30
parent fc0b627f55
commit 388f4d873d
7 changed files with 82 additions and 30 deletions

View file

@ -86,10 +86,7 @@ detail [here][gsdiff].
### security ### security
Due to the environment in which this was created and the need it fills, I Due to the environment in which this was created and the need it fills, I
consider this a "security" program, albeit a very modest one. The code is consider this a "security" program, albeit a very modest one.
very small and easily reviewable -- the 2 programs that actually control
access when a user logs in total about 220 lines of code (about 90 lines
according to "sloccount").
For the first person to find a security hole in it, defined as allowing a For the first person to find a security hole in it, defined as allowing a
normal user (not the gitolite admin) to read a repo, or write/rewind a ref, normal user (not the gitolite admin) to read a repo, or write/rewind a ref,
@ -99,10 +96,10 @@ or in Unix, perl, shell, etc.)... well I can't afford 1000 USD rewards like
djb, so you'll have to settle for 1000 INR (Indian Rupees) as a "token" prize djb, so you'll have to settle for 1000 INR (Indian Rupees) as a "token" prize
:-) :-)
Update 2010-01-31: this security promise does not apply if you enable any of However, there are a few optional features (which must be explicitly enabled
the external command helpers (like rsync). It's probably quite secure, but I in the RC file) where I just haven't had the time to reason about security
just haven't thought about it enough to be able to make such promises, like I thoroughly enough. Please read the comments in `conf/example.gitolite.rc` for
can for the rest of "master". details, looking for the word "security".
---- ----

View file

@ -108,6 +108,26 @@ $GIT_PATH="";
# -------------------------------------- # --------------------------------------
# ----------------------------------------------------------------------
# SECURITY SENSITIVE SETTINGS
#
# Settings below this point may have security implications. That
# usually means that I have not thought hard enough about all the
# possible ways to crack security if these settings are enabled.
# Please see details on each setting for specifics, if any.
# ----------------------------------------------------------------------
# --------------------------------------
# EXTERNAL COMMAND HELPER -- HTPASSWD
# security note: runs an external command (htpasswd) with specific arguments,
# including a user-chosen "password".
# if you want to enable the "htpasswd" command, give this the absolute path to # if you want to enable the "htpasswd" command, give this the absolute path to
# whatever file apache (etc) expect to find the passwords in. # whatever file apache (etc) expect to find the passwords in.
@ -118,7 +138,10 @@ $HTPASSWD_FILE = "";
# -------------------------------------- # --------------------------------------
# EXTERNAL COMMAND HELPER -- RSYNC # EXTERNAL COMMAND HELPER -- RSYNC
#
# security note: runs an external command (rsync) with specific arguments, all
# presumably filled in correctly by the client-side rsync.
# base path of all the files that are accessible via rsync. Must be an # base path of all the files that are accessible via rsync. Must be an
# absolute path. Leave it undefined or set to the empty string to disable the # absolute path. Leave it undefined or set to the empty string to disable the
# rsync helper. # rsync helper.
@ -126,6 +149,21 @@ $RSYNC_BASE = "";
# $RSYNC_BASE = "/home/git/up-down"; # $RSYNC_BASE = "/home/git/up-down";
# $RSYNC_BASE = "/tmp/up-down"; # $RSYNC_BASE = "/tmp/up-down";
# --------------------------------------
# ALLOW REPO CONFIG TO USE WILDCARDS
# security note: this used to in a separate "wildrepos" branch. You can
# create repositories based on wild cards, give "ownership" to the specific
# user who created it, allow him/her to hand out R and RW permissions to other
# users to collaborate, etc. This is powerful stuff, and I've made it as
# secure as I can, but it hasn't had the kind of rigorous line-by-line
# analysis that the old "master" branch had.
# This has now been rolled into master, with all the functionality gated by
# this variable. Set this to 1 if you want to enable the wildrepos features.
# Please see doc/4-wildcard-repositories.mkd for details.
# $GL_WILDREPOS = 0;
# -------------------------------------- # --------------------------------------
# per perl rules, this should be the last line in such a file: # per perl rules, this should be the last line in such a file:
1; 1;

View file

@ -149,7 +149,7 @@ plain "git archive", because the Makefile adds a file called
git clone git://sitaramc.indefero.net/sitaramc/gitolite.git git clone git://sitaramc.indefero.net/sitaramc/gitolite.git
cd gitolite cd gitolite
make master.tar make master.tar
# or maybe "make wildrepos.tar" or "make pu.tar" # or maybe "make pu.tar"
<a name="diff"></a> <a name="diff"></a>
@ -626,8 +626,7 @@ per-repo "gitconfig" settings. Please see `doc/2-admin.mkd` and
#### repos named with wildcards #### repos named with wildcards
**This feature only exists in the "wildrepos" branch!** Please see Please see `doc/4-wildcard-repositories.mkd` for all the details.
`doc/4-wildcard-repositories.mkd` for all the details.
#### access control for external commands #### access control for external commands

View file

@ -2,15 +2,14 @@
***IMPORTANT NOTE***: ***IMPORTANT NOTE***:
This branch contains features that are likely to be much more brittle than the This feature may be somewhat "brittle" in terms of security. Creating
"master" branch. Creating repositories based on wild cards, giving repositories based on wild cards, giving "ownership" to the specific user who
"ownership" to the specific user who created it, allowing him/her to hand out created it, allowing him/her to hand out R and RW permissions to other users
R and RW permissions to other users to collaborate, all these are possible. to collaborate, all these are possible. And any of these could have a bug in
And any of these could have a bug in it. it. I haven't found any yet, but that doesn't mean there aren't any.
"Brittle" also means some features in "master" may not work here. For Also, there are some limitations. For example, you cannot specify gitconfig
example, you cannot specify gitconfig values for a wildcard repo; it only values for a wildcard repo; it only works for actual repos.
works for actual repos.
There may be other such missing features. Sometimes it's just not possible to There may be other such missing features. Sometimes it's just not possible to
make it work. Or it may be cumbersome enough that unless there are *no* make it work. Or it may be cumbersome enough that unless there are *no*
@ -25,7 +24,8 @@ In this document:
* wildcard repos without creater name in them * wildcard repos without creater name in them
* side-note: line-anchored regexes * side-note: line-anchored regexes
* contrast with refexes * contrast with refexes
* handing out rights to wildcard-matached repos * handing out rights to wildcard-matched repos
* setting a gitweb description for a wildcard-matched repo
* reporting * reporting
* other issues and discussion * other issues and discussion
@ -121,7 +121,7 @@ actually push such a branch! You can anchor it if you really care, by using
`master$` instead of `master`, but anchoring is *not* the default for `master$` instead of `master`, but anchoring is *not* the default for
refexes.] refexes.]
### Handing out rights to wildcard-matached repos ### Handing out rights to wildcard-matched repos
In the examples above, we saw two special "user" names: READERS and WRITERS. In the examples above, we saw two special "user" names: READERS and WRITERS.
The permissions they have are controlled by the config file, but ***who is The permissions they have are controlled by the config file, but ***who is
@ -166,7 +166,12 @@ The following points are important:
* whoever you specify as "R" will match the special user READERS. "RW" will * whoever you specify as "R" will match the special user READERS. "RW" will
match WRITERS. match WRITERS.
### Reporting ### setting a gitweb description for a wildcard-matched repo
Similar to the getperm/setperm commands, there are the getdesc/setdesc
commands, thanks to Teemu.
### reporting
Remember the cool stuff you see when you just do `ssh git@server` (grep for Remember the cool stuff you see when you just do `ssh git@server` (grep for
"myrights" in `doc/3-faq-tips-etc.mkd` if you forgot, or go [here][mr]). "myrights" in `doc/3-faq-tips-etc.mkd` if you forgot, or go [here][mr]).
@ -177,7 +182,11 @@ This still works, except the format is a little more compressed to accommodate
a new column (at the start) for "C" permissions, which indicate that you are a new column (at the start) for "C" permissions, which indicate that you are
allowed to *create* repos matching that pattern. allowed to *create* repos matching that pattern.
### Other issues and discussion In addition, there is also the "expand" command, which takes any regex pattern
and returns you a list of all wildcard-created repos that you have access to
which fit that pattern.
### other issues and discussion
* *what if the repo name being pushed matches more than one pattern*? * *what if the repo name being pushed matches more than one pattern*?

View file

@ -33,7 +33,8 @@ our $USERNAME_PATT=qr(^\@?[0-9a-zA-Z][0-9a-zA-Z._\@+-]*$); # very simple patter
# same as REPONAME, plus some common regex metas # same as REPONAME, plus some common regex metas
our $REPOPATT_PATT=qr(^\@?[0-9a-zA-Z][\\^.$|()[\]*+?{}0-9a-zA-Z._\@/-]*$); our $REPOPATT_PATT=qr(^\@?[0-9a-zA-Z][\\^.$|()[\]*+?{}0-9a-zA-Z._\@/-]*$);
our $REPO_UMASK; # these come from the RC file
our ($REPO_UMASK, $GL_WILDREPOS);
our %repos; our %repos;
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
@ -134,6 +135,8 @@ sub new_repo
my ($repo, $hooks_dir, $creater) = @_; my ($repo, $hooks_dir, $creater) = @_;
umask($REPO_UMASK); umask($REPO_UMASK);
die "wildrepos disabled, can't set creater $creater on new repo $repo\n"
if $creater and not $GL_WILDREPOS;
system("mkdir", "-p", "$repo.git") and die "$ABRT mkdir $repo.git failed: $!\n"; system("mkdir", "-p", "$repo.git") and die "$ABRT mkdir $repo.git failed: $!\n";
# erm, note that's "and die" not "or die" as is normal in perl # erm, note that's "and die" not "or die" as is normal in perl
@ -226,6 +229,7 @@ sub parse_acl
# please update that also if the interface or the env vars change # please update that also if the interface or the env vars change
my ($GL_CONF_COMPILED, $repo, $c, $r, $w) = @_; my ($GL_CONF_COMPILED, $repo, $c, $r, $w) = @_;
$c = $r = $w = "NOBODY" unless $GL_WILDREPOS;
# void $r if same as $w (otherwise "readers" overrides "writers"; this is # void $r if same as $w (otherwise "readers" overrides "writers"; this is
# the same problem that needed a sort sub for the Dumper in the compile # the same problem that needed a sort sub for the Dumper in the compile
@ -251,6 +255,8 @@ sub parse_acl
return unless $repo; return unless $repo;
return $ENV{GL_REPOPATT} = "" if $repos{$repo}; return $ENV{GL_REPOPATT} = "" if $repos{$repo};
# didn't find it, but wild is off? too bad, die!!! muahahaha
die "$repo not found in compiled config\n" unless $GL_WILDREPOS;
# didn't find $repo in %repos, so it must be a wildcard-match case # didn't find $repo in %repos, so it must be a wildcard-match case
my @matched = grep { $repo =~ /^$_$/ } sort keys %repos; my @matched = grep { $repo =~ /^$_$/ } sort keys %repos;

View file

@ -24,7 +24,7 @@ use warnings;
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
# these are set by the "rc" file # 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); our ($GL_LOGT, $GL_CONF_COMPILED, $REPO_BASE, $GIT_PATH, $REPO_UMASK, $GL_ADMINDIR, $RSYNC_BASE, $HTPASSWD_FILE, $GL_WILDREPOS);
# and these are set by gitolite.pm # and these are set by gitolite.pm
our ($R_COMMANDS, $W_COMMANDS, $REPONAME_PATT, $REPOPATT_PATT); our ($R_COMMANDS, $W_COMMANDS, $REPONAME_PATT, $REPOPATT_PATT);
our %repos; our %repos;
@ -110,6 +110,7 @@ my $CUSTOM_COMMANDS=qr/^\s*(expand|(get|set)(perms|desc))\s/;
# commands is sort of a dead end for normal (git) processing # commands is sort of a dead end for normal (git) processing
if ($ENV{SSH_ORIGINAL_COMMAND} =~ $CUSTOM_COMMANDS) { if ($ENV{SSH_ORIGINAL_COMMAND} =~ $CUSTOM_COMMANDS) {
die "wildrepos disabled, sorry\n" unless $GL_WILDREPOS;
my $cmd = $ENV{SSH_ORIGINAL_COMMAND}; my $cmd = $ENV{SSH_ORIGINAL_COMMAND};
my ($verb, $repo) = ($cmd =~ /^\s*(\S+)\s+\/?(.*?)(?:.git)?$/); my ($verb, $repo) = ($cmd =~ /^\s*(\S+)\s+\/?(.*?)(?:.git)?$/);
if ($repo =~ $REPONAME_PATT and $verb =~ /getperms|setperms/) { if ($repo =~ $REPONAME_PATT and $verb =~ /getperms|setperms/) {
@ -171,8 +172,8 @@ if ( -d "$repo_base_abs/$repo.git" ) {
} else { } else {
&parse_acl($GL_CONF_COMPILED, $repo, $user, $user, $user); &parse_acl($GL_CONF_COMPILED, $repo, $user, $user, $user);
# auto-vivify new repo if you have C access # auto-vivify new repo if you have C access (and wildrepos is on)
if ( $repos{$repo}{C}{$user} || $repos{$repo}{C}{'@all'} ) { if ( $GL_WILDREPOS and $repos{$repo}{C}{$user} || $repos{$repo}{C}{'@all'} ) {
wrap_chdir("$repo_base_abs"); wrap_chdir("$repo_base_abs");
new_repo($repo, "$GL_ADMINDIR/src/hooks", $user); new_repo($repo, "$GL_ADMINDIR/src/hooks", $user);
wrap_chdir($ENV{HOME}); wrap_chdir($ENV{HOME});

View file

@ -61,7 +61,7 @@ $Data::Dumper::Sortkeys = sub { return [ reverse sort keys %{$_[0]} ]; };
open STDOUT, ">", "/dev/null" if (@ARGV and shift eq '-q'); open STDOUT, ">", "/dev/null" if (@ARGV and shift eq '-q');
# these are set by the "rc" file # 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, $SHELL_USERS); our ($GL_ADMINDIR, $GL_CONF, $GL_KEYDIR, $GL_CONF_COMPILED, $REPO_BASE, $REPO_UMASK, $PROJECTS_LIST, $GIT_PATH, $SHELL_USERS, $GL_WILDREPOS);
# and these are set by gitolite.pm # and these are set by gitolite.pm
our ($REPONAME_PATT, $REPOPATT_PATT, $USERNAME_PATT, $AUTH_COMMAND, $AUTH_OPTIONS, $ABRT, $WARN); our ($REPONAME_PATT, $REPOPATT_PATT, $USERNAME_PATT, $AUTH_COMMAND, $AUTH_OPTIONS, $ABRT, $WARN);
@ -133,7 +133,8 @@ sub expand_list
for my $item (@list) for my $item (@list)
{ {
die "$ABRT bad user or repo name $item\n" unless $item =~ $REPOPATT_PATT or $item =~ $USERNAME_PATT; die "$ABRT bad user or repo name $item\n"
unless ($GL_WILDREPOS ? $item =~ $REPOPATT_PATT : $item =~ $REPONAME_PATT) or $item =~ $USERNAME_PATT;
if ($item =~ /^@/) # nested group if ($item =~ /^@/) # nested group
{ {
die "$ABRT undefined group $item\n" unless $groups{$item}; die "$ABRT undefined group $item\n" unless $groups{$item};
@ -206,6 +207,7 @@ sub parse_conf_file
my $perms = $1; my $perms = $1;
my @refs; @refs = split(' ', $2) if $2; my @refs; @refs = split(' ', $2) if $2;
my @users = split ' ', $3; my @users = split ' ', $3;
die "wildrepos disabled, cant use 'C' in config\n" if $perms eq 'C' and not $GL_WILDREPOS;
# if no ref is given, this PERM applies to all refs # if no ref is given, this PERM applies to all refs
@refs = qw(refs/.*) unless @refs; @refs = qw(refs/.*) unless @refs;