From 0eb853eb2ef7e7063c0219ce2cbd1e239d5579b7 Mon Sep 17 00:00:00 2001 From: Bill MacAllister Date: Thu, 3 Dec 2015 00:27:33 +0000 Subject: Implement support for managed Active Directory keytabs This version implements Active Directory as the store for keytabs. The interface to Active Directory uses a combination of direct LDAP queries and the msktutil utility. This version does not support the wallet unchanging flag. Unchanging requires that a keytab be retrieved without changing the password/kvno which is not supported by msktutil. --- NEWS | 9 + perl/lib/Wallet/Kadmin.pm | 3 + perl/lib/Wallet/Kadmin/AD.pm | 440 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 452 insertions(+) create mode 100644 perl/lib/Wallet/Kadmin/AD.pm diff --git a/NEWS b/NEWS index 272b109..0e268a9 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,14 @@ User-Visible wallet Changes +wallet 1.3 (2015-11-27) + + This version implements Active Directory as the store for keytabs. + The interface to Active Directory uses a combination of direct + LDAP queries and the msktutil utility. This version does not + support the wallet unchanging flag. Unchanging requires that a + keytab be retrieved without changing the password/kvno which is + not supported by msktutil. + wallet 1.2 (2014-12-08) The duo object type has been split into several sub-types, each for a diff --git a/perl/lib/Wallet/Kadmin.pm b/perl/lib/Wallet/Kadmin.pm index 65a5700..cb3bd47 100644 --- a/perl/lib/Wallet/Kadmin.pm +++ b/perl/lib/Wallet/Kadmin.pm @@ -69,6 +69,9 @@ sub new { } elsif (lc ($Wallet::Config::KEYTAB_KRBTYPE) eq 'heimdal') { require Wallet::Kadmin::Heimdal; $kadmin = Wallet::Kadmin::Heimdal->new; + } elsif (lc ($Wallet::Config::KEYTAB_KRBTYPE) eq 'ad') { + require Wallet::Kadmin::AD; + $kadmin = Wallet::Kadmin::AD->new; } else { my $type = $Wallet::Config::KEYTAB_KRBTYPE; die "unknown KEYTAB_KRBTYPE setting: $type\n"; diff --git a/perl/lib/Wallet/Kadmin/AD.pm b/perl/lib/Wallet/Kadmin/AD.pm new file mode 100644 index 0000000..acdd144 --- /dev/null +++ b/perl/lib/Wallet/Kadmin/AD.pm @@ -0,0 +1,440 @@ +# Wallet::Kadmin::AD -- Wallet Kerberos administration API for AD. +# +# Written by Bill MacAllister +# Based on work by Russ Allbery and +# Jon Robertson +# Copyright 2015 +# Dropbox +# +# See LICENSE for licensing terms. + +############################################################################## +# Modules and declarations +############################################################################## + +package Wallet::Kadmin::AD; +require 5.006; + +use strict; +use warnings; +use vars qw(@ISA $VERSION); + +use Wallet::Config (); +use Wallet::Kadmin (); + +use Authen::SASL (); +use Net::LDAP; +use IPC::Run qw( run timeout ); + +@ISA = qw(Wallet::Kadmin); + +# This version should be increased on any code change to this module. Always +# use two digits for the minor version with a leading zero if necessary so +# that it will sort properly. +$VERSION = '0.01'; + +############################################################################## +# kadmin Interaction +############################################################################## + +# Make sure that principals are well-formed and don't contain characters that +# will cause us problems when talking to kadmin. Takes a principal and +# returns true if it's okay, false otherwise. Note that we do not permit +# realm information here. +sub valid_principal { + my ($self, $principal) = @_; + my $valid = 0; + if ($principal =~ m,^(host|service)(/[\w_.-]+)?\z,) { + my $k_type = $1; + my $k_id = $2; + if ($k_type eq 'host') { + $valid = 1 if $k_id =~ m/[.]/xms; + } elsif ($k_type eq 'service') { + $valid = 1 if length($k_id) < 19; + } + } + return $valid; +} + +# Connect to the Active Directory server using LDAP. The connection is +# used to retrieve information about existing keytabs since msktutil +# does not have this functionality. +sub ldap_connect { + my ($self) = @_; + + if (!-e $Wallet::Config::AD_CACHE) { + die 'Missing kerberos ticket cache ' . $Wallet::Config::AD_CACHE; + } + + my $ldap; + eval { + local $ENV{KRB5CCNAME} = $Wallet::Config::AD_CACHE; + my $sasl = Authen::SASL->new (mechanism => 'GSSAPI'); + $ldap + = Net::LDAP->new ($Wallet::Config::KEYTAB_HOST, onerror => 'die'); + my $mesg = eval { $ldap->bind (undef, sasl => $sasl) }; + }; + if ($@) { + my $error = $@; + chomp $error; + 1 while ($error =~ s/ at \S+ line \d+\.?\z//); + die "LDAP bind to AD failed: $error\n"; + } + + return $ldap; +} + +sub ldap_base_filter { + my ($self, $principal) = @_; + my $base; + my $filter; + if ($principal =~ m,^host/(\S+),xms) { + my $fqdn = $1; + my $host = $fqdn; + $host =~ s/[.].*//xms; + $base = $Wallet::Config::AD_COMPUTER_DN; + $filter = "(samAccountName=${host}\$)"; + } elsif ($principal =~ m,^service/(\S+),xms) { + my $id = $1; + $base = $Wallet::Config::AD_USER_DN; + $filter = "(servicePrincipalName=service/${id})"; + } + return ($base, $filter); +} + +# TODO: Get a keytab from the keytab cache. +sub get_ad_keytab { + my ($self, $principal) = @_; + return; +} + +# Run a msktutil command and capture the output. Returns the output, +# either as a list of lines or, in scalar context, as one string. +# Depending on the exit status of msktutil or on the eval trap to know +# when the msktutil command fails. The error string returned from the +# call to run frequently contains information about a success rather +# that error output. +sub msktutil { + my ($self, $args_ref) = @_; + unless (defined ($Wallet::Config::KEYTAB_PRINCIPAL) + and defined ($Wallet::Config::KEYTAB_FILE) + and defined ($Wallet::Config::KEYTAB_REALM)) { + die "keytab object implementation not configured\n"; + } + unless (defined ($Wallet::Config::AD_SERVER) + and defined ($Wallet::Config::AD_COMPUTER_DN) + and defined ($Wallet::Config::AD_USER_DN) + and defined ($Wallet::Config::AD_KEYTAB_BUCKET)) { + die "Active Directory support not configured\n"; + } + my @args = @{$args_ref}; + my @cmd = ($Wallet::Config::AD_MSKTUTIL); + push @cmd, @args; + + my $in; + my $out; + my $err; + my $err_msg; + my $err_no; + eval { + local $ENV{KRB5CCNAME} = $Wallet::Config::AD_CACHE; + run \@cmd, \$in, \$out, \$err, timeout(120); + if ($?) { + $err_no = $?; + } + }; + if ($@) { + $err_msg .= "ERROR ($err_no): $@\n"; + } + if ($err_no || $err_msg) { + if ($err) { + $err_msg .= "ERROR: $err\n" + } + if ($Wallet::Config::AD_DEBUG) { + $err_msg .= 'Problem command: ' . join(' ', @cmd) . "\n"; + } + die $err_msg; + } else { + if ($err) { + $out .= "\n" . $err; + } + } + return $out; +} + +# Either create or update a keytab for the principal. Return the +# name of the keytab file created. +sub ad_create_update { + my ($self, $principal, $action) = @_; + my $keytab = $Wallet::Config::KEYTAB_TMP . "/keytab.$$"; + if (-e $keytab) { + unlink $keytab or die "Problem deleting $keytab\n"; + } + my @cmd = ('--' . $action); + push @cmd, '--server', $Wallet::Config::AD_SERVER; + push @cmd, '--enctypes', '0x4'; + push @cmd, '--enctypes', '0x8'; + push @cmd, '--enctypes', '0x10'; + push @cmd, '--keytab', $keytab; + push @cmd, '--realm', $Wallet::Config::KEYTAB_REALM; + if ($principal =~ m,^host/(\S+),xms) { + my $fqdn = $1; + my $host = $fqdn; + $host =~ s/[.].*//xms; + push @cmd, '--dont-expire-password'; + push @cmd, '--computer-name', $host; + push @cmd, '--upn', "host/$fqdn"; + push @cmd, '--hostname', $fqdn; + } elsif ($principal =~ m,^service/(\S+),xms) { + my $service_id = $1; + push @cmd, '--use-service-account'; + push @cmd, '--service', "service/$service_id"; + push @cmd, '--account-name', "srv-${service_id}"; + push @cmd, '--no-pac'; + } + $self->msktutil(\@cmd); + return $keytab; +} + +############################################################################## +# Public interfaces +############################################################################## + +# Set a callback to be called for forked kadmin processes. +sub fork_callback { + my ($self, $callback) = @_; + $self->{fork_callback} = $callback; +} + +# Check whether a given principal already exists. Returns true if so, +# false otherwise. The best way to do this with AD is to perform an +# ldap query. +sub exists { + my ($self, $principal) = @_; + return unless $self->valid_principal ($principal); + + my $ldap = $self->ldap_connect(); + my ($base, $filter) = $self->ldap_base_filter($principal); + my @attrs = ('objectClass', 'msds-KeyVersionNumber'); + + my $result; + eval { + $result = $ldap->search( + base => $base, + scope => 'subtree', + filter => $filter, + attrs => \@attrs + ); + }; + if ($@) { + my $error = $@; + die "LDAP search error: $error\n"; + } + if ($result->code) { + my $m; + if ($Wallet::Config::AD_DEBUG) { + $m .= "INFO base:$base filter:$filter scope:subtree\n"; + } + $m .= 'ERROR:' . $result->error . "\n"; + die $m + } + if ($result->count > 1) { + my $m = "ERROR: too many AD entries for this keytab\n"; + for my $entry ($result->entries) { + $m .= 'INFO: dn found ' . $entry->dn . "\n"; + } + die $m; + } + if ($result->count) { + for my $entry ($result->entries) { + return $entry->get_value('msds-KeyVersionNumber'); + } + } else { + return 0; + } + return; +} + +# Call msktutil to Create a principal in Kerberos. Sets the error and +# returns undef on failure, and returns 1 on either success or the +# principal already existing. Note, this creates a keytab that is +# never used because it is not returned to the user. +sub create { + my ($self, $principal) = @_; + unless ($self->valid_principal ($principal)) { + die "ERROR: invalid principal name $principal\n"; + return; + } + return 1 if $self->exists($principal); + my $file = $self->ad_create_update($principal, 'create'); + if (-e $file) { + unlink $file or die "Problem deleting $file\n"; + } + return 1; +} + +# TODO: Return a keytab. Need to create a local keytab cache when +# a keytab is marked unchanging and return that. +sub keytab { + my ($self, $principal) = @_; + unless ($self->valid_principal ($principal)) { + die "ERROR: invalid principal name $principal\n"; + return; + } + my $file = 'call to route to get the file name of local keytab file'; + if (!-e $file) { + die "ERROR: keytab file $file does not exist.\n"; + } + return $self->read_keytab ($file); +} + +# Update a keytab for a principal. This action changes the AD +# password for the principal and increments the kvno. The enctypes +# passed in are ignored. +sub keytab_rekey { + my ($self, $principal, @enctypes) = @_; + unless ($self->valid_principal ($principal)) { + die "ERROR: invalid principal name: $principal\n"; + return; + } + if (!$self->exists($principal)) { + die "ERROR: $principal does not exist\n"; + } + unless ($self->valid_principal($principal)) { + die "ERROR: invalid principal name $principal\n"; + return; + } + my $file = $self->ad_create_update($principal, 'update'); + return $self->read_keytab ($file); +} + +# Delete a principal from Kerberos. Return true if successful, false +# otherwise. If the deletion fails, sets the error. If the principal +# doesn't exist, return success; we're bringing reality in line with +# our expectations. For AD this means just delete the object using +# LDAP. +sub destroy { + my ($self, $principal) = @_; + unless ($self->valid_principal ($principal)) { + $self->error ("invalid principal name: $principal"); + } + my $exists = $self->exists ($principal); + if (!defined $exists) { + return; + } elsif (not $exists) { + return 1; + } + + my $k_type; + my $k_id; + my $dn; + if ($principal =~ m,^(host|service)/(\S+),xms) { + $k_type = $1; + $k_id = $2; + if ($k_type eq 'host') { + my $host = $k_id; + $host =~ s/[.].*//; + $dn = "cn=${host}," . $Wallet::Config::AD_COMPUTER_DN; + } elsif ($k_type eq 'service') { + $dn = "cn=srv-${k_id}," . $Wallet::Config::AD_USER_DN; + } + } + + my $ldap = $self->ldap_connect(); + my $msgid = $ldap->delete($dn); + if ($msgid->code) { + my $m; + if ($Wallet::Config::AD_DEBUG) { + $m .= "ERROR: Problem deleting $dn\n"; + } + $m .= $msgid->error; + die $m; + } + return 1; +} + +# Create a new AD kadmin object. Very empty for the moment, but later it +# will probably fill out if we go to using a module rather than calling +# 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; +} + +1; +__END__ + +############################################################################## +# Documentation +############################################################################## + +=for stopwords +rekeying rekeys remctl backend keytabs keytab kadmin KDC API Allbery +unlinked + +=head1 NAME + +Wallet::Kadmin::AD - Wallet Kerberos administration API for Active Directory + +=head1 SYNOPSIS + + my $kadmin = Wallet::Kadmin::AD->new; + $kadmin->create ('host/foo.example.com'); + my $data = $kadmin->keytab_rekey ('host/foo.example.com'); + $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 + +Wallet::Kadmin::AD implements the Wallet::Kadmin API for Active +Directory Kerberos, providing an interface to create and delete +principals and create keytabs. It provides the API documented in +L for an Active Directory Kerberos KDC. + +AD erberos does not provide any method via msktuil 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 local keytab cache. + +To use this class, several configuration parameters must be set. See +L for details. + +=head1 FILES + +=over 4 + +=item KEYTAB_TMP/keytab. + +The keytab is created in this file and then read into memory. KEYTAB_TMP +is set in the wallet configuration, and is the process ID of the +current process. The file is unlinked after being read. + +=back + +=head1 LIMITATIONS + +Currently, this implementation calls an external B program rather +than using a native Perl module and therefore requires B be +installed and parses its output. + +=head1 SEE ALSO + +msktutil, Wallet::Config(3), Wallet::Kadmin(3), +Wallet::Object::Keytab(3), wallet-backend(8) + +This module is part of the wallet system. The current version is +available from L. + +=head1 AUTHORS + +Bill MacAllister +and Russ Allbery +and Jon Robertson . + +=cut -- cgit v1.2.3 From d1b81776c05b858dca73c58a900c56d41f9c0e9b Mon Sep 17 00:00:00 2001 From: Bill MacAllister Date: Tue, 29 Dec 2015 20:03:02 +0000 Subject: Add error check for partially created AD keytabs The msktutil script does not always signal error conditions. This change implements a check that examines the output from msktutil and reports and error when the keytab creation fails to create the keytab but does create a computer entry in the directory. If an error is detected the directory entry is deleted leaving the directory in a clean state. Also, support has been added for output of debugging information to syslog using the AD_DEBUG configuration variable. Finally perltidy suggested changes were made to AD.pm. --- perl/lib/Wallet/Kadmin/AD.pm | 165 ++++++++++++++++++++++++++----------------- 1 file changed, 102 insertions(+), 63 deletions(-) diff --git a/perl/lib/Wallet/Kadmin/AD.pm b/perl/lib/Wallet/Kadmin/AD.pm index acdd144..30d4e9e 100644 --- a/perl/lib/Wallet/Kadmin/AD.pm +++ b/perl/lib/Wallet/Kadmin/AD.pm @@ -28,19 +28,31 @@ use IPC::Run qw( run timeout ); @ISA = qw(Wallet::Kadmin); -# This version should be increased on any code change to this module. Always -# use two digits for the minor version with a leading zero if necessary so -# that it will sort properly. -$VERSION = '0.01'; +# This version should be increased on any code change to this module. +# Always use two digits for the minor version with a leading zero if +# necessary so that it will sort properly. +$VERSION = '0.02'; ############################################################################## # kadmin Interaction ############################################################################## -# Make sure that principals are well-formed and don't contain characters that -# will cause us problems when talking to kadmin. Takes a principal and -# returns true if it's okay, false otherwise. Note that we do not permit -# realm information here. +# Send debugging output to syslog. + +sub ad_debug { + my ($self, $l, $m) = @_; + if (!$self->{SYSLOG}) { + openlog('wallet-server', 'ndelay,nofatal', 'local3'); + $self->{SYSLOG} = 1; + } + syslog($l, $m); + return; +} + +# Make sure that principals are well-formed and don't contain +# characters that will cause us problems when talking to kadmin. +# Takes a principal and returns true if it's okay, false otherwise. +# Note that we do not permit realm information here. sub valid_principal { my ($self, $principal) = @_; my $valid = 0; @@ -69,10 +81,9 @@ sub ldap_connect { my $ldap; eval { local $ENV{KRB5CCNAME} = $Wallet::Config::AD_CACHE; - my $sasl = Authen::SASL->new (mechanism => 'GSSAPI'); - $ldap - = Net::LDAP->new ($Wallet::Config::KEYTAB_HOST, onerror => 'die'); - my $mesg = eval { $ldap->bind (undef, sasl => $sasl) }; + my $sasl = Authen::SASL->new(mechanism => 'GSSAPI'); + $ldap = Net::LDAP->new($Wallet::Config::KEYTAB_HOST, onerror => 'die'); + my $mesg = eval { $ldap->bind(undef, sasl => $sasl) }; }; if ($@) { my $error = $@; @@ -84,6 +95,8 @@ sub ldap_connect { return $ldap; } +# Construct a base filter for searching Active Directory. + sub ldap_base_filter { my ($self, $principal) = @_; my $base; @@ -92,10 +105,10 @@ sub ldap_base_filter { my $fqdn = $1; my $host = $fqdn; $host =~ s/[.].*//xms; - $base = $Wallet::Config::AD_COMPUTER_DN; - $filter = "(samAccountName=${host}\$)"; + $base = $Wallet::Config::AD_COMPUTER_DN; + $filter = "(samAccountName=${host}\$)"; } elsif ($principal =~ m,^service/(\S+),xms) { - my $id = $1; + my $id = $1; $base = $Wallet::Config::AD_USER_DN; $filter = "(servicePrincipalName=service/${id})"; } @@ -109,27 +122,32 @@ sub get_ad_keytab { } # Run a msktutil command and capture the output. Returns the output, -# either as a list of lines or, in scalar context, as one string. -# Depending on the exit status of msktutil or on the eval trap to know -# when the msktutil command fails. The error string returned from the -# call to run frequently contains information about a success rather +# either as a list of lines or, in scalar context, as one string. +# Depending on the exit status of msktutil or on the eval trap to know +# when the msktutil command fails. The error string returned from the +# call to run frequently contains information about a success rather # that error output. sub msktutil { my ($self, $args_ref) = @_; - unless (defined ($Wallet::Config::KEYTAB_PRINCIPAL) - and defined ($Wallet::Config::KEYTAB_FILE) - and defined ($Wallet::Config::KEYTAB_REALM)) { + unless (defined($Wallet::Config::KEYTAB_PRINCIPAL) + and defined($Wallet::Config::KEYTAB_FILE) + and defined($Wallet::Config::KEYTAB_REALM)) + { die "keytab object implementation not configured\n"; } - unless (defined ($Wallet::Config::AD_SERVER) - and defined ($Wallet::Config::AD_COMPUTER_DN) - and defined ($Wallet::Config::AD_USER_DN) - and defined ($Wallet::Config::AD_KEYTAB_BUCKET)) { + unless (defined($Wallet::Config::AD_SERVER) + and defined($Wallet::Config::AD_COMPUTER_DN) + and defined($Wallet::Config::AD_USER_DN) + and defined($Wallet::Config::AD_KEYTAB_BUCKET)) + { die "Active Directory support not configured\n"; } my @args = @{$args_ref}; - my @cmd = ($Wallet::Config::AD_MSKTUTIL); + my @cmd = ($Wallet::Config::AD_MSKTUTIL); push @cmd, @args; + if ($Wallet::Config::AD_DEBUG) { + $self->ad_debug(LOG_DEBUG, join(' ', @cmd)); + } my $in; my $out; @@ -148,9 +166,7 @@ sub msktutil { } if ($err_no || $err_msg) { if ($err) { - $err_msg .= "ERROR: $err\n" - } - if ($Wallet::Config::AD_DEBUG) { + $err_msg .= "ERROR: $err\n"; $err_msg .= 'Problem command: ' . join(' ', @cmd) . "\n"; } die $err_msg; @@ -159,6 +175,9 @@ sub msktutil { $out .= "\n" . $err; } } + if ($Wallet::Config::AD_DEBUG) { + $self->ad_debug(LOG_DEBUG, $out); + } return $out; } @@ -171,28 +190,37 @@ sub ad_create_update { unlink $keytab or die "Problem deleting $keytab\n"; } my @cmd = ('--' . $action); - push @cmd, '--server', $Wallet::Config::AD_SERVER; - push @cmd, '--enctypes', '0x4'; - push @cmd, '--enctypes', '0x8'; - push @cmd, '--enctypes', '0x10'; - push @cmd, '--keytab', $keytab; - push @cmd, '--realm', $Wallet::Config::KEYTAB_REALM; + push @cmd, '--server', $Wallet::Config::AD_SERVER; + push @cmd, '--enctypes', '0x4'; + push @cmd, '--enctypes', '0x8'; + push @cmd, '--enctypes', '0x10'; + push @cmd, '--keytab', $keytab; + push @cmd, '--realm', $Wallet::Config::KEYTAB_REALM; + if ($principal =~ m,^host/(\S+),xms) { my $fqdn = $1; my $host = $fqdn; $host =~ s/[.].*//xms; push @cmd, '--dont-expire-password'; push @cmd, '--computer-name', $host; - push @cmd, '--upn', "host/$fqdn"; - push @cmd, '--hostname', $fqdn; + push @cmd, '--upn', "host/$fqdn"; + push @cmd, '--hostname', $fqdn; } elsif ($principal =~ m,^service/(\S+),xms) { my $service_id = $1; push @cmd, '--use-service-account'; - push @cmd, '--service', "service/$service_id"; + push @cmd, '--service', "service/$service_id"; push @cmd, '--account-name', "srv-${service_id}"; push @cmd, '--no-pac'; } - $self->msktutil(\@cmd); + my $out = $self->msktutil(\@cmd); + if ($out =~ /Error:\s+\S+\s+failed/xms) { + $self->ad_delete($principal); + my $m = "ERROR: problem creating keytab:\n" . $out; + $m .= 'INFO: the keytab used to by wallet probably has' + . " insufficient access to AD\n"; + die $m; + } + return $keytab; } @@ -211,7 +239,7 @@ sub fork_callback { # ldap query. sub exists { my ($self, $principal) = @_; - return unless $self->valid_principal ($principal); + return unless $self->valid_principal($principal); my $ldap = $self->ldap_connect(); my ($base, $filter) = $self->ldap_base_filter($principal); @@ -226,17 +254,16 @@ sub exists { attrs => \@attrs ); }; + if ($@) { my $error = $@; die "LDAP search error: $error\n"; } if ($result->code) { my $m; - if ($Wallet::Config::AD_DEBUG) { - $m .= "INFO base:$base filter:$filter scope:subtree\n"; - } + $m .= "INFO base:$base filter:$filter scope:subtree\n"; $m .= 'ERROR:' . $result->error . "\n"; - die $m + die $m; } if ($result->count > 1) { my $m = "ERROR: too many AD entries for this keytab\n"; @@ -256,16 +283,21 @@ sub exists { } # Call msktutil to Create a principal in Kerberos. Sets the error and -# returns undef on failure, and returns 1 on either success or the -# principal already existing. Note, this creates a keytab that is -# never used because it is not returned to the user. +# returns undef on failure, and returns 1 on either success or if the +# principal already exists. Note, this creates a keytab that is never +# used because it is not returned to the user. sub create { my ($self, $principal) = @_; - unless ($self->valid_principal ($principal)) { + unless ($self->valid_principal($principal)) { die "ERROR: invalid principal name $principal\n"; return; } - return 1 if $self->exists($principal); + if ($self->exists($principal)) { + if ($Wallet::Config::AD_DEBUG) { + $self->ad_debug(LOG_DEBUG, "$principal exists"); + } + return 1; + } my $file = $self->ad_create_update($principal, 'create'); if (-e $file) { unlink $file or die "Problem deleting $file\n"; @@ -277,7 +309,7 @@ sub create { # a keytab is marked unchanging and return that. sub keytab { my ($self, $principal) = @_; - unless ($self->valid_principal ($principal)) { + unless ($self->valid_principal($principal)) { die "ERROR: invalid principal name $principal\n"; return; } @@ -285,7 +317,7 @@ sub keytab { if (!-e $file) { die "ERROR: keytab file $file does not exist.\n"; } - return $self->read_keytab ($file); + return $self->read_keytab($file); } # Update a keytab for a principal. This action changes the AD @@ -293,7 +325,7 @@ sub keytab { # passed in are ignored. sub keytab_rekey { my ($self, $principal, @enctypes) = @_; - unless ($self->valid_principal ($principal)) { + unless ($self->valid_principal($principal)) { die "ERROR: invalid principal name: $principal\n"; return; } @@ -305,7 +337,7 @@ sub keytab_rekey { return; } my $file = $self->ad_create_update($principal, 'update'); - return $self->read_keytab ($file); + return $self->read_keytab($file); } # Delete a principal from Kerberos. Return true if successful, false @@ -315,16 +347,24 @@ sub keytab_rekey { # LDAP. sub destroy { my ($self, $principal) = @_; - unless ($self->valid_principal ($principal)) { - $self->error ("invalid principal name: $principal"); + unless ($self->valid_principal($principal)) { + $self->error("invalid principal name: $principal"); } - my $exists = $self->exists ($principal); + my $exists = $self->exists($principal); if (!defined $exists) { return; } elsif (not $exists) { return 1; } + return $self->ad_delete($principal); +} + +# Delete an entry from AD using LDAP. + +sub ad_delete { + my ($self, $principal) = @_; + my $k_type; my $k_id; my $dn; @@ -340,13 +380,11 @@ sub destroy { } } - my $ldap = $self->ldap_connect(); + my $ldap = $self->ldap_connect(); my $msgid = $ldap->delete($dn); if ($msgid->code) { my $m; - if ($Wallet::Config::AD_DEBUG) { - $m .= "ERROR: Problem deleting $dn\n"; - } + $m .= "ERROR: Problem deleting $dn\n"; $m .= $msgid->error; die $m; } @@ -358,11 +396,12 @@ sub destroy { # kadmin directly. sub new { my ($class) = @_; - unless (defined ($Wallet::Config::KEYTAB_TMP)) { + unless (defined($Wallet::Config::KEYTAB_TMP)) { die "KEYTAB_TMP configuration variable not set\n"; } my $self = {}; - bless ($self, $class); + $self->{SYSLOG} = undef; + bless($self, $class); return $self; } -- cgit v1.2.3 From 2a03ce35be9b900cc0fd5f305dec54ebcf3fed5a Mon Sep 17 00:00:00 2001 From: Bill MacAllister Date: Tue, 29 Dec 2015 13:57:37 -0800 Subject: Add in missing use statement for Sys::Syslog --- perl/lib/Wallet/Kadmin/AD.pm | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/perl/lib/Wallet/Kadmin/AD.pm b/perl/lib/Wallet/Kadmin/AD.pm index 30d4e9e..4efc643 100644 --- a/perl/lib/Wallet/Kadmin/AD.pm +++ b/perl/lib/Wallet/Kadmin/AD.pm @@ -25,6 +25,7 @@ use Wallet::Kadmin (); use Authen::SASL (); use Net::LDAP; use IPC::Run qw( run timeout ); +use Sys::Syslog qw( :standard :macros ); @ISA = qw(Wallet::Kadmin); @@ -146,7 +147,7 @@ sub msktutil { my @cmd = ($Wallet::Config::AD_MSKTUTIL); push @cmd, @args; if ($Wallet::Config::AD_DEBUG) { - $self->ad_debug(LOG_DEBUG, join(' ', @cmd)); + $self->ad_debug('debug', join(' ', @cmd)); } my $in; @@ -176,7 +177,7 @@ sub msktutil { } } if ($Wallet::Config::AD_DEBUG) { - $self->ad_debug(LOG_DEBUG, $out); + $self->ad_debug('debug', $out); } return $out; } @@ -294,7 +295,7 @@ sub create { } if ($self->exists($principal)) { if ($Wallet::Config::AD_DEBUG) { - $self->ad_debug(LOG_DEBUG, "$principal exists"); + $self->ad_debug('debug', "$principal exists"); } return 1; } -- cgit v1.2.3