my $callback = sub { my @res; while (@_) { my $code = shift; my $msg = shift; my $ans = ""; $ans = $username if ($code == PAM_PROMPT_ECHO_ON()); $ans = $password if ($code == PAM_PROMPT_ECHO_OFF()); push @res, (PAM_SUCCESS(), $ans); } push @res, PAM_SUCCESS();
return @res; };
my $pamh = new Authen::PAM('bootmenu', $username, $callback);
{ last unless ref $pamh; last unless $pamh->pam_authenticate() == PAM_SUCCESS; $success = 1; }
# if another instance of this script is running, wait for it to finish "$ENV{FLOCKER}" eq 'MKTGT' or exec "env FLOCKER=MKTGT flock /tmp $0 @ARGV";
# use "RETURN" to print to STDOUT; everything else goes to STDERR by default open(RETURN, '>&', STDOUT); open(STDOUT, '>&', STDERR);
my $instance = shift or die "instance not provided"; my $username = shift or die "username not provided";
my $img = "/$instance.img"; my $dir = "/$instance.cow"; my $top = "$dir/$username";
-f "$img" or die "'$img' is not a file"; -d "$dir" or die "'$dir' is not a directory";
my $base; die unless $base = `losetup --show --read-only --nooverlap --find $img`; chomp $base;
my $size; die unless $size = `blockdev --getsz $base`; chomp $size;
# create the per-user sparse file if it does not exist if (! -e "$top") { die unless system("dd if=/dev/zero of=$top status=none bs=512 count=0 seek=$size") == 0; }
# create the copy-on-write overlay if it does not exist my $cow="$instance-$username"; my $dev="/dev/mapper/$cow"; if (! -e "$dev") { my $over; die unless $over = `losetup --show --nooverlap --find $top`; chomp $over; die unless system("echo 0 $size snapshot $base $over p 8 | dmsetup create $cow") == 0; }
my $tgtadm = '/usr/sbin/tgtadm --lld iscsi';
# get textual representations of the iscsi targets my $text = `$tgtadm --op show --mode target`; my @targets = $text =~ /(?:^T.*\n)(?:^ .*\n)*/mg;
# convert the textual representations into a hash table my $targets = {}; foreach (@targets) { my $tgt; my $sid;
# find the target id corresponding to the provided target name and # close any existing connections to it my $tid = 0; foreach (@targets) { next unless /^Target (\d+)(?{ $tid = $^N }): $target$/m; foreach (@{$targets->{$tid}}) { die unless system("$tgtadm --op delete --mode conn --tid $tid --sid $_->[0] --cid $_->[1]") == 0; } }
# create a new target if an existing one was not found if ($tid == 0) { # find an available target id my @ids = (0, sort keys %{$targets}); $tid = 1; while ($ids[$tid]==$tid) { $tid++ }
# create the target die unless -e "$dev"; die unless system("$tgtadm --op new --mode target --tid $tid --targetname $target") == 0; die unless system("$tgtadm --op new --mode logicalunit --tid $tid --lun 1 --backing-store $dev") == 0; die unless system("$tgtadm --op bind --mode target --tid $tid --initiator-address ALL") == 0; }
# (re)set the provided target's chap password my $password = join('', map(chr(int(rand(26))+65), 1..8)); my $accounts = `$tgtadm --op show --mode account`; if ($accounts =~ / $username$/m) { die unless system("$tgtadm --op delete --mode account --user $username") == 0; } die unless system("$tgtadm --op new --mode account --user $username --password $password") == 0; die unless system("$tgtadm --op bind --mode account --tid $tid --user $username") == 0;
# return the new password to the iscsi target on stdout print RETURN $password; END # chmod +x $MY_MOJO/scripts/mktgt
@ARGV >= 2 or die "usage: $0 <instance> <username> [+d|+f]\n";
my $instance = shift; my $username = shift;
my $rmd = ($ARGV[0] eq '+d'); #remove device node if +d flag is set my $rmf = ($ARGV[0] eq '+f'); #remove sparse file if +f flag is set my $cow = "$instance-$username";
my $hostname; die unless $hostname = `hostname`; chomp $hostname;
my $tgtadm = '/usr/sbin/tgtadm'; my $target = 'iqn.' . join('.', reverse split('\.', $hostname)) . ":$cow";
my $text = `$tgtadm --op show --mode target`; my @targets = $text =~ /(?:^T.*\n)(?:^ .*\n)*/mg;
my $targets = {}; foreach (@targets) { my $tgt; my $sid;
my $dev = "/dev/mapper/$cow"; if ($rmd or ($rmf and -e $dev)) { die unless system("dmsetup remove $cow") == 0; print "device node $dev deleted\n"; }
if ($rmf) { my $sf = "/$instance.cow/$username"; die "sparse file $sf not found" unless -e "$sf"; die unless system("rm -f $sf") == 0; die unless not -e "$sf"; print "sparse file $sf deleted\n"; } END # chmod +x $HOME/bin/rmtgt