diff -r 000000000000 -r cc246ac74f0d update-schlittermann-ssh-keys.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/update-schlittermann-ssh-keys.pl Mon Jan 31 12:40:15 2011 +0100 @@ -0,0 +1,202 @@ +#! /usr/bin/perl +# $Id: update-schlittermann-ssh-keys.pl 4805 2009-12-03 14:39:57Z foerste $ +# $URL: https://ssl.schlittermann.de/svn/is/schlittermann-ssh-key/trunk/update-schlittermann-ssh-keys.pl $ + +use strict; +use warnings; +use File::Basename; +use File::Copy; +use Getopt::Long; +use Term::ReadKey; +use Pod::Usage; +use if $ENV{DEBUG} => "Smart::Comments"; + +my $ME = basename $0; +my $effective_uid = $>; +my $home_dir = (getpwuid $effective_uid)[7]; +my $opt_update = 1; +my $opt_help = 0; +my $opt_man = 0; +my $opt_keys_dir = "/usr/share/schlittermann-ssh-keys"; +my $opt_force = 0; + +my $SSHD_CONF = "/etc/ssh/sshd_config"; +my $KEYS_DIR = undef; # set later +my $SSH_DIR = "$home_dir/.ssh"; +my $AUTH_KEYS = "$SSH_DIR/authorized_keys"; +my $AUTH_KEYS_LOCAL = "$SSH_DIR/authorized_keys.local"; + +sub read_keys(@) { + local @ARGV = grep -f, @_; + my %h; + if (@ARGV) { + while (<>) { chomp; $h{$_} = 1 } + } + return %h; +} + +MAIN: { + + GetOptions( + "update!" => \$opt_update, + "help!" => \$opt_help, + "man!" => \$opt_man, + "keys-dir=s" => \$opt_keys_dir, + "force!" => \$opt_force, + ) or pod2usage(-exitval => 1, -verbose => 0); + + $KEYS_DIR = $opt_keys_dir; + + pod2usage(-exitval => 0, -verbose => 0) if $opt_help; + pod2usage(-exitval => 0, -verbose => 2) if $opt_man; + + # update authorized_keys file + if ($opt_update) { + + # checking Schlittermann keys directory + -d $KEYS_DIR + or die "\n[$KEYS_DIR] doesn't exist.\n\n"; + + # creating .ssh directory if not exists + -d $SSH_DIR + or mkdir $SSH_DIR, 0700 + or die "Can't create directory $SSH_DIR: $!\n"; + + # backup authorized_keys file + if (-e $AUTH_KEYS) { + my $copy = $opt_force || !-e "$AUTH_KEYS.bak"; + if (!$copy) { + print +"\nWARNING: [$AUTH_KEYS.bak] already exists. Overwrite? [yes/N]: "; + chomp(my $input = ); + $copy = lc $input eq "yes"; + } + copy($AUTH_KEYS => "$AUTH_KEYS.bak") + or die "Can't copy $AUTH_KEYS: $!\n" + if $copy; + } + + # read Schlittermann keys + my %schlittermann_keys = read_keys(glob("$KEYS_DIR/*")); + my %local_keys = read_keys($AUTH_KEYS_LOCAL); + my %auth_keys = read_keys($AUTH_KEYS); + + delete @auth_keys{ keys %schlittermann_keys, keys %local_keys }; + + foreach (keys %auth_keys) { # die noch unbekannten + /^(.* ssh-\S+ ).*? (.*)$/ or /^(.{30}).*?(.{30})$/; + print "Keep unknown: " . ((defined $1 and defined $2) ? "$1 ... $2" : $_) . ": [y/N] "; + ReadMode "cbreak"; + my $answer = lc ReadKey; + ReadMode "restore"; + + $answer = "n" if not $answer eq "y"; + print "$answer\n"; + next if $answer ne "y"; + $local_keys{$_} = 1; + } + + my $fh; + open $fh, ">$AUTH_KEYS_LOCAL" + or die "Can't open $AUTH_KEYS_LOCAL: $!\n"; + print $fh map { "$_\n" } keys %local_keys; + close $fh; + + open $fh, ">$AUTH_KEYS" or die "Can't open $AUTH_KEYS: $!\n"; + print $fh map { "$_\n" } keys %schlittermann_keys, keys %local_keys; + close $fh; + + } + + # check /etc/ssh/sshd_config for the keyword PermitUserEnvironment + if (open(my $fh, $SSHD_CONF)) { + grep { /^\s*PermitUserEnvironment\s+yes/i } <$fh> + and print "$SSHD_CONF is ok\n" + and exit 0; + } + else { + warn "Can't check $SSHD_CONF: $!\n"; + exit 0; + } + + warn "PermitUserEnvironment not set!\n"; + + if (open(my $fh, "+<$SSHD_CONF")) { + copy($SSHD_CONF => "$SSHD_CONF.bak") + or die "Can't copy $SSHD_CONF -> $SSHD_CONF.bak: $!\n"; + $_ = join "", <$fh>; + s/^(\s*PermitUserEnvironment\s+).*$/# modified by $ME:\n$1yes/im + or $_ .= "# inserted by $ME:\nPermitUserEnvironment yes\n"; + + seek($fh, 0, 0); + print $fh $_; + truncate($fh, tell($fh)); + close($fh) or rename("$SSHD_CONF.bak" => $SSHD_CONF); + + system("invoke-rc.d ssh reload"); + + exit 0; + } + else { + warn "Can't modify $SSHD_CONF: $!\n"; + } +} + +__END__ + +=head1 NAME + +update-schlittermann-ssh-keys - import public ssh keys from the Schlittermann technician + +=head1 SYNOPSIS + +B [OPTION] + + Options: + -u, --update update the authorized_keys file + -h, --help display this help and exit + -m, --man display full documentation + -f, --force overwriting backup file + --keys-dir the default keys + +=head1 DESCRIPION + +B make a backup from F<~/.ssh/authorized_keys> and generate a new file which +contains the public ssh keys from the Schlittermann technician. + +If exists the F<~/.ssh/authorized_keys.local> file, the public ssh keys from +this file will be appand to the F<~/.ssh/authorized_keys> file too. + +=cut + +=head1 OPTIONS + +=over 8 + + +=item B<-u, --update> + +import the public ssh keys from the Schlittermann technician and the keys from the F<~/.ssh/authorized_keys.local> file + +=item B<-f, --force> + +force some actions (e.g. overwriting backup file) (default: 0) + +=item B<--keys-dir> I + +The directory where the "default" keys are stored +(default: F) + +=item B<-h, --help> + +display this help and exit + +=item B<-m, --man> + +display full documentation + +=back + +=cut + +# vim:ts=4 sts=4 sw=4 aw ai sm: