update-schlittermann-ssh-keys.pl
changeset 0 cc246ac74f0d
child 50 7aeb74df004b
--- /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 = <STDIN>);
+                $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<update-schlittermann-ssh-keys> [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<update-schlittermann-ssh-keys> 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<dir>
+
+The directory where the "default" keys are stored 
+(default: F</usr/share/schlittermann-ssh-keys/>)
+
+=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: