07cf7fedfe
...otherwise 'gitolite help' was getting too confusing, mixing up stuff that users should not be running directly (even on the server) ---- implementation notes: those who are worried about the '../triggers/' in various parts of the code here, remember you can only do that from a command line on the server. Remote users can only use commands that have been explicitly listed in the COMMANDS hash in the rc file. This means they can't even access other commands in the same directory as, say, the 'info' command, so a '../' is definitely not going to work.
134 lines
3.6 KiB
Perl
Executable file
134 lines
3.6 KiB
Perl
Executable file
#!/usr/bin/perl
|
|
use strict;
|
|
use warnings;
|
|
|
|
use File::Temp qw(tempfile);
|
|
|
|
use lib $ENV{GL_BINDIR};
|
|
use Gitolite::Rc;
|
|
use Gitolite::Common;
|
|
|
|
$|++;
|
|
|
|
# can be called directly, or as a post-update hook. Since it ignores
|
|
# arguments anyway, it hardly matters.
|
|
|
|
my $ab = `gitolite query-rc -n GL_ADMIN_BASE`;
|
|
trace( 2, "'keydir' not found in '$ab'; exiting" ), exit if not -d "$ab/keydir";
|
|
my $akdir = "$ENV{HOME}/.ssh";
|
|
my $akfile = "$ENV{HOME}/.ssh/authorized_keys";
|
|
my $glshell = `gitolite query-rc -n GL_BINDIR` . "/gitolite-shell";
|
|
my $auth_options = auth_options();
|
|
|
|
sanity();
|
|
|
|
# ----------------------------------------------------------------------
|
|
|
|
_chdir($ab);
|
|
|
|
# old data
|
|
my $old_ak = slurp($akfile);
|
|
my @non_gl = grep { not /^# gito.*start/ .. /^# gito.*end/ } slurp($akfile);
|
|
chomp(@non_gl);
|
|
my %seen = map { $_ => 'a non-gitolite key' } ( fp(@non_gl) );
|
|
# die 1;
|
|
|
|
# pubkey files
|
|
chomp( my @pubkeys = `find keydir -type f -name "*.pub" | sort` );
|
|
my @gl_keys = ();
|
|
for my $f (@pubkeys) {
|
|
my $fp = fp($f);
|
|
if ( $seen{$fp} ) {
|
|
_warn "$f duplicates $seen{$fp}, sshd will ignore it";
|
|
} else {
|
|
$seen{$fp} = $f;
|
|
}
|
|
push @gl_keys, grep { /./ } optionise($f);
|
|
}
|
|
|
|
# dump it out
|
|
if (@gl_keys) {
|
|
my $out = join( "\n", map { my $_ = $_; chomp($_); $_ } @non_gl, "# gitolite start", @gl_keys, "# gitolite end" ) . "\n";
|
|
|
|
my $ak = slurp($akfile);
|
|
_die "$akfile changed between start and end of this program!" if $ak ne $old_ak;
|
|
_print( $akfile, $out );
|
|
}
|
|
|
|
# ----------------------------------------------------------------------
|
|
|
|
sub sanity {
|
|
_die "$glshell not found; this should NOT happen..." if not -f $glshell;
|
|
_die "$glshell found but not readable; this should NOT happen..." if not -r $glshell;
|
|
_die "$glshell found but not executable; this should NOT happen..." if not -x $glshell;
|
|
|
|
_warn "$akdir missing; creating a new one" if not -d $akdir;
|
|
_warn "$akfile missing; creating a new one" if not -f $akfile;
|
|
|
|
_mkdir($akdir, 0700) if not -d $akfile;
|
|
if ( not -f $akfile ) {
|
|
_print( $akfile, "" );
|
|
chmod 0700, $akfile;
|
|
}
|
|
}
|
|
|
|
sub auth_options {
|
|
my $auth_options = `gitolite query-rc AUTH_OPTIONS`;
|
|
chomp($auth_options);
|
|
$auth_options ||= "no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty";
|
|
|
|
return $auth_options;
|
|
}
|
|
|
|
sub fp {
|
|
# input: see below
|
|
# output: a (list of) FPs
|
|
my $in = shift || '';
|
|
if ( $in =~ /\.pub$/ ) {
|
|
# single pubkey file
|
|
_die "bad pubkey file '$in'" unless $in =~ $REPONAME_PATT;
|
|
return fp_file($in);
|
|
} elsif ( -f $in ) {
|
|
# an authkeys file
|
|
return map { fp_line($_) } grep { !/^#/ and /\S/ } slurp($in);
|
|
} else {
|
|
# one or more actual keys
|
|
return map { fp_line($_) } grep { !/^#/ and /\S/ } ( $in, @_ );
|
|
}
|
|
}
|
|
|
|
sub fp_file {
|
|
my $f = shift;
|
|
my $fp = `ssh-keygen -l -f '$f'`;
|
|
chomp($fp);
|
|
_die "fingerprinting failed for $f" unless $fp =~ /([0-9a-f][0-9a-f](:[0-9a-f][0-9a-f])+)/;
|
|
$fp = $1;
|
|
return $fp;
|
|
}
|
|
|
|
sub fp_line {
|
|
my ( $fh, $fn ) = tempfile();
|
|
print $fh shift;
|
|
close $fh;
|
|
my $fp = fp_file($fn);
|
|
unlink $fn;
|
|
return $fp;
|
|
}
|
|
|
|
sub optionise {
|
|
my $f = shift;
|
|
|
|
my $user = $f;
|
|
$user =~ s(.*/)(); # foo/bar/baz.pub -> baz.pub
|
|
$user =~ s/(\@[^.]+)?\.pub$//; # baz.pub, baz@home.pub -> baz
|
|
|
|
my @line = slurp($f);
|
|
if ( @line != 1 ) {
|
|
_warn "$f does not contain exactly 1 line; ignoring";
|
|
return '';
|
|
}
|
|
chomp(@line);
|
|
return "command=\"$glshell $user\",$auth_options $line[0]";
|
|
}
|
|
|