diff options
Diffstat (limited to 'perl/Wallet')
-rw-r--r-- | perl/Wallet/Object/Keytab.pm | 196 |
1 files changed, 158 insertions, 38 deletions
diff --git a/perl/Wallet/Object/Keytab.pm b/perl/Wallet/Object/Keytab.pm index 34f580f..4727590 100644 --- a/perl/Wallet/Object/Keytab.pm +++ b/perl/Wallet/Object/Keytab.pm @@ -121,10 +121,12 @@ sub kadmin_addprinc { return 1; } -# Create a keytab from a principal. Return true if successful, false -# otherwise. If the keytab creation fails, sets the error. +# 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. sub kadmin_ktadd { - my ($self, $principal, $file) = @_; + my ($self, $principal, $file, @enctypes) = @_; unless ($self->valid_principal ($principal)) { $self->error ("invalid principal name: $principal"); return undef; @@ -132,7 +134,12 @@ sub kadmin_ktadd { if ($Wallet::Config::KEYTAB_REALM) { $principal .= '@' . $Wallet::Config::KEYTAB_REALM; } - my $output = eval { $self->kadmin ("ktadd -q -k $file $principal") }; + my $command = "ktadd -q -k $file"; + if (@enctypes) { + @enctypes = map { /:/ ? $_ : "$_:normal" } @enctypes; + $command .= ' -e "' . join (' ', @enctypes) . '"'; + } + my $output = eval { $self->kadmin ("$command $principal") }; if ($@) { $self->error ($@); return undef; @@ -388,6 +395,77 @@ sub kaserver_clear { } ############################################################################## +# Enctype restriction +############################################################################## + +# Set the enctype restrictions for a keytab. Called by attr() and takes a +# reference to the encryption types to set. Returns true on success and false +# on failure, setting the object error if it fails. +sub enctypes_set { + my ($self, $enctypes, $user, $host, $time) = @_; + $time ||= time; + my @trace = ($user, $host, $time); + my $name = $self->{name}; + my %enctypes = map { $_ => 1 } @$enctypes; + eval { + my $sql = 'select ke_enctype from keytab_enctypes where ke_name = ?'; + my $sth = $self->{dbh}->prepare ($sql); + $sth->execute ($name); + my (@current, $entry); + while (defined ($entry = $sth->fetchrow_arrayref)) { + push (@current, @$entry); + } + for my $enctype (@current) { + if ($enctypes{$enctype}) { + delete $enctypes{$enctype}; + } else { + $sql = 'delete from keytab_enctypes where ke_name = ? and + ke_enctype = ?'; + $self->{dbh}->do ($sql, undef, $name, $enctype); + $self->log_set ('type_data enctypes', $enctype, undef, @trace); + } + } + for my $enctype (keys %enctypes) { + $sql = 'insert into keytab_enctypes (ke_name, ke_enctype) values + (?, ?)'; + $self->{dbh}->do ($sql, undef, $name, $enctype); + $self->log_set ('type_data enctypes', undef, $enctype, @trace); + } + $self->{dbh}->commit; + }; + if ($@) { + $self->error ($@); + $self->{dbh}->rollback; + return undef; + } + return 1; +} + +# Return a list of the encryption types current set for a keytab. Called by +# attr() or get(). Returns the empty list on failure or on an empty list of +# enctype restrictions, but sets the object error on failure so the caller +# should use that to determine success. +sub enctypes_list { + my ($self) = @_; + my @enctypes; + eval { + my $sql = 'select ke_enctype from keytab_enctypes where ke_name = ? + order by ke_enctype'; + my $sth = $self->{dbh}->prepare ($sql); + $sth->execute ($self->{name}); + my $entry; + while (defined ($entry = $sth->fetchrow_arrayref)) { + push (@enctypes, @$entry); + } + }; + if ($@) { + $self->error ($@); + return; + } + return @enctypes; +} + +############################################################################## # Keytab retrieval ############################################################################## @@ -434,60 +512,77 @@ sub keytab_retrieve { # Core methods ############################################################################## -# Override attr to support setting the sync attribute. +# Override attr to support setting the enctypes and sync attributes. sub attr { my ($self, $attribute, $values, $user, $host, $time) = @_; + my %known = map { $_ => 1 } qw(enctypes sync); undef $self->{error}; - if ($attribute ne 'sync') { + unless ($known{$attribute}) { $self->error ("unknown attribute $attribute"); return; } if ($values) { - if (@$values > 1) { - $self->error ('only one synchronization target supported'); - return; - } elsif (@$values and $values->[0] ne 'kaserver') { - $self->error ("unsupported synchronization target $values->[0]"); - return; - } - $time ||= time; - my @trace = ($user, $host, $time); - if (@$values) { - return $self->kaserver_set ($user, $host, $time); - } else { - return $self->kaserver_clear ($user, $host, $time); + if ($attribute eq 'enctypes') { + $self->enctypes_set ($values, $user, $host, $time); + } elsif ($attribute eq 'sync') { + if (@$values > 1) { + $self->error ('only one synchronization target supported'); + return; + } elsif (@$values and $values->[0] ne 'kaserver') { + my $target = $values->[0]; + $self->error ("unsupported synchronization target $target"); + return; + } elsif (@$values) { + return $self->kaserver_set ($user, $host, $time); + } else { + return $self->kaserver_clear ($user, $host, $time); + } } } else { - my @targets; - eval { - my $sql = 'select ks_target from keytab_sync where ks_name = ? - order by ks_target'; - my $sth = $self->{dbh}->prepare ($sql); - $sth->execute ($self->{name}); - my $target; - while (defined ($target = $sth->fetchrow_array)) { - push (@targets, $target); + if ($attribute eq 'enctypes') { + return $self->enctypes_list; + } elsif ($attribute eq 'sync') { + my @targets; + eval { + my $sql = 'select ks_target from keytab_sync where ks_name = ? + order by ks_target'; + my $sth = $self->{dbh}->prepare ($sql); + $sth->execute ($self->{name}); + my $target; + while (defined ($target = $sth->fetchrow_array)) { + push (@targets, $target); + } + }; + if ($@) { + $self->error ($@); + return; } - }; - if ($@) { - $self->error ($@); - return; + return @targets; } - return @targets; } } -# Override attr_show to display the sync attribute. +# Override attr_show to display the enctypes and sync attributes. sub attr_show { my ($self) = @_; + my $output = ''; my @targets = $self->attr ('sync'); if (not @targets and $self->error) { return undef; } elsif (@targets) { - return sprintf ("%15s: %s\n", 'Synced with', "@targets"); - } else { - return ''; + $output .= sprintf ("%15s: %s\n", 'Synced with', "@targets"); + } + my @enctypes = $self->attr ('enctypes'); + if (not @enctypes and $self->error) { + return undef; + } elsif (@enctypes) { + $output .= sprintf ("%15s: %s\n", 'Enctypes', $enctypes[0]); + shift @enctypes; + for my $enctype (@enctypes) { + $output .= (' ' x 17) . $enctype . "\n"; + } } + return $output; } # Override create to start by creating the principal in Kerberos and only @@ -514,6 +609,18 @@ sub destroy { return undef; } } + eval { + my $sql = 'delete from keytab_sync where ks_name = ?'; + $self->{dbh}->do ($sql, undef, $self->{name}); + $sql = 'delete from keytab_enctypes where ke_name = ?'; + $self->{dbh}->do ($sql, undef, $self->{name}); + $self->{dbh}->commit; + }; + if ($@) { + $self->error ($@); + $self->{dbh}->rollback; + return undef; + } return undef if not $self->kadmin_delprinc ($self->{name}); return $self->SUPER::destroy ($user, $host, $time); } @@ -541,7 +648,8 @@ sub get { } my $file = $Wallet::Config::KEYTAB_TMP . "/keytab.$$"; unlink $file; - return undef if not $self->kadmin_ktadd ($self->{name}, $file); + my @enctypes = $self->attr ('enctypes'); + return undef if not $self->kadmin_ktadd ($self->{name}, $file, @enctypes); local *KEYTAB; unless (open (KEYTAB, '<', $file)) { my $princ = $self->{name}; @@ -627,6 +735,18 @@ supported: =over 4 +=item enctypes + +Restricts the generated keytab to a specific set of encryption types. The +values of this attribute must be enctype strings recognized by Kerberos +(strings like C<aes256-cts> or C<des-cbc-crc>). Note that the salt should +not be included; since the salt is irrelevant for keytab keys, it will +always be set to C<normal> by the wallet. + +If this attribute is set, the specified enctype list will be passed to +ktadd when get() is called for that keytab. If it is not set, the default +set in the KDC will be used. + =item sync Sets the external systems to which the key of a given principal is |