#!/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; }