summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--perl/Wallet/Kadmin.pm54
-rw-r--r--perl/Wallet/Kadmin/Heimdal.pm41
-rw-r--r--perl/Wallet/Kadmin/MIT.pm39
-rw-r--r--perl/Wallet/Object/Keytab.pm42
-rwxr-xr-xperl/t/kadmin.t15
-rwxr-xr-xperl/t/keytab.t42
-rw-r--r--perl/t/lib/Util.pm21
7 files changed, 137 insertions, 117 deletions
diff --git a/perl/Wallet/Kadmin.pm b/perl/Wallet/Kadmin.pm
index f3c2895..074dd1e 100644
--- a/perl/Wallet/Kadmin.pm
+++ b/perl/Wallet/Kadmin.pm
@@ -23,6 +23,33 @@ use Wallet::Config ();
$VERSION = '0.03';
##############################################################################
+# Utility functions for child classes
+##############################################################################
+
+# Read the entirety of a possibly binary file and return the contents,
+# deleting the file after reading it. If reading the file fails, set the
+# error message and return undef.
+sub read_keytab {
+ my ($self, $file) = @_;
+ local *TMPFILE;
+ unless (open (TMPFILE, '<', $file)) {
+ $self->error ("cannot open temporary file $file: $!");
+ return;
+ }
+ local $/;
+ undef $!;
+ my $data = <TMPFILE>;
+ if ($!) {
+ $self->error ("cannot read temporary file $file: $!");
+ unlink $file;
+ return;
+ }
+ close TMPFILE;
+ unlink $file;
+ return $data;
+}
+
+##############################################################################
# Public methods
##############################################################################
@@ -84,9 +111,9 @@ Wallet::Kadmin - Kerberos administration API for wallet keytab backend
my $kadmin = Wallet::Kadmin->new;
$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 $data = $kadmin->keytab_rekey ('host/foo.example.com',
+ 'aes256-cts-hmac-sha1-96');
+ $data = $kadmin->keytab ('host/foo.example.com');
my $exists = $kadmin->exists ('host/oldshell.example.com');
$kadmin->destroy ('host/oldshell.example.com') if $exists;
@@ -101,9 +128,8 @@ interact with that implementation's kadmin interface.
The class uses Wallet::Config to find which type of kadmin interface is in
use and then returns an object to use for interacting with that interface.
-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.
+See L<Wallet::Config/"KEYTAB OBJECT CONFIGURATION"> for details on how to
+configure this module.
=head1 CLASS METHODS
@@ -174,7 +200,7 @@ 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 ...])
+=item keytab_rekey(PRINCIPAL [, 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
@@ -183,7 +209,19 @@ 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.
+Returns the keytab as binary data on success and undef on failure.
+
+=back
+
+The following methods are utility methods to aid with child class
+implementation and should only be called by child classes.
+
+=over 4
+
+=item read_keytab(FILE)
+
+Reads the contents of the keytab stored in FILE into memory and returns it
+as binary data. On failure, returns undef and sets the object error.
=back
diff --git a/perl/Wallet/Kadmin/Heimdal.pm b/perl/Wallet/Kadmin/Heimdal.pm
index e066006..d1eecda 100644
--- a/perl/Wallet/Kadmin/Heimdal.pm
+++ b/perl/Wallet/Kadmin/Heimdal.pm
@@ -39,23 +39,6 @@ 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
##############################################################################
@@ -132,17 +115,15 @@ sub keytab {
$self->error ("error creating keytab for principal: $@");
return;
}
- my $data = $self->slurp_file ($file);
- unlink $file;
- return $data;
+ return $self->read_keytab ($file);
}
# 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.
+# the same time. Takes the principal and an optional list of encryption types
+# to which to limit the keytab. Return the keytab data on success and undef
+# on failure. If the keytab creation fails, sets the error.
sub keytab_rekey {
- my ($self, $principal, $file, @enctypes) = @_;
+ my ($self, $principal, @enctypes) = @_;
$principal = $self->canonicalize_principal ($principal);
# The way Heimdal works, you can only remove enctypes from a principal,
@@ -188,12 +169,14 @@ sub keytab_rekey {
}
# Create the keytab.
+ my $file = $Wallet::Config::KEYTAB_TMP . "/keytab.$$";
+ unlink $file;
eval { $kadmin->extractKeytab ($princdata, $file) };
if ($@) {
$self->error ("error creating keytab for principal: $@");
return;
}
- return 1;
+ return $self->read_keytab ($file);
}
# Delete a principal from Kerberos. Return true if successful, false
@@ -227,6 +210,9 @@ sub new {
and defined ($Wallet::Config::KEYTAB_REALM)) {
die "keytab object implementation not configured\n";
}
+ unless (defined ($Wallet::Config::KEYTAB_TMP)) {
+ die "KEYTAB_TMP configuration variable not set\n";
+ }
my @options = (RaiseError => 1,
Principal => $Wallet::Config::KEYTAB_PRINCIPAL,
Realm => $Wallet::Config::KEYTAB_REALM,
@@ -270,9 +256,8 @@ Wallet::Kadmin::Heimdal implements the Wallet::Kadmin API for Heimdal,
providing an interface to create and delete principals and create keytabs.
It provides the API documented in Wallet::Kadmin(3) for a Heimdal KDC.
-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.
+To use this class, several configuration parameters must be set. See
+L<Wallet::Config/"KEYTAB OBJECT CONFIGURATION"> for details.
=head1 FILES
diff --git a/perl/Wallet/Kadmin/MIT.pm b/perl/Wallet/Kadmin/MIT.pm
index 1c6d2c1..434e93d 100644
--- a/perl/Wallet/Kadmin/MIT.pm
+++ b/perl/Wallet/Kadmin/MIT.pm
@@ -178,12 +178,11 @@ sub keytab {
}
# 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.
+# in the process. Takes the principal and an optional list of encryption
+# types to which to limit the keytab. Return the keytab data on success
+# and undef otherwise. If the keytab creation fails, sets the error.
sub keytab_rekey {
- my ($self, $principal, $file, @enctypes) = @_;
+ my ($self, $principal, @enctypes) = @_;
unless ($self->valid_principal ($principal)) {
$self->error ("invalid principal name: $principal");
return;
@@ -191,6 +190,8 @@ sub keytab_rekey {
if ($Wallet::Config::KEYTAB_REALM) {
$principal .= '@' . $Wallet::Config::KEYTAB_REALM;
}
+ my $file = $Wallet::Config::KEYTAB_TMP . "/keytab.$$";
+ unlink $file;
my $command = "ktadd -q -k $file";
if (@enctypes) {
@enctypes = map { /:/ ? $_ : "$_:normal" } @enctypes;
@@ -203,7 +204,7 @@ sub keytab_rekey {
$self->error ("error creating keytab for $principal: $1");
return;
}
- return 1;
+ return $self->read_keytab ($file);
}
# Delete a principal from Kerberos. Return true if successful, false
@@ -238,6 +239,9 @@ sub destroy {
# kadmin directly.
sub new {
my ($class) = @_;
+ unless (defined ($Wallet::Config::KEYTAB_TMP)) {
+ die "KEYTAB_TMP configuration variable not set\n";
+ }
my $self = {};
bless ($self, $class);
return $self;
@@ -261,9 +265,9 @@ Wallet::Kadmin::MIT - Wallet Kerberos administration API for MIT
my $kadmin = Wallet::Kadmin::MIT->new;
$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 $data = $kadmin->keytab_rekey ('host/foo.example.com',
+ 'aes256-cts-hmac-sha1-96');
+ $data = $kadmin->keytab ('host/foo.example.com');
my $exists = $kadmin->exists ('host/oldshell.example.com');
$kadmin->destroy ('host/oldshell.example.com') if $exists;
@@ -281,9 +285,20 @@ 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.
+To use this class, several configuration parameters must be set. See
+L<Wallet::Config/"KEYTAB OBJECT CONFIGURATION"> for details.
+
+=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 LIMITATIONS
diff --git a/perl/Wallet/Object/Keytab.pm b/perl/Wallet/Object/Keytab.pm
index 5c66967..edb26b3 100644
--- a/perl/Wallet/Object/Keytab.pm
+++ b/perl/Wallet/Object/Keytab.pm
@@ -323,43 +323,19 @@ sub get {
return;
}
my $kadmin = $self->{kadmin};
+ my $result;
if ($self->flag_check ('unchanging')) {
- my $result = $kadmin->keytab ($self->{name});
- if (defined $result) {
- $self->log_action ('get', $user, $host, $time);
- }
- return $result;
- }
- unless (defined ($Wallet::Config::KEYTAB_TMP)) {
- $self->error ('KEYTAB_TMP configuration variable not set');
- return;
+ $result = $kadmin->keytab ($self->{name});
+ } else {
+ my @enctypes = $self->attr ('enctypes');
+ $result = $kadmin->keytab_rekey ($self->{name}, @enctypes);
}
- my $file = $Wallet::Config::KEYTAB_TMP . "/keytab.$$";
- unlink $file;
- my @enctypes = $self->attr ('enctypes');
- if (not $kadmin->keytab_rekey ($self->{name}, $file, @enctypes)) {
+ if (defined $result) {
+ $self->log_action ('get', $user, $host, $time);
+ } else {
$self->error ($kadmin->error);
- return;
- }
- local *KEYTAB;
- unless (open (KEYTAB, '<', $file)) {
- my $princ = $self->{name};
- $self->error ("error opening keytab for principal $princ: $!");
- return;
- }
- local $/;
- undef $!;
- my $data = <KEYTAB>;
- if ($!) {
- my $princ = $self->{name};
- $self->error ("error reading keytab for principal $princ: $!");
- unlink $file;
- return;
}
- close KEYTAB;
- unlink $file;
- $self->log_action ('get', $user, $host, $time);
- return $data;
+ return $result;
}
1;
diff --git a/perl/t/kadmin.t b/perl/t/kadmin.t
index a29cae3..b9ac769 100755
--- a/perl/t/kadmin.t
+++ b/perl/t/kadmin.t
@@ -8,7 +8,9 @@
# See LICENSE for licensing terms.
use POSIX qw(strftime);
-use Test::More tests => 33;
+use Test::More tests => 32;
+
+BEGIN { $Wallet::Config::KEYTAB_TMP = '.' }
use Wallet::Admin;
use Wallet::Config;
@@ -90,13 +92,10 @@ SKIP: {
# check the details of the return in the keytab check.
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_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"),
- 1, ' and works for authentication');
- unlink ('./tmp.keytab');
+ my $data = $kadmin->keytab_rekey ('wallet/one');
+ ok (defined ($data), ' and retrieving a keytab works');
+ is (keytab_valid ($data, 'wallet/one'), 1,
+ ' and works for authentication');
# Delete the principal and confirm behavior.
is ($kadmin->destroy ('wallet/one'), 1, 'Deleting principal works');
diff --git a/perl/t/keytab.t b/perl/t/keytab.t
index a702c0f..4e253eb 100755
--- a/perl/t/keytab.t
+++ b/perl/t/keytab.t
@@ -11,6 +11,8 @@
use POSIX qw(strftime);
use Test::More tests => 135;
+BEGIN { $Wallet::Config::KEYTAB_TMP = '.' }
+
use Wallet::Admin;
use Wallet::Config;
use Wallet::Kadmin;
@@ -89,21 +91,6 @@ sub created {
}
}
-# Given keytab data and the principal, write it to a file and try
-# authenticating using kinit.
-sub valid {
- my ($keytab, $principal) = @_;
- open (KEYTAB, '>', 'keytab') or die "cannot create keytab: $!\n";
- print KEYTAB $keytab;
- close KEYTAB;
- $principal .= '@' . $Wallet::Config::KEYTAB_REALM;
- my $result = getcreds ('keytab', $principal);
- if ($result) {
- unlink 'keytab';
- }
- return $result;
-}
-
# Given keytab data, write it to a file and try to determine the enctypes of
# the keys present in that file. Returns the enctypes as a list, with UNKNOWN
# for encryption types that weren't recognized. This is an ugly way of doing
@@ -168,7 +155,6 @@ SKIP: {
$Wallet::Config::KEYTAB_PRINCIPAL = contents ('t/data/test.principal');
$Wallet::Config::KEYTAB_REALM = contents ('t/data/test.realm');
$Wallet::Config::KEYTAB_KRBTYPE = contents ('t/data/test.krbtype');
- $Wallet::Config::KEYTAB_TMP = '.';
my $realm = $Wallet::Config::KEYTAB_REALM;
# Clean up the principals we're going to use.
@@ -178,6 +164,16 @@ SKIP: {
# Don't destroy the user's Kerberos ticket cache.
$ENV{KRB5CCNAME} = 'krb5cc_test';
+ # Test that object creation without KEYTAB_TMP fails.
+ undef $Wallet::Config::KEYTAB_TMP;
+ $object = eval {
+ Wallet::Object::Keytab->create ('keytab', 'wallet/one', $dbh, @trace)
+ };
+ is ($object, undef, 'Creating keytab without KEYTAB_TMP fails');
+ is ($@, "KEYTAB_TMP configuration variable not set\n",
+ ' with the right error');
+ $Wallet::Config::KEYTAB_TMP = '.';
+
# Okay, now we can test. First, create.
$object = eval {
Wallet::Object::Keytab->create ('keytab', "wallet\nf", $dbh, @trace)
@@ -244,7 +240,7 @@ SKIP: {
is ($object->error, '', ' and getting the keytab works');
}
ok (! -f "./keytab.$$", ' and the temporary file was cleaned up');
- ok (valid ($data, 'wallet/one'), ' and the keytab is valid');
+ ok (keytab_valid ($data, 'wallet/one'), ' and the keytab is valid');
# For right now, this is the only backend type that we have for which we
# can do a get, so test display of the last download information.
@@ -261,12 +257,6 @@ EOO
is ($object->show, $expected, 'Show output is correct');
# Test error handling on keytab retrieval.
- undef $Wallet::Config::KEYTAB_TMP;
- $data = $object->get (@trace);
- is ($data, undef, 'Getting a keytab without a tmp directory fails');
- is ($object->error, 'KEYTAB_TMP configuration variable not set',
- ' with the right error');
- $Wallet::Config::KEYTAB_TMP = '.';
SKIP: {
skip 'no kadmin program test for Heimdal', 2
if $Wallet::Config::KEYTAB_KRBTYPE eq 'Heimdal';
@@ -447,7 +437,7 @@ SKIP: {
'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');
+ ok (keytab_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",
@@ -464,7 +454,7 @@ SKIP: {
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');
+ ok (keytab_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;
@@ -474,7 +464,7 @@ SKIP: {
'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');
+ ok (keytab_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');
diff --git a/perl/t/lib/Util.pm b/perl/t/lib/Util.pm
index ac0f530..ab88b39 100644
--- a/perl/t/lib/Util.pm
+++ b/perl/t/lib/Util.pm
@@ -20,7 +20,8 @@ $VERSION = '0.02';
use Exporter ();
@ISA = qw(Exporter);
-@EXPORT = qw(contents db_setup getcreds remctld_spawn remctld_stop);
+@EXPORT = qw(contents db_setup getcreds keytab_valid remctld_spawn
+ remctld_stop);
##############################################################################
# General utility functions
@@ -66,7 +67,7 @@ sub db_setup {
}
##############################################################################
-# Local ticket cache
+# Kerberos utility functions
##############################################################################
# Given a keytab file and a principal, try authenticating with kinit.
@@ -85,6 +86,22 @@ sub getcreds {
return 0;
}
+# Given keytab data and the principal, write it to a file and try
+# authenticating using kinit.
+sub keytab_valid {
+ my ($keytab, $principal) = @_;
+ open (KEYTAB, '>', 'keytab') or die "cannot create keytab: $!\n";
+ print KEYTAB $keytab;
+ close KEYTAB;
+ $principal .= '@' . $Wallet::Config::KEYTAB_REALM
+ unless $principal =~ /\@/;
+ my $result = getcreds ('keytab', $principal);
+ if ($result) {
+ unlink 'keytab';
+ }
+ return $result;
+}
+
##############################################################################
# remctld handling
##############################################################################