aboutsummaryrefslogtreecommitdiff
path: root/perl
diff options
context:
space:
mode:
Diffstat (limited to 'perl')
-rw-r--r--perl/Wallet/Object/Keytab.pm86
-rwxr-xr-xperl/t/keytab.t39
2 files changed, 76 insertions, 49 deletions
diff --git a/perl/Wallet/Object/Keytab.pm b/perl/Wallet/Object/Keytab.pm
index 64e7ce1..293e41e 100644
--- a/perl/Wallet/Object/Keytab.pm
+++ b/perl/Wallet/Object/Keytab.pm
@@ -200,6 +200,40 @@ sub kaserver_name {
return $k4;
}
+# Run kasetkey with the given arguments. Returns true on success and false on
+# failure. On failure, sets the internal error to the error from kasetkey.
+sub kaserver_kasetkey {
+ my ($self, @args) = @_;
+ my $admin = $Wallet::Config::KEYTAB_AFS_ADMIN;
+ my $admin_srvtab = $Wallet::Config::KEYTAB_AFS_SRVTAB;
+ my $kasetkey = $Wallet::Config::KEYTAB_AFS_KASETKEY;
+ unless ($kasetkey and $admin and $admin_srvtab) {
+ $self->error ('kaserver synchronization not configured');
+ return undef;
+ }
+ my $pid = open (KASETKEY, '-|');
+ if (not defined $pid) {
+ $self->error ("cannot fork: $!");
+ return undef;
+ } elsif ($pid == 0) {
+ open (STDERR, '>&STDOUT') or die "cannot redirect stderr: $!\n";
+ exec ($kasetkey, '-k', $admin_srvtab, '-a', $admin, @args)
+ or die "cannot exec $kasetkey: $!\n";
+ } else {
+ local $/;
+ my $output = <KASETKEY>;
+ close KASETKEY;
+ if ($? != 0) {
+ $output =~ s/\s+\z//;
+ $output =~ s/\n/, /g;
+ $output = ': ' . $output if $output;
+ $self->error ("cannot synchronize key with kaserver$output");
+ return undef;
+ }
+ }
+ return 1;
+}
+
# Given a keytab file name, the Kerberos v5 principal that's stored in that
# keytab, a srvtab file name, and the corresponding Kerberos v4 principal,
# write out a srvtab file containing the DES key in that keytab. Fails if
@@ -246,7 +280,9 @@ sub kaserver_srvtab {
# nul-terminated realm, single character kvno (which we always set to 0),
# and DES keyblock.
my ($principal, $realm) = split ('@', $k4);
+ $realm ||= '';
my ($name, $inst) = split (/\./, $principal, 2);
+ $inst ||= '';
my $data = join ("\0", $name, $inst, $realm);
$data .= "\0\0" . $key->contents;
print SRVTAB $data;
@@ -263,13 +299,6 @@ sub kaserver_srvtab {
# On failure, sets the internal error.
sub kaserver_sync {
my ($self, $principal, $keytab) = @_;
- my $admin = $Wallet::Config::KEYTAB_AFS_ADMIN;
- my $admin_srvtab = $Wallet::Config::KEYTAB_AFS_SRVTAB;
- my $kasetkey = $Wallet::Config::KEYTAB_AFS_KASETKEY;
- unless ($kasetkey and $admin and $admin_srvtab) {
- $self->error ('kaserver synchronization not configured');
- return undef;
- }
if ($Wallet::Config::KEYTAB_REALM) {
$principal .= '@' . $Wallet::Config::KEYTAB_REALM;
}
@@ -282,33 +311,27 @@ sub kaserver_sync {
unless ($self->kaserver_srvtab ($keytab, $principal, $srvtab, $k4)) {
return undef;
}
- my $pid = open (KASETKEY, '-|');
- if (not defined $pid) {
- $self->error ("cannot fork: $!");
+ unless ($self->kaserver_kasetkey ('-c', $srvtab, '-s', $k4)) {
unlink $srvtab;
return undef;
- } elsif ($pid == 0) {
- open (STDERR, '>&STDOUT') or die "cannot redirect stderr: $!\n";
- exec ($kasetkey, '-k', $admin_srvtab, '-a', $admin, '-c', $srvtab,
- '-s', $k4)
- or die "cannot exec $kasetkey: $!\n";
- } else {
- local $/;
- my $output = <KASETKEY>;
- close KASETKEY;
- if ($? != 0) {
- $output =~ s/\s+\z//;
- $output =~ s/\n/, /g;
- $output = ': ' . $output if $output;
- $self->error ("cannot synchronize key with kaserver$output");
- unlink $srvtab;
- return undef;
- }
}
unlink $srvtab;
return 1;
}
+# Given a principal name, destroy the corresponding principal in the AFS
+# kaserver. Returns true on success and false on failure, setting the object
+# error if it fails.
+sub kaserver_destroy {
+ my ($self, $principal) = @_;
+ my $k4 = $self->kaserver_name ($principal);
+ if (not defined $k4) {
+ $self->error ("cannot convert $principal to Kerberos v4");
+ return undef;
+ }
+ return $self->kaserver_kasetkey ('-D', $k4);
+}
+
# Set the kaserver sync attribute. Called by attr(). Returns true on success
# and false on failure, setting the object error if it fails.
sub kaserver_set {
@@ -472,6 +495,12 @@ sub destroy {
$self->error ("cannot destroy $id: object is locked");
return;
}
+ my @sync = $self->attr ('sync');
+ if (grep { $_ eq 'kaserver' } @sync) {
+ unless ($self->kaserver_destroy ($self->{name})) {
+ return undef;
+ }
+ }
return undef if not $self->kadmin_delprinc ($self->{name});
return $self->SUPER::destroy ($user, $host, $time);
}
@@ -598,6 +627,9 @@ C<smtp>; and the first component is C<rcmd> if the Kerberos v5 principal
component is C<host>. The principal name must not contain more than two
components.
+If this attribute is set, calling destroy() will also destroy the principal
+from the AFS kaserver, with a principal mapping determined as above.
+
=back
If no other arguments besides ATTRIBUTE are given, returns the values of
diff --git a/perl/t/keytab.t b/perl/t/keytab.t
index d90699c..93eea1d 100755
--- a/perl/t/keytab.t
+++ b/perl/t/keytab.t
@@ -3,7 +3,7 @@
#
# t/keytab.t -- Tests for the keytab object implementation.
-use Test::More tests => 96;
+use Test::More tests => 100;
use Wallet::Config;
use Wallet::Object::Keytab;
@@ -96,21 +96,6 @@ sub created {
return (system_quiet ('kvno', $principal) == 0);
}
-# Check whether a principal exists in the kaserver. Requires that the admin
-# and srvtab variables be set up already.
-sub created_kaserver {
- my ($principal) = @_;
- my $admin = $Wallet::Config::KEYTAB_AFS_ADMIN;
- my $srvtab = $Wallet::Config::KEYTAB_AFS_SRVTAB;
- my $realm = $Wallet::Config::KEYTAB_AFS_REALM;
- my ($name, $instance) = split (/\./, $principal);
- $ENV{KRBTKFILE} = 'krb4cc_temp';
- system ("k4start -f $srvtab -r $realm -S $name -I $instance $admin"
- . " 2>&1 >/dev/null </dev/null");
- unlink 'krb4cc_temp';
- return ($? == 0) ? 1 : 0;
-}
-
# Given keytab data and the principal, write it to a file and try
# authenticating using kinit.
sub valid {
@@ -412,8 +397,8 @@ SKIP: {
# Tests for kaserver synchronization support.
SKIP: {
- skip 'no keytab configuration', 30 unless -f 't/data/test.keytab';
- skip 'no AFS kaserver configuration', 30 unless -f 't/data/test.srvtab';
+ skip 'no keytab configuration', 34 unless -f 't/data/test.keytab';
+ skip 'no AFS kaserver configuration', 34 unless -f 't/data/test.srvtab';
# Set up our configuration.
$Wallet::Config::KEYTAB_FILE = 't/data/test.keytab';
@@ -477,12 +462,20 @@ SKIP: {
@targets = $one->attr ('sync');
is (scalar (@targets), 0, ' and now there is no attribute');
is ($one->error, undef, ' and no error');
- $keytab = $one->get (@trace);
- ok (defined ($keytab), ' and get still works');
- ok (! valid_srvtab ($one, $keytab, $k5, $k4), ' but the srvtab does not');
- ok (created_kaserver ('wallet.one'), ' and the principal is still there');
+ my $new_keytab = $one->get (@trace);
+ ok (defined ($new_keytab), ' and get still works');
+ ok (! valid_srvtab ($one, $new_keytab, $k5, $k4),
+ ' but the srvtab does not');
+ ok (valid_srvtab ($one, $keytab, $k5, $k4), ' and the old one does');
+ is ($one->destroy (@trace), 1, ' and destroying wallet/one works');
+ ok (valid_srvtab ($one, $keytab, $k5, $k4),
+ ' and the principal is still there');
# Put it back and make sure it works again.
+ $one = eval {
+ Wallet::Object::Keytab->create ('keytab', 'wallet/one', $dbh, @trace)
+ };
+ ok (defined ($one), 'Creating wallet/one succeeds');
is ($one->attr ('sync', [ 'kaserver' ], @trace), 1, 'Setting sync works');
$keytab = $one->get (@trace);
ok (defined ($keytab), ' and get works');
@@ -490,6 +483,8 @@ SKIP: {
# Destroy the principal.
is ($one->destroy (@trace), 1, 'Destroying wallet/one works');
+ ok (! valid_srvtab ($one, $keytab, $k5, $k4),
+ ' and the principal is gone');
}
# Clean up.