diff options
Diffstat (limited to 'perl/Wallet')
-rw-r--r-- | perl/Wallet/Config.pm | 21 | ||||
-rw-r--r-- | perl/Wallet/Kadmin.pm | 43 | ||||
-rw-r--r-- | perl/Wallet/Kadmin/Heimdal.pm | 74 | ||||
-rw-r--r-- | perl/Wallet/Kadmin/MIT.pm | 68 | ||||
-rw-r--r-- | perl/Wallet/Object/Keytab.pm | 49 |
5 files changed, 169 insertions, 86 deletions
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; } |