gitolite/src/triggers/post-compile/ssh-authkeys
Sitaram Chamarty 9c460a4b9a patch to make things work under selinux...
...at the cost of some nice warnings

(thanks to Seth Robertson for reporting the issue and then verifying the
fix, since I don't run selinux)
2012-03-27 22:25:39 +05:30

138 lines
3.7 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.
tsh_try("sestatus");
my $selinux = (tsh_text() =~ /enabled/);
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", @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 {
return $selinux++ if $selinux; # return a unique "fingerprint" to prevent noise
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]";
}