diff options
-rw-r--r-- | README.Developer | 8 | ||||
-rw-r--r-- | README.Gentoo | 42 | ||||
-rwxr-xr-x | dist.sh | 31 | ||||
-rwxr-xr-x | src/commands/sshkeys-lint | 4 | ||||
-rwxr-xr-x | src/gitolite-shell | 2 | ||||
-rw-r--r-- | src/lib/Gitolite/Conf/Load.pm | 40 | ||||
-rw-r--r-- | src/lib/Gitolite/Rc.pm | 16 | ||||
-rw-r--r-- | src/lib/Gitolite/Setup.pm | 3 | ||||
-rwxr-xr-x | src/triggers/post-compile/ssh-authkeys | 79 | ||||
-rwxr-xr-x | src/triggers/post-compile/ssh-authkeys-split | 4 |
10 files changed, 224 insertions, 5 deletions
diff --git a/README.Developer b/README.Developer new file mode 100644 index 0000000..913fe8a --- /dev/null +++ b/README.Developer @@ -0,0 +1,8 @@ +git remote set-url --push origin git+ssh://git@git.overlays.gentoo.org/proj/gitolite-gentoo.git +git remote add upstream-g2 git://github.com/sitaramc/gitolite.git --no-tags -t g2 +git remote add upstream-g3 git://github.com/sitaramc/gitolite.git --no-tags -t master +git fetch upstream-g2 +git fetch upstream-g3 +git branch -t -l upstream-g2 upstream-g2/g2 +git branch -t -l upstream-g3 upstream-g3/master +git branch -t -l master-g2 origin/master-g2 diff --git a/README.Gentoo b/README.Gentoo new file mode 100644 index 0000000..50d9c4b --- /dev/null +++ b/README.Gentoo @@ -0,0 +1,42 @@ +gitolite-gentoo: + +Features: + SSH-Keys behavior + Also allow comments + Add the ability to preserve key options like from="1.1.1.1" (AUTH_OPTIONS_PRESERVE) + Some kind of key validation + + Additional metadata can be provided to be passed to the gitolite environment + This can be useful if you want to pass additional metadata to the hooks, + for e.g. cia.vc or other services. + You can set a list of allow/parsed variables (GL_METADATA) and a list of + *required* variables (GL_METADATA_REQUIRED). + + Example: + .gitolite.rc: + %RC = ( + ... + GL_METADATA => [ 'realname-ascii', 'cia-user' ], + GL_METADATA_REQUIRED => [ 'realname-ascii', 'cia-user' ], + ... + ) + + keydir/$user.pub: + # realname-ascii: foo bar + # cia-user: foo + ssh-rsa ... user@host + + The hooks can then use $realname_ascii and $cia_user from the + environment. + Each '-' (dash) will be replaced by an '_' (underscore). + + If you want other metadata or information from the .pub files, you + should look at the base Gitolite v3 documentation for "distinguishing + one key from another" and enable the '--key-file-name' option to + 'ssh-authkeys'. + +Non-Features: + SSH-Keys + In Gitolite-Gentoo v2 we supported multiple keys in a single file. This + support is discontinued. You should migrate to one key per user; we are + using $EMAIL@$N for Gentoo in future. @@ -0,0 +1,31 @@ +#!/bin/bash + +branch=$(git rev-parse --abbrev-ref HEAD) + +if [ "${branch}" = "master-g2" ]; then + # GL2 + export GL_BINDIR="$(pwd)/src" + export GL_RC="$(pwd)/conf/example.gitolite.rc" + + dirs="conf/ hooks/ src/" +else + # GL3 + export GL_LIBDIR="$(pwd)/src" + + dirs="src/" + perl_opts="-Isrc/lib/" +fi + +if [ -z "${1}" ]; then + tag=$(git tag | grep '^gitolite-gentoo-.*$' | sort -r | head -n 1) +else + tag=$1 +fi + +for foo in $(find ${dirs} -type f); do + [ "${foo:$((${#foo}-3))}" = ".pm" ] && { perl $perl_opts -c $foo; continue; } + [ -n "$(grep -m 1 '^#!/usr/bin/perl' $foo)" ] && { perl $perl_opts -c $foo; continue; } +done + +git archive --prefix=${tag}/ --format tar $branch > ${tag}.tar +bzip2 -9 ${tag}.tar diff --git a/src/commands/sshkeys-lint b/src/commands/sshkeys-lint index 3f07b13..b67e77d 100755 --- a/src/commands/sshkeys-lint +++ b/src/commands/sshkeys-lint @@ -120,7 +120,9 @@ sub check { sub user { my $user = ''; - $user ||= "user $1" if /^command=.*gitolite-shell (.*?)"/; + # Remove all other options + s/^(((no-)?((agent|port|x11)-forwarding|pty|cert-authority|user-rc|(environment|from|permitopen|principals|tunnel)="[^"]+")),)+//g; + $user ||= "user $1" if /^command="[^"]*gitolite-shell (.*?)"/; $user ||= "unknown command" if /^command/; $user ||= "shell access" if /$KEYTYPE_REGEX/; diff --git a/src/gitolite-shell b/src/gitolite-shell index 072e0ff..e8efe3d 100755 --- a/src/gitolite-shell +++ b/src/gitolite-shell @@ -114,7 +114,7 @@ sub main { my $aa = ( $verb =~ 'upload' ? 'R' : 'W' ); # set up env vars from options set for this repo - env_options($repo); + env_options($repo, $user); # auto-create? if ( repo_missing($repo) and access( $repo, $user, '^C', 'any' ) !~ /DENIED/ ) { diff --git a/src/lib/Gitolite/Conf/Load.pm b/src/lib/Gitolite/Conf/Load.pm index 7dea259..57d1396 100644 --- a/src/lib/Gitolite/Conf/Load.pm +++ b/src/lib/Gitolite/Conf/Load.pm @@ -234,7 +234,47 @@ sub env_options { $ENV{ "GL_OPTION_" . $1 } = $v; } + # The user find block might return, so we should switch directory now. + # GL_ADMIN_BASE should also be absolute chdir($cwd); + + my $user = shift; + if($user) { + my @pubkeys; + # ssh-authkeys --key-file-name passes the actual pubkey file! + if(defined($ARGV[0])) { + my $f = $rc{GL_ADMIN_BASE}.'/'.$ARGV[0]; + push @pubkeys, $f if -f $f; + } + # This catches the base 'user.pub', 'user@host.pub', exact matches + push @pubkeys, `find $rc{GL_ADMIN_BASE}/keydir -type f -name "${user}.pub"`; + # this catches 'user@host@NN.pub' variant, for email-named users with multiple keys + push @pubkeys, `find $rc{GL_ADMIN_BASE}/keydir -type f -name "${user}@*.pub"` if $user =~ m/@/; + chomp(@pubkeys); + return if $#pubkeys <= 0; + + # If they have multiple pubkeys, they SHOULD be the same, but we check + # anyway. + foreach my $pubkey (@pubkeys) { + my $pk_fh = _open('<', $pubkey); + while(defined(my $line = <$pk_fh>)) { + chomp($line); + next if $line !~ m/^\s*#/; + $line =~ s/^\s*#\s*//; + + my ($variable, $value) = split(/:\s*/, $line, 2); + + if(grep(/^\Q${variable}\E$/, @{$rc{'GL_METADATA'}})) { + if(length($value) > 0) { + $variable =~ s/-/_/g; + _die "Metadata $variable has conflicted values: '$ENV{$variable}' vs '$value'" if(defined($ENV{$variable}) and $ENV{$variable} ne $value); + $ENV{$variable} = $value; + } + } + } + close($pk_fh); + } + } } sub option { diff --git a/src/lib/Gitolite/Rc.pm b/src/lib/Gitolite/Rc.pm index 41996fb..5a0e83d 100644 --- a/src/lib/Gitolite/Rc.pm +++ b/src/lib/Gitolite/Rc.pm @@ -308,7 +308,12 @@ sub trigger { # name, so setup env from options require Gitolite::Conf::Load; Gitolite::Conf::Load->import('env_options'); - env_options( $_[0] ) if $_[0]; + if($_[0] && $_[1]) { + env_options($_[0], $_[1]); + } + elsif($_[0]) { + env_options($_[0]); + } if ( exists $rc{$rc_section} ) { if ( ref( $rc{$rc_section} ) ne 'ARRAY' ) { @@ -536,6 +541,15 @@ __DATA__ # enable caching (currently only Redis). PLEASE RTFM BEFORE USING!!! # CACHE => 'Redis', + # Define which metadata variables shall be exported to the gitolite + # environment. + # Those variables can be used in hooks, e.g. for cia.vc + # A pubkey file might contain one or more of those variable. + # They can be defined by e.g:"# git-username: idl0r" + # Each '-' (dash) will be replaced by an '_' (underscore). + #GL_METADATA => [ "git-username", "git-email", "git-realname", "git-realname-ascii", "cia-vc-username" ], + #GL_METADATA_REQUIRED => [ "git-username", "git-email", "git-realname" ], + # ------------------------------------------------------------------ # rc variables used by various features diff --git a/src/lib/Gitolite/Setup.pm b/src/lib/Gitolite/Setup.pm index 8ad5d34..69a9be0 100644 --- a/src/lib/Gitolite/Setup.pm +++ b/src/lib/Gitolite/Setup.pm @@ -92,7 +92,8 @@ sub args { if ($pubkey) { $pubkey =~ /\.pub$/ or _die "'$pubkey' name does not end in .pub"; tsh_try("cat $pubkey") or _die "'$pubkey' not a readable file"; - tsh_lines() == 1 or _die "'$pubkey' must have exactly one line"; + my @lines = grep {!/^(#|$)/} tsh_lines(); + scalar(@lines) == 1 or _die "'$pubkey' must have exactly one non-empty, non-comment line"; tsh_try("ssh-keygen -l -f $pubkey") or _die "'$pubkey' does not seem to be a valid ssh pubkey file"; $admin = $pubkey; diff --git a/src/triggers/post-compile/ssh-authkeys b/src/triggers/post-compile/ssh-authkeys index cd59aec..a95018d 100755 --- a/src/triggers/post-compile/ssh-authkeys +++ b/src/triggers/post-compile/ssh-authkeys @@ -8,6 +8,11 @@ use lib $ENV{GL_LIBDIR}; use Gitolite::Rc; use Gitolite::Common; +# To parse the pubkeyfile with options etc. +# 0.16 adds ecdsa keys +# 0.17 adds ed25519 keys +use Net::SSH::AuthorizedKeysFile 0.17; + $|++; # best called via 'gitolite trigger POST_COMPILE'; other modes at your own @@ -32,6 +37,7 @@ my $akdir = "$ENV{HOME}/.ssh"; my $akfile = "$ENV{HOME}/.ssh/authorized_keys"; my $glshell = $rc{GL_BINDIR} . "/gitolite-shell"; my $auth_options = auth_options(); +my $auth_options_preserve = auth_options_preserve(); sanity(); @@ -55,7 +61,7 @@ for my $f (@pubkeys) { } else { $seen{$fp} = $f; } - push @gl_keys, grep { /./ } optionise($f); + @gl_keys = (@gl_keys, optionise_gentoo($f)); } # dump it out @@ -92,6 +98,13 @@ sub auth_options { return $auth_options; } +sub auth_options_preserve { + my $auth_options_preserve = $rc{AUTH_OPTIONS_PRESERVE}; + $auth_options_preserve ||= "from"; + + return $auth_options_preserve; +} + sub fp { # input: see below # output: a (list of) FPs @@ -124,6 +137,7 @@ sub fp_line { return $fp; } +# NOTE: optionise() is not used in gitolite-gentoo sub optionise { my $f = shift; @@ -140,3 +154,66 @@ sub optionise { return "command=\"$glshell $user" . ( $kfn ? " $f" : "" ) . "\",$auth_options $line[0]"; } +sub optionise_gentoo { + my $f = shift; + + my $user = $f; + $user =~ s(.*/)(); # foo/bar/baz.pub -> baz.pub + $user =~ s/(\@[^.]+)?\.pub$//; # baz.pub, baz@home.pub -> baz + + # Metadata check + if(exists($rc{"GL_METADATA_REQUIRED"}) && @{$rc{"GL_METADATA_REQUIRED"}} gt 0) { + my @not_met = @{$rc{"GL_METADATA_REQUIRED"}}; + my $pubkey = _open('<', $f); + while(defined(my $line = <$pubkey>)) { + chomp($line); + next if $line !~ m/^\s*#\s*[-a-zA-Z0-9_]+:/; + $line =~ s/^\s*#\s*//; + + my ($variable, $value) = split(/:\s*/, $line, 2); + + if(grep(/^\Q${variable}\E$/, @{$rc{"GL_METADATA_REQUIRED"}})) { + if(length($value) > 0) { + @not_met = grep(!/^\Q${variable}\E$/, @not_met); + } + } + } + close($pubkey); + + if( $#not_met ne -1 ) { + _warn "Skipping '${f}' due to missed required variables: ".join(", ", sort @not_met); + return (); + } + } + + # Use strict mode to abort on faulty files + my $akf = Net::SSH::AuthorizedKeysFile->new( strict => 1, ); + $akf->read($f); + + my @keys = (); + + foreach my $keyobj ($akf->keys()) { + if(!defined($keyobj)) { + _warn "Malformed key '${f}', skipping...\n"; + next; + } + + # Preserve only options specified in AUTH_OPTIONS_PRESERVE + foreach my $option (keys(%{$keyobj->options})) { + if(!grep(/^\Q${option}\E$/, split(",", $auth_options_preserve))) { + delete($keyobj->options->{$option}); + } + } + + # Add our options as well + foreach my $option (split(",", $auth_options)) { + $keyobj->option($option, 1); + } + + $keyobj->option("command", "${glshell} ${user}" . ( $kfn ? " $f" : "" )); + + push(@keys, $keyobj->as_string()); + } + + return @keys; +} diff --git a/src/triggers/post-compile/ssh-authkeys-split b/src/triggers/post-compile/ssh-authkeys-split index 031bd07..a7d5133 100755 --- a/src/triggers/post-compile/ssh-authkeys-split +++ b/src/triggers/post-compile/ssh-authkeys-split @@ -29,6 +29,10 @@ # to enable, uncomment the 'ssh-authkeys-split' line in the ENABLE list in the # rc file. +echo "ERROR: ssh-authkeys-split is not support by gitolite-gentoo" 1>&2 +echo "ERROR: because metadata might be lost. You should split the keys manually!" 1>&2 +exit 1 + cd $GL_ADMIN_BASE/keydir rm -rf __split_keys__ |