aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBill MacAllister <whm@dropbox.com>2016-04-03 18:40:00 +0000
committerRuss Allbery <eagle@eyrie.org>2018-05-27 17:33:31 -0700
commit2b05e1d33eff84aec21202d09821a54c95446a24 (patch)
treec1771862000218526c44c158cc5e60f6f35bd8cd
parent18f0408114e67c218382d013c255f1101954ac68 (diff)
Add ad-keytab, update Wallet::Config
* This ad-keytab is useful in the initial setup of AD as a keytab store for wallet. * Change configuration variables to correctly reflect that some values are relative distinguished names. * Add a configuration variable for the base distinguished name for ActiveDirectory.
-rwxr-xr-xcontrib/ad-keytab610
-rw-r--r--perl/lib/Wallet/Config.pm78
-rw-r--r--perl/lib/Wallet/Kadmin/AD.pm51
3 files changed, 691 insertions, 48 deletions
diff --git a/contrib/ad-keytab b/contrib/ad-keytab
new file mode 100755
index 0000000..2af9f85
--- /dev/null
+++ b/contrib/ad-keytab
@@ -0,0 +1,610 @@
+#!/usr/bin/perl -w
+#
+# Create, update, delete, and display keytabs stored in Active Directory.
+#
+# Written by Bill MacAllister <whm@dropbox.com>
+# Copyright 2016 Dropbox, Inc.
+#
+# See LICENSE for licensing terms.
+
+##############################################################################
+# Declarations
+##############################################################################
+
+use Authen::SASL;
+use Carp;
+use Getopt::Long;
+use IPC::Run qw( run timeout );
+use Net::LDAP;
+use Pod::Usage;
+use strict;
+
+my $opt_ad_server;
+my $opt_base_dn;
+my $opt_computer_rdn;
+my $opt_config;
+my $opt_debug;
+my $opt_dump;
+my $opt_help;
+my $opt_manual;
+my $opt_realm;
+my $opt_user_rdn;
+
+# Configuration variables
+our $AD_DEBUG;
+our $AD_SERVER;
+our $AD_COMPUTER_RDN;
+our $AD_USER_RDN;
+our $KEYTAB_REALM;
+our $AD_BASE_DN;
+
+##############################################################################
+# Subroutines
+##############################################################################
+
+# Write messages to standard output and check the return status
+sub msg {
+ my @msgs = @_;
+ for my $m (@msgs) {
+ print STDOUT $m . "\n" or croak("Problem printing to STDOUT");
+ }
+ return;
+}
+
+# Write debugging messages
+sub dbg {
+ my ($m) = @_;
+ msg("DEBUG:$m");
+ return;
+}
+
+# Decode Active Directory's userAccountControl attribute
+# Flags are powers of two starting at zero.
+sub list_userAccountControl {
+ my ($uac) = @_;
+ my @flags = (
+ 'SCRIPT',
+ 'ACCOUNTDISABLE',
+ 'HOMEDIR_REQUIRED',
+ 'LOCKOUT',
+ 'PASSWD_NOTREQD',
+ 'PASSWD_CANT_CHANGE',
+ 'ENCRYPTED_TEXT_PWD_ALLOWED',
+ 'TEMP_DUPLICATE_ACCOUNT',
+ 'NORMAL_ACCOUNT',
+ 'INTERDOMAIN_TRUST_ACCOUNT',
+ 'WORKSTATION_TRUST_ACCOUNT',
+ 'SERVER_TRUST_ACCOUNT',
+ 'DONT_EXPIRE_PASSWORD',
+ 'MNS_LOGON_ACCOUNT',
+ 'SMARTCARD_REQUIRED',
+ 'TRUSTED_FOR_DELEGATION',
+ 'NOT_DELEGATED',
+ 'USE_DES_KEY_ONLY',
+ 'DONT_REQ_PREAUTH',
+ 'PASSWORD_EXPIRED',
+ 'TRUSTED_TO_AUTH_FOR_DELEGATION',
+ 'PARTIAL_SECRETS_ACCOUNT'
+ );
+
+ my $flag_list;
+ my $comma = '';
+ for (my $i=0; $i<scalar(@flags); $i++) {
+ if ($uac & (2**$i)) {
+ $flag_list .= $comma . $flags[$i];
+ $comma = ', ';
+ }
+ }
+ return $flag_list;
+}
+
+# GSS-API bind to the active directory server
+sub ldap_connect {
+ my $ldap;
+ if ($AD_DEBUG) {
+ dbg('binding to ' . $AD_SERVER);
+ }
+ if (!$AD_SERVER) {
+ croak("Missing ldap host name, specify ad_server=\n");
+ }
+ eval {
+ my $sasl = Authen::SASL->new(mechanism => 'GSSAPI');
+ $ldap = Net::LDAP->new($AD_SERVER, onerror => 'die');
+ my $mesg = eval { $ldap->bind(undef, sasl => $sasl) };
+ };
+ if ($@) {
+ my $error = $@;
+ die "ldap bind to AD failed: $error\n";
+ }
+ return $ldap;
+}
+
+# Take a principal and split into parts. The parts are keytab type,
+# keytab identifier, the base dn, an LDAP filter, and if the keytab
+# type is host the host name.
+sub kerberos_attrs {
+ my ($principal) = @_;
+
+ my %attr = ();
+ my $dn;
+ my $host;
+ my $k_type;
+ my $k_id;
+ if ($principal =~ m,^(host|service)/(\S+),xms) {
+ $attr{type} = $1;
+ $attr{id} = $2;
+ if ($attr{type} eq 'host') {
+ $attr{base} = $AD_COMPUTER_RDN . ',' . $AD_BASE_DN;
+ $attr{host} = $attr{id};
+ $attr{host} =~ s/[.].*//;
+ $attr{dn} = "cn=$attr{host},$attr{base}";
+ $attr{filter} = "(samAccountName=$attr{host}\$)";
+ } elsif ($attr{'type'} eq 'service') {
+ $attr{base} = $AD_USER_RDN . ',' . $AD_BASE_DN;
+ $attr{dn} = "cn=srv-$attr{id},$attr{base}";
+ $attr{filter} = "(servicePrincipalName=$attr{type}/$attr{id})";
+ }
+ }
+ if ($AD_DEBUG) {
+ for my $a (sort keys %attr) {
+ dbg("$a = $attr{$a}");
+ }
+ }
+ return %attr;
+}
+
+# Perform an LDAP search against AD and return information about
+# service and host accounts.
+sub ad_show {
+ my ($principal, $kattr_ref) = @_;
+
+ my $ldap = ldap_connect();
+ my %kattr = %{$kattr_ref};
+ my $base = $kattr{base};
+ my $filter = $kattr{filter};
+ my @attrs = ();
+ if (!$opt_dump) {
+ @attrs = (
+ 'distinguishedName', 'objectclass',
+ 'dnsHostname', 'msds-KeyVersionNumber',
+ 'msds-SupportedEncryptionTypes', 'name',
+ 'servicePrincipalName', 'samAccountName',
+ 'userAccountControl', 'userPrincipalName',
+ 'whenChanged', 'whenCreated',
+ );
+ }
+
+ if ($AD_DEBUG) {
+ dbg("base:$base filter:$filter scope:subtree\n");
+ }
+
+ 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) {
+ msg("INFO base:$base filter:$filter scope:subtree\n");
+ die $result->error;
+ }
+ if ($AD_DEBUG) {
+ dbg('returned: ' . $result->count);
+ }
+ if ($result->count > 0) {
+ for my $entry ($result->entries) {
+ for my $attr ( sort $entry->attributes ) {
+ my $out = '';
+ if ($attr =~ /userAccountControl/xmsi) {
+ my $val = $entry->get_value($attr);
+ $out = "$attr: $val";
+ $out .= ' (' . list_userAccountControl($val) . ')';
+ msg($out);
+ } else {
+ my $val_ref = $entry->get_value($attr, asref => 1);
+ my @vals = @{$val_ref};
+ for my $val (@vals) {
+ msg("$attr: $val");
+ }
+ }
+ }
+ }
+ } else {
+ msg("$kattr{type}/$kattr{id} not found");
+ }
+ msg(' ');
+ return;
+}
+
+# Check to see if a keytab exists
+sub ad_exists {
+ my ($principal, $kattr_ref) = @_;
+
+ my $ldap = ldap_connect();
+ my %kattr = %{$kattr_ref};
+ my $base = $kattr{base};
+ my $filter = $kattr{filter};
+ my @attrs = ('objectClass', 'msds-KeyVersionNumber');
+ if ($AD_DEBUG) {
+ dbg("base:$base filter:$filter scope:subtree\n");
+ }
+
+ 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) {
+ msg("INFO base:$base filter:$filter scope:subtree\n");
+ die $result->error;
+ }
+ if ($AD_DEBUG) {
+ dbg('returned: ' . $result->count);
+ }
+ if ($result->count > 1) {
+ msg('ERROR: too many AD entries for this keytab');
+ for my $entry ($result->entries) {
+ msg('INFO: dn found ' . $entry->dn . "\n");
+ }
+ die("INFO: use show to examine the problem\n");
+ }
+ if ($result->count) {
+ for my $entry ($result->entries) {
+ return $entry->get_value('msds-KeyVersionNumber');
+ }
+ } else {
+ return 0;
+ }
+ return;
+}
+
+# Run a shell command. In this case the command will always be msktutil.
+sub run_cmd {
+ my @cmd = @_;
+
+ if ($AD_DEBUG) {
+ dbg('running command:' . join(q{ }, @cmd));
+ }
+
+ my $in;
+ my $out;
+ my $err;
+ my $err_flag;
+ eval {
+ run(\@cmd, \$in, \$out, \$err, timeout(60));
+ if ($?) {
+ my $this_err = $?;
+ $err_flag = 1;
+ if ($this_err) {
+ msg('ERROR:' . $?);
+ }
+ if ($err) {
+ msg('ERROR (err):' . $err);
+ }
+ }
+ };
+ if ($@) {
+ msg('ERROR (status):' . $@);
+ $err_flag = 1;
+ }
+ if ($err_flag) {
+ msg('ERROR: Problem executing:' . join(q{ }, @cmd));
+ die "FATAL: Execution failed\n";
+ }
+
+ msg($out);
+ return;
+}
+
+# Either create or update a keytab for the principal. Return the name
+# of the keytab file created.
+sub ad_create_update {
+ my ($principal, $file, $action) = @_;
+ my @cmd = ('/usr/sbin/msktutil');
+ push @cmd, '--' . $action;
+ push @cmd, '--server', $AD_SERVER;
+ push @cmd, '--enctypes', '0x4';
+ push @cmd, '--enctypes', '0x8';
+ push @cmd, '--enctypes', '0x10';
+ push @cmd, '--keytab', $file;
+ if ($KEYTAB_REALM) {
+ push @cmd, '--realm', $KEYTAB_REALM;
+ }
+ if ($principal =~ m,^host/(\S+),xms) {
+ my $fqdn = $1;
+ my $host = $fqdn;
+ $host =~ s/[.].*//xms;
+ push @cmd, '--base', $AD_COMPUTER_RDN;
+ 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, '--base', $AD_USER_RDN;
+ push @cmd, '--use-service-account';
+ push @cmd, '--service', "service/$service_id";
+ push @cmd, '--account-name', "srv-${service_id}";
+ push @cmd, '--no-pac';
+ }
+ run_cmd(@cmd);
+ return;
+}
+
+# Delete a principal from Kerberos. For AD this means just delete the
+# object using LDAP.
+sub ad_delete {
+ my ($principal, $kattr_ref) = @_;
+
+ my %kattr = %{$kattr_ref};
+ if (!ad_exists($principal, $kattr_ref)) {
+ msg("WARN: the keytab for $principal does not appear to exist.");
+ msg("INFO: attempting the delete anyway.\n");
+ }
+
+ my $ldap = ldap_connect();
+ my $msgid = $ldap->delete($kattr{dn});
+ if ($msgid->code) {
+ my $m;
+ $m .= "ERROR: Problem deleting $kattr{dn}\n";
+ $m .= $msgid->error;
+ die $m;
+ }
+ return 1;
+}
+
+##############################################################################
+# Main Routine
+##############################################################################
+
+# Get options
+GetOptions(
+ 'ad_server=s' => \$opt_ad_server,
+ 'base_dn=s' => \$opt_base_dn,
+ 'computer_rdn=s' => \$opt_computer_rdn,
+ 'config=s' => \$opt_config,
+ 'debug' => \$opt_debug,
+ 'dump' => \$opt_dump,
+ 'help' => \$opt_help,
+ 'manual' => \$opt_manual,
+ 'realm' => \$opt_realm,
+ 'user_rdn=s' => \$opt_user_rdn
+);
+
+# Help the user
+if ($opt_manual) {
+ pod2usage(-verbose => 2);
+}
+if ($opt_help || !$ARGV[0]) {
+ pod2usage(-verbose => 0);
+}
+
+# Make sure that we have kerberos credentials and that KRB5CCNAME
+# points to them.
+if (!$ENV{'KRB5CCNAME'}) {
+ msg('ERROR: Kerberos credentials are required ... try kinit');
+ pod2usage(-verbose => 0);
+}
+
+# Read the configuration file or croak
+my $conf_file;
+if ($opt_config) {
+ if (-e $opt_config) {
+ $conf_file = $opt_config;
+ } else {
+ msg("ERROR: Config file ($opt_config) not found");
+ pod2usage(-verbose => 0);
+ }
+} elsif ($ENV{'ADKEYTAB'}) {
+ $conf_file = $ENV{'ADKEYTAB'};
+} elsif (-e '.ad-keytab.conf') {
+ $conf_file = '.ad-keytab.conf';
+} else {
+ $conf_file = '/etc/wallet/wallet.conf';
+}
+do $conf_file or die (($@ || $!) . "\n");
+
+# Process command line options
+if ($opt_ad_server) {
+ $AD_SERVER = $opt_ad_server;
+}
+if ($opt_base_dn) {
+ $AD_BASE_DN = $opt_base_dn;
+}
+if ($opt_computer_rdn) {
+ $AD_COMPUTER_RDN = $opt_computer_rdn;
+}
+if ($opt_user_rdn) {
+ $AD_USER_RDN = $opt_user_rdn;
+}
+if ($opt_debug) {
+ $AD_DEBUG = 1;
+}
+
+# -- Get command line arguments
+my $action = shift;
+my $id = shift;
+my $keytab;
+if ($ARGV[0]) {
+ $keytab = shift;
+} else {
+ $keytab = '/etc/krb5.keytab';
+}
+
+my %kattr = kerberos_attrs($id);
+# Validate that the keytab id makes sense for the keytab type
+if ($kattr{type} eq 'service') {
+ if ($kattr{id} =~ /[.]/xms) {
+ msg('ERROR: service principal names may not contain periods');
+ pod2usage(-verbose => 0);
+ }
+ if (length($kattr{id}) > 22) {
+ msg('ERROR: service principal name too long');
+ pod2usage(-verbose => 0);
+ }
+} elsif ($kattr{type} eq 'host') {
+ if ($kattr{id} !~ /[.]/xms) {
+ msg('ERROR: FQDN is required');
+ pod2usage(-verbose => 0);
+ }
+} else {
+ msg("ERROR: unknown keytab type $kattr{type}");
+ pod2usage(-verbose => 0);
+}
+
+if ($action =~ /^(create|update)/xms) {
+ ad_create_update($id, $keytab, $1);
+} elsif ($action =~ /^del/xms) {
+ ad_delete($id, \%kattr);
+} elsif ($action =~ /^sh/xms) {
+ ad_show($id, \%kattr);
+} else {
+ msg("ERROR: unknown action $action");
+ pod2usage(-verbose => 0);
+}
+
+exit;
+
+__END__
+
+=head1 NAME
+
+ad-keytab
+
+=head1 SYNOPSIS
+
+ad-keytab create|update|delete|show keytab-id [keytab-file]
+[--ad_server=hostname] [--computer_rdn=dn] [--user_rdn] [--dump]
+[--help] [--manual] [--debug]
+
+=head1 DESCRIPTION
+
+This script is a wrapper around msktutil and ldapsearch to simplify
+the creation of host and service keytabs. The script is useful for
+boot strapping the kerberos credentials required to use Active
+Directory as a backend keytab store for wallet. The script shares
+the wallet configuration file.
+
+Generally, two keytabs will need to be created to setup update. One
+host keytab for the wallet server host and one service keytab for
+wallet to use when connecting to an Active Directory Domain
+Controller.
+
+Note, this script does not update the Wallet database which means
+any keytabs created by it will be invisible from wallet.
+
+=head1 ACTIONS
+
+=over 4
+
+=item create
+
+Add a keytab to AD and update the keytab file. Fails if the keytab
+already exists.
+
+=item update
+
+Update an existing keytab in AD and update the keytab file. Fails if
+the keytab does not exist.
+
+=item delete
+
+Delete a keytab from AD and remove it from the keytab file.
+
+=item show
+
+Show AD's view of the account corresponding to the keytab. This action
+does not use msktutil and queries AD directly using LDAP.
+
+=back
+
+=head1 OPTIONS AND ARGUMENTS
+
+=over 4
+
+=item keytab-id
+
+This is either host principal name of the form host/<fqdn> or a
+service principal name of the form service/<id>. Service keytab
+identifiers cannot be longer than 18 characters because of an
+ActiveDirectory restriction.
+
+=item keytab-filename
+
+The name of the keytab file. Defaults to /etc/krb5.keytab.
+
+=item --conf=filename
+
+The configuration file to read. The script searches for a configuration
+file in the following order.
+
+ * The command line switch --conf
+ * The environment variable ADKEYTAB
+ * The file .ad-keytab.conf
+ * The file /etc/ad-keytab.conf
+
+=item --ad_server=hostname
+
+The name of the Active Directory host to connect to. It is important
+what the script contact only _one_ server due to the fact that
+propagation within an Active Directory domain can be quite slow.
+
+=item --base_dn=ou=org,dc=domain,dc=tld
+
+The base distinguished name holding both computer and user accounts.
+
+=item --computer_rdn=dn
+
+The relative distinguished name to use as the base DN for both the
+creation of host keytabs and searches of Active Directory. The
+distinguished name formed will be computer_rdn,base_dn.
+
+=item --user_rdn=dn
+
+The relative distinguished name to use as the base DN for ldap
+searches of Active Directory for service keytabs. The distinguished
+name formed will be user_rdn_rdn,base_dn.
+
+=item --dump
+
+When displaying keytab attributes show all of the attributes.
+
+=item --help
+
+Displays help text.
+
+=item --manual
+
+Displays more complete help text.
+
+=item --debug
+
+Turns on debugging displays.
+
+=back
+
+=head1 SEE ALSO
+
+Set the documentation for Wallet::Config for configuration information, i.e.
+perldoc Wallet::Config.
+
+=head1 AUTHOR
+
+Bill MacAllister <whm@dropbox.com>
+
+=cut
diff --git a/perl/lib/Wallet/Config.pm b/perl/lib/Wallet/Config.pm
index 6515756..2222aba 100644
--- a/perl/lib/Wallet/Config.pm
+++ b/perl/lib/Wallet/Config.pm
@@ -415,40 +415,39 @@ our $KEYTAB_TMP;
=back
-The following parameters are specific to generating keytabs from Active
-Directory (KEYTAB_KRBTYPE is set to C<AD>).
+The following parameters are specific to generating keytabs from
+Active Directory (KEYTAB_KRBTYPE is set to C<AD>).
=over 4
-=item AD_CACHE
-
-Specifies the ticket cache to use when manipulating Active Directory objects.
-The ticket cache must be for a principal able to bind to Active Directory and
-run B<msktutil>.
+=item AD_BASE_DN
-AD_CACHE must be set to use Active Directory support.
+The base distinguished name of the ActiveDirectory instance. This is
+use when Wallet uses LDAP directly to examine objects in Active
+Directory.
=cut
-our $AD_CACHE;
+our $AD_BASE_DN;
-=item AD_COMPUTER_DN
+=item AD_COMPUTER_RDN
-The LDAP base DN for computer objects inside Active Directory. All keytabs of
-the form host/<hostname> will be mapped to objects with a C<samAccountName> of
-the <hostname> portion under this DN.
+The LDAP base DN for computer objects inside Active Directory. All
+keytabs of the form host/<hostname> will be mapped to objects with a
+C<samAccountName> of the <hostname> portion under this DN.
-AD_COMPUTER_DN must be set if using Active Directory as the keytab backend.
+AD_COMPUTER_RDN must be set if using Active Directory as the keytab
+backend.
=cut
-our $AD_COMPUTER_DN;
+our $AD_COMPUTER_RDN;
=item AD_DEBUG
-If set to true, asks for some additional debugging information, such as the
-B<msktutil> command, to be logged to syslog. These debugging messages will be
-logged to the C<local3> facility.
+If set to true, asks for some additional debugging information, such
+as the B<msktutil> command, to be logged to syslog. These debugging
+messages will be logged to the C<local3> facility.
=cut
@@ -464,17 +463,25 @@ default PATH.
our $AD_MSKTUTIL = 'msktutil';
-=item AD_USER_DN
+=item AD_SERVER
+
+The hostname of the Active Directory Domain Controller.
+
+=cut
+
+our $AD_SERVER;
+
+=item AD_USER_RDN
The LDAP base DN for user objects inside Active Directory. All keytabs of the
form service/<user> will be mapped to objects with a C<servicePrincipalName>
matching the wallet object name under this DN.
-AD_USER_DN must be set if using Active Directory as the keytab backend.
+AD_USER_RDN must be set if using Active Directory as the keytab backend.
=cut
-our $AD_USER_DN;
+our $AD_USER_RDN;
=back
@@ -482,8 +489,9 @@ our $AD_USER_DN;
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.
+keys. Neither MIT Kerberos or ActiveDirectory support retrieving an
+existing keytab; downloading a keytab over the kadmin protocol or
+using msktutil always rekeys the principal.
For MIT Kerberos, the keytab object backend therefore optionally supports
retrieving existing keys, and hence keytabs, for Kerberos principals by
@@ -491,6 +499,11 @@ 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.
+For ActiveDirectory Kerberos, the keytab object backend supports
+storing the keytabs on the wallet server. This functionality is
+enabled by setting the configuration variable AD_KEYTAB_BUCKET. (This
+had not been implemented yet.)
+
This is not required for Heimdal; for Heimdal, setting the C<unchanging>
flag is all that's needed.
@@ -542,6 +555,25 @@ will be used.
our $KEYTAB_REMCTL_PORT;
+=item AD_CACHE
+
+The ticket cache that hold credentials used to access the
+ActiveDirectory KDC. This must be created and maintained externally.
+
+=cut
+
+our $AD_CACHE;
+
+=item AD_KEYTAB_BUCKET
+
+The path to store a copy of keytabs created. This is required for the
+support of unchanging keytabs with an ActiveDirectory KDC. (This has
+not been implemented yet.)
+
+=cut
+
+our $AD_KEYTAB_BUCKET = '/var/lib/wallet/keytabs';
+
=back
=head1 WEBAUTH KEYRING OBJECT CONFIGURATION
diff --git a/perl/lib/Wallet/Kadmin/AD.pm b/perl/lib/Wallet/Kadmin/AD.pm
index ec60af9..1c13ab6 100644
--- a/perl/lib/Wallet/Kadmin/AD.pm
+++ b/perl/lib/Wallet/Kadmin/AD.pm
@@ -1,8 +1,8 @@
# Wallet::Kadmin::AD -- Wallet Kerberos administration API for AD
#
-# Written by Bill MacAllister <bill@ca-zephyr.org>
+# Written by Bill MacAllister <whm@dropbox.com>
# Copyright 2016 Russ Allbery <eagle@eyrie.org>
-# Copyright 2015 Dropbox, Inc.
+# Copyright 2015,2016 Dropbox, Inc.
# Copyright 2007, 2008, 2009, 2010, 2014
# The Board of Trustees of the Leland Stanford Junior University
#
@@ -100,17 +100,19 @@ 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_RDN . ','
+ . $Wallet::Config::AD_BASE_DN;
} elsif ($principal =~ m,^service/(\S+),xms) {
my $id = $1;
- $base = $Wallet::Config::AD_USER_DN;
$filter = "(servicePrincipalName=service/${id})";
+ $base
+ = $Wallet::Config::AD_USER_RDN . ',' . $Wallet::Config::AD_BASE_DN;
}
return ($base, $filter);
}
-# TODO: Get a keytab from the keytab cache.
+# TODO: Get a keytab from the keytab bucket.
sub get_ad_keytab {
my ($self, $principal) = @_;
return;
@@ -125,13 +127,16 @@ sub get_ad_keytab {
sub msktutil {
my ($self, $args_ref) = @_;
unless (defined($Wallet::Config::KEYTAB_HOST)
+ and 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_CACHE)
- and defined($Wallet::Config::AD_COMPUTER_DN)
- and defined($Wallet::Config::AD_USER_DN))
+ unless (-e $Wallet::Config::AD_MSKTUTIL
+ and defined($Wallet::Config::AD_BASE_DN)
+ and defined($Wallet::Config::AD_COMPUTER_RDN)
+ and defined($Wallet::Config::AD_USER_RDN))
{
die "Active Directory support not configured\n";
}
@@ -192,14 +197,16 @@ sub ad_create_update {
my $fqdn = $1;
my $host = $fqdn;
$host =~ s/[.].*//xms;
+ push @cmd, '--base', $Wallet::Config::COMPUTER_RDN;
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, '--base', $Wallet::Config::USER_RDN;
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';
}
@@ -365,9 +372,15 @@ sub ad_delete {
if ($k_type eq 'host') {
my $host = $k_id;
$host =~ s/[.].*//;
- $dn = "cn=${host}," . $Wallet::Config::AD_COMPUTER_DN;
+ $dn
+ = "cn=${host},"
+ . $Wallet::Config::AD_COMPUTER_RDN . ','
+ . $Wallet::Config::AD_BASE_DN;
} elsif ($k_type eq 'service') {
- $dn = "cn=srv-${k_id}," . $Wallet::Config::AD_USER_DN;
+ $dn
+ = "cn=srv-${k_id},"
+ . $Wallet::Config::AD_USER_RDN . ','
+ . $Wallet::Config::AD_BASE_DN;
}
}
@@ -435,18 +448,6 @@ using a local keytab cache.
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
Currently, this implementation calls an external B<msktutil> program rather