From 39806f8ad0f2171ec5727ee46e05d5aac3dc541d Mon Sep 17 00:00:00 2001 From: Dmitry Nedospasov Date: Mon, 7 Jun 2010 17:35:52 +0200 Subject: [PATCH] Added a genpass flag to generate a password and install it in the guest * We could use the same functions to set a password via a --password flag * It would nice to move more functionality to subroutines * The current generatePassword subroutine, only generates alphanum passwords and hashes --- bin/xen-create-image | 98 +++++++++++++++++++++-- roles/passwd | 186 ------------------------------------------- 2 files changed, 91 insertions(+), 193 deletions(-) delete mode 100755 roles/passwd diff --git a/bin/xen-create-image b/bin/xen-create-image index 31b3ed9..1e5cf7b 100755 --- a/bin/xen-create-image +++ b/bin/xen-create-image @@ -104,8 +104,10 @@ xen-create-image - Easily create new Xen instances with networking and OpenSSH. fs, size, swap and noswap are ignored when using this option. + --genpass Generate a random root password + --passwd Ask for a root password during setup. - NOTE: This is done interactively. + NOTE: This is done interactively and overrides --genpass --role=role Run the specified role script(s) post-install. Role scripts are discussed later in this manpage. @@ -732,6 +734,7 @@ use Digest::MD5 qw/ md5_hex /; use Env; use File::Path qw/ mkpath /; use File::Temp qw/ tempdir /; +use File::Copy qw/ cp /; use Getopt::Long; use Pod::Usage; @@ -784,6 +787,11 @@ my $RELEASE = '4.2beta1'; my $IP_ADDRESSES = ''; +# +# Variable for generated password +# +my $PASSWORD = ''; + # # Setup default options. # @@ -1018,7 +1026,7 @@ runXenConfigCreation(); # # Setup the password if the user wanted that. # -setupRootPassword() if ( $CONFIG{ 'passwd' } ); +setupRootPassword() if ( $CONFIG{ 'passwd' } or $CONFIG{ 'genpass' } ); # @@ -1342,6 +1350,13 @@ sub setupDefaultOptions $CONFIG{ 'install-method' } = 'debootstrap'; $CONFIG{ 'debootstrap-cmd' } = ''; + # + # Default values for passwords + # + $CONFIG{ 'genpass' } = 1; + $CONFIG{ 'genpass_len' } = 8; + $CONFIG{ 'password' } = ''; + # # The program to run to create a filesystem. # @@ -1551,6 +1566,9 @@ sub parseCommandLineArguments "hooks=i", \$CONFIG{ 'hooks' }, "pygrub", \$CONFIG{ 'pygrub' }, "passwd", \$CONFIG{ 'passwd' }, + "genpass=i", \$CONFIG{ 'genpass' }, + "genpass-len=i", \$CONFIG{ 'genpass_len' }, + "password=s", \$CONFIG{ 'password' }, "partitions=s", \$CONFIG{ 'partitions' }, "role=s", \$CONFIG{ 'role' }, "role-args=s", \$CONFIG{ 'role-args' }, @@ -3729,16 +3747,81 @@ sub setupRootPassword { logprint("Setting up root password\n"); - if ( -x $MOUNT_POINT . "/usr/bin/passwd" ) + if ( $CONFIG{ 'passwd' } ) { - system("chroot $MOUNT_POINT /usr/bin/passwd"); + if ( -x $MOUNT_POINT . "/usr/bin/passwd" ) + { + system("chroot $MOUNT_POINT /usr/bin/passwd"); + } + else + { + logprint("'passwd' command not found in the new install.\n"); + } } else { - logprint("'passwd' command not found in the new install.\n"); + logprint("Generating a password for the new guest.\n"); + # + # Replace the password in the /etc/shadow file + # + my $shadow_path = $MOUNT_POINT . '/etc/shadow'; + if ( -e $shadow_path ) + { + # + # Generate a password, salt and use that to generating a hash + # + my $salt = generatePassword(8); + $PASSWORD = generatePassword( $CONFIG{ 'genpass_len' } ); + my $hash = `echo -n $PASSWORD | openssl passwd -stdin -1 -salt $salt`; + $hash =~ s/\s+$//; + + # + # Copy the file to ensure the original retains the correct + # permissions set by the System + # + my $tmp_shadow_path = "$shadow_path.tmp"; + cp("$shadow_path","$tmp_shadow_path"); + open(TMP, "<", $tmp_shadow_path) or die $!; + open(SHADOW, ">", $shadow_path) or die $!; + my $line; + while(defined($line = )) + { + chomp $line; + $line =~ s#^root:[^:]*:#root:$hash:#; + print SHADOW "$line\n"; + } + + # + # Close the files and delete the temporary file + # + close(SHADOW); + close(TMP); + unlink($tmp_shadow_path); + } + else + { + logprint("Failed to find /etc/passwd in the install.\n"); + } } } +=begin doc + + create a random "string" + +=end doc + +=cut + +sub generatePassword { + my $length = $_[0]; + my $possible = 'abcdefghijkmnpqrstuvwxyz23456789ABCDEFGHJKLMNPQRSTUVWXYZ'; + my $password = ''; + while (length($password) < $length) { + $password .= substr($possible, (int(rand(length($possible)))), 1); + } + return $password +} =begin doc @@ -4010,7 +4093,8 @@ sub END logprint( $IP_ADDRESSES ); } logprint("\n"); - logprint("RSA Fingerprint : $host_rsa_key"); - logprint("\n\n"); + logprint("RSA Fingerprint : $host_rsa_key\n"); + logprint("Root Password : $PASSWORD\n"); + logprint("\n"); } } diff --git a/roles/passwd b/roles/passwd deleted file mode 100755 index 43236bd..0000000 --- a/roles/passwd +++ /dev/null @@ -1,186 +0,0 @@ -#!/usr/bin/perl -w - -=head1 NAME - -passwd - xen-tools role-script to setup root password for new guests. - -=head1 AUTHOR - - Steve - -- - http://www.steve.org.uk/ - -=cut - - - -use strict; -use warnings; -use Digest::MD5; -use Expect; - - - -# -# Get the arguments our role script was passed. -# -my( $prefix, $passwd ) = ( @ARGV ); - -# -# Make sure they are valid. -# -if ( ! -d $prefix ) -{ - print "Prefix not found: $prefix\n"; - exit; -} - -if ( ! length( $passwd ) ) -{ - print "Password missing.\n"; - exit; -} - - -# -# Now make sure we have the module we require. -# -eval "use Expect;"; -if ( $@ ) -{ - print "Expect.pm not found. Aborting.\n"; - print "(For Debian systems run:\n\tapt-get install libexpect-perl\n"; - exit; -} - - -# -# OK now we're good to go: Continue until it succeeds. -# -my $count = 0; -while( $count < 10 ) -{ - changePassword( $prefix, $passwd ); - $count += 1; -} - -print "Failed to setup root password\n"; -print "-----------------------------\n"; - - - -# -# Don't look at this code. -# -# OK. Expect sometimes fails. It sucks. -# -# So how do we know if a password change operation fails? We take -# an MD5(/etc/passwd + /etc/shadow) and if they don't change we've -# failed. -# -# Upon success we will simply exit(); -# -# -sub changePassword -{ - my ( $prefix, $passwd ) = ( @_ ); - - # - # Find current checksum. - # - my $orig = checksum( $prefix ); - - # - # Create the expect object. - # - my $exp = Expect->spawn( "/usr/sbin/chroot", - $prefix, - "/usr/bin/passwd", - "root" ) - or die "Cannot spawn the password under chroot: $!\n"; - - # prompt - unless ($exp->expect(5,"Enter new")) - { - print "Failed 1st prompt\n"; - $exp->hard_close(); - return; - } - - # send + wait. - $exp->send( $passwd . "\n" ); - sleep( 1 ); - - # confirm - unless ($exp->expect(5,"Retype new")) - { - print "Failed 2nd prompt\n"; - $exp->hard_close(); - return; - } - - # send. - $exp->send( $passwd . "\n" ); - - - # Closeup. - $exp->soft_close(); - - # - # Did it work? - # - my $updated = checksum( $prefix ); - - if ( $updated ne $orig ) - { - print "Password setup correctly.\n"; - exit; - } - else - { - print "Setting password failed.\n"; - } -} - - - -# -# Checksum /etc/passwd + /etc/shadow if they exist in the -# given chroot() -# -sub checksum -{ - my( $prefix ) = ( @_ ); - - my $sum = ''; - - foreach my $file ( qw! /etc/passwd /etc/shadow ! ) - { - if ( -e $prefix . "/" . $file ) - { - # - # Open the file. - # - open(FILE, $prefix . "/" . $file) - or die "Can¡Çt open ¡Ç$prefix/$file¡Ç: $!"; - binmode(FILE); - - # - # Add the data - # - my $md5 = Digest::MD5->new; - while () - { - $md5->add($_); - } - close(FILE); - - # - # Update the sum - # - $sum .= $md5->b64digest; - } - } - - return $sum; -}