Skip to content
executable file 143 lines (112 sloc) 4.07 KB
#!/usr/bin/perl
use strict;
use warnings;
use Getopt::Long;
use lib $ENV{GL_LIBDIR};
use Gitolite::Rc;
use Gitolite::Common;
$|++;
# best called via 'gitolite trigger POST_COMPILE'; other modes at your own
# risk, especially if the rc file specifies arguments for it. (That is also
# why it doesn't respond to "-h" like most gitolite commands do).
# option procesing
# ----------------------------------------------------------------------
# currently has one option:
# -kfn, --key-file-name adds the keyfilename as a second argument
my $kfn = '';
GetOptions( 'key-file-name|kfn' => \$kfn, );
tsh_try("sestatus");
my $selinux = ( tsh_text() =~ /enabled/ );
my $ab = $rc{GL_ADMIN_BASE};
trace( 1, "'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 = $rc{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) );
# 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
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 );
_warn "you have no keys left; I hope you intended to do that!" unless @gl_keys;
# ----------------------------------------------------------------------
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;
my $n = " (this is normal on a brand new install)";
_warn "$akdir missing; creating a new one\n$n" if not -d $akdir;
_warn "$akfile missing; creating a new one\n$n" if not -f $akfile;
_mkdir( $akdir, 0700 ) if not -d $akdir;
if ( not -f $akfile ) {
_print( $akfile, "" );
chmod 0600, $akfile;
}
}
sub auth_options {
my $auth_options = $rc{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, $output) = ssh_fingerprint_file($f);
_die "fingerprinting failed for '$f': $output" unless $fp;
return $fp;
}
sub fp_line {
my $line = shift;
my ($fp, $output) = ssh_fingerprint_line($line);
_die "fingerprinting failed for '$line': $output" unless $fp;
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" . ( $kfn ? " $f" : "" ) . "\",$auth_options $line[0]";
}
Jump to Line
Something went wrong with that request. Please try again.