summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--TODO2
-rw-r--r--perl/Wallet/Config.pm21
-rw-r--r--perl/Wallet/Kadmin.pm43
-rw-r--r--perl/Wallet/Kadmin/Heimdal.pm74
-rw-r--r--perl/Wallet/Kadmin/MIT.pm68
-rw-r--r--perl/Wallet/Object/Keytab.pm49
-rwxr-xr-xperl/t/kadmin.t4
-rwxr-xr-xperl/t/keytab.t127
8 files changed, 257 insertions, 131 deletions
diff --git a/TODO b/TODO
index 92bd025..662ea47 100644
--- a/TODO
+++ b/TODO
@@ -2,8 +2,6 @@
Release 0.10:
-* Handle unchanging support for Heimdal.
-
* Move reporting code from Wallet::Admin to Wallet::Report.
* Check whether we can just drop the realm restriction on keytabs and
diff --git a/perl/Wallet/Config.pm b/perl/Wallet/Config.pm
index c59d3e3..396bf7d 100644
--- a/perl/Wallet/Config.pm
+++ b/perl/Wallet/Config.pm
@@ -26,7 +26,8 @@ Wallet::Config - Configuration handling for the wallet server
=for stopwords
DBI DSN SQLite subdirectories KEYTAB keytab kadmind KDC add-ons kadmin DNS
SRV kadmin keytabs remctl backend lowercased NETDB ACL NetDB unscoped
-usernames rekey hostnames Allbery wallet-backend keytab-backend
+usernames rekey hostnames Allbery wallet-backend keytab-backend Heimdal
+rekeys
=head1 SYNOPSIS
@@ -313,11 +314,19 @@ our $KEYTAB_TMP;
=head2 Retrieving Existing Keytabs
-The keytab object backend optionally supports retrieving existing keys,
-and hence keytabs, for Kerberos principals by contacting the KDC via
-remctl and talking to B<keytab-backend>. This is enabled by setting the
-C<unchanging> flag on keytab objects. To configure that support, set the
-following variables.
+Heimdal provides the choice, over the network protocol, of either
+downloading the existing keys for a principal or generating new random
+keys. MIT Kerberos does not; downloading a keytab over the kadmin
+protocol always rekeys the principal.
+
+For MIT Kerberos, the keytab object backend therefore optionally supports
+retrieving existing keys, and hence keytabs, for Kerberos principals by
+contacting the KDC via remctl and talking to B<keytab-backend>. This is
+enabled by setting the C<unchanging> flag on keytab objects. To configure
+that support, set the following variables.
+
+This is not required for Heimdal; for Heimdal, setting the C<unchanging>
+flag is all that's needed.
=over 4
diff --git a/perl/Wallet/Kadmin.pm b/perl/Wallet/Kadmin.pm
index 3ca531e..f3c2895 100644
--- a/perl/Wallet/Kadmin.pm
+++ b/perl/Wallet/Kadmin.pm
@@ -83,10 +83,12 @@ Wallet::Kadmin - Kerberos administration API for wallet keytab backend
=head1 SYNOPSIS
my $kadmin = Wallet::Kadmin->new;
- $kadmin->create ("host/foo.example.com");
- $kadmin->keytab ("host/foo.example.com", "aes256-cts-hmac-sha1-96");
- my $exists = $kadmin->exists ("host/oldshell.example.com");
- $kadmin->destroy ("host/oldshell.example.com") if $exists;
+ $kadmin->create ('host/foo.example.com');
+ $kadmin->keytab_rekey ('host/foo.example.com', 'keytab',
+ 'aes256-cts-hmac-sha1-96');
+ my $data = $kadmin->keytab ('host/foo.example.com');
+ my $exists = $kadmin->exists ('host/oldshell.example.com');
+ $kadmin->destroy ('host/oldshell.example.com') if $exists;
=head1 DESCRIPTION
@@ -162,19 +164,26 @@ kadmin command-line client, the sub CALLBACK will be called in the child
process before running the program. This can be used to, for example,
properly clean up shared database handles.
-=item keytab(PRINCIPAL, FILE [, ENCTYPE ... ])
-
-A keytab is an on-disk store for the key or keys for a Kerberos principal.
-Keytabs are used by services to verify incoming authentication from
-clients or by automated processes that need to authenticate to Kerberos.
-To create a keytab, the principal has to be created in Kerberos and then a
-keytab is generated and stored in a file on disk.
-
-ktadd() creates a new keytab for the given principal, storing it in the
-given file and limited to the enctypes supplied. The enctype values must
-be enctype strings recognized by the Kerberos implementation (strings like
-C<aes256-cts-hmac-sha1-96> or C<des-cbc-crc>). Returns true on success
-and false on failure.
+=item keytab(PRINCIPAL)
+
+keytab() creates a keytab for the given principal, storing it in the given
+file. A keytab is an on-disk store for the key or keys for a Kerberos
+principal. Keytabs are used by services to verify incoming authentication
+from clients or by automated processes that need to authenticate to
+Kerberos. To create a keytab, the principal has to have previously been
+created in the Kerberos KDC. Returns the keytab as binary data on success
+and undef on failure.
+
+=item keytab_rekey(PRINCIPAL, FILE [, ENCTYPE ...])
+
+Like keytab(), but randomizes the key for the principal before generating
+the keytab and writes it to the given file. This will invalidate any
+existing keytabs for that principal. This method can also limit the
+encryption types of the keys for that principal via the optional ENCTYPE
+arguments. The enctype values must be enctype strings recognized by the
+Kerberos implementation (strings like C<aes256-cts-hmac-sha1-96> or
+C<des-cbc-crc>). If none are given, the KDC defaults will be used.
+Returns true on success and false on failure.
=back
diff --git a/perl/Wallet/Kadmin/Heimdal.pm b/perl/Wallet/Kadmin/Heimdal.pm
index 0ac8cd9..e066006 100644
--- a/perl/Wallet/Kadmin/Heimdal.pm
+++ b/perl/Wallet/Kadmin/Heimdal.pm
@@ -39,6 +39,23 @@ sub canonicalize_principal {
return $principal;
}
+# Read the entirety of a possibly binary file and return the contents. If
+# reading the file fails, set the error message and return undef.
+sub slurp_file {
+ my ($self, $file) = @_;
+ unless (open (TMPFILE, '<', $file)) {
+ $self->error ("cannot open temporary file $file: $!");
+ return;
+ }
+ local $/;
+ my $data = <TMPFILE>;
+ unless (close TMPFILE) {
+ $self->error ("cannot read temporary file $file: $!");
+ return;
+ }
+ return $data;
+}
+
##############################################################################
# Public interfaces
##############################################################################
@@ -93,11 +110,38 @@ sub create {
return 1;
}
-# Create a keytab from a principal. Takes the principal, the file, and
-# optionally a list of encryption types to which to limit the keytab. Return
-# true if successful, false otherwise. If the keytab creation fails, sets the
-# error.
+# Create a keytab for a principal. Returns the keytab as binary data or undef
+# on failure, setting the error.
sub keytab {
+ my ($self, $principal) = @_;
+ $principal = $self->canonicalize_principal ($principal);
+ my $kadmin = $self->{client};
+ my $file = $Wallet::Config::KEYTAB_TMP . "/keytab.$$";
+ unlink $file;
+ my $princdata = eval { $kadmin->getPrincipal ($principal) };
+ if ($@) {
+ $self->error ("error creating keytab for $principal: $@");
+ return;
+ } elsif (!$princdata) {
+ $self->error ("error creating keytab for $principal: principal does"
+ . " not exist");
+ return;
+ }
+ eval { $kadmin->extractKeytab ($princdata, $file) };
+ if ($@) {
+ $self->error ("error creating keytab for principal: $@");
+ return;
+ }
+ my $data = $self->slurp_file ($file);
+ unlink $file;
+ return $data;
+}
+
+# Create a keytab for a principal, randomizing the keys for that principal at
+# the same time. Takes the principal, the file, and optionally a list of
+# encryption types to which to limit the keytab. Return true if successful,
+# false otherwise. If the keytab creation fails, sets the error.
+sub keytab_rekey {
my ($self, $principal, $file, @enctypes) = @_;
$principal = $self->canonicalize_principal ($principal);
@@ -213,10 +257,12 @@ Wallet::Kadmin::Heimdal - Wallet Kerberos administration API for Heimdal
=head1 SYNOPSIS
my $kadmin = Wallet::Kadmin::Heimdal->new;
- $kadmin->create ("host/foo.example.com");
- $kadmin->keytab ("host/foo.example.com", "aes256-cts-hmac-sha1-96");
- my $exists = $kadmin->exists ("host/oldshell.example.com");
- $kadmin->destroy ("host/oldshell.example.com") if $exists;
+ $kadmin->create ('host/foo.example.com');
+ $kadmin->keytab_rekey ('host/foo.example.com', 'keytab',
+ 'aes256-cts-hmac-sha1-96');
+ my $data = $kadmin->keytab ('host/foo.example.com');
+ my $exists = $kadmin->exists ('host/oldshell.example.com');
+ $kadmin->destroy ('host/oldshell.example.com') if $exists;
=head1 DESCRIPTION
@@ -228,6 +274,18 @@ To use this object, several configuration parameters must be set. See
Wallet::Config(3) for details on those configuration parameters and
information about how to set wallet configuration.
+=head1 FILES
+
+=over 4
+
+=item KEYTAB_TMP/keytab.<pid>
+
+The keytab is created in this file and then read into memory. KEYTAB_TMP
+is set in the wallet configuration, and <pid> is the process ID of the
+current process. The file is unlinked after being read.
+
+=back
+
=head1 SEE ALSO
kadmin(8), Wallet::Config(3), Wallet::Kadmin(3),
diff --git a/perl/Wallet/Kadmin/MIT.pm b/perl/Wallet/Kadmin/MIT.pm
index 9ab575c..1c6d2c1 100644
--- a/perl/Wallet/Kadmin/MIT.pm
+++ b/perl/Wallet/Kadmin/MIT.pm
@@ -137,11 +137,52 @@ sub create {
return 1;
}
-# Create a keytab from a principal. Takes the principal, the file, and
-# optionally a list of encryption types to which to limit the keytab. Return
-# true if successful, false otherwise. If the keytab creation fails, sets the
-# error.
+# Retrieve an existing keytab from the KDC via a remctl call. The KDC needs
+# to be running the keytab-backend script and support the keytab retrieve
+# remctl command. In addition, the user must have configured us with the path
+# to a ticket cache and the host to which to connect with remctl. Returns the
+# keytab on success and undef on failure.
sub keytab {
+ my ($self, $principal) = @_;
+ my $host = $Wallet::Config::KEYTAB_REMCTL_HOST;
+ unless ($host and $Wallet::Config::KEYTAB_REMCTL_CACHE) {
+ $self->error ('keytab unchanging support not configured');
+ return;
+ }
+ eval { require Net::Remctl };
+ if ($@) {
+ $self->error ("keytab unchanging support not available: $@");
+ return;
+ }
+ if ($principal !~ /\@/ && $Wallet::Config::KEYTAB_REALM) {
+ $principal .= '@' . $Wallet::Config::KEYTAB_REALM;
+ }
+ local $ENV{KRB5CCNAME} = $Wallet::Config::KEYTAB_REMCTL_CACHE;
+ my $port = $Wallet::Config::KEYTAB_REMCTL_PORT || 0;
+ my $remctl_princ = $Wallet::Config::KEYTAB_REMCTL_PRINCIPAL || '';
+ my @command = ('keytab', 'retrieve', $principal);
+ my $result = Net::Remctl::remctl ($host, $port, $remctl_princ, @command);
+ if ($result->error) {
+ $self->error ("cannot retrieve keytab for $principal: ",
+ $result->error);
+ return;
+ } elsif ($result->status != 0) {
+ my $error = $result->stderr;
+ $error =~ s/\s+$//;
+ $error =~ s/\n/ /g;
+ $self->error ("cannot retrieve keytab for $principal: $error");
+ return;
+ } else {
+ return $result->stdout;
+ }
+}
+
+# Create a keytab for a principal, randomizing the keys for that principal
+# in the process. Takes the principal, the file, and optionally a list of
+# encryption types to which to limit the keytab. Return true if
+# successful, false otherwise. If the keytab creation fails, sets the
+# error.
+sub keytab_rekey {
my ($self, $principal, $file, @enctypes) = @_;
unless ($self->valid_principal ($principal)) {
$self->error ("invalid principal name: $principal");
@@ -210,7 +251,7 @@ __END__
##############################################################################
=for stopwords
-keytabs keytab kadmin KDC API Allbery
+rekeying rekeys remctl backend keytabs keytab kadmin KDC API Allbery
=head1 NAME
@@ -219,10 +260,12 @@ Wallet::Kadmin::MIT - Wallet Kerberos administration API for MIT
=head1 SYNOPSIS
my $kadmin = Wallet::Kadmin::MIT->new;
- $kadmin->create ("host/foo.example.com");
- $kadmin->keytab ("host/foo.example.com", "aes256-cts-hmac-sha1-96");
- my $exists = $kadmin->exists ("host/oldshell.example.com");
- $kadmin->destroy ("host/oldshell.example.com") if $exists;
+ $kadmin->create ('host/foo.example.com');
+ $kadmin->keytab_rekey ('host/foo.example.com', 'keytab',
+ 'aes256-cts-hmac-sha1-96');
+ my $data = $kadmin->keytab ('host/foo.example.com');
+ my $exists = $kadmin->exists ('host/oldshell.example.com');
+ $kadmin->destroy ('host/oldshell.example.com') if $exists;
=head1 DESCRIPTION
@@ -231,6 +274,13 @@ providing an interface to create and delete principals and create keytabs.
It provides the API documented in Wallet::Kadmin(3) for an MIT Kerberos
KDC.
+MIT Kerberos does not provide any method via the kadmin network protocol
+to retrieve a keytab for a principal without rekeying it, so the keytab()
+method (as opposed to keytab_rekey(), which rekeys the principal) is
+implemented using a remctl backend. For that method (used for unchanging
+keytab objects) to work, the necessary wallet configuration and remctl
+interface on the KDC must be set up.
+
To use this object, several configuration parameters must be set. See
Wallet::Config(3) for details on those configuration parameters and
information about how to set wallet configuration.
diff --git a/perl/Wallet/Object/Keytab.pm b/perl/Wallet/Object/Keytab.pm
index 44ee003..5c66967 100644
--- a/perl/Wallet/Object/Keytab.pm
+++ b/perl/Wallet/Object/Keytab.pm
@@ -180,49 +180,6 @@ sub sync_list {
}
##############################################################################
-# Keytab retrieval
-##############################################################################
-
-# Retrieve an existing keytab from the KDC via a remctl call. The KDC needs
-# to be running the keytab-backend script and support the keytab retrieve
-# remctl command. In addition, the user must have configured us with the path
-# to a ticket cache and the host to which to connect with remctl. Returns the
-# keytab on success and undef on failure.
-sub keytab_retrieve {
- my ($self, $keytab) = @_;
- my $host = $Wallet::Config::KEYTAB_REMCTL_HOST;
- unless ($host and $Wallet::Config::KEYTAB_REMCTL_CACHE) {
- $self->error ('keytab unchanging support not configured');
- return;
- }
- eval { require Net::Remctl };
- if ($@) {
- $self->error ("keytab unchanging support not available: $@");
- return;
- }
- if ($Wallet::Config::KEYTAB_REALM) {
- $keytab .= '@' . $Wallet::Config::KEYTAB_REALM;
- }
- local $ENV{KRB5CCNAME} = $Wallet::Config::KEYTAB_REMCTL_CACHE;
- my $port = $Wallet::Config::KEYTAB_REMCTL_PORT || 0;
- my $principal = $Wallet::Config::KEYTAB_REMCTL_PRINCIPAL || '';
- my @command = ('keytab', 'retrieve', $keytab);
- my $result = Net::Remctl::remctl ($host, $port, $principal, @command);
- if ($result->error) {
- $self->error ("cannot retrieve keytab for $keytab: ", $result->error);
- return;
- } elsif ($result->status != 0) {
- my $error = $result->stderr;
- $error =~ s/\s+$//;
- $error =~ s/\n/ /g;
- $self->error ("cannot retrieve keytab for $keytab: $error");
- return;
- } else {
- return $result->stdout;
- }
-}
-
-##############################################################################
# Core methods
##############################################################################
@@ -365,8 +322,9 @@ sub get {
$self->error ("cannot get $id: object is locked");
return;
}
+ my $kadmin = $self->{kadmin};
if ($self->flag_check ('unchanging')) {
- my $result = $self->keytab_retrieve ($self->{name});
+ my $result = $kadmin->keytab ($self->{name});
if (defined $result) {
$self->log_action ('get', $user, $host, $time);
}
@@ -379,8 +337,7 @@ sub get {
my $file = $Wallet::Config::KEYTAB_TMP . "/keytab.$$";
unlink $file;
my @enctypes = $self->attr ('enctypes');
- my $kadmin = $self->{kadmin};
- if (not $kadmin->keytab ($self->{name}, $file, @enctypes)) {
+ if (not $kadmin->keytab_rekey ($self->{name}, $file, @enctypes)) {
$self->error ($kadmin->error);
return;
}
diff --git a/perl/t/kadmin.t b/perl/t/kadmin.t
index 9c49995..a29cae3 100755
--- a/perl/t/kadmin.t
+++ b/perl/t/kadmin.t
@@ -91,7 +91,7 @@ SKIP: {
is ($kadmin->create ('wallet/one'), 1, 'Creating wallet/one works');
is ($kadmin->exists ('wallet/one'), 1, ' and it now exists');
unlink ('./tmp.keytab');
- is ($kadmin->keytab ('wallet/one', './tmp.keytab'), 1,
+ is ($kadmin->keytab_rekey ('wallet/one', './tmp.keytab'), 1,
' and retrieving a keytab works');
ok (-s './tmp.keytab', ' and the resulting keytab is non-zero');
is (getcreds ('./tmp.keytab', "wallet/one\@$Wallet::Config::KEYTAB_REALM"),
@@ -101,7 +101,7 @@ SKIP: {
# Delete the principal and confirm behavior.
is ($kadmin->destroy ('wallet/one'), 1, 'Deleting principal works');
is ($kadmin->exists ('wallet/one'), 0, ' and now it does not exist');
- is ($kadmin->keytab ('wallet/one', './tmp.keytab'), undef,
+ is ($kadmin->keytab_rekey ('wallet/one', './tmp.keytab'), undef,
' and retrieving the keytab does not work');
ok (! -f './tmp.keytab', ' and no file was created');
like ($kadmin->error, qr%^error creating keytab for wallet/one%,
diff --git a/perl/t/keytab.t b/perl/t/keytab.t
index a14b63e..a702c0f 100755
--- a/perl/t/keytab.t
+++ b/perl/t/keytab.t
@@ -9,7 +9,7 @@
# See LICENSE for licensing terms.
use POSIX qw(strftime);
-use Test::More tests => 125;
+use Test::More tests => 135;
use Wallet::Admin;
use Wallet::Config;
@@ -378,12 +378,7 @@ EOO
# Tests for unchanging support. Skip these if we don't have a keytab or if we
# can't find remctld.
SKIP: {
- skip 'no keytab configuration', 17 unless -f 't/data/test.keytab';
- my @path = (split (':', $ENV{PATH}), '/usr/local/sbin', '/usr/sbin');
- my ($remctld) = grep { -x $_ } map { "$_/remctld" } @path;
- skip 'remctld not found', 17 unless $remctld;
- eval { require Net::Remctl };
- skip 'Net::Remctl not available', 17 if $@;
+ skip 'no keytab configuration', 27 unless -f 't/data/test.keytab';
# Set up our configuration.
$Wallet::Config::KEYTAB_FILE = 't/data/test.keytab';
@@ -406,41 +401,85 @@ SKIP: {
ok (defined ($two), 'Creating wallet/two succeeds');
is ($two->flag_set ('unchanging', @trace), 1, ' and setting unchanging');
- # Now spawn our remctld server and get a ticket cache.
- remctld_spawn ($remctld, $principal, 't/data/test.keytab',
- 't/data/keytab.conf');
- $ENV{KRB5CCNAME} = 'krb5cc_test';
- getcreds ('t/data/test.keytab', $principal);
- $ENV{KRB5CCNAME} = 'krb5cc_good';
+ # Finally we can test. First the MIT Kerberos tests.
+ SKIP: {
+ skip 'skipping MIT unchanging tests for Heimdal', 12
+ if (lc ($Wallet::Config::KEYTAB_KRBTYPE) eq 'heimdal');
+
+ # We need remctld and Net::Remctl.
+ my @path = (split (':', $ENV{PATH}), '/usr/local/sbin', '/usr/sbin');
+ my ($remctld) = grep { -x $_ } map { "$_/remctld" } @path;
+ skip 'remctld not found', 12 unless $remctld;
+ eval { require Net::Remctl };
+ skip 'Net::Remctl not available', 12 if $@;
+
+ # Now spawn our remctld server and get a ticket cache.
+ remctld_spawn ($remctld, $principal, 't/data/test.keytab',
+ 't/data/keytab.conf');
+ $ENV{KRB5CCNAME} = 'krb5cc_test';
+ getcreds ('t/data/test.keytab', $principal);
+ $ENV{KRB5CCNAME} = 'krb5cc_good';
+
+ # Do the unchanging tests for MIT Kerberos.
+ is ($one->get (@trace), undef, 'Get without configuration fails');
+ is ($one->error, 'keytab unchanging support not configured',
+ ' with the right error');
+ $Wallet::Config::KEYTAB_REMCTL_CACHE = 'krb5cc_test';
+ is ($one->get (@trace), undef, ' and still fails without host');
+ is ($one->error, 'keytab unchanging support not configured',
+ ' with the right error');
+ $Wallet::Config::KEYTAB_REMCTL_HOST = 'localhost';
+ $Wallet::Config::KEYTAB_REMCTL_PRINCIPAL = $principal;
+ $Wallet::Config::KEYTAB_REMCTL_PORT = 14373;
+ is ($one->get (@trace), undef, ' and still fails without ACL');
+ is ($one->error,
+ "cannot retrieve keytab for wallet/one\@$realm: Access denied",
+ ' with the right error');
+ open (ACL, '>', 'test-acl') or die "cannot create test-acl: $!\n";
+ print ACL "$principal\n";
+ close ACL;
+ is ($one->get (@trace), 'Keytab for wallet/one', 'Now get works');
+ is ($ENV{KRB5CCNAME}, 'krb5cc_good',
+ ' and we did not nuke the cache name');
+ is ($one->get (@trace), 'Keytab for wallet/one',
+ ' and we get the same thing the second time');
+ is ($one->flag_clear ('unchanging', @trace), 1,
+ 'Clearing the unchanging flag works');
+ my $data = $object->get (@trace);
+ ok (defined ($data), ' and getting the keytab works');
+ ok (valid ($data, 'wallet/one'), ' and the keytab is valid');
+ is ($two->get (@trace), undef, 'Get for wallet/two does not work');
+ is ($two->error,
+ "cannot retrieve keytab for wallet/two\@$realm: bite me",
+ ' with the right error');
+ is ($one->destroy (@trace), 1, 'Destroying wallet/one works');
+ is ($two->destroy (@trace), 1, ' as does destroying wallet/two');
+ remctld_stop;
+ }
- # Finally we can test.
- is ($one->get (@trace), undef, 'Get without configuration fails');
- is ($one->error, 'keytab unchanging support not configured',
- ' with the right error');
- $Wallet::Config::KEYTAB_REMCTL_CACHE = 'krb5cc_test';
- is ($one->get (@trace), undef, ' and still fails without host');
- is ($one->error, 'keytab unchanging support not configured',
- ' with the right error');
- $Wallet::Config::KEYTAB_REMCTL_HOST = 'localhost';
- $Wallet::Config::KEYTAB_REMCTL_PRINCIPAL = $principal;
- $Wallet::Config::KEYTAB_REMCTL_PORT = 14373;
- is ($one->get (@trace), undef, ' and still fails without ACL');
- is ($one->error,
- "cannot retrieve keytab for wallet/one\@$realm: Access denied",
- ' with the right error');
- open (ACL, '>', 'test-acl') or die "cannot create test-acl: $!\n";
- print ACL "$principal\n";
- close ACL;
- is ($one->get (@trace), 'Keytab for wallet/one', 'Now get works');
- is ($ENV{KRB5CCNAME}, 'krb5cc_good',
- ' and we did not nuke the cache name');
- is ($two->get (@trace), undef, ' but get for wallet/two does not');
- is ($two->error,
- "cannot retrieve keytab for wallet/two\@$realm: bite me",
- ' with the right error');
- is ($one->destroy (@trace), 1, 'Destroying wallet/one works');
- is ($two->destroy (@trace), 1, ' as does destroying wallet/two');
- remctld_stop;
+ # Now Heimdal. Since the keytab contains timestamps, before testing for
+ # equality we have to substitute out the timestamps.
+ SKIP: {
+ skip 'skipping Heimdal unchanging tests for MIT', 10
+ if (lc ($Wallet::Config::KEYTAB_KRBTYPE) eq 'mit');
+ my $data = $one->get (@trace);
+ ok (defined $data, 'Get of unchanging keytab works');
+ ok (valid ($data, 'wallet/one'), ' and the keytab is valid');
+ my $second = $one->get (@trace);
+ ok (defined $second, ' and second retrieval also works');
+ $data =~ s/one.{8}/one\000\000\000\000\000\000\000\000/g;
+ $second =~ s/one.{8}/one\000\000\000\000\000\000\000\000/g;
+ is ($data, $second, ' and the keytab matches');
+ is ($one->flag_clear ('unchanging', @trace), 1,
+ 'Clearing the unchanging flag works');
+ $data = $one->get (@trace);
+ ok (defined ($data), ' and getting the keytab works');
+ ok (valid ($data, 'wallet/one'), ' and the keytab is valid');
+ $data =~ s/one.{8}/one\000\000\000\000\000\000\000\000/g;
+ ok ($data ne $second, ' and the new keytab is different');
+ is ($one->destroy (@trace), 1, 'Destroying wallet/one works');
+ is ($two->destroy (@trace), 1, ' as does destroying wallet/two');
+ }
# Check that history has been updated correctly.
$history .= <<"EOO";
@@ -450,6 +489,12 @@ $date set flag unchanging
by $user from $host
$date get
by $user from $host
+$date get
+ by $user from $host
+$date clear flag unchanging
+ by $user from $host
+$date get
+ by $user from $host
$date destroy
by $user from $host
EOO