[PATCHSET] Samba AD with MIT Kerberos

Andreas Schneider asn at samba.org
Wed Apr 26 06:21:06 UTC 2017


On Tuesday, 25 April 2017 22:39:39 CEST Jeremy Allison wrote:
> >     Your autobuild on sn-devel-144 has succeeded after 244.0 minutes.
> > 
> > Please review.
> 
> Just a few minor nits I've found so far.
> 

Thank you very much, updated patchset which addresses these things attached.



	Andreas

-- 
Andreas Schneider                   GPG-ID: CC014E3D
Samba Team                             asn at samba.org
www.samba.org
-------------- next part --------------
From 503432757bb486766abfd191eda409e1c6bc7dac Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Wed, 21 Dec 2016 19:08:58 +0100
Subject: [PATCH 01/51] s4:torture: Fix the remote_pac test

All the Kerberos implementation do not expect an order of the pac
buffer. The buffers are not processed in the oder they are sent but when
required just located.

I confirmed this with MS at the IO Lab.

Signed-off-by: Andreas Schneider <asn at samba.org>
---
 source4/torture/rpc/remote_pac.c | 72 +++++++++++++++++++++++++---------------
 1 file changed, 46 insertions(+), 26 deletions(-)

diff --git a/source4/torture/rpc/remote_pac.c b/source4/torture/rpc/remote_pac.c
index 25a581bb46b..091309874fe 100644
--- a/source4/torture/rpc/remote_pac.c
+++ b/source4/torture/rpc/remote_pac.c
@@ -122,6 +122,23 @@ static NTSTATUS test_generate_session_info_pac(struct auth4_context *auth_ctx,
 
 /* Check to see if we can pass the PAC across to the NETLOGON server for validation */
 
+static const struct PAC_BUFFER *get_pac_buffer(const struct PAC_DATA *pac_data,
+					       enum PAC_TYPE type)
+{
+	const struct PAC_BUFFER *pac_buf = NULL;
+	uint32_t i;
+
+	for (i = 0; i < pac_data->num_buffers; ++i) {
+		pac_buf = &pac_data->buffers[i];
+
+		if (pac_buf->type == type) {
+			break;
+		}
+	}
+
+	return pac_buf;
+}
+
 /* Also happens to be a really good one-step verfication of our Kerberos stack */
 
 static bool test_PACVerify(struct torture_context *tctx,
@@ -274,42 +291,45 @@ static bool test_PACVerify(struct torture_context *tctx,
 	torture_assert_int_equal(tctx, pac_data_struct.version, 0, "version");
 	torture_assert_int_equal(tctx, pac_data_struct.num_buffers, num_pac_buffers, "num_buffers");
 
-	pac_buf = pac_data_struct.buffers;
-	torture_assert_int_equal(tctx, pac_buf->type,
-				 PAC_TYPE_LOGON_INFO, "PAC_TYPE_LOGON_INFO");
-	torture_assert(tctx, pac_buf->info != NULL,
+	pac_buf = get_pac_buffer(&pac_data_struct, PAC_TYPE_LOGON_INFO);
+	torture_assert_not_null(tctx, pac_buf, "PAC_TYPE_LOGON_INFO");
+	torture_assert(tctx,
+		       pac_buf->info != NULL,
 		       "PAC_TYPE_LOGON_INFO info");
-	pac_buf++;
+
 	if (pkinit_in_use) {
-		torture_assert_int_equal(tctx, pac_buf->type,
-					 PAC_TYPE_CREDENTIAL_INFO,
-					 "PAC_TYPE_CREDENTIAL_INFO");
-		torture_assert(tctx, pac_buf->info != NULL,
+		pac_buf = get_pac_buffer(&pac_data_struct, PAC_TYPE_CREDENTIAL_INFO);
+		torture_assert_not_null(tctx, pac_buf, "PAC_TYPE_CREDENTIAL_INFO");
+		torture_assert(tctx,
+			       pac_buf->info != NULL,
 			       "PAC_TYPE_CREDENTIAL_INFO info");
-		pac_buf++;
 	}
-	torture_assert_int_equal(tctx, pac_buf->type,
-				 PAC_TYPE_LOGON_NAME, "PAC_TYPE_LOGON_NAME");
-	torture_assert(tctx, pac_buf->info != NULL,
+
+	pac_buf = get_pac_buffer(&pac_data_struct, PAC_TYPE_LOGON_NAME);
+	torture_assert_not_null(tctx, pac_buf, "PAC_TYPE_LOGON_NAME");
+	torture_assert(tctx,
+		       pac_buf->info != NULL,
 		       "PAC_TYPE_LOGON_NAME info");
-	pac_buf++;
+
 	if (expect_pac_upn_dns_info) {
-		torture_assert_int_equal(tctx, pac_buf->type,
-					 PAC_TYPE_UPN_DNS_INFO, "PAC_TYPE_UPN_DNS_INFO");
-		torture_assert(tctx, pac_buf->info != NULL,
+		pac_buf = get_pac_buffer(&pac_data_struct, PAC_TYPE_UPN_DNS_INFO);
+		torture_assert_not_null(tctx, pac_buf, "PAC_TYPE_UPN_DNS_INFO");
+		torture_assert(tctx,
+			       pac_buf->info != NULL,
 			       "PAC_TYPE_UPN_DNS_INFO info");
-		pac_buf++;
 	}
-	torture_assert_int_equal(tctx, pac_buf->type,
-				 PAC_TYPE_SRV_CHECKSUM, "PAC_TYPE_SRV_CHECKSUM");
-	torture_assert(tctx, pac_buf->info != NULL,
+
+	pac_buf = get_pac_buffer(&pac_data_struct, PAC_TYPE_SRV_CHECKSUM);
+	torture_assert_not_null(tctx, pac_buf, "PAC_TYPE_SRV_CHECKSUM");
+	torture_assert(tctx,
+		       pac_buf->info != NULL,
 		       "PAC_TYPE_SRV_CHECKSUM info");
-	pac_buf++;
-	torture_assert_int_equal(tctx, pac_buf->type,
-				 PAC_TYPE_KDC_CHECKSUM, "PAC_TYPE_KDC_CHECKSUM");
-	torture_assert(tctx, pac_buf->info != NULL,
+
+	pac_buf = get_pac_buffer(&pac_data_struct, PAC_TYPE_KDC_CHECKSUM);
+	torture_assert_not_null(tctx, pac_buf, "PAC_TYPE_KDC_CHECKSUM");
+	torture_assert(tctx,
+		       pac_buf->info != NULL,
 		       "PAC_TYPE_KDC_CHECKSUM info");
-	pac_buf++;
 
 	pac_wrapped_struct.ChecksumLength = pac_data->pac_srv_sig->signature.length;
 	pac_wrapped_struct.SignatureType = pac_data->pac_kdc_sig->type;
-- 
2.12.2


From 16e416b4c5fbe33ccc73110415ab1a0937a5f7e2 Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Tue, 13 Sep 2016 08:24:06 +0200
Subject: [PATCH 02/51] testprogs: Add common kinit function

Signed-off-by: Andreas Schneider <asn at samba.org>
---
 testprogs/blackbox/common_test_fns.inc | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/testprogs/blackbox/common_test_fns.inc b/testprogs/blackbox/common_test_fns.inc
index f77879ae39f..77c635bc5d7 100755
--- a/testprogs/blackbox/common_test_fns.inc
+++ b/testprogs/blackbox/common_test_fns.inc
@@ -88,3 +88,19 @@ test_rpcclient_expect_failure_grep() {
 	fi
 	return $status
 }
+
+kerberos_kinit() {
+	kinit_tool="${1}"
+	principal="${2}"
+	password="${3}"
+	shift 3
+	kbase=$(basename ${kinit_tool})
+	if [ "${kbase}" = "samba4kinit" ]; then
+		kpassfile=$(mktemp)
+		echo $password > ${kpassfile}
+		$kinit_tool --password-file=${kpassfile} $principal $@
+		rm -f ${kpassfile}
+	else
+		echo $password | $kinit_tool $principal $@
+	fi
+}
-- 
2.12.2


From dfd1872401633d31dfcb8a1dc30f0bdd9463ae64 Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Tue, 13 Sep 2016 08:24:41 +0200
Subject: [PATCH 03/51] s3-tests: Use common functions in
 test_smbclient_netbios_aliases.sh

Signed-off-by: Andreas Schneider <asn at samba.org>
---
 .../script/tests/test_smbclient_netbios_aliases.sh   | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/source3/script/tests/test_smbclient_netbios_aliases.sh b/source3/script/tests/test_smbclient_netbios_aliases.sh
index 610eeda5ab6..fe42c93e8fe 100755
--- a/source3/script/tests/test_smbclient_netbios_aliases.sh
+++ b/source3/script/tests/test_smbclient_netbios_aliases.sh
@@ -7,7 +7,7 @@ EOF
 exit 1;
 fi
 
-SMBCLIENT3=$1
+smbclient=$1
 SERVER=$2
 USERNAME=$3
 PASSWORD=$4
@@ -15,11 +15,11 @@ PREFIX=$5
 shift 5
 ADDARGS="$*"
 
-samba4bindir="$BINDIR"
-samba4srcdir="$SRCDIR/source4"
-samba4kinit=kinit
-if test -x $BINDIR/samba4kinit; then
-	samba4kinit=$BINDIR/samba4kinit
+samba_bindir="$BINDIR"
+samba_srcdir="$SRCDIR/source4"
+samba_kinit=kinit
+if test -x ${samba_bindir}/samba4kinit; then
+	samba_kinit=${samba_bindir}/samba4kinit
 fi
 
 KRB5CCNAME_PATH="$PREFIX/test_smbclient_netbios_aliases_krb5ccache"
@@ -30,11 +30,11 @@ export KRB5CCNAME
 
 incdir=`dirname $0`/../../../testprogs/blackbox
 . $incdir/subunit.sh
+. $incdir/common_test_fns.inc
 
-echo $PASSWORD > $PREFIX/tmppassfile
-testit "kinit" $samba4kinit --password-file=$PREFIX/tmppassfile $USERNAME || failed=`expr $failed + 1`
-rm -f $PREFIX/tmppassfile
-testit "smbclient" $VALGRIND $SMBCLIENT3 -k //$SERVER/tmp -c 'ls' $ADDARGS || failed=`expr $failed + 1`
+testit "kinit" kerberos_kinit ${samba_kinit} ${USERNAME} ${PASSWORD}
+
+test_smbclient "smbclient (krb5)" "ls" "//$SERVER/tmp" -k || failed=`expr $failed + 1`
 
 rm -rf $KRB5CCNAME_PATH
 
-- 
2.12.2


From 1af03ea288f6818683fb58757d652d5ef4388044 Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Thu, 30 Jul 2015 17:38:34 +0200
Subject: [PATCH 04/51] samba_dnsupdate: Do not rewrite krb5.conf in selftest

The samba_dnsupdate script is responsible to provision the DNS entries.
The private krb5.conf uses dns lookups to find the KDC to acquire a
Kerberos ticket.  Obviously this will fail because currently we are are
in the process of adding the DNS entries for the KDC.

If we are inside of selftest we need to use the krb5.conf created by
selftest itself.

Signed-off-by: Andreas Schneider <asn at samba.org>
---
 source4/scripting/bin/samba_dnsupdate | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/source4/scripting/bin/samba_dnsupdate b/source4/scripting/bin/samba_dnsupdate
index f9e835bc5c3..d382758168b 100755
--- a/source4/scripting/bin/samba_dnsupdate
+++ b/source4/scripting/bin/samba_dnsupdate
@@ -662,10 +662,13 @@ if opts.update_cache:
 else:
     dns_update_cache = lp.private_path('dns_update_cache')
 
-# use our private krb5.conf to avoid problems with the wrong domain
-# bind9 nsupdate wants the default domain set
-krb5conf = lp.private_path('krb5.conf')
-os.environ['KRB5_CONFIG'] = krb5conf
+krb5conf = None
+# only change the krb5.conf if we are not in selftest
+if 'SOCKET_WRAPPER_DIR' not in os.environ:
+    # use our private krb5.conf to avoid problems with the wrong domain
+    # bind9 nsupdate wants the default domain set
+    krb5conf = lp.private_path('krb5.conf')
+    os.environ['KRB5_CONFIG'] = krb5conf
 
 file = open(dns_update_list, "r")
 
-- 
2.12.2


From 4406b92cdd215877adb7b867dba8289e8e275613 Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Thu, 26 Jan 2017 16:54:30 +0100
Subject: [PATCH 05/51] mit-kdb: Zero the db principal when we allocate it

Signed-off-by: Andreas Schneider <asn at samba.org>
---
 source4/kdc/mit_samba.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/source4/kdc/mit_samba.c b/source4/kdc/mit_samba.c
index f5015840055..8a2bfe9b715 100644
--- a/source4/kdc/mit_samba.c
+++ b/source4/kdc/mit_samba.c
@@ -188,7 +188,7 @@ int mit_samba_get_principal(struct mit_samba_context *ctx,
 	int ret;
 	int sflags = 0;
 
-	kentry = malloc(sizeof(krb5_db_entry));
+	kentry = calloc(1, sizeof(krb5_db_entry));
 	if (kentry == NULL) {
 		return ENOMEM;
 	}
-- 
2.12.2


From e1c8839a00ef204534f1f7b8940d99d8bf7376fd Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Fri, 20 Jan 2017 09:14:03 +0100
Subject: [PATCH 06/51] waf: Require MIT Kerberos 1.15.1 for Samba AD

Are build without AD DC still only requried MIT Kerberos 1.9.

Signed-off-by: Andreas Schneider <asn at samba.org>
---
 wscript                          |  4 ++--
 wscript_configure_system_mitkrb5 | 28 +++++++++++++++++++---------
 2 files changed, 21 insertions(+), 11 deletions(-)

diff --git a/wscript b/wscript
index de85591223c..a7c4f4c31b9 100644
--- a/wscript
+++ b/wscript
@@ -48,12 +48,12 @@ def set_options(opt):
     opt.samba_add_onoff_option('pthreadpool', with_name="enable", without_name="disable", default=True)
 
     opt.add_option('--with-system-mitkrb5',
-                   help='enable system MIT krb5 build (includes Samba 4 client and Samba 3 code base).'+
+                   help='build Samba with system MIT Kerberos. ' +
                         'You may specify list of paths where Kerberos is installed (e.g. /usr/local /usr/kerberos) to search krb5-config',
                    action='callback', callback=system_mitkrb5_callback, dest='with_system_mitkrb5', default=False)
 
     opt.add_option('--without-ad-dc',
-                   help='disable AD DC functionality (enables Samba 4 client and Samba 3 code base).',
+                   help='disable AD DC functionality (enables only Samba FS (File Server, Winbind, NMBD) and client utilities.',
                    action='store_true', dest='without_ad_dc', default=False)
 
     opt.add_option('--with-ntvfs-fileserver',
diff --git a/wscript_configure_system_mitkrb5 b/wscript_configure_system_mitkrb5
index d3e8ebf0dcd..3e9d4ffb076 100644
--- a/wscript_configure_system_mitkrb5
+++ b/wscript_configure_system_mitkrb5
@@ -3,6 +3,14 @@ import Logs, Options, sys
 # Check for kerberos
 have_gssapi=False
 
+# Requried versions
+krb5_required_version = "1.9"
+if conf.CONFIG_SET('AD_DC_BUILD_IS_ENABLED'):
+    krb5_required_version = "1.15.1"
+
+def parse_version(v):
+    return tuple(map(int, (v.split("."))))
+
 def krb5_define_syslib(conf, lib, deps):
     found = 'FOUND_SYSTEMLIB_' + lib
     if found in conf.env:
@@ -44,19 +52,21 @@ if conf.env.KRB5_CONFIG:
     if conf.env.KRB5_VENDOR != 'heimdal':
         conf.define('USING_SYSTEM_KRB5', 1)
         del conf.env.HEIMDAL_KRB5_CONFIG
-        kversion = conf.cmd_and_log("%(path)s --version" % dict(path=conf.env.KRB5_CONFIG), dict()).strip()
-        kversion_split = kversion.split(' ')[-1].split('.')
+        krb5_conf_version = conf.cmd_and_log("%(path)s --version" % dict(path=conf.env.KRB5_CONFIG), dict()).strip()
+
+        krb5_version = krb5_conf_version.split()[-1]
+
         # drop '-prerelease' suffix
-        if kversion_split[-1].find('-') > 0:
-            last_digit = kversion_split[-1].split('-')[0]
-            kversion_split[-1] = last_digit
-        kversion_check = map(int, kversion_split)
-        if kversion_check < [1, 9]:
-            Logs.error('ERROR: MIT krb5 build requires at least 1.9.0. %s is found and cannot be used' % (kversion))
+        if krb5_version.find('-') > 0:
+            krb5_version = krb5_version.split("-")[0]
+
+        if parse_version(krb5_version) < parse_version(krb5_required_version):
+            Logs.error('ERROR: MIT krb5 build requires at least %s. %s is found and cannot be used' % (krb5_required_version, krb5_version))
+            Logs.error('ERROR: If you want to just build Samba FS use the option --without-ad-dc')
             Logs.error('ERROR: You may try to build with embedded Heimdal Kerebros by not specifying --with-system-mitkrb5')
             sys.exit(1)
         else:
-            Logs.info('%s is detected, MIT krb5 build can proceed' % (kversion))
+            Logs.info('MIT Kerberos %s detected, MIT krb5 build can proceed' % (krb5_version))
 
 conf.CHECK_CFG(args="--cflags --libs", package="com_err", uselib_store="com_err")
 conf.CHECK_FUNCS_IN('_et_list', 'com_err')
-- 
2.12.2


From f877accfa33ba174c95a8b6227a9b41a7d362ede Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Thu, 26 Jan 2017 16:52:15 +0100
Subject: [PATCH 07/51] mit-kdb: Update KDB vtable for DAL version 6

This changed between 1.14 and 1.15. Also the 1.15 change removed the
ability that the KDB module can free memory. This caused issues of
serveral projects. It got fixed with 1.15.1.

Signed-off-by: Andreas Schneider <asn at samba.org>
---
 source4/kdc/mit-kdb/kdb_samba.c            | 92 +++++++++++++-----------------
 source4/kdc/mit-kdb/kdb_samba.h            |  6 --
 source4/kdc/mit-kdb/kdb_samba_common.c     | 48 ----------------
 source4/kdc/mit-kdb/kdb_samba_principals.c | 33 ++++-------
 source4/kdc/sdb_to_kdb.c                   | 16 ++++--
 5 files changed, 63 insertions(+), 132 deletions(-)

diff --git a/source4/kdc/mit-kdb/kdb_samba.c b/source4/kdc/mit-kdb/kdb_samba.c
index b7f802c8c66..c5157d6ed1b 100644
--- a/source4/kdc/mit-kdb/kdb_samba.c
+++ b/source4/kdc/mit-kdb/kdb_samba.c
@@ -126,60 +126,50 @@ static krb5_error_code kdb_samba_db_unlock(krb5_context context)
 	return 0;
 }
 
-static void *kdb_samba_db_alloc(krb5_context context, void *ptr, size_t size)
+static void kdb_samba_db_free_principal_e_data(krb5_context context,
+					       krb5_octet *e_data)
 {
-	return realloc(ptr, size);
-}
+	struct samba_kdc_entry *skdc_entry;
 
-static void kdb_samba_db_free(krb5_context context, void *ptr)
-{
-	free(ptr);
+	skdc_entry = talloc_get_type_abort(e_data,
+					   struct samba_kdc_entry);
+	talloc_set_destructor(skdc_entry, NULL);
+	TALLOC_FREE(skdc_entry);
 }
 
 kdb_vftabl kdb_function_table = {
-	KRB5_KDB_DAL_MAJOR_VERSION,        /* major version number */
-	0,                                 /* minor version number */
-	kdb_samba_init_library,            /* init_library */
-	kdb_samba_fini_library,            /* fini_library */
-	kdb_samba_init_module,             /* init_module */
-	kdb_samba_fini_module,             /* fini_module */
-
-	kdb_samba_db_create,               /* db_create */
-	kdb_samba_db_destroy,              /* db_destroy */
-	kdb_samba_db_get_age,              /* db_get_age */
-	kdb_samba_db_lock,                 /* db_lock */
-	kdb_samba_db_unlock,               /* db_unlock */
-
-	kdb_samba_db_get_principal,        /* db_get_principal */
-	kdb_samba_db_free_principal,       /* db_free_principal */
-	kdb_samba_db_put_principal,        /* db_put_principal */
-	kdb_samba_db_delete_principal,     /* db_delete_principal */
-	kdb_samba_db_iterate,              /* db_iterate */
-
-	NULL,                              /* create_policy */
-	NULL,                              /* get_policy */
-	NULL,                              /* put_policy */
-	NULL,                              /* iter_policy */
-	NULL,                              /* delete_policy */
-	NULL,                              /* free_policy */
-
-	kdb_samba_db_alloc,                /* db_alloc */
-	kdb_samba_db_free,                 /* db_free */
-
-	kdb_samba_fetch_master_key,        /* fetch_master_key */
-	kdb_samba_fetch_master_key_list,   /* fetch_master_key_list */
-	NULL,                              /* store_master_key_list */
-	NULL,                              /* dbe_search_enctype */
-	kdb_samba_change_pwd,              /* change_pwd */
-	NULL,                              /* promote_db */
-	kdb_samba_dbekd_decrypt_key_data,  /* decrypt_key_data */
-	kdb_samba_dbekd_encrypt_key_data,  /* encrypt_key_data */
-
-	kdb_samba_db_sign_auth_data,       /* sign_authdata */
-	NULL,                              /* check_transited_realms */
-	kdb_samba_db_check_policy_as,      /* check_policy_as */
-	NULL,                              /* check_policy_tgs */
-	kdb_samba_db_audit_as_req,         /* audit_as_req */
-	NULL,                              /* refresh_config */
-	kdb_samba_db_check_allowed_to_delegate
+	.maj_ver                   = KRB5_KDB_DAL_MAJOR_VERSION,
+	.min_ver                   = 1,
+
+	.init_library              = kdb_samba_init_library,
+	.fini_library              = kdb_samba_fini_library,
+	.init_module               = kdb_samba_init_module,
+	.fini_module               = kdb_samba_fini_module,
+
+	.create                    = kdb_samba_db_create,
+	.destroy                   = kdb_samba_db_destroy,
+	.get_age                   = kdb_samba_db_get_age,
+	.lock                      = kdb_samba_db_lock,
+	.unlock                    = kdb_samba_db_unlock,
+
+	.get_principal             = kdb_samba_db_get_principal,
+	.put_principal             = kdb_samba_db_put_principal,
+	.delete_principal          = kdb_samba_db_delete_principal,
+
+	.iterate                   = kdb_samba_db_iterate,
+
+	.fetch_master_key          = kdb_samba_fetch_master_key,
+	.fetch_master_key_list     = kdb_samba_fetch_master_key_list,
+
+	.change_pwd                = kdb_samba_change_pwd,
+
+	.decrypt_key_data          = kdb_samba_dbekd_decrypt_key_data,
+	.encrypt_key_data          = kdb_samba_dbekd_encrypt_key_data,
+
+	.sign_authdata             = kdb_samba_db_sign_auth_data,
+	.check_policy_as           = kdb_samba_db_check_policy_as,
+	.audit_as_req              = kdb_samba_db_audit_as_req,
+	.check_allowed_to_delegate = kdb_samba_db_check_allowed_to_delegate,
+
+	.free_principal_e_data     = kdb_samba_db_free_principal_e_data,
 };
diff --git a/source4/kdc/mit-kdb/kdb_samba.h b/source4/kdc/mit-kdb/kdb_samba.h
index 0258b2d313f..abca2c166ae 100644
--- a/source4/kdc/mit-kdb/kdb_samba.h
+++ b/source4/kdc/mit-kdb/kdb_samba.h
@@ -48,9 +48,6 @@
 
 struct mit_samba_context *ks_get_context(krb5_context kcontext);
 
-void ks_free_krb5_db_entry(krb5_context context,
-			   krb5_db_entry *entry);
-
 bool ks_data_eq_string(krb5_data d, const char *s);
 
 krb5_data ks_make_data(void *data, unsigned int len);
@@ -74,9 +71,6 @@ krb5_error_code kdb_samba_db_get_principal(krb5_context context,
 					   unsigned int kflags,
 					   krb5_db_entry **kentry);
 
-void kdb_samba_db_free_principal(krb5_context context,
-				 krb5_db_entry *entry);
-
 krb5_error_code kdb_samba_db_put_principal(krb5_context context,
 					   krb5_db_entry *entry,
 					   char **db_args);
diff --git a/source4/kdc/mit-kdb/kdb_samba_common.c b/source4/kdc/mit-kdb/kdb_samba_common.c
index 1cd546977b7..e89aed6aeba 100644
--- a/source4/kdc/mit-kdb/kdb_samba_common.c
+++ b/source4/kdc/mit-kdb/kdb_samba_common.c
@@ -43,54 +43,6 @@ struct mit_samba_context *ks_get_context(krb5_context kcontext)
 	return (struct mit_samba_context *)db_ctx;
 }
 
-void ks_free_krb5_db_entry(krb5_context context,
-			   krb5_db_entry *entry)
-{
-	krb5_tl_data *tl_data_next = NULL;
-	krb5_tl_data *tl_data = NULL;
-	int i, j;
-
-	if (entry == NULL) {
-		return;
-	}
-
-#if 0 /* TODO FIXME do we have something to free? */
-	if (entry->e_data != NULL) {
-		/* FREE ME! */
-	}
-#endif
-
-	krb5_free_principal(context, entry->princ);
-
-	for (tl_data = entry->tl_data; tl_data; tl_data = tl_data_next) {
-		tl_data_next = tl_data->tl_data_next;
-		if (tl_data->tl_data_contents != NULL)
-			free(tl_data->tl_data_contents);
-		free(tl_data);
-	}
-
-	if (entry->key_data != NULL) {
-		for (i = 0; i < entry->n_key_data; i++) {
-			for (j = 0; j < entry->key_data[i].key_data_ver; j++) {
-				if (entry->key_data[i].key_data_length[j] != 0) {
-					if (entry->key_data[i].key_data_contents[j] != NULL) {
-						memset(entry->key_data[i].key_data_contents[j],
-								0,
-								entry->key_data[i].key_data_length[j]);
-						free(entry->key_data[i].key_data_contents[j]);
-					}
-				}
-				entry->key_data[i].key_data_contents[j] = NULL;
-				entry->key_data[i].key_data_length[j] = 0;
-				entry->key_data[i].key_data_type[j] = 0;
-			}
-		}
-		free(entry->key_data);
-	}
-
-	free(entry);
-}
-
 bool ks_data_eq_string(krb5_data d, const char *s)
 {
 	int rc;
diff --git a/source4/kdc/mit-kdb/kdb_samba_principals.c b/source4/kdc/mit-kdb/kdb_samba_principals.c
index 7b6fd6a81e9..1dbb69b561d 100644
--- a/source4/kdc/mit-kdb/kdb_samba_principals.c
+++ b/source4/kdc/mit-kdb/kdb_samba_principals.c
@@ -93,7 +93,7 @@ static krb5_error_code ks_get_master_key_principal(krb5_context context,
 		code = krb5_copy_principal(context, princ, &kentry->princ);
 	}
 	if (code != 0) {
-		ks_free_krb5_db_entry(context, kentry);
+		krb5_db_free_principal(context, kentry);
 		return code;
 	}
 
@@ -101,7 +101,7 @@ static krb5_error_code ks_get_master_key_principal(krb5_context context,
 
 	code = krb5_dbe_update_mod_princ_data(context, kentry, now, kentry->princ);
 	if (code != 0) {
-		ks_free_krb5_db_entry(context, kentry);
+		krb5_db_free_principal(context, kentry);
 		return code;
 	}
 
@@ -109,7 +109,7 @@ static krb5_error_code ks_get_master_key_principal(krb5_context context,
 	kentry->n_key_data = 1;
 	kentry->key_data = calloc(1, sizeof(krb5_key_data));
 	if (code != 0) {
-		ks_free_krb5_db_entry(context, kentry);
+		krb5_db_free_principal(context, kentry);
 		return code;
 	}
 
@@ -119,7 +119,7 @@ static krb5_error_code ks_get_master_key_principal(krb5_context context,
 	key_data->key_data_kvno         = 1;
 	key_data->key_data_type[0]      = ENCTYPE_UNKNOWN;
 	if (code != 0) {
-		ks_free_krb5_db_entry(context, kentry);
+		krb5_db_free_principal(context, kentry);
 		return code;
 	}
 
@@ -169,7 +169,7 @@ static krb5_error_code ks_create_principal(krb5_context context,
 
 	code = krb5_copy_principal(context, princ, &kentry->princ);
 	if (code != 0) {
-		ks_free_krb5_db_entry(context, kentry);
+		krb5_db_free_principal(context, kentry);
 		return code;
 	}
 
@@ -177,13 +177,13 @@ static krb5_error_code ks_create_principal(krb5_context context,
 
 	code = krb5_dbe_update_mod_princ_data(context, kentry, now, kentry->princ);
 	if (code != 0) {
-		ks_free_krb5_db_entry(context, kentry);
+		krb5_db_free_principal(context, kentry);
 		return code;
 	}
 
 	code = mit_samba_generate_salt(&salt);
 	if (code != 0) {
-		ks_free_krb5_db_entry(context, kentry);
+		krb5_db_free_principal(context, kentry);
 		return code;
 	}
 
@@ -194,7 +194,7 @@ static krb5_error_code ks_create_principal(krb5_context context,
 		/* create a random password */
 		code = mit_samba_generate_random_password(&pwd);
 		if (code != 0) {
-			ks_free_krb5_db_entry(context, kentry);
+			krb5_db_free_principal(context, kentry);
 			return code;
 		}
 	}
@@ -202,14 +202,14 @@ static krb5_error_code ks_create_principal(krb5_context context,
 	code = krb5_c_string_to_key(context, enctype, &pwd, &salt, &key);
 	SAFE_FREE(pwd.data);
 	if (code != 0) {
-		ks_free_krb5_db_entry(context, kentry);
+		krb5_db_free_principal(context, kentry);
 		return code;
 	}
 
 	kentry->n_key_data = 1;
 	kentry->key_data = calloc(1, sizeof(krb5_key_data));
 	if (code != 0) {
-		ks_free_krb5_db_entry(context, kentry);
+		krb5_db_free_principal(context, kentry);
 		return code;
 	}
 
@@ -288,19 +288,6 @@ krb5_error_code kdb_samba_db_get_principal(krb5_context context,
 	return code;
 }
 
-void kdb_samba_db_free_principal(krb5_context context,
-				 krb5_db_entry *entry)
-{
-	struct mit_samba_context *mit_ctx;
-
-	mit_ctx = ks_get_context(context);
-	if (mit_ctx == NULL) {
-		return;
-	}
-
-	ks_free_krb5_db_entry(context, entry);
-}
-
 krb5_error_code kdb_samba_db_put_principal(krb5_context context,
 					   krb5_db_entry *entry,
 					   char **db_args)
diff --git a/source4/kdc/sdb_to_kdb.c b/source4/kdc/sdb_to_kdb.c
index ff50c0cab87..74d882738f8 100644
--- a/source4/kdc/sdb_to_kdb.c
+++ b/source4/kdc/sdb_to_kdb.c
@@ -318,27 +318,35 @@ static int samba_kdc_kdb_entry_destructor(struct samba_kdc_entry *p)
 	krb5_error_code ret;
 	krb5_context context;
 
+	if (entry_ex->e_data != NULL) {
+		struct samba_kdc_entry *skdc_entry;
+
+		skdc_entry = talloc_get_type(entry_ex->e_data,
+					     struct samba_kdc_entry);
+		talloc_set_destructor(skdc_entry, NULL);
+		entry_ex->e_data = NULL;
+	}
+
 	ret = krb5_init_context(&context);
 	if (ret) {
 		return ret;
 	}
 
-	free_krb5_db_entry(context, entry_ex);
+	krb5_db_free_principal(context, entry_ex);
 	krb5_free_context(context);
 
 	return 0;
 }
 
-
 int sdb_entry_ex_to_kdb_entry_ex(krb5_context context,
 				 const struct sdb_entry_ex *s,
 				 krb5_db_entry *k)
 {
-	struct samba_kdc_entry *skdc_entry;
-
 	ZERO_STRUCTP(k);
 
 	if (s->ctx != NULL) {
+		struct samba_kdc_entry *skdc_entry;
+
 		skdc_entry = talloc_get_type(s->ctx, struct samba_kdc_entry);
 
 		k->e_data	= (void *)skdc_entry;
-- 
2.12.2


From 055f67457aa1b43fda693f8328769bfbe01251c3 Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Thu, 23 Jul 2015 13:49:09 +0200
Subject: [PATCH 08/51] waf: Check for MIT KDC binary

Signed-off-by: Andreas Schneider <asn at samba.org>
---
 wscript                          |  5 +++++
 wscript_configure_system_mitkrb5 | 13 +++++++++++++
 2 files changed, 18 insertions(+)

diff --git a/wscript b/wscript
index a7c4f4c31b9..032f2ae5fd2 100644
--- a/wscript
+++ b/wscript
@@ -51,6 +51,11 @@ def set_options(opt):
                    help='build Samba with system MIT Kerberos. ' +
                         'You may specify list of paths where Kerberos is installed (e.g. /usr/local /usr/kerberos) to search krb5-config',
                    action='callback', callback=system_mitkrb5_callback, dest='with_system_mitkrb5', default=False)
+    opt.add_option('--with-system-mitkdc',
+                   help=('Specify the path to the krb5kdc binary from MIT Kerberos'),
+                   type="string",
+                   dest='with_system_mitkdc',
+                   default=None)
 
     opt.add_option('--without-ad-dc',
                    help='disable AD DC functionality (enables only Samba FS (File Server, Winbind, NMBD) and client utilities.',
diff --git a/wscript_configure_system_mitkrb5 b/wscript_configure_system_mitkrb5
index 3e9d4ffb076..39924577431 100644
--- a/wscript_configure_system_mitkrb5
+++ b/wscript_configure_system_mitkrb5
@@ -291,3 +291,16 @@ conf.CHECK_CODE('''
     'HAVE_FLAGS_IN_KRB5_CREDS',
     headers='krb5.h', lib='krb5', execute=False,
     msg="Checking whether krb5_creds have flags property")
+
+# Check for MIT KDC
+if conf.CONFIG_SET('AD_DC_BUILD_IS_ENABLED'):
+    Logs.info("Looking for MIT KDC")
+    conf.DEFINE('SAMBA_USES_MITKDC', 1);
+
+    kdc_path_list = [ '/usr/sbin', '/usr/lib/mit/sbin']
+
+    if getattr(Options.options, 'with_system_mitkdc', None):
+        conf.DEFINE('MIT_KDC_PATH', '"' + Options.options.with_system_mitkdc + '"')
+    else:
+        conf.find_program('krb5kdc', path_list=kdc_path_list, var='MIT_KDC_BINARY', mandatory=True)
+        conf.DEFINE('MIT_KDC_PATH', '"' + conf.env.MIT_KDC_BINARY + '"')
-- 
2.12.2


From 305e440ac9bdc49e9aa4c2ff941489065cfc254d Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Mon, 28 Apr 2014 15:22:34 +0200
Subject: [PATCH 09/51] param: Add 'mit kdc command' to change the default.

Signed-off-by: Andreas Schneider <asn at samba.org>
---
 docs-xml/smbdotconf/security/mitkdccommand.xml | 15 +++++++++++++++
 lib/param/loadparm.c                           |  5 +++++
 source3/param/loadparm.c                       |  4 ++++
 3 files changed, 24 insertions(+)
 create mode 100644 docs-xml/smbdotconf/security/mitkdccommand.xml

diff --git a/docs-xml/smbdotconf/security/mitkdccommand.xml b/docs-xml/smbdotconf/security/mitkdccommand.xml
new file mode 100644
index 00000000000..2c7601fb5f5
--- /dev/null
+++ b/docs-xml/smbdotconf/security/mitkdccommand.xml
@@ -0,0 +1,15 @@
+<samba:parameter name="mit kdc command"
+                 context="G"
+                 type="list"
+                 advanced="1"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+<description>
+    <para>This option specifies the path to the MIT kdc binary.</para>
+
+    <para>If the KDC is not installed in the default location and wasn't
+    correctly detected during build then you should moify this variable and
+    point it to the correct binary.</para>
+</description>
+
+<value type="example">/opt/mit/sbin/krb5kdc</value>
+</samba:parameter>
diff --git a/lib/param/loadparm.c b/lib/param/loadparm.c
index c8a8b6d95c4..860f3e2c96c 100644
--- a/lib/param/loadparm.c
+++ b/lib/param/loadparm.c
@@ -2732,6 +2732,11 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx)
 	lpcfg_do_global_parameter_var(lp_ctx, "spn update command", "%s/samba_spnupdate", dyn_SCRIPTSBINDIR);
 	lpcfg_do_global_parameter_var(lp_ctx, "samba kcc command",
 					"%s/samba_kcc", dyn_SCRIPTSBINDIR);
+#ifdef MIT_KDC_PATH
+	lpcfg_do_global_parameter_var(lp_ctx,
+				      "mit kdc command",
+				      MIT_KDC_PATH);
+#endif
 	lpcfg_do_global_parameter(lp_ctx, "template shell", "/bin/false");
 	lpcfg_do_global_parameter(lp_ctx, "template homedir", "/home/%D/%U");
 
diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c
index 3c597ec2f40..91ecba88ad8 100644
--- a/source3/param/loadparm.c
+++ b/source3/param/loadparm.c
@@ -900,6 +900,10 @@ static void init_globals(struct loadparm_context *lp_ctx, bool reinit_globals)
 	Globals.samba_kcc_command = str_list_make_v3_const(NULL, s, NULL);
 	TALLOC_FREE(s);
 
+#ifdef MIT_KDC_PATH
+	Globals.mit_kdc_command = str_list_make_v3_const(NULL, MIT_KDC_PATH, NULL);
+#endif
+
 	s = talloc_asprintf(talloc_tos(), "%s/samba_dnsupdate", get_dyn_SCRIPTSBINDIR());
 	if (s == NULL) {
 		smb_panic("init_globals: ENOMEM");
-- 
2.12.2


From 8cee76ab8f8f64a2e2616435d82091a6e726a141 Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Thu, 8 Sep 2016 09:46:52 +0200
Subject: [PATCH 10/51] s4-kdc: Add a MIT Kerberos KDC service

This starts the krb5kdc binary shipped with MIT Kerberos.

Signed-off-by: Andreas Schneider <asn at samba.org>
---
 source4/kdc/kdc-service-mit.c | 120 ++++++++++++++++++++++++++++++++++++++++++
 source4/kdc/kdc-service-mit.h |  27 ++++++++++
 source4/kdc/wscript_build     |  50 +++++++++++-------
 3 files changed, 179 insertions(+), 18 deletions(-)
 create mode 100644 source4/kdc/kdc-service-mit.c
 create mode 100644 source4/kdc/kdc-service-mit.h

diff --git a/source4/kdc/kdc-service-mit.c b/source4/kdc/kdc-service-mit.c
new file mode 100644
index 00000000000..fde7c066ddf
--- /dev/null
+++ b/source4/kdc/kdc-service-mit.c
@@ -0,0 +1,120 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   Start MIT krb5kdc server within Samba AD
+
+   Copyright (c) 2014      Andreas Schneider <asn at samba.org>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "talloc.h"
+#include "tevent.h"
+#include "system/filesys.h"
+#include "lib/param/param.h"
+#include "lib/util/samba_util.h"
+#include "source4/smbd/service.h"
+#include "source4/smbd/process_model.h"
+#include "kdc/kdc-service-mit.h"
+#include "dynconfig.h"
+#include "libds/common/roles.h"
+
+static void mitkdc_server_done(struct tevent_req *subreq);
+
+/*
+ * Startup a copy of the krb5kdc as a child daemon
+ */
+void mitkdc_task_init(struct task_server *task)
+{
+	struct tevent_req *subreq;
+	const char * const *kdc_cmd;
+
+	task_server_set_title(task, "task[mitkdc_parent]");
+
+	switch (lpcfg_server_role(task->lp_ctx)) {
+	case ROLE_STANDALONE:
+		task_server_terminate(task,
+				      "The KDC is not required in standalone "
+				      "server configuration, terminate!",
+				      false);
+		return;
+	case ROLE_DOMAIN_MEMBER:
+		task_server_terminate(task,
+				      "The KDC is not required in member "
+				      "server configuration",
+				      false);
+		return;
+	case ROLE_ACTIVE_DIRECTORY_DC:
+		/* Yes, we want to start the KDC */
+		break;
+	}
+
+	/* start it as a child process */
+	kdc_cmd = lpcfg_mit_kdc_command(task->lp_ctx);
+
+	subreq = samba_runcmd_send(task,
+				   task->event_ctx,
+				   timeval_zero(),
+				   1, /* stdout log level */
+				   0, /* stderr log level */
+				   kdc_cmd,
+				   "-n", /* Don't go into background */
+#if 0
+				   "-w 2", /* Start two workers */
+#endif
+				   NULL);
+	if (subreq == NULL) {
+		DEBUG(0, ("Failed to start MIT KDC as child daemon\n"));
+
+		task_server_terminate(task,
+				      "Failed to startup mitkdc task",
+				      true);
+		return;
+	}
+
+	tevent_req_set_callback(subreq, mitkdc_server_done, task);
+
+	DEBUG(5,("Started krb5kdc process\n"));
+}
+
+/*
+ * This gets called the kdc exits.
+ */
+static void mitkdc_server_done(struct tevent_req *subreq)
+{
+	struct task_server *task =
+		tevent_req_callback_data(subreq,
+		struct task_server);
+	int sys_errno;
+	int ret;
+
+	ret = samba_runcmd_recv(subreq, &sys_errno);
+	if (ret != 0) {
+		DEBUG(0, ("The MIT KDC daemon died with exit status %d\n",
+			  sys_errno));
+	} else {
+		DEBUG(0,("The MIT KDC daemon exited normally\n"));
+	}
+
+	task_server_terminate(task, "mitkdc child process exited", true);
+}
+
+/* Called at MIT KRB5 startup - register ourselves as a server service */
+NTSTATUS server_service_mitkdc_init(TALLOC_CTX *mem_ctx);
+
+NTSTATUS server_service_mitkdc_init(TALLOC_CTX *mem_ctx)
+{
+	return register_server_service("kdc", mitkdc_task_init);
+}
diff --git a/source4/kdc/kdc-service-mit.h b/source4/kdc/kdc-service-mit.h
new file mode 100644
index 00000000000..6f38fe7ed97
--- /dev/null
+++ b/source4/kdc/kdc-service-mit.h
@@ -0,0 +1,27 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   Start MIT krb5kdc server within Samba AD
+
+   Copyright (c) 2014      Andreas Schneider <asn at samba.org>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _KDC_SERVICE_MIT_H
+#define _KDC_SERVICE_MIT_H
+
+void mitkdc_task_init(struct task_server *task);
+
+#endif /* _KDC_SERVICE_MIT_H */
diff --git a/source4/kdc/wscript_build b/source4/kdc/wscript_build
index 76efb1f02ca..b700c11ee44 100644
--- a/source4/kdc/wscript_build
+++ b/source4/kdc/wscript_build
@@ -6,24 +6,38 @@ if not bld.CONFIG_SET("USING_SYSTEM_KDC"):
 else:
     kdc_include = getattr(bld.env, "CPPPATH_KDC")
 
-bld.SAMBA_MODULE('service_kdc',
-                 source='kdc-heimdal.c',
-                 subsystem='service',
-                 init_function='server_service_kdc_init',
-                 deps='''
-                      kdc
-                      HDB_SAMBA4
-                      WDC_SAMBA4
-                      samba-hostconfig
-                      com_err
-                      samba_server_gensec
-                      PAC_GLUE
-                      KDC-GLUE
-                      KDC-SERVER
-                      KPASSWD-SERVICE
-                      KPASSWD_GLUE
-                 ''',
-                 internal_module=False)
+if bld.CONFIG_SET('SAMBA4_USES_HEIMDAL'):
+    bld.SAMBA_MODULE('service_kdc',
+                     source='kdc-heimdal.c',
+                     subsystem='service',
+                     init_function='server_service_kdc_init',
+                     deps='''
+                          kdc
+                          HDB_SAMBA4
+                          WDC_SAMBA4
+                          samba-hostconfig
+                          com_err
+                          samba_server_gensec
+                          PAC_GLUE
+                          KDC-GLUE
+                          KDC-SERVER
+                          KPASSWD-SERVICE
+                          KPASSWD_GLUE
+                     ''',
+                     internal_module=False)
+
+if bld.CONFIG_GET('SAMBA_USES_MITKDC'):
+    bld.SAMBA_MODULE('service_kdc',
+                     source='kdc-service-mit.c',
+                     subsystem='service',
+                     init_function='server_service_mitkdc_init',
+                     deps='''
+                          samba-hostconfig
+                          service
+                          talloc
+                          UTIL_RUNCMD
+                     ''',
+                     internal_module=False)
 
 bld.SAMBA_LIBRARY('HDB_SAMBA4',
                   source='hdb-samba4.c hdb-samba4-plugin.c',
-- 
2.12.2


From 8fe16ccfb03af71c5fb20364b31685e6716a9449 Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Thu, 8 Sep 2016 09:55:41 +0200
Subject: [PATCH 11/51] s4-kdc: Add MIT KRB5 based irpc service for PAC
 validation

Pair-Programmed-With: Guenther Deschner <gd at samba.org>
Signed-off-by: Andreas Schneider <asn at samba.org>
Signed-off-by: Guenther Deschner <gd at samba.org>
---
 source4/kdc/mit_kdc_irpc.c | 193 +++++++++++++++++++++++++++++++++++++++++++++
 source4/kdc/mit_kdc_irpc.h |  20 +++++
 source4/kdc/wscript_build  |  14 ++++
 3 files changed, 227 insertions(+)
 create mode 100644 source4/kdc/mit_kdc_irpc.c
 create mode 100644 source4/kdc/mit_kdc_irpc.h

diff --git a/source4/kdc/mit_kdc_irpc.c b/source4/kdc/mit_kdc_irpc.c
new file mode 100644
index 00000000000..d94ef24685c
--- /dev/null
+++ b/source4/kdc/mit_kdc_irpc.c
@@ -0,0 +1,193 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Copyright (c) 2015      Andreas Schneider <asn at samba.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "system/kerberos.h"
+#include "source4/auth/kerberos/kerberos.h"
+#include "auth/kerberos/pac_utils.h"
+
+#include "librpc/gen_ndr/irpc.h"
+#include "lib/messaging/irpc.h"
+#include "source4/librpc/gen_ndr/ndr_irpc.h"
+#include "source4/librpc/gen_ndr/irpc.h"
+
+#include "librpc/gen_ndr/ndr_krb5pac.h"
+
+#include "source4/smbd/process_model.h"
+#include "lib/param/param.h"
+
+#include "samba_kdc.h"
+#include "db-glue.h"
+#include "sdb.h"
+#include "mit_kdc_irpc.h"
+
+struct mit_kdc_irpc_context {
+	struct task_server *task;
+	krb5_context krb5_context;
+	struct samba_kdc_db_context *db_ctx;
+};
+
+static NTSTATUS netr_samlogon_generic_logon(struct irpc_message *msg,
+					    struct kdc_check_generic_kerberos *r)
+{
+	struct PAC_Validate pac_validate;
+	DATA_BLOB pac_chksum;
+	struct PAC_SIGNATURE_DATA pac_kdc_sig;
+	struct mit_kdc_irpc_context *mki_ctx =
+		talloc_get_type(msg->private_data,
+				struct mit_kdc_irpc_context);
+	enum ndr_err_code ndr_err;
+	int code;
+	krb5_principal principal;
+	struct sdb_entry_ex sentry = {};
+	struct sdb_keys skeys;
+	unsigned int i;
+
+	/* There is no reply to this request */
+	r->out.generic_reply = data_blob(NULL, 0);
+
+	ndr_err = ndr_pull_struct_blob(&r->in.generic_request,
+				       msg,
+				       &pac_validate,
+				       (ndr_pull_flags_fn_t)ndr_pull_PAC_Validate);
+	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+		return NT_STATUS_INVALID_PARAMETER;
+	}
+
+	if (pac_validate.MessageType != NETLOGON_GENERIC_KRB5_PAC_VALIDATE) {
+		/*
+		 * We don't implement any other message types - such as
+		 * certificate validation - yet
+		 */
+		return NT_STATUS_INVALID_PARAMETER;
+	}
+
+	if (pac_validate.ChecksumAndSignature.length != (pac_validate.ChecksumLength + pac_validate.SignatureLength)
+	    || pac_validate.ChecksumAndSignature.length < pac_validate.ChecksumLength
+	    || pac_validate.ChecksumAndSignature.length < pac_validate.SignatureLength ) {
+		return NT_STATUS_INVALID_PARAMETER;
+	}
+
+	/* PAC Checksum */
+	pac_chksum = data_blob_const(pac_validate.ChecksumAndSignature.data,
+				     pac_validate.ChecksumLength);
+
+	/* Create the krbtgt principal */
+	code = smb_krb5_make_principal(mki_ctx->krb5_context,
+				      &principal,
+				      lpcfg_realm(mki_ctx->task->lp_ctx),
+				      "krbtgt",
+				      lpcfg_realm(mki_ctx->task->lp_ctx),
+				      NULL);
+	if (code != 0) {
+		DEBUG(0, ("Failed to create krbtgt@%s principal!\n",
+			  lpcfg_realm(mki_ctx->task->lp_ctx)));
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	/* Get the krbtgt from the DB */
+	code = samba_kdc_fetch(mki_ctx->krb5_context,
+			       mki_ctx->db_ctx,
+			       principal,
+			       SDB_F_GET_KRBTGT | SDB_F_DECRYPT,
+			       0,
+			       &sentry);
+	krb5_free_principal(mki_ctx->krb5_context, principal);
+	if (code != 0) {
+		DEBUG(0, ("Failed to fetch krbtgt@%s principal entry!\n",
+			  lpcfg_realm(mki_ctx->task->lp_ctx)));
+		return NT_STATUS_LOGON_FAILURE;
+	}
+
+	/* PAC Signature */
+	pac_kdc_sig.type = pac_validate.SignatureType;
+	pac_kdc_sig.signature = data_blob_const(&pac_validate.ChecksumAndSignature.data[pac_validate.ChecksumLength],
+					    pac_validate.SignatureLength);
+
+	/*
+	 * Brute force variant because MIT KRB5 doesn't provide a function like
+	 * krb5_checksum_to_enctype().
+	 */
+	skeys = sentry.entry.keys;
+
+	for (i = 0; i < skeys.len; i++) {
+		krb5_keyblock krbtgt_keyblock = skeys.val[i].key;
+
+		code = check_pac_checksum(pac_chksum,
+					  &pac_kdc_sig,
+					  mki_ctx->krb5_context,
+					  &krbtgt_keyblock);
+		if (code == 0) {
+			break;
+		}
+	}
+
+	sdb_free_entry(&sentry);
+
+	if (code != 0) {
+		return NT_STATUS_LOGON_FAILURE;
+	}
+
+	return NT_STATUS_OK;
+}
+
+NTSTATUS samba_setup_mit_kdc_irpc(struct task_server *task)
+{
+	struct samba_kdc_base_context base_ctx;
+	struct mit_kdc_irpc_context *mki_ctx;
+	NTSTATUS status;
+	int code;
+
+	mki_ctx = talloc_zero(task, struct mit_kdc_irpc_context);
+	if (mki_ctx == NULL) {
+		return NT_STATUS_NO_MEMORY;
+	}
+	mki_ctx->task = task;
+
+	base_ctx.ev_ctx = task->event_ctx;
+	base_ctx.lp_ctx = task->lp_ctx;
+
+	/* db-glue.h */
+	status = samba_kdc_setup_db_ctx(mki_ctx,
+					&base_ctx,
+					&mki_ctx->db_ctx);
+	if (!NT_STATUS_IS_OK(status)) {
+		return status;
+	}
+
+	code = smb_krb5_init_context_basic(mki_ctx,
+					   task->lp_ctx,
+					   &mki_ctx->krb5_context);
+	if (code != 0) {
+		return NT_STATUS_INTERNAL_ERROR;
+	}
+
+	status = IRPC_REGISTER(task->msg_ctx,
+			       irpc,
+			       KDC_CHECK_GENERIC_KERBEROS,
+			       netr_samlogon_generic_logon,
+			       mki_ctx);
+	if (!NT_STATUS_IS_OK(status)) {
+		return status;
+	}
+
+	irpc_add_name(task->msg_ctx, "kdc_server");
+
+	return status;
+}
diff --git a/source4/kdc/mit_kdc_irpc.h b/source4/kdc/mit_kdc_irpc.h
new file mode 100644
index 00000000000..943c76cfb38
--- /dev/null
+++ b/source4/kdc/mit_kdc_irpc.h
@@ -0,0 +1,20 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Copyright (c) 2015      Andreas Schneider <asn at samba.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+NTSTATUS samba_setup_mit_kdc_irpc(struct task_server *task);
diff --git a/source4/kdc/wscript_build b/source4/kdc/wscript_build
index b700c11ee44..9d8288129e3 100644
--- a/source4/kdc/wscript_build
+++ b/source4/kdc/wscript_build
@@ -143,6 +143,20 @@ bld.SAMBA_SUBSYSTEM('KPASSWD_GLUE',
         includes=kdc_include,
         deps='ldb com_err')
 
+bld.SAMBA_SUBSYSTEM('MIT_KDC_IRPC',
+                    source='mit_kdc_irpc.c',
+                    deps='''
+                    ldb
+                    auth4_sam
+                    samba-credentials
+                    db-glue
+                    samba-hostconfig
+                    com_err
+                    kdb5
+                    ''',
+                    enabled=(bld.CONFIG_SET('SAMBA_USES_MITKDC') and bld.CONFIG_SET('HAVE_KDB_H'))
+                    )
+
 bld.SAMBA_SUBSYSTEM('MIT_SAMBA',
                     source='mit_samba.c',
                     deps='''
-- 
2.12.2


From 136fc0619c1bc2ae0931eef7789e87afd55eca74 Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Thu, 8 Sep 2016 09:56:37 +0200
Subject: [PATCH 12/51] s4-kdc: Register the MIT irpc PAC validation service

Signed-off-by: Andreas Schneider <asn at samba.org>
---
 source4/kdc/kdc-service-mit.c | 12 ++++++++++++
 source4/kdc/wscript_build     |  1 +
 2 files changed, 13 insertions(+)

diff --git a/source4/kdc/kdc-service-mit.c b/source4/kdc/kdc-service-mit.c
index fde7c066ddf..36d0063e4ed 100644
--- a/source4/kdc/kdc-service-mit.c
+++ b/source4/kdc/kdc-service-mit.c
@@ -31,6 +31,8 @@
 #include "dynconfig.h"
 #include "libds/common/roles.h"
 
+#include "source4/kdc/mit_kdc_irpc.h"
+
 static void mitkdc_server_done(struct tevent_req *subreq);
 
 /*
@@ -40,6 +42,7 @@ void mitkdc_task_init(struct task_server *task)
 {
 	struct tevent_req *subreq;
 	const char * const *kdc_cmd;
+	NTSTATUS status;
 
 	task_server_set_title(task, "task[mitkdc_parent]");
 
@@ -87,6 +90,15 @@ void mitkdc_task_init(struct task_server *task)
 	tevent_req_set_callback(subreq, mitkdc_server_done, task);
 
 	DEBUG(5,("Started krb5kdc process\n"));
+
+	status = samba_setup_mit_kdc_irpc(task);
+	if (!NT_STATUS_IS_OK(status)) {
+		task_server_terminate(task,
+				      "Failed to setup kdc irpc service",
+				      true);
+	}
+
+	DEBUG(5,("Started irpc service for kdc_server\n"));
 }
 
 /*
diff --git a/source4/kdc/wscript_build b/source4/kdc/wscript_build
index 9d8288129e3..a19932cca50 100644
--- a/source4/kdc/wscript_build
+++ b/source4/kdc/wscript_build
@@ -36,6 +36,7 @@ if bld.CONFIG_GET('SAMBA_USES_MITKDC'):
                           service
                           talloc
                           UTIL_RUNCMD
+                          MIT_KDC_IRPC
                      ''',
                      internal_module=False)
 
-- 
2.12.2


From e789715999632ddbd09c9b52cbf96f6c8a34b363 Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Wed, 7 Oct 2015 14:36:57 +0200
Subject: [PATCH 13/51] param: Add 'mit kdc config' option to smb.conf

This points to the kdc config file created by Samba by default.

Signed-off-by: Andreas Schneider <asn at samba.org>
---
 docs-xml/smbdotconf/security/mitkdcconfig.xml | 11 +++++++++++
 source4/kdc/kdc-service-mit.c                 |  7 +++++++
 2 files changed, 18 insertions(+)
 create mode 100644 docs-xml/smbdotconf/security/mitkdcconfig.xml

diff --git a/docs-xml/smbdotconf/security/mitkdcconfig.xml b/docs-xml/smbdotconf/security/mitkdcconfig.xml
new file mode 100644
index 00000000000..013d407fe0b
--- /dev/null
+++ b/docs-xml/smbdotconf/security/mitkdcconfig.xml
@@ -0,0 +1,11 @@
+<samba:parameter name="mit kdc config"
+                 context="G"
+                 type="string"
+                 advanced="1"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+<description>
+    <para>This option specifies the path to the MIT KDC config file.</para>
+</description>
+
+<value type="example">/etc/samba/kdc.conf</value>
+</samba:parameter>
diff --git a/source4/kdc/kdc-service-mit.c b/source4/kdc/kdc-service-mit.c
index 36d0063e4ed..719ea48c090 100644
--- a/source4/kdc/kdc-service-mit.c
+++ b/source4/kdc/kdc-service-mit.c
@@ -42,6 +42,7 @@ void mitkdc_task_init(struct task_server *task)
 {
 	struct tevent_req *subreq;
 	const char * const *kdc_cmd;
+	const char *kdc_config;
 	NTSTATUS status;
 
 	task_server_set_title(task, "task[mitkdc_parent]");
@@ -64,6 +65,12 @@ void mitkdc_task_init(struct task_server *task)
 		break;
 	}
 
+	kdc_config = lpcfg_mit_kdc_config(task->lp_ctx, task);
+	if (kdc_config != NULL && kdc_config[0] != '\0') {
+		/* Do not overwrite the variable if already set! */
+		setenv("KRB5_KDC_PROFILE", kdc_config, 0);
+	}
+
 	/* start it as a child process */
 	kdc_cmd = lpcfg_mit_kdc_command(task->lp_ctx);
 
-- 
2.12.2


From 31a71c7ea6233737cf232f51fb71450efe5f99fb Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Fri, 4 Dec 2015 08:12:03 +0100
Subject: [PATCH 14/51] waf: Do not disable the ntvfs fileserver when we have
 MIT DC build

Signed-off-by: Andreas Schneider <asn at samba.org>
---
 wscript | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/wscript b/wscript
index 032f2ae5fd2..57b87850896 100644
--- a/wscript
+++ b/wscript
@@ -190,17 +190,15 @@ def configure(conf):
         if Options.options.with_pam:
             conf.RECURSE('lib/pam_wrapper')
         if Options.options.with_ntvfs_fileserver != False:
-            if not (Options.options.without_ad_dc or Options.options.with_system_mitkrb5):
+            if not (Options.options.without_ad_dc):
                 conf.DEFINE('WITH_NTVFS_FILESERVER', 1)
         if Options.options.with_ntvfs_fileserver == False:
-            if not (Options.options.without_ad_dc or Options.options.with_system_mitkrb5):
+            if not (Options.options.without_ad_dc):
                 raise Utils.WafError('--without-ntvfs-fileserver conflicts with --enable-selftest while building the AD DC')
 
     if Options.options.with_ntvfs_fileserver == True:
         if Options.options.without_ad_dc:
             raise Utils.WafError('--with-ntvfs-fileserver conflicts with --without-ad-dc')
-        if Options.options.with_system_mitkrb5:
-            raise Utils.WafError('--with-ntvfs-fileserver conflicts with --with-system-mitkrb5')
         conf.DEFINE('WITH_NTVFS_FILESERVER', 1)
 
     if Options.options.with_pthreadpool:
-- 
2.12.2


From c2314ccdcee7ca915fe4091d933c0b2977e75928 Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Mon, 5 May 2014 13:27:58 +0200
Subject: [PATCH 15/51] selftest: Start MIT KDC if Kerberos is from MIT

Signed-off-by: Andreas Schneider <asn at samba.org>
---
 selftest/selftest.pl | 6 ++++++
 selftest/wscript     | 3 +++
 2 files changed, 9 insertions(+)

diff --git a/selftest/selftest.pl b/selftest/selftest.pl
index 32fc845bde5..b00ab486e87 100755
--- a/selftest/selftest.pl
+++ b/selftest/selftest.pl
@@ -49,6 +49,7 @@ my @opt_exclude = ();
 my @opt_include = ();
 my $opt_testenv = 0;
 my $opt_list = 0;
+my $opt_mitkrb5 = 0;
 my $ldap = undef;
 my $opt_resetup_env = undef;
 my $opt_load_list = undef;
@@ -246,6 +247,7 @@ my $result = GetOptions (
 		'bindir=s' => \$bindir,
 		'testenv' => \$opt_testenv,
 		'list' => \$opt_list,
+		'mitkrb5' => \$opt_mitkrb5,
 		'ldap:s' => \$ldap,
 		'resetup-environment' => \$opt_resetup_env,
 		'testlist=s' => \@testlists,
@@ -418,6 +420,10 @@ if ($opt_use_dns_faking) {
 my $target;
 my $testenv_default = "none";
 
+if ($opt_mitkrb5 == 1) {
+	$ENV{MITKRB5} = $opt_mitkrb5;
+}
+
 # After this many seconds, the server will self-terminate.  All tests
 # must terminate in this time, and testenv will only stay alive this
 # long
diff --git a/selftest/wscript b/selftest/wscript
index f35efa8e7a3..34dd7a0d1f9 100644
--- a/selftest/wscript
+++ b/selftest/wscript
@@ -230,6 +230,9 @@ def cmd_testonly(opt):
     # FIXME REMOVE ME!
     env.OPTIONS += " --use-dns-faking"
 
+    if CONFIG_GET(opt, 'USING_SYSTEM_KRB5') and CONFIG_GET(opt, 'MIT_KDC_PATH'):
+        env.OPTIONS += " --mitkrb5"
+
     if not CONFIG_GET(opt, 'HAVE_GSS_KRB5_CRED_NO_CI_FLAGS_X'):
         # older MIT krb5 libraries (< 1.14) don't have
         # GSS_KRB5_CRED_NO_CI_FLAGS_X
-- 
2.12.2


From 960ee01b8b463471036c4cde83d529ffa018c6ae Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Tue, 20 Sep 2016 12:43:38 +0200
Subject: [PATCH 16/51] selftest: Disable RODC tests with MIT KDC

Signed-off-by: Andreas Schneider <asn at samba.org>
---
 selftest/skip_mit_kdc | 3 +++
 selftest/wscript      | 2 +-
 2 files changed, 4 insertions(+), 1 deletion(-)
 create mode 100644 selftest/skip_mit_kdc

diff --git a/selftest/skip_mit_kdc b/selftest/skip_mit_kdc
new file mode 100644
index 00000000000..b0c901514d5
--- /dev/null
+++ b/selftest/skip_mit_kdc
@@ -0,0 +1,3 @@
+# We do not support RODC yet
+.*rodc
+.*RODC
diff --git a/selftest/wscript b/selftest/wscript
index 34dd7a0d1f9..2299195428f 100644
--- a/selftest/wscript
+++ b/selftest/wscript
@@ -231,7 +231,7 @@ def cmd_testonly(opt):
     env.OPTIONS += " --use-dns-faking"
 
     if CONFIG_GET(opt, 'USING_SYSTEM_KRB5') and CONFIG_GET(opt, 'MIT_KDC_PATH'):
-        env.OPTIONS += " --mitkrb5"
+        env.OPTIONS += " --mitkrb5 --exclude=${srcdir}/selftest/skip_mit_kdc"
 
     if not CONFIG_GET(opt, 'HAVE_GSS_KRB5_CRED_NO_CI_FLAGS_X'):
         # older MIT krb5 libraries (< 1.14) don't have
-- 
2.12.2


From 2516851e162994f42212974d106e6336d8911d60 Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Wed, 30 Apr 2014 09:32:49 +0200
Subject: [PATCH 17/51] selftest: Setup configs for MIT KDC

Signed-off-by: Andreas Schneider <asn at samba.org>
---
 selftest/target/Samba.pm  | 49 +++++++++++++++++++++++++++++++++++++++++++++++
 selftest/target/Samba4.pm |  8 ++++++++
 2 files changed, 57 insertions(+)

diff --git a/selftest/target/Samba.pm b/selftest/target/Samba.pm
index e53d8dc4e9e..3e5a7c3aa97 100644
--- a/selftest/target/Samba.pm
+++ b/selftest/target/Samba.pm
@@ -274,6 +274,55 @@ sub mk_realms_stanza($$$$)
         return $realms_stanza;
 }
 
+sub mk_mitkdc_conf($$)
+{
+	# samba_kdb_dir is the path to mit_samba.so
+	my ($ctx, $samba_kdb_dir) = @_;
+
+	unless (open(KDCCONF, ">$ctx->{mitkdc_conf}")) {
+	        warn("can't open $ctx->{mitkdc_conf}$?");
+		return undef;
+	}
+
+	print KDCCONF "
+# Generated kdc.conf for $ctx->{realm}
+
+[kdcdefaults]
+	kdc_ports = 88
+	kdc_tcp_ports = 88
+
+[realms]
+	$ctx->{realm} = {
+	}
+
+	$ctx->{dnsname} = {
+	}
+
+	$ctx->{domain} = {
+	}
+
+[dbmodules]
+	db_module_dir = $samba_kdb_dir
+
+	$ctx->{realm} = {
+		db_library = samba
+	}
+
+	$ctx->{dnsname} = {
+		db_library = samba
+	}
+
+	$ctx->{domain} = {
+		db_library = samba
+	}
+
+[logging]
+	kdc = FILE:$ctx->{logdir}/mit_kdc.log
+";
+
+	close(KDCCONF);
+}
+
 sub get_interface($)
 {
     my ($netbiosname) = @_;
diff --git a/selftest/target/Samba4.pm b/selftest/target/Samba4.pm
index 30bb2552997..0d75c471de5 100755
--- a/selftest/target/Samba4.pm
+++ b/selftest/target/Samba4.pm
@@ -123,6 +123,9 @@ sub check_or_start($$$)
 
 		$ENV{KRB5_CONFIG} = $env_vars->{KRB5_CONFIG};
 		$ENV{KRB5CCNAME} = "$env_vars->{KRB5_CCACHE}.samba";
+		if (defined($ENV{MITKRB5})) {
+			$ENV{KRB5_KDC_PROFILE} = $env_vars->{MITKDC_CONFIG};
+		}
 		$ENV{SELFTEST_WINBINDD_SOCKET_DIR} = $env_vars->{SELFTEST_WINBINDD_SOCKET_DIR};
 		$ENV{NMBD_SOCKET_DIR} = $env_vars->{NMBD_SOCKET_DIR};
 
@@ -440,6 +443,7 @@ sub provision_raw_prepare($$$$$$$$$$$)
 	$ctx->{smb_conf} = "$ctx->{etcdir}/smb.conf";
 	$ctx->{krb5_conf} = "$ctx->{etcdir}/krb5.conf";
 	$ctx->{krb5_ccache} = "$prefix_abs/krb5_ccache";
+	$ctx->{mitkdc_conf} = "$ctx->{etcdir}/mitkdc.conf";
 	$ctx->{privatedir} = "$prefix_abs/private";
 	$ctx->{ncalrpcdir} = "$prefix_abs/ncalrpc";
 	$ctx->{lockdir} = "$prefix_abs/lockdir";
@@ -617,6 +621,7 @@ sub provision_raw_step1($$)
 	}
 
 	Samba::mk_krb5_conf($ctx);
+	Samba::mk_mitkdc_conf($ctx, abs_path(Samba::bindir_path($self, "shared")));
 
 	open(PWD, ">$ctx->{nsswrap_passwd}");
 	if ($ctx->{unix_uid} != 0) {
@@ -680,6 +685,7 @@ nogroup:x:65534:nobody
 	my $ret = {
 		KRB5_CONFIG => $ctx->{krb5_conf},
 		KRB5_CCACHE => $ctx->{krb5_ccache},
+		MITKDC_CONFIG => $ctx->{mitkdc_conf},
 		PIDDIR => $ctx->{piddir},
 		SERVER => $ctx->{hostname},
 		SERVER_IP => $ctx->{ipv4},
@@ -1367,6 +1373,7 @@ sub provision_subdom_dc($$$)
 	}
 
 	Samba::mk_krb5_conf($ctx);
+	Samba::mk_mitkdc_conf($ctx, abs_path(Samba::bindir_path($self, "shared")));
 
 	my $samba_tool =  Samba::bindir_path($self, "samba-tool");
 	my $cmd = "";
@@ -1675,6 +1682,7 @@ sub provision_rodc($$$)
 	$ctx->{kdc_ipv4} = $ret->{SERVER_IP};
 	$ctx->{kdc_ipv6} = $ret->{SERVER_IPV6};
 	Samba::mk_krb5_conf($ctx);
+	Samba::mk_mitkdc_conf($ctx, abs_path(Samba::bindir_path($self, "shared")));
 
 	$ret->{RODC_DC_SERVER} = $ret->{SERVER};
 	$ret->{RODC_DC_SERVER_IP} = $ret->{SERVER_IP};
-- 
2.12.2


From 65b806c814f9b32d9a1f4e0ee38a83841185c930 Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Mon, 26 Sep 2016 18:51:33 +0200
Subject: [PATCH 18/51] selftest: Set clockskew grace time to 5 seconds

Signed-off-by: Andreas Schneider <asn at samba.org>
---
 selftest/target/Samba.pm | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/selftest/target/Samba.pm b/selftest/target/Samba.pm
index 3e5a7c3aa97..8b2e4a664b3 100644
--- a/selftest/target/Samba.pm
+++ b/selftest/target/Samba.pm
@@ -201,6 +201,10 @@ sub mk_krb5_conf($$)
  ticket_lifetime = 24h
  forwardable = yes
  allow_weak_crypto = yes
+ # Set the grace clocskew to 5 seconds
+ # This is especially required by samba3.raw.session krb5 and
+ # reauth tests
+ clockskew = 5
 
 ";
 
-- 
2.12.2


From adddf9ff042ebb25d6131f9d15f680f00d720114 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?G=C3=BCnther=20Deschner?= <gd at samba.org>
Date: Sat, 7 Feb 2015 12:48:54 +0100
Subject: [PATCH 19/51] s4-torture: disable s4u2self/proxy remote pac tests for
 MIT build for now.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Guenther

Signed-off-by: G√ľnther Deschner <gd at samba.org>
---
 source4/torture/rpc/remote_pac.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/source4/torture/rpc/remote_pac.c b/source4/torture/rpc/remote_pac.c
index 091309874fe..9fca10f1b08 100644
--- a/source4/torture/rpc/remote_pac.c
+++ b/source4/torture/rpc/remote_pac.c
@@ -616,6 +616,7 @@ static bool test_PACVerify_workstation_des(struct torture_context *tctx,
 
 
 /* Check various ways to get the PAC, in particular check the group membership and other details between the PAC from a normal kinit, S2U4Self and a SamLogon */
+#ifdef SAMBA4_USES_HEIMDAL
 static bool test_S2U4Self(struct torture_context *tctx,
 			  struct dcerpc_pipe *p1,
 			  struct cli_credentials *credentials,
@@ -929,6 +930,7 @@ static bool test_S2U4Self_workstation_aes(struct torture_context *tctx,
 			     TEST_MACHINE_NAME_S2U4SELF_WKSTA,
 			     NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES);
 }
+#endif
 
 struct torture_suite *torture_rpc_remote_pac(TALLOC_CTX *mem_ctx)
 {
@@ -954,7 +956,7 @@ struct torture_suite *torture_rpc_remote_pac(TALLOC_CTX *mem_ctx)
 	tcase = torture_suite_add_machine_workstation_rpc_iface_tcase(suite, "netlogon-member-des",
 								      &ndr_table_netlogon, TEST_MACHINE_NAME_WKSTA_DES);
 	torture_rpc_tcase_add_test_join(tcase, "verify-sig", test_PACVerify_workstation_des);
-
+#ifdef SAMBA4_USES_HEIMDAL
 	tcase = torture_suite_add_machine_bdc_rpc_iface_tcase(suite, "netr-bdc-arcfour",
 							      &ndr_table_netlogon, TEST_MACHINE_NAME_S2U4SELF_BDC);
 	torture_rpc_tcase_add_test_creds(tcase, "s2u4self-arcfour", test_S2U4Self_bdc_arcfour);
@@ -970,6 +972,6 @@ struct torture_suite *torture_rpc_remote_pac(TALLOC_CTX *mem_ctx)
 	tcase = torture_suite_add_machine_workstation_rpc_iface_tcase(suite, "netr-mem-aes",
 								      &ndr_table_netlogon, TEST_MACHINE_NAME_S2U4SELF_WKSTA);
 	torture_rpc_tcase_add_test_creds(tcase, "s2u4self-aes", test_S2U4Self_workstation_aes);
-
+#endif
 	return suite;
 }
-- 
2.12.2


From fbf923aa5c83485378ae1e1fb4c69750d0867841 Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Wed, 22 Apr 2015 15:19:10 +0200
Subject: [PATCH 20/51] testprogs: Fix test_chgdcpass blackbox test with MIT

Signed-off-by: Andreas Schneider <asn at samba.org>
---
 testprogs/blackbox/test_chgdcpass.sh | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/testprogs/blackbox/test_chgdcpass.sh b/testprogs/blackbox/test_chgdcpass.sh
index 120f0024cff..3830cb4e31d 100755
--- a/testprogs/blackbox/test_chgdcpass.sh
+++ b/testprogs/blackbox/test_chgdcpass.sh
@@ -25,7 +25,9 @@ samba4bindir="$BINDIR"
 samba4srcdir="$SRCDIR/source4"
 
 samba4kinit=kinit
+heimdal=0
 if test -x $BINDIR/samba4kinit; then
+	heimdal=1
 	samba4kinit=bin/samba4kinit
 fi
 
@@ -59,7 +61,12 @@ enctype="-e $ENCTYPE"
 KRB5CCNAME="$PREFIX/tmpccache"
 export KRB5CCNAME
 rm -f $KRB5CCNAME
-testit "kinit with keytab" $samba4kinit $enctype -t $PROVDIR/private/secrets.keytab --use-keytab $USERNAME   || failed=`expr $failed + 1`
+
+if [ $heimdal -eq 1 ]; then
+	testit "kinit with keytab" $samba4kinit $enctype -t $PROVDIR/private/secrets.keytab --use-keytab $USERNAME   || failed=`expr $failed + 1`
+else
+	testit "kinit with keytab" $samba4kinit -k -t $PROVDIR/private/secrets.keytab $USERNAME || failed=`expr $failed + 1`
+fi
 
 #This is important because it puts the ticket for the old KVNO and password into a local ccache
 test_smbclient "Test login with kerberos ccache before password change" 'ls' "$unc" -k yes || failed=`expr $failed + 1`
@@ -94,8 +101,13 @@ test_drs bind "Test drs bind after 2nd password change" || failed=`expr $failed
 test_drs options "Test drs options after 2nd password change" || failed=`expr $failed + 1`
 
 #This confirms that the DC password is valid for a kinit too
-testit "kinit with keytab" $samba4kinit $enctype -t $PROVDIR/private/secrets.keytab --use-keytab $USERNAME   || failed=`expr $failed + 1`
+if [ $heimdal -eq 1 ]; then
+	testit "kinit with keytab" $samba4kinit $enctype -t $PROVDIR/private/secrets.keytab --use-keytab $USERNAME   || failed=`expr $failed + 1`
+else
+	testit "kinit with keytab" $samba4kinit -k -t $PROVDIR/private/secrets.keytab $USERNAME || failed=`expr $failed + 1`
+fi
 test_smbclient "Test login with kerberos ccache with fresh kinit" 'ls' "$unc" -k yes || failed=`expr $failed + 1`
+
 rm -f $KRB5CCNAME
 
 rm -f $PREFIX/tmpccache tmpccfile tmppassfile tmpuserpassfile tmpuserccache tmpkpasswdscript
-- 
2.12.2


From 63c98748fd37f309b9bfb8a506d4cf03b9705f6d Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Wed, 22 Apr 2015 15:39:45 +0200
Subject: [PATCH 21/51] testprogs: Fix usage printout of bogus blackbox test

Signed-off-by: Andreas Schneider <asn at samba.org>
---
 testprogs/blackbox/bogus.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/testprogs/blackbox/bogus.sh b/testprogs/blackbox/bogus.sh
index be67e1992e7..3056b538aee 100755
--- a/testprogs/blackbox/bogus.sh
+++ b/testprogs/blackbox/bogus.sh
@@ -2,7 +2,7 @@
 
 if [ $# -lt 1 ]; then
 cat <<EOF
-Usage: blackbox_newuser.sh PREFIX
+Usage: bogus.sh SERVER SHARE USER PASSWORD DC_USER DC_PASSWORD SMBCLIENT
 EOF
 exit 1;
 fi
-- 
2.12.2


From 3ed296733ed517917604cc97e24b3560cadcadaf Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Wed, 22 Apr 2015 12:00:21 +0200
Subject: [PATCH 22/51] s4-torture: Fix kinit of samba4.blackbox.locktest

Signed-off-by: Andreas Schneider <asn at samba.org>
---
 source4/torture/tests/test_locktest.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/source4/torture/tests/test_locktest.sh b/source4/torture/tests/test_locktest.sh
index c4368363536..95fc7ffc275 100755
--- a/source4/torture/tests/test_locktest.sh
+++ b/source4/torture/tests/test_locktest.sh
@@ -23,6 +23,6 @@ locktest="$samba4bindir/locktest"
 
 . `dirname $0`/../../../testprogs/blackbox/subunit.sh
 
-testit "locktest" $VALGRIND $locktest //$SERVER/test1 //$SERVER/test2 --num-ops=100  -W "$DOMAIN" -U"$USERNAME%$PASSWORD" $@ || failed=`expr $failed + 1`
+testit "locktest" $VALGRIND $locktest //$SERVER/test1 //$SERVER/test2 --num-ops=100  -W "$DOMAIN" -U"$DOMAIN\\$USERNAME%$PASSWORD" $@ || failed=`expr $failed + 1`
 
 exit $failed
-- 
2.12.2


From 1596c1e439a05f99f388fa43235ee8401499329f Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Thu, 14 Jan 2016 16:41:36 +0100
Subject: [PATCH 23/51] testprogs: Add test_kinit_mit.sh test

Signed-off-by: Andreas Schneider <asn at samba.org>
---
 source4/selftest/tests.py            |   4 +
 testprogs/blackbox/test_kinit_mit.sh | 310 +++++++++++++++++++++++++++++++++++
 2 files changed, 314 insertions(+)
 create mode 100755 testprogs/blackbox/test_kinit_mit.sh

diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py
index 8312f4886e9..798ec62bd89 100755
--- a/source4/selftest/tests.py
+++ b/source4/selftest/tests.py
@@ -397,6 +397,10 @@ if have_heimdal_support:
     plantestsuite("samba4.blackbox.kinit_trust(fl2003dc:local)", "fl2003dc:local", [os.path.join(bbdir, "test_kinit_trusts_heimdal.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$TRUST_SERVER', '$TRUST_USERNAME', '$TRUST_PASSWORD', '$TRUST_REALM', '$TRUST_DOMAIN', '$PREFIX', "external", "arcfour-hmac-md5"])
     plantestsuite("samba4.blackbox.export.keytab(ad_dc_ntvfs:local)", "ad_dc_ntvfs:local", [os.path.join(bbdir, "test_export_keytab_heimdal.sh"), '$SERVER', '$USERNAME', '$REALM', '$DOMAIN', "$PREFIX", smbclient4])
     plantestsuite("samba4.blackbox.kpasswd(ad_dc_ntvfs:local)", "ad_dc_ntvfs:local", [os.path.join(bbdir, "test_kpasswd_heimdal.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', "$PREFIX/ad_dc_ntvfs"])
+else:
+    plantestsuite("samba4.blackbox.kinit(ad_dc_ntvfs:local)", "ad_dc_ntvfs:local", [os.path.join(bbdir, "test_kinit_mit.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$PREFIX', smbclient4, configuration])
+    plantestsuite("samba4.blackbox.kinit(fl2000dc:local)", "fl2000dc:local", [os.path.join(bbdir, "test_kinit_mit.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$PREFIX', smbclient4, configuration])
+    plantestsuite("samba4.blackbox.kinit(fl2008r2dc:local)", "fl2008r2dc:local", [os.path.join(bbdir, "test_kinit_mit.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$PREFIX', smbclient4, configuration])
 
 plantestsuite("samba4.blackbox.trust_ntlm", "fl2008r2dc:local", [os.path.join(bbdir, "test_trust_ntlm.sh"), '$SERVER_IP', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$TRUST_USERNAME', '$TRUST_PASSWORD', '$TRUST_REALM', '$TRUST_DOMAIN', 'forest', 'auto', 'NT_STATUS_NO_TRUST_LSA_SECRET'])
 plantestsuite("samba4.blackbox.trust_ntlm", "fl2003dc:local", [os.path.join(bbdir, "test_trust_ntlm.sh"), '$SERVER_IP', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$TRUST_USERNAME', '$TRUST_PASSWORD', '$TRUST_REALM', '$TRUST_DOMAIN', 'external', 'auto', 'NT_STATUS_NO_TRUST_LSA_SECRET'])
diff --git a/testprogs/blackbox/test_kinit_mit.sh b/testprogs/blackbox/test_kinit_mit.sh
new file mode 100755
index 00000000000..3e07281b8c7
--- /dev/null
+++ b/testprogs/blackbox/test_kinit_mit.sh
@@ -0,0 +1,310 @@
+#!/bin/sh
+# Blackbox tests for kinit and kerberos integration with smbclient etc
+# Copyright (c) 2015-2016 Andreas Schneider <asn at samba.org>
+
+if [ $# -lt 5 ]; then
+cat <<EOF
+Usage: test_kinit.sh SERVER USERNAME PASSWORD REALM DOMAIN PREFIX SMBCLIENT
+EOF
+exit 1;
+fi
+
+SERVER=$1
+USERNAME=$2
+PASSWORD=$3
+REALM=$4
+DOMAIN=$5
+PREFIX=$6
+smbclient=$7
+shift 7
+failed=0
+
+samba_bindir="$BINDIR"
+samba_srcdir="$SRCDIR/source4"
+samba_kinit=kinit
+samba_kdestroy=kdestroy
+samba_kpasswd=kpasswd
+
+samba_tool="$samba_bindir/samba-tool"
+samba_texpect="$samba_bindir/texpect"
+
+samba_enableaccount="$samba_tool user enable"
+machineaccountccache="$samba_srcdir/scripting/bin/machineaccountccache"
+
+ldbmodify="ldbmodify"
+if [ -x "$samba4bindir/ldbmodify" ]; then
+	ldbmodify="$samba4bindir/ldbmodify"
+fi
+
+ldbsearch="ldbsearch"
+if [ -x "$samba4bindir/ldbsearch" ]; then
+	ldbsearch="$samba4bindir/ldbsearch"
+fi
+
+. `dirname $0`/subunit.sh
+
+test_smbclient() {
+	name="$1"
+	cmd="$2"
+	shift
+	shift
+	echo "test: $name"
+	$VALGRIND $smbclient $CONFIGURATION //$SERVER/tmp -c "$cmd" $@
+	status=$?
+	if [ x$status = x0 ]; then
+		echo "success: $name"
+	else
+		echo "failure: $name"
+	fi
+	return $status
+}
+
+ADMIN_LDBMODIFY_CONFIG="-H ldap://$SERVER -U$USERNAME%$PASSWORD"
+export ADMIN_LDBMODIFY_CONFIG
+
+KRB5CCNAME_PATH="$PREFIX/tmpccache"
+KRB5CCNAME="FILE:$KRB5CCNAME_PATH"
+ADMIN_KRB5CCNAME="FILE:$KRB5CCNAME_PATH"
+export KRB5CCNAME
+rm -rf $KRB5CCNAME_PATH
+
+testit "reset password policies beside of minimum password age of 0 days" $VALGRIND $samba_tool domain passwordsettings $ADMIN_LDBMODIFY_CONFIG set --complexity=default --history-length=default --min-pwd-length=default --min-pwd-age=0 --max-pwd-age=default || failed=`expr $failed + 1`
+
+cat > $PREFIX/tmpkinitscript <<EOF
+expect Password for
+send ${PASSWORD}\n
+EOF
+
+###########################################################
+### Test kinit defaults
+###########################################################
+
+testit "kinit with password" $samba_texpect $PREFIX/tmpkinitscript $samba_kinit $USERNAME@$REALM   || failed=`expr $failed + 1`
+test_smbclient "Test login with user kerberos ccache" 'ls' -k yes || failed=`expr $failed + 1`
+
+testit "kinit renew ticket" $samba_kinit -R   || failed=`expr $failed + 1`
+test_smbclient "Test login with kerberos ccache" 'ls' -k yes || failed=`expr $failed + 1`
+
+$samba_kdestroy
+
+###########################################################
+### Test kinit with enterprice principal
+###########################################################
+
+testit "kinit with password (enterprise style)" $samba_texpect $PREFIX/tmpkinitscript $samba_kinit -E $USERNAME@$REALM   || failed=`expr $failed + 1`
+test_smbclient "Test login with user kerberos ccache" 'ls' -k yes || failed=`expr $failed + 1`
+
+# This does not work with MIT Kerberos 1.14 or older
+testit "kinit renew ticket (enterprise style)" $samba_kinit -R   || failed=`expr $failed + 1`
+test_smbclient "Test login with kerberos ccache" 'ls' -k yes || failed=`expr $failed + 1`
+
+$samba_kdestroy
+
+###########################################################
+### Tests with kinit default again
+###########################################################
+
+testit "kinit with password" $samba_texpect $PREFIX/tmpkinitscript $samba_kinit $USERNAME@$REALM   || failed=`expr $failed + 1`
+testit "check time with kerberos ccache" $VALGRIND $samba_tool time $SERVER $CONFIGURATION -k yes $@ || failed=`expr $failed + 1`
+
+USERPASS="testPass at 12%"
+
+testit "add user with kerberos ccache" $VALGRIND $samba_tool user create nettestuser $USERPASS $CONFIGURATION  -k yes $@ || failed=`expr $failed + 1`
+
+echo "Getting defaultNamingContext"
+BASEDN=`$ldbsearch $options --basedn='' -H ldap://$SERVER -s base DUMMY=x defaultNamingContext | grep defaultNamingContext | awk '{print $2}'`
+
+cat > $PREFIX/tmpldbmodify <<EOF
+dn: cn=nettestuser,cn=users,$BASEDN
+changetype: modify
+add: servicePrincipalName
+servicePrincipalName: host/nettestuser
+replace: userPrincipalName
+userPrincipalName: nettest@$REALM
+EOF
+
+testit "modify servicePrincipalName and userPrincpalName" $VALGRIND $ldbmodify -H ldap://$SERVER $PREFIX/tmpldbmodify -k yes $@ || failed=`expr $failed + 1`
+
+testit "set user password with kerberos ccache" $VALGRIND $samba_tool user setpassword nettestuser --newpassword=$USERPASS $CONFIGURATION  -k yes $@ || failed=`expr $failed + 1`
+
+testit "enable user with kerberos cache" $VALGRIND $samba_enableaccount nettestuser -H ldap://$SERVER -k yes $@ || failed=`expr $failed + 1`
+
+###########################################################
+### Test kinit with user credentials
+###########################################################
+
+KRB5CCNAME_PATH="$PREFIX/tmpuserccache"
+KRB5CCNAME="FILE:$KRB5CCNAME_PATH"
+export KRB5CCNAME
+
+rm -f $KRB5CCNAME_PATH
+
+cat > $PREFIX/tmpkinituserpassscript <<EOF
+expect Password for
+send ${USERPASS}\n
+EOF
+
+testit "kinit with user password" $samba_texpect $PREFIX/tmpkinituserpassscript $samba_kinit nettestuser@$REALM   || failed=`expr $failed + 1`
+test_smbclient "Test login with user kerberos ccache" 'ls' -k yes || failed=`expr $failed + 1`
+
+### Change password
+
+NEWUSERPASS="testPaSS at 34%"
+testit "change user password with 'samba-tool user password' (rpc)" $VALGRIND $samba_tool user password -W$DOMAIN -Unettestuser%$USERPASS $CONFIGURATION -k no --newpassword=$NEWUSERPASS $@ || failed=`expr $failed + 1`
+
+cat > $PREFIX/tmpkinituserpassscript <<EOF
+expect Password for
+send ${NEWUSERPASS}\n
+EOF
+
+testit "kinit with new user password" $samba_texpect $PREFIX/tmpkinituserpassscript $samba_kinit nettestuser@$REALM   || failed=`expr $failed + 1`
+test_smbclient "Test login with user kerberos ccache" 'ls' -k yes || failed=`expr $failed + 1`
+
+$samba_kdestroy
+
+###########################################################
+### Test kinit with user credentials in special formats
+###########################################################
+
+testit "kinit with new (NT-Principal style) using UPN" $samba_texpect $PREFIX/tmpkinituserpassscript $samba_kinit nettest@$REALM   || failed=`expr $failed + 1`
+test_smbclient "Test login with user kerberos ccache from NT UPN" 'ls' -k yes || failed=`expr $failed + 1`
+
+$samba_kdestroy
+
+testit "kinit with new (enterprise style) using UPN" $samba_texpect $PREFIX/tmpkinituserpassscript $samba_kinit -E nettest@$REALM   || failed=`expr $failed + 1`
+test_smbclient "Test login with user kerberos ccache from enterprise UPN" 'ls' -k yes || failed=`expr $failed + 1`
+
+$samba_kdestroy
+
+###########################################################
+### Test kinit with user credentials and changed realm
+###########################################################
+
+cat > $PREFIX/tmpldbmodify <<EOF
+dn: cn=nettestuser,cn=users,$BASEDN
+changetype: modify
+replace: userPrincipalName
+userPrincipalName: nettest@$REALM.org
+EOF
+
+testit "modify userPrincipalName to be a different domain" $VALGRIND $ldbmodify $ADMIN_LDBMODIFY_CONFIG $PREFIX/tmpldbmodify $PREFIX/tmpldbmodify -k yes $@ || failed=`expr $failed + 1`
+
+testit "kinit with new (enterprise style) using UPN" $samba_texpect $PREFIX/tmpkinituserpassscript $samba_kinit -E nettest@$REALM.org   || failed=`expr $failed + 1`
+test_smbclient "Test login with user kerberos ccache from enterprise UPN" 'ls' -k yes || failed=`expr $failed + 1`
+
+$samba_kdestroy
+
+###########################################################
+### Test password change with kpasswd
+###########################################################
+
+testit "kinit with user password" $samba_texpect $PREFIX/tmpkinituserpassscript $samba_kinit nettestuser@$REALM   || failed=`expr $failed + 1`
+test_smbclient "Test login with user kerberos ccache" 'ls' -k yes || failed=`expr $failed + 1`
+
+USERPASS=$NEWUSERPASS
+NEWUSERPASS=testPaSS at 56%
+
+cat > $PREFIX/tmpkpasswdscript <<EOF
+expect Password for
+password ${USERPASS}\n
+expect Enter new password
+send ${NEWUSERPASS}\n
+expect Enter it again
+send ${NEWUSERPASS}\n
+expect Password changed
+EOF
+
+testit "change user password with kpasswd" $samba_texpect $PREFIX/tmpkpasswdscript $samba_kpasswd nettestuser@$REALM || failed=`expr $failed + 1`
+
+$samba_kdestroy
+
+USERPASS=$NEWUSERPASS
+cat > $PREFIX/tmpkinituserpassscript <<EOF
+expect Password for
+send ${USERPASS}\n
+EOF
+
+testit "kinit with user password" $samba_texpect $PREFIX/tmpkinituserpassscript $samba_kinit nettestuser@$REALM   || failed=`expr $failed + 1`
+test_smbclient "Test login with user kerberos ccache" 'ls' -k yes || failed=`expr $failed + 1`
+
+$samba_kdestroy
+
+###########################################################
+### TODO Test set password with kpasswd
+###########################################################
+
+# This is not implemented in kpasswd
+
+###########################################################
+### Test password expiry
+###########################################################
+
+cat > $PREFIX/tmpldbmodify <<EOF
+dn: cn=nettestuser,cn=users,$BASEDN
+changetype: modify
+replace: pwdLastSet
+pwdLastSet: 0
+EOF
+
+USERPASS=$NEWUSERPASS
+NEWUSERPASS=testPaSS at 911%
+
+testit "modify pwdLastSet" $VALGRIND $ldbmodify $ADMIN_LDBMODIFY_CONFIG $PREFIX/tmpldbmodify $PREFIX/tmpldbmodify -k yes $@ || failed=`expr $failed + 1`
+
+cat > $PREFIX/tmpkinituserpassscript <<EOF
+expect Password for
+send ${USERPASS}\n
+expect Password expired.  You must change it now.
+expect Enter new password
+send ${NEWUSERPASS}\n
+expect Enter it again
+send ${NEWUSERPASS}\n
+EOF
+
+testit "kinit (MIT) with user password for expired password" $samba_texpect $PREFIX/tmpkinituserpassscript $samba_kinit nettestuser@$REALM || failed=`expr $failed + 1`
+test_smbclient "Test login with user kerberos ccache" 'ls' -k yes || failed=`expr $failed + 1`
+
+USERPASS=$NEWUSERPASS
+cat > $PREFIX/tmpkinituserpassscript <<EOF
+expect Password for
+send ${USERPASS}\n
+EOF
+
+testit "kinit with user password" $samba_texpect $PREFIX/tmpkinituserpassscript $samba_kinit nettestuser@$REALM   || failed=`expr $failed + 1`
+test_smbclient "Test login with user kerberos ccache" 'ls' -k yes || failed=`expr $failed + 1`
+
+###########################################################
+### Test login with lowercase realm
+###########################################################
+
+KRB5CCNAME_PATH="$PREFIX/tmpccache"
+KRB5CCNAME="FILE:$KRB5CCNAME_PATH"
+export KRB5CCNAME
+
+rm -rf $KRB5CCNAME_PATH
+
+lowerrealm=$(echo $REALM | tr '[A-Z]' '[a-z]')
+test_smbclient "Test login with user kerberos lowercase realm" 'ls' -k yes -Unettestuser@$lowerrealm%$NEWUSERPASS || failed=`expr $failed + 1`
+test_smbclient "Test login with user kerberos lowercase realm 2" 'ls' -k yes -Unettestuser@$REALM%$NEWUSERPASS --realm=$lowerrealm || failed=`expr $failed + 1`
+
+testit "del user with kerberos ccache" $VALGRIND $samba_tool user delete nettestuser $CONFIGURATION -k yes $@ || failed=`expr $failed + 1`
+
+###########################################################
+### Test login with machine account
+###########################################################
+
+rm -f $KRB5CCNAME_PATH
+testit "kinit with machineaccountccache script" $machineaccountccache $CONFIGURATION $KRB5CCNAME || failed=`expr $failed + 1`
+test_smbclient "Test machine account login with kerberos ccache" 'ls' -k yes || failed=`expr $failed + 1`
+
+testit "reset password policies" $VALGRIND $samba_tool domain passwordsettings $ADMIN_LDBMODIFY_CONFIG set --complexity=default --history-length=default --min-pwd-length=default --min-pwd-age=default --max-pwd-age=default || failed=`expr $failed + 1`
+
+### Cleanup
+
+$samba_kdestroy
+
+rm -f $KRB5CCNAME_PATH
+rm -f $PREFIX/tmpkinituserpassscript
+rm -f $PREFIX/tmpkinitscript
+
+exit $failed
-- 
2.12.2


From b35c3184bcfbdc44ba8131f58e4a173b6b85817c Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Mon, 15 Feb 2016 08:22:58 +0100
Subject: [PATCH 24/51] testprogs: Add a kinit trust test for MIT KDC

Signed-off-by: Andreas Schneider <asn at samba.org>
---
 source4/selftest/tests.py                   |   3 +
 testprogs/blackbox/test_kinit_trusts_mit.sh | 139 ++++++++++++++++++++++++++++
 2 files changed, 142 insertions(+)
 create mode 100755 testprogs/blackbox/test_kinit_trusts_mit.sh

diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py
index 798ec62bd89..b94d1edc4ce 100755
--- a/source4/selftest/tests.py
+++ b/source4/selftest/tests.py
@@ -401,11 +401,14 @@ else:
     plantestsuite("samba4.blackbox.kinit(ad_dc_ntvfs:local)", "ad_dc_ntvfs:local", [os.path.join(bbdir, "test_kinit_mit.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$PREFIX', smbclient4, configuration])
     plantestsuite("samba4.blackbox.kinit(fl2000dc:local)", "fl2000dc:local", [os.path.join(bbdir, "test_kinit_mit.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$PREFIX', smbclient4, configuration])
     plantestsuite("samba4.blackbox.kinit(fl2008r2dc:local)", "fl2008r2dc:local", [os.path.join(bbdir, "test_kinit_mit.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$PREFIX', smbclient4, configuration])
+    plantestsuite("samba4.blackbox.kinit_trust(fl2008r2dc:local)", "fl2008r2dc:local", [os.path.join(bbdir, "test_kinit_trusts_mit.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$TRUST_SERVER', '$TRUST_USERNAME', '$TRUST_PASSWORD', '$TRUST_REALM', '$TRUST_DOMAIN', '$PREFIX', "forest"])
+    plantestsuite("samba4.blackbox.kinit_trust(fl2003dc:local)", "fl2003dc:local", [os.path.join(bbdir, "test_kinit_trusts_mit.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$TRUST_SERVER', '$TRUST_USERNAME', '$TRUST_PASSWORD', '$TRUST_REALM', '$TRUST_DOMAIN', '$PREFIX', "external"])
 
 plantestsuite("samba4.blackbox.trust_ntlm", "fl2008r2dc:local", [os.path.join(bbdir, "test_trust_ntlm.sh"), '$SERVER_IP', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$TRUST_USERNAME', '$TRUST_PASSWORD', '$TRUST_REALM', '$TRUST_DOMAIN', 'forest', 'auto', 'NT_STATUS_NO_TRUST_LSA_SECRET'])
 plantestsuite("samba4.blackbox.trust_ntlm", "fl2003dc:local", [os.path.join(bbdir, "test_trust_ntlm.sh"), '$SERVER_IP', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$TRUST_USERNAME', '$TRUST_PASSWORD', '$TRUST_REALM', '$TRUST_DOMAIN', 'external', 'auto', 'NT_STATUS_NO_TRUST_LSA_SECRET'])
 plantestsuite("samba4.blackbox.trust_ntlm", "ad_member:local", [os.path.join(bbdir, "test_trust_ntlm.sh"), '$SERVER_IP', '$USERNAME', '$PASSWORD', '$SERVER', '$SERVER', '$DC_USERNAME', '$DC_PASSWORD', '$REALM', '$DOMAIN', 'member', 'auto', 'NT_STATUS_LOGON_FAILURE'])
 plantestsuite("samba4.blackbox.trust_ntlm", "nt4_member:local", [os.path.join(bbdir, "test_trust_ntlm.sh"), '$SERVER_IP', '$USERNAME', '$PASSWORD', '$SERVER', '$SERVER', '$DC_USERNAME', '$DC_PASSWORD', '$DOMAIN', '$DOMAIN', 'member', 'auto', 'NT_STATUS_LOGON_FAILURE'])
+
 plantestsuite("samba4.blackbox.trust_utils(fl2008r2dc:local)", "fl2008r2dc:local", [os.path.join(bbdir, "test_trust_utils.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$TRUST_SERVER', '$TRUST_USERNAME', '$TRUST_PASSWORD', '$TRUST_REALM', '$TRUST_DOMAIN', '$PREFIX', "forest"])
 plantestsuite("samba4.blackbox.trust_utils(fl2003dc:local)", "fl2003dc:local", [os.path.join(bbdir, "test_trust_utils.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$TRUST_SERVER', '$TRUST_USERNAME', '$TRUST_PASSWORD', '$TRUST_REALM', '$TRUST_DOMAIN', '$PREFIX', "external"])
 plantestsuite("samba4.blackbox.ktpass(ad_dc_ntvfs)", "ad_dc_ntvfs", [os.path.join(bbdir, "test_ktpass.sh"), '$PREFIX/ad_dc_ntvfs'])
diff --git a/testprogs/blackbox/test_kinit_trusts_mit.sh b/testprogs/blackbox/test_kinit_trusts_mit.sh
new file mode 100755
index 00000000000..6696f441363
--- /dev/null
+++ b/testprogs/blackbox/test_kinit_trusts_mit.sh
@@ -0,0 +1,139 @@
+#!/bin/sh
+# Blackbox tests for kinit and trust validation
+# Copyright (c) 2015 Stefan Metzmacher <metze at samba.org>
+# Copyright (c) 2016 Andreas Schneider <asn at samba.org>
+
+if [ $# -lt 5 ]; then
+cat <<EOF
+Usage: test_kinit_trusts.sh SERVER USERNAME PASSWORD REALM DOMAIN TRUST_USERNAME TRUST_PASSWORD TRUST_REALM TRUST_DOMAIN PREFIX TYPE
+EOF
+exit 1;
+fi
+
+SERVER=$1
+USERNAME=$2
+PASSWORD=$3
+REALM=$4
+DOMAIN=$5
+shift 5
+TRUST_SERVER=$1
+TRUST_USERNAME=$2
+TRUST_PASSWORD=$3
+TRUST_REALM=$4
+TRUST_DOMAIN=$5
+shift 5
+PREFIX=$1
+TYPE=$2
+shift 2
+
+failed=0
+
+samba_bindir="$BINDIR"
+samba_srcdir="$SRCDIR/source4"
+samba_kinit=kinit
+samba_kdestroy=kdestroy
+samba_kpasswd=kpasswd
+
+samba_tool="$samba_bindir/samba-tool"
+samba_texpect="$samba_bindir/texpect"
+
+smbclient="$samba_bindir/smbclient"
+wbinfo="$samba_bindir/wbinfo"
+rpcclient="$samba_bindir/rpcclient"
+
+SMBCLIENT_UNC="//$SERVER.$REALM/tmp"
+
+. `dirname $0`/subunit.sh
+
+test_smbclient() {
+	name="$1"
+	cmd="$2"
+	shift
+	shift
+	echo "test: $name"
+	$VALGRIND $smbclient $CONFIGURATION $SMBCLIENT_UNC -c "$cmd" $@
+	status=$?
+	if [ x$status = x0 ]; then
+		echo "success: $name"
+	else
+		echo "failure: $name"
+	fi
+	return $status
+}
+
+KRB5CCNAME_PATH="$PREFIX/test_kinit_trusts_ccache"
+KRB5CCNAME="FILE:$KRB5CCNAME_PATH"
+export KRB5CCNAME
+rm -rf $KRB5CCNAME_PATH
+
+cat > $PREFIX/tmpkinitscript <<EOF
+expect Password for
+send ${TRUST_PASSWORD}\n
+EOF
+
+###########################################################
+### Test incoming trust direction
+###########################################################
+
+testit "kinit with password" $samba_texpect $PREFIX/tmpkinitscript $samba_kinit $TRUST_USERNAME@$TRUST_REALM || failed=`expr $failed + 1`
+test_smbclient "Test login with kerberos ccache" 'ls' -k yes || failed=`expr $failed + 1`
+$samba_kdestroy
+
+smbclient="$samba_bindir/smbclient4"
+
+testit "kinit with password" $samba_texpect $PREFIX/tmpkinitscript $samba_kinit $TRUST_USERNAME@$TRUST_REALM || failed=`expr $failed + 1`
+test_smbclient "Test login with kerberos ccache (smbclient4)" 'ls' -k yes || failed=`expr $failed + 1`
+$samba_kdestroy
+
+smbclient="$samba_bindir/smbclient"
+
+testit "kinit with password (enterprise)" $samba_texpect $PREFIX/tmpkinitscript $samba_kinit -E $TRUST_USERNAME@$TRUST_REALM || failed=`expr $failed + 1`
+test_smbclient "Test login with kerberos ccache" 'ls' -k yes || failed=`expr $failed + 1`
+
+$samba_kdestroy
+
+if test x"${TYPE}" = x"forest" ;then
+    testit "kinit with password (enterprise UPN)" $samba_texpect $PREFIX/tmpkinitscript $samba_kinit -E testdenied_upn@${TRUST_REALM}.upn || failed=`expr $failed + 1`
+    test_smbclient "Test login with user kerberos ccache" 'ls' -k yes || failed=`expr $failed + 1`
+fi
+
+$samba_kdestroy
+
+testit "kinit with password (enterprise)" $samba_texpect $PREFIX/tmpkinitscript $samba_kinit -E $TRUST_USERNAME@$TRUST_REALM || failed=`expr $failed + 1`
+test_smbclient "Test login with kerberos ccache" 'ls' -k yes || failed=`expr $failed + 1`
+
+testit "kinit renew ticket" $samba_kinit -R
+test_smbclient "Test login with kerberos ccache" 'ls' -k yes || failed=`expr $failed + 1`
+
+testit "check time with kerberos ccache" $VALGRIND $samba_tool time $SERVER.$REALM $CONFIGURATION -k yes $@ || failed=`expr $failed + 1`
+
+$samba_kdestroy
+
+lowerrealm=$(echo $TRUST_REALM | tr '[A-Z]' '[a-z]')
+test_smbclient "Test login with user kerberos lowercase realm" 'ls' -k yes -d5 -U$TRUST_USERNAME@$lowerrealm%$TRUST_PASSWORD || failed=`expr $failed + 1`
+test_smbclient "Test login with user kerberos lowercase realm 2" 'ls' -k yes -U$TRUST_USERNAME@$TRUST_REALM%$TRUST_PASSWORD --realm=$lowerrealm || failed=`expr $failed + 1`
+
+###########################################################
+### Test outgoing trust direction
+###########################################################
+
+SMBCLIENT_UNC="//$TRUST_SERVER.$TRUST_REALM/tmp"
+test_smbclient "Test user login with the first outgoing secret" 'ls' -k yes -U$USERNAME@$REALM%$PASSWORD || failed=`expr $failed + 1`
+
+testit_expect_failure "setpassword should not work" $VALGRIND $samba_tool user setpassword "${TRUST_DOMAIN}\$" --random-password || failed=`expr $failed + 1`
+
+testit "wbinfo ping dc" $VALGRIND $wbinfo --ping-dc --domain=$TRUST_DOMAIN || failed=`expr $failed + 1`
+testit "wbinfo change outgoing trust pw" $VALGRIND $wbinfo --change-secret --domain=$TRUST_DOMAIN || failed=`expr $failed + 1`
+testit "wbinfo check outgoing trust pw" $VALGRIND $wbinfo --check-secret --domain=$TRUST_DOMAIN || failed=`expr $failed + 1`
+
+test_smbclient "Test user login with the changed outgoing secret" 'ls' -k yes -U$USERNAME@$REALM%$PASSWORD || failed=`expr $failed + 1`
+
+### Cleanup
+
+$samba_kdestroy
+
+rm -f $KRB5CCNAME_PATH
+rm -f $PREFIX/tmpkinituserpassscript
+rm -f $PREFIX/tmpkinitscript
+
+exit $failed
-- 
2.12.2


From cd0764db4ae041fd2f05021da4a0d1c2389df713 Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Thu, 10 Mar 2016 14:35:23 +0100
Subject: [PATCH 25/51] testprogs: Add test with exported keytab from
 samba-tool

Signed-off-by: Andreas Schneider <asn at samba.org>
---
 source4/selftest/tests.py                    |   1 +
 testprogs/blackbox/test_export_keytab_mit.sh | 127 +++++++++++++++++++++++++++
 2 files changed, 128 insertions(+)
 create mode 100755 testprogs/blackbox/test_export_keytab_mit.sh

diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py
index b94d1edc4ce..b7ac0c5f5f7 100755
--- a/source4/selftest/tests.py
+++ b/source4/selftest/tests.py
@@ -403,6 +403,7 @@ else:
     plantestsuite("samba4.blackbox.kinit(fl2008r2dc:local)", "fl2008r2dc:local", [os.path.join(bbdir, "test_kinit_mit.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$PREFIX', smbclient4, configuration])
     plantestsuite("samba4.blackbox.kinit_trust(fl2008r2dc:local)", "fl2008r2dc:local", [os.path.join(bbdir, "test_kinit_trusts_mit.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$TRUST_SERVER', '$TRUST_USERNAME', '$TRUST_PASSWORD', '$TRUST_REALM', '$TRUST_DOMAIN', '$PREFIX', "forest"])
     plantestsuite("samba4.blackbox.kinit_trust(fl2003dc:local)", "fl2003dc:local", [os.path.join(bbdir, "test_kinit_trusts_mit.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$TRUST_SERVER', '$TRUST_USERNAME', '$TRUST_PASSWORD', '$TRUST_REALM', '$TRUST_DOMAIN', '$PREFIX', "external"])
+    plantestsuite("samba4.blackbox.export.keytab(ad_dc_ntvfs:local)", "ad_dc_ntvfs:local", [os.path.join(bbdir, "test_export_keytab_mit.sh"), '$SERVER', '$USERNAME', '$REALM', '$DOMAIN', "$PREFIX", smbclient4])
 
 plantestsuite("samba4.blackbox.trust_ntlm", "fl2008r2dc:local", [os.path.join(bbdir, "test_trust_ntlm.sh"), '$SERVER_IP', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$TRUST_USERNAME', '$TRUST_PASSWORD', '$TRUST_REALM', '$TRUST_DOMAIN', 'forest', 'auto', 'NT_STATUS_NO_TRUST_LSA_SECRET'])
 plantestsuite("samba4.blackbox.trust_ntlm", "fl2003dc:local", [os.path.join(bbdir, "test_trust_ntlm.sh"), '$SERVER_IP', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$TRUST_USERNAME', '$TRUST_PASSWORD', '$TRUST_REALM', '$TRUST_DOMAIN', 'external', 'auto', 'NT_STATUS_NO_TRUST_LSA_SECRET'])
diff --git a/testprogs/blackbox/test_export_keytab_mit.sh b/testprogs/blackbox/test_export_keytab_mit.sh
new file mode 100755
index 00000000000..b972cd8f1c4
--- /dev/null
+++ b/testprogs/blackbox/test_export_keytab_mit.sh
@@ -0,0 +1,127 @@
+#!/bin/sh
+#
+# Blackbox tests for an exported keytab with kinit
+#
+# Copyright (C) 2006-2007 Jelmer Vernooij <jelmer at samba.org>
+# Copyright (C) 2006-2008 Andrew Bartlett <abartlet at samba.org>
+# Copyright (C) 2016      Andreas Schneider <asn at cryptomilk.org>
+
+if [ $# -lt 5 ]; then
+cat <<EOF
+Usage: test_extract_keytab.sh SERVER USERNAME REALM DOMAIN PREFIX SMBCLIENT
+EOF
+exit 1;
+fi
+
+SERVER=$1
+USERNAME=$2
+REALM=$3
+DOMAIN=$4
+PREFIX=$5
+smbclient=$6
+shift 6
+failed=0
+
+samba_bindir="$BINDIR"
+samba_tool="$samba_bindir/samba-tool"
+samba_newuser="$samba_tool user create"
+samba_texpect="$samba_bindir/texpect"
+samba_ktutil="$BINDIR/samba4ktutil"
+
+samba_kinit=kinit
+samba_kdestroy=kdestroy
+
+SERVER_FQDN="$SERVER.$(echo $REALM | tr '[:upper:]' '[:lower:]')"
+
+source `dirname $0`/subunit.sh
+
+test_smbclient() {
+	name="$1"
+	cmd="$2"
+	shift
+	shift
+	echo "test: $name"
+	$VALGRIND $smbclient //$SERVER/tmp -c "$cmd" $@
+	status=$?
+	if [ x$status = x0 ]; then
+		echo "success: $name"
+	else
+		echo "failure: $name"
+	fi
+	return $status
+}
+
+test_keytab() {
+	testname="$1"
+	keytab="$2"
+	principal="$3"
+	expected_nkeys="$4"
+
+	echo "test: $testname"
+
+	NKEYS=$($VALGRIND $samba_ktutil $keytab | grep -i "$principal" | egrep -c "DES|AES|ArcFour")
+	status=$?
+	if [ x$status != x0 ]; then
+		echo "failure: $testname"
+		return $status
+	fi
+
+	if [ x$NKEYS != x$expected_nkeys ] ; then
+		echo "failure: $testname"
+		return 1
+	fi
+	echo "success: $testname"
+	return 0
+}
+
+TEST_USER=nettestuser
+TEST_PASSWORD=testPaSS at 01%
+
+testit "create local user $TEST_USER" $VALGRIND $samba_newuser $TEST_USER $TEST_PASSWORD $@ || failed=`expr $failed + 1`
+
+testit "dump keytab from domain" $VALGRIND $samba_tool domain exportkeytab $PREFIX/tmpkeytab-all $@ || failed=`expr $failed + 1`
+test_keytab "read keytab from domain" "$PREFIX/tmpkeytab-all" "$SERVER\\\$" 5
+
+testit "dump keytab from domain (2nd time)" $VALGRIND $samba_tool domain exportkeytab $PREFIX/tmpkeytab-all $@ || failed=`expr $failed + 1`
+test_keytab "read keytab from domain (2nd time)" "$PREFIX/tmpkeytab-all" "$SERVER\\\$" 5
+
+testit "dump keytab from domain for cifs service principal" $VALGRIND $samba_tool domain exportkeytab $PREFIX/tmpkeytab-server --principal=cifs/$SERVER_FQDN $@ || failed=`expr $failed + 1`
+test_keytab "read keytab from domain for cifs service principal" "$PREFIX/tmpkeytab-server" "cifs/$SERVER_FQDN" 5
+testit "dump keytab from domain for cifs service principal (2nd time)" $VALGRIND $samba_tool domain exportkeytab $PREFIX/tmpkeytab-server --principal=cifs/$SERVER_FQDN $@ || failed=`expr $failed + 1`
+test_keytab "read keytab from domain for cifs service principal (2nd time)" "$PREFIX/tmpkeytab-server" "cifs/$SERVER_FQDN" 5
+
+testit "dump keytab from domain for user principal" $VALGRIND $samba_tool domain exportkeytab $PREFIX/tmpkeytab-user-princ --principal=$TEST_USER $@ || failed=`expr $failed + 1`
+test_keytab "dump keytab from domain for user principal" "$PREFIX/tmpkeytab-user-princ" "$TEST_USER@$REALM" 5
+testit "dump keytab from domain for user principal (2nd time)" $VALGRIND $samba_tool domain exportkeytab $PREFIX/tmpkeytab-user-princ --principal=$TEST_USER@$REALM $@ || failed=`expr $failed + 1`
+test_keytab "dump keytab from domain for user principal (2nd time)" "$PREFIX/tmpkeytab-user-princ" "$TEST_USER@$REALM" 5
+
+KRB5CCNAME="$PREFIX/tmpuserccache"
+export KRB5CCNAME
+
+testit "kinit with keytab as user" $VALGRIND $samba_kinit -k -t $PREFIX/tmpkeytab-all $TEST_USER@$REALM || failed=`expr $failed + 1`
+test_smbclient "Test login with user kerberos ccache" 'ls' -k yes || failed=`expr $failed + 1`
+$samba_kdestroy
+
+testit "kinit with keytab as user (one princ)" $VALGRIND $samba_kinit -k -t $PREFIX/tmpkeytab-user-princ $TEST_USER@$REALM || failed=`expr $failed + 1`
+test_smbclient "Test login with user kerberos ccache (one princ)" 'ls' -k yes || failed=`expr $failed + 1`
+$samba_kdestroy
+
+KRB5CCNAME="$PREFIX/tmpadminccache"
+export KRB5CCNAME
+
+testit "kinit with keytab as $USERNAME" $VALGRIND $samba_kinit -k -t $PREFIX/tmpkeytab-all $USERNAME@$REALM || failed=`expr $failed + 1`
+
+KRB5CCNAME="$PREFIX/tmpserverccache"
+export KRB5CCNAME
+echo "$samba_kinit -k -t $PREFIX/tmpkeytab-server cifs/$SERVER_FQDN"
+testit "kinit with SPN from keytab" $VALGRIND $samba_kinit -k -t $PREFIX/tmpkeytab-server cifs/$SERVER_FQDN || failed=`expr $failed + 1`
+
+exit 0
+
+# cleanup
+testit "delete user $TEST_USER" $VALGRIND $samba_tool user delete nettestuser -k yes $@ || failed=`expr $failed + 1`
+
+$samba_kdestroy
+rm -f $PREFIX/tmpadminccache $PREFIX/tmpuserccache $PREFIX/tmpkeytab $PREFIX/tmpkeytab-2 $PREFIX/tmpkeytab-server
+
+exit $failed
-- 
2.12.2


From ab2a5c8e79fbf1fe1bb0a40ad6e08dec4397dc19 Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Tue, 25 Apr 2017 08:32:01 +0200
Subject: [PATCH 26/51] waf: Only build KRB5 KDC tests when AD_DC build is
 enabled

Signed-off-by: Andreas Schneider <asn at samba.org>
---
 source4/torture/krb5/wscript_build | 34 +++++++++++++++++-----------------
 1 file changed, 17 insertions(+), 17 deletions(-)

diff --git a/source4/torture/krb5/wscript_build b/source4/torture/krb5/wscript_build
index b9d9eb70d03..49947fe4d19 100644
--- a/source4/torture/krb5/wscript_build
+++ b/source4/torture/krb5/wscript_build
@@ -1,19 +1,19 @@
 #!/usr/bin/env python
 
-if bld.CONFIG_SET('SAMBA4_USES_HEIMDAL'):
-      bld.SAMBA_MODULE('TORTURE_KRB5',
-                       source='kdc-heimdal.c kdc-canon-heimdal.c',
-                       autoproto='proto.h',
-                       subsystem='smbtorture',
-                       init_function='torture_krb5_init',
-                       deps='authkrb5 popt POPT_CREDENTIALS torture KERBEROS_UTIL',
-                       internal_module=True
-                 )
-else:
-      bld.SAMBA_MODULE('TORTURE_KRB5',
-                       source='kdc-mit.c',
-                       autoproto='proto.h',
-                       subsystem='smbtorture',
-                       init_function='torture_krb5_init',
-                       deps='authkrb5 popt POPT_CREDENTIALS torture KERBEROS_UTIL',
-                       internal_module=True)
+if bld.CONFIG_SET('AD_DC_BUILD_IS_ENABLED'):
+    if bld.CONFIG_SET('SAMBA4_USES_HEIMDAL'):
+        bld.SAMBA_MODULE('TORTURE_KRB5',
+                         source='kdc-heimdal.c kdc-canon-heimdal.c',
+                         autoproto='proto.h',
+                         subsystem='smbtorture',
+                         init_function='torture_krb5_init',
+                         deps='authkrb5 popt POPT_CREDENTIALS torture KERBEROS_UTIL',
+                         internal_module=True)
+    else:
+            bld.SAMBA_MODULE('TORTURE_KRB5',
+                             source='kdc-mit.c',
+                             autoproto='proto.h',
+                             subsystem='smbtorture',
+                             init_function='torture_krb5_init',
+                             deps='authkrb5 popt POPT_CREDENTIALS torture KERBEROS_UTIL',
+                             internal_module=True)
-- 
2.12.2


From 13d6dbbea1a444698e2a6b49ec5a790d64316c81 Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Fri, 13 May 2016 09:36:34 +0200
Subject: [PATCH 27/51] s4-torture: Add KDC test harness and first test

Signed-off-by: Andreas Schneider <asn at samba.org>
---
 source4/torture/krb5/kdc-mit.c | 347 ++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 343 insertions(+), 4 deletions(-)

diff --git a/source4/torture/krb5/kdc-mit.c b/source4/torture/krb5/kdc-mit.c
index 882627eb6f3..dfb32019ceb 100644
--- a/source4/torture/krb5/kdc-mit.c
+++ b/source4/torture/krb5/kdc-mit.c
@@ -1,4 +1,3 @@
-
 /*
    Unix SMB/CIFS implementation.
 
@@ -31,13 +30,339 @@
 #include "source4/auth/kerberos/kerberos_util.h"
 #include "lib/util/util_net.h"
 
-static bool test_skip(struct torture_context *tctx)
+#define krb5_is_app_tag(dat,tag)                          \
+	((dat != NULL) && (dat)->length &&                \
+	 ((((dat)->data[0] & ~0x20) == ((tag) | 0x40))))
+
+#define krb5_is_as_req(dat)                   krb5_is_app_tag(dat, 10)
+#define krb5_is_as_rep(dat)                   krb5_is_app_tag(dat, 11)
+#define krb5_is_krb_error(dat)                krb5_is_app_tag(dat, 30)
+
+enum torture_krb5_test {
+	TORTURE_KRB5_TEST_PLAIN,
+	TORTURE_KRB5_TEST_PAC_REQUEST,
+	TORTURE_KRB5_TEST_BREAK_PW,
+	TORTURE_KRB5_TEST_CLOCK_SKEW,
+};
+
+struct torture_krb5_context {
+	struct torture_context *tctx;
+	krb5_context krb5_context;
+	enum torture_krb5_test test;
+	int recv_packet_count;
+	krb5_kdc_req *as_req;
+	krb5_kdc_rep *as_rep;
+};
+
+krb5_error_code decode_krb5_error(const krb5_data *output, krb5_error **rep);
+
+krb5_error_code decode_krb5_as_req(const krb5_data *output, krb5_kdc_req **req);
+krb5_error_code decode_krb5_as_rep(const krb5_data *output, krb5_kdc_rep **rep);
+
+void krb5_free_kdc_req(krb5_context ctx, krb5_kdc_req *req);
+void krb5_free_kdc_rep(krb5_context ctx, krb5_kdc_rep *rep);
+
+static bool torture_check_krb5_as_req(struct torture_krb5_context *test_context,
+				      krb5_context context,
+				      const krb5_data *message)
+{
+	krb5_error_code code;
+	int nktypes;
+
+	code = decode_krb5_as_req(message, &test_context->as_req);
+	torture_assert_int_equal(test_context->tctx,
+				 code, 0,
+				 "decode_as_req failed");
+	torture_assert_int_equal(test_context->tctx,
+				 test_context->as_req->msg_type,
+				 KRB5_AS_REQ,
+				 "Not a AS REQ");
+
+	nktypes = test_context->as_req->nktypes;
+	torture_assert_int_not_equal(test_context->tctx,
+				     nktypes, 0,
+				     "No keytypes");
+
+	return true;
+}
+
+static krb5_error_code torture_krb5_pre_send_test(krb5_context context,
+						  void *data,
+						  const krb5_data *realm,
+						  const krb5_data *message,
+						  krb5_data **new_message_out,
+						  krb5_data **new_reply_out)
+{
+	bool ok;
+	struct torture_krb5_context *test_context =
+		(struct torture_krb5_context *)data;
+
+	switch (test_context->test)
+	{
+	case TORTURE_KRB5_TEST_PLAIN:
+	case TORTURE_KRB5_TEST_PAC_REQUEST:
+	case TORTURE_KRB5_TEST_BREAK_PW:
+	case TORTURE_KRB5_TEST_CLOCK_SKEW:
+		ok = torture_check_krb5_as_req(test_context,
+					       context,
+					       message);
+		if (!ok) {
+			return KRB5KDC_ERR_BADOPTION;
+		}
+		break;
+	}
+
+	return 0;
+}
+
+/*
+ * We need these function to validate packets because our torture macros
+ * do a 'return false' on error.
+ */
+static bool torture_check_krb5_error(struct torture_krb5_context *test_context,
+				     krb5_context context,
+				     const krb5_data *reply,
+				     krb5_error_code error_code)
+
 {
-	torture_skip(tctx, "Skip kdc tests with MIT Kerberos");
+	krb5_error *krb_error;
+	krb5_error_code code;
+
+	code = decode_krb5_error(reply, &krb_error);
+	torture_assert_int_equal(test_context->tctx,
+				 code,
+				 0,
+				 "decode_krb5_error failed");
+
+	torture_assert_int_equal(test_context->tctx,
+				 krb_error->error,
+				 error_code - KRB5KDC_ERR_NONE,
+				 "Got wrong error code");
+
+	krb5_free_error(context, krb_error);
 
 	return true;
 }
 
+static bool torture_check_krb5_as_rep(struct torture_krb5_context *test_context,
+				      krb5_context context,
+				      const krb5_data *reply)
+{
+	krb5_error_code code;
+	bool ok;
+
+	code = decode_krb5_as_rep(reply, &test_context->as_rep);
+	torture_assert_int_equal(test_context->tctx,
+				 code,
+				 0,
+				 "decode_krb5_as_rep failed");
+
+	torture_assert(test_context->tctx,
+		       test_context->as_rep->ticket->enc_part.kvno,
+		       "No KVNO set");
+
+	ok = torture_setting_bool(test_context->tctx,
+				  "expect_cached_at_rodc",
+				  false);
+	if (ok) {
+		torture_assert_int_not_equal(test_context->tctx,
+					     test_context->as_rep->ticket->enc_part.kvno & 0xFFFF0000,
+					     0,
+					     "Did not get a RODC number in the KVNO");
+	} else {
+		torture_assert_int_equal(test_context->tctx,
+					 test_context->as_rep->ticket->enc_part.kvno & 0xFFFF0000,
+					 0,
+					 "Unexpecedly got a RODC number in the KVNO");
+	}
+
+	return true;
+}
+
+static krb5_error_code torture_krb5_post_recv_test(krb5_context context,
+						   void *data,
+						   krb5_error_code kdc_code,
+						   const krb5_data *realm,
+						   const krb5_data *message,
+						   const krb5_data *reply,
+						   krb5_data **new_reply_out)
+{
+	struct torture_krb5_context *test_context =
+		(struct torture_krb5_context *)data;
+	krb5_error_code code;
+	bool ok = true;
+
+	torture_comment(test_context->tctx,
+			"PACKET COUNT = %d\n",
+			test_context->recv_packet_count);
+
+	torture_comment(test_context->tctx,
+			"KRB5_AS_REP = %d\n",
+			krb5_is_as_req(reply));
+
+	torture_comment(test_context->tctx,
+			"KRB5_ERROR = %d\n",
+			krb5_is_krb_error(reply));
+
+	torture_comment(test_context->tctx,
+			"KDC ERROR CODE = %d\n",
+			kdc_code);
+
+	switch (test_context->test)
+	{
+	case TORTURE_KRB5_TEST_PLAIN:
+		if (test_context->recv_packet_count == 0) {
+			ok = torture_check_krb5_error(test_context,
+						      context,
+						      reply,
+						      KRB5KDC_ERR_PREAUTH_REQUIRED);
+			torture_assert_goto(test_context->tctx,
+					    ok,
+					    ok,
+					    out,
+					    "torture_check_krb5_error failed");
+		} else {
+			ok = torture_check_krb5_as_rep(test_context,
+						       context,
+						       reply);
+			torture_assert_goto(test_context->tctx,
+					    ok,
+					    ok,
+					    out,
+					    "torture_check_krb5_as_rep failed");
+		}
+
+		torture_assert_goto(test_context->tctx,
+				    test_context->recv_packet_count < 2,
+				    ok,
+				    out,
+				    "Too many packets");
+
+		break;
+	case TORTURE_KRB5_TEST_PAC_REQUEST:
+	case TORTURE_KRB5_TEST_BREAK_PW:
+	case TORTURE_KRB5_TEST_CLOCK_SKEW:
+		break;
+	}
+
+	code = kdc_code;
+out:
+	if (!ok) {
+		code = EINVAL;
+	}
+
+	/* Cleanup */
+	krb5_free_kdc_req(test_context->krb5_context, test_context->as_req);
+	krb5_free_kdc_rep(test_context->krb5_context, test_context->as_rep);
+
+	test_context->recv_packet_count++;
+
+	return code;
+}
+
+static bool torture_krb5_init_context(struct torture_context *tctx,
+				      enum torture_krb5_test test,
+				      struct smb_krb5_context **smb_krb5_context)
+{
+	krb5_error_code code;
+
+	struct torture_krb5_context *test_context = talloc_zero(tctx,
+								struct torture_krb5_context);
+	torture_assert(tctx, test_context != NULL, "Failed to allocate");
+
+	test_context->test = test;
+	test_context->tctx = tctx;
+
+	code = smb_krb5_init_context(tctx, tctx->lp_ctx, smb_krb5_context);
+	torture_assert_int_equal(tctx, code, 0, "smb_krb5_init_context failed");
+
+	test_context->krb5_context = (*smb_krb5_context)->krb5_context;
+
+	krb5_set_kdc_send_hook((*smb_krb5_context)->krb5_context,
+			       torture_krb5_pre_send_test,
+			       test_context);
+
+	krb5_set_kdc_recv_hook((*smb_krb5_context)->krb5_context,
+			       torture_krb5_post_recv_test,
+			       test_context);
+
+	return true;
+}
+static bool torture_krb5_as_req_creds(struct torture_context *tctx,
+				      struct cli_credentials *credentials,
+				      enum torture_krb5_test test)
+{
+	krb5_get_init_creds_opt *krb_options = NULL;
+	struct smb_krb5_context *smb_krb5_context;
+	enum credentials_obtained obtained;
+	const char *error_string;
+	const char *password;
+	krb5_principal principal;
+	krb5_error_code code;
+	krb5_creds my_creds;
+	bool ok;
+
+	ok = torture_krb5_init_context(tctx, test, &smb_krb5_context);
+	torture_assert(tctx, ok, "torture_krb5_init_context failed");
+
+	code = principal_from_credentials(tctx,
+					  credentials,
+					  smb_krb5_context,
+					  &principal,
+					  &obtained,
+					  &error_string);
+	torture_assert_int_equal(tctx, code, 0, error_string);
+
+	switch (test)
+	{
+	case TORTURE_KRB5_TEST_PLAIN:
+	case TORTURE_KRB5_TEST_PAC_REQUEST:
+	case TORTURE_KRB5_TEST_BREAK_PW:
+	case TORTURE_KRB5_TEST_CLOCK_SKEW:
+		break;
+	}
+
+	password = cli_credentials_get_password(credentials);
+
+	code = krb5_get_init_creds_password(smb_krb5_context->krb5_context,
+					    &my_creds,
+					    principal,
+					    password,
+					    NULL,
+					    NULL,
+					    0,
+					    NULL,
+					    krb_options);
+	krb5_get_init_creds_opt_free(smb_krb5_context->krb5_context,
+				     krb_options);
+
+	switch (test)
+	{
+	case TORTURE_KRB5_TEST_PLAIN:
+	case TORTURE_KRB5_TEST_PAC_REQUEST:
+		torture_assert_int_equal(tctx,
+					 code,
+					 0,
+					 "krb5_get_init_creds_password failed");
+		break;
+	case TORTURE_KRB5_TEST_BREAK_PW:
+	case TORTURE_KRB5_TEST_CLOCK_SKEW:
+		break;
+	}
+
+	krb5_free_cred_contents(smb_krb5_context->krb5_context,
+				&my_creds);
+
+	return true;
+}
+
+static bool torture_krb5_as_req_cmdline(struct torture_context *tctx)
+{
+	return torture_krb5_as_req_creds(tctx,
+					 cmdline_credentials,
+					 TORTURE_KRB5_TEST_PLAIN);
+}
+
 NTSTATUS torture_krb5_init(TALLOC_CTX *ctx)
 {
 	struct torture_suite *suite =
@@ -46,8 +371,22 @@ NTSTATUS torture_krb5_init(TALLOC_CTX *ctx)
 	suite->description = talloc_strdup(suite, "Kerberos tests");
 	kdc_suite->description = talloc_strdup(kdc_suite, "Kerberos KDC tests");
 
-	torture_suite_add_simple_test(kdc_suite, "skip", test_skip);
+	torture_suite_add_simple_test(kdc_suite,
+				      "as-req-cmdline",
+				      torture_krb5_as_req_cmdline);
+
+#if 0
+	torture_suite_add_simple_test(kdc_suite, "as-req-pac-request",
+				      torture_krb5_as_req_pac_request);
+
+	torture_suite_add_simple_test(kdc_suite, "as-req-break-pw",
+				      torture_krb5_as_req_break_pw);
+
+	torture_suite_add_simple_test(kdc_suite, "as-req-clock-skew",
+				      torture_krb5_as_req_clock_skew);
 
+	torture_suite_add_suite(kdc_suite, torture_krb5_canon(kdc_suite));
+#endif
 	torture_suite_add_suite(suite, kdc_suite);
 
 	torture_register_suite(suite);
-- 
2.12.2


From c17039b1c81e5a9fc99342e41686a160773760b7 Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Mon, 4 Jul 2016 11:35:19 +0200
Subject: [PATCH 28/51] s4-torture: Add TORTURE_KRB5_TEST_PAC_REQUEST test

Signed-off-by: Andreas Schneider <asn at samba.org>
---
 source4/torture/krb5/kdc-mit.c | 84 +++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 83 insertions(+), 1 deletion(-)

diff --git a/source4/torture/krb5/kdc-mit.c b/source4/torture/krb5/kdc-mit.c
index dfb32019ceb..073d5c69380 100644
--- a/source4/torture/krb5/kdc-mit.c
+++ b/source4/torture/krb5/kdc-mit.c
@@ -240,6 +240,53 @@ static krb5_error_code torture_krb5_post_recv_test(krb5_context context,
 
 		break;
 	case TORTURE_KRB5_TEST_PAC_REQUEST:
+		if (test_context->recv_packet_count == 0) {
+			ok = torture_check_krb5_error(test_context,
+						      context,
+						      reply,
+						      KRB5KRB_ERR_RESPONSE_TOO_BIG);
+			torture_assert_goto(test_context->tctx,
+					    ok,
+					    ok,
+					    out,
+					    "torture_check_krb5_error failed");
+		} else if (test_context->recv_packet_count == 1) {
+			ok = torture_check_krb5_error(test_context,
+						      context,
+						      reply,
+						      KRB5KDC_ERR_PREAUTH_REQUIRED);
+			torture_assert_goto(test_context->tctx,
+					    ok,
+					    ok,
+					    out,
+					    "torture_check_krb5_error failed");
+		} else if (krb5_is_krb_error(reply)) {
+			ok = torture_check_krb5_error(test_context,
+						      context,
+						      reply,
+						      KRB5KRB_ERR_RESPONSE_TOO_BIG);
+			torture_assert_goto(test_context->tctx,
+					    ok,
+					    ok,
+					    out,
+					    "torture_check_krb5_error failed");
+		} else {
+			ok = torture_check_krb5_as_rep(test_context,
+						       context,
+						       reply);
+			torture_assert_goto(test_context->tctx,
+					    ok,
+					    ok,
+					    out,
+					    "torture_check_krb5_as_rep failed");
+		}
+
+		torture_assert_goto(test_context->tctx,
+				    test_context->recv_packet_count < 3,
+				    ok,
+				    out,
+				    "Too many packets");
+		break;
 	case TORTURE_KRB5_TEST_BREAK_PW:
 	case TORTURE_KRB5_TEST_CLOCK_SKEW:
 		break;
@@ -316,7 +363,23 @@ static bool torture_krb5_as_req_creds(struct torture_context *tctx,
 	switch (test)
 	{
 	case TORTURE_KRB5_TEST_PLAIN:
+		break;
 	case TORTURE_KRB5_TEST_PAC_REQUEST:
+#ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_PAC_REQUEST
+		code = krb5_get_init_creds_opt_alloc(smb_krb5_context->krb5_context,
+						     &krb_options);
+		torture_assert_int_equal(tctx,
+					 code, 0,
+					 "krb5_get_init_creds_opt_alloc failed");
+
+		code = krb5_get_init_creds_opt_set_pac_request(smb_krb5_context->krb5_context,
+							       krb_options,
+							       1);
+		torture_assert_int_equal(tctx,
+					 code, 0,
+					 "krb5_get_init_creds_opt_set_pac_request failed");
+#endif
+		break;
 	case TORTURE_KRB5_TEST_BREAK_PW:
 	case TORTURE_KRB5_TEST_CLOCK_SKEW:
 		break;
@@ -363,6 +426,22 @@ static bool torture_krb5_as_req_cmdline(struct torture_context *tctx)
 					 TORTURE_KRB5_TEST_PLAIN);
 }
 
+#ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_PAC_REQUEST
+static bool torture_krb5_as_req_pac_request(struct torture_context *tctx)
+{
+	bool ok;
+
+	ok = torture_setting_bool(tctx, "expect_rodc", false);
+	if (ok) {
+		torture_skip(tctx,
+			     "This test needs further investigation in the "
+			     "RODC case against a Windows DC, in particular "
+			     "with non-cached users");
+	}
+	return torture_krb5_as_req_creds(tctx, cmdline_credentials, TORTURE_KRB5_TEST_PAC_REQUEST);
+}
+#endif /* HAVE_KRB5_GET_INIT_CREDS_OPT_SET_PAC_REQUEST */
+
 NTSTATUS torture_krb5_init(TALLOC_CTX *ctx)
 {
 	struct torture_suite *suite =
@@ -375,10 +454,13 @@ NTSTATUS torture_krb5_init(TALLOC_CTX *ctx)
 				      "as-req-cmdline",
 				      torture_krb5_as_req_cmdline);
 
-#if 0
+#ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_PAC_REQUEST
+	/* Only available with MIT Kerveros 1.15 and newer */
 	torture_suite_add_simple_test(kdc_suite, "as-req-pac-request",
 				      torture_krb5_as_req_pac_request);
+#endif
 
+#if 0
 	torture_suite_add_simple_test(kdc_suite, "as-req-break-pw",
 				      torture_krb5_as_req_break_pw);
 
-- 
2.12.2


From 79d9daaadcf7e3994197e9cd3a1ade66541dc6d4 Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Mon, 4 Jul 2016 16:37:08 +0200
Subject: [PATCH 29/51] s4-torture: Add TORTURE_KRB5_TEST_BREAK_PW test

Signed-off-by: Andreas Schneider <asn at samba.org>
---
 source4/torture/krb5/kdc-mit.c | 100 +++++++++++++++++++++++++++++++++++++----
 1 file changed, 92 insertions(+), 8 deletions(-)

diff --git a/source4/torture/krb5/kdc-mit.c b/source4/torture/krb5/kdc-mit.c
index 073d5c69380..1e12a17b3cf 100644
--- a/source4/torture/krb5/kdc-mit.c
+++ b/source4/torture/krb5/kdc-mit.c
@@ -59,8 +59,11 @@ krb5_error_code decode_krb5_error(const krb5_data *output, krb5_error **rep);
 krb5_error_code decode_krb5_as_req(const krb5_data *output, krb5_kdc_req **req);
 krb5_error_code decode_krb5_as_rep(const krb5_data *output, krb5_kdc_rep **rep);
 
+krb5_error_code decode_krb5_padata_sequence(const krb5_data *output, krb5_pa_data ***rep);
+
 void krb5_free_kdc_req(krb5_context ctx, krb5_kdc_req *req);
 void krb5_free_kdc_rep(krb5_context ctx, krb5_kdc_rep *rep);
+void krb5_free_pa_data(krb5_context ctx, krb5_pa_data **data);
 
 static bool torture_check_krb5_as_req(struct torture_krb5_context *test_context,
 				      krb5_context context,
@@ -122,7 +125,8 @@ static krb5_error_code torture_krb5_pre_send_test(krb5_context context,
 static bool torture_check_krb5_error(struct torture_krb5_context *test_context,
 				     krb5_context context,
 				     const krb5_data *reply,
-				     krb5_error_code error_code)
+				     krb5_error_code error_code,
+				     bool check_pa_data)
 
 {
 	krb5_error *krb_error;
@@ -139,6 +143,34 @@ static bool torture_check_krb5_error(struct torture_krb5_context *test_context,
 				 error_code - KRB5KDC_ERR_NONE,
 				 "Got wrong error code");
 
+	if (check_pa_data) {
+		krb5_pa_data **d, **pa_data = NULL;
+		bool timestamp_found = false;
+
+		torture_assert_int_not_equal(test_context->tctx,
+					     krb_error->e_data.length, 0,
+					     "No e-data returned");
+
+		code = decode_krb5_padata_sequence(&krb_error->e_data,
+						   &pa_data);
+		torture_assert_int_equal(test_context->tctx,
+					 code,
+					 0,
+					 "decode_krb5_padata_sequence failed");
+
+		for (d = pa_data; d != NULL; d++) {
+			if ((*d)->pa_type == KRB5_PADATA_ENC_TIMESTAMP) {
+				timestamp_found = true;
+				break;
+			}
+		}
+		torture_assert(test_context->tctx,
+			       timestamp_found,
+			       "Encrypted timestamp not found");
+
+		krb5_free_pa_data(context, pa_data);
+	}
+
 	krb5_free_error(context, krb_error);
 
 	return true;
@@ -215,7 +247,8 @@ static krb5_error_code torture_krb5_post_recv_test(krb5_context context,
 			ok = torture_check_krb5_error(test_context,
 						      context,
 						      reply,
-						      KRB5KDC_ERR_PREAUTH_REQUIRED);
+						      KRB5KDC_ERR_PREAUTH_REQUIRED,
+						      false);
 			torture_assert_goto(test_context->tctx,
 					    ok,
 					    ok,
@@ -244,7 +277,8 @@ static krb5_error_code torture_krb5_post_recv_test(krb5_context context,
 			ok = torture_check_krb5_error(test_context,
 						      context,
 						      reply,
-						      KRB5KRB_ERR_RESPONSE_TOO_BIG);
+						      KRB5KRB_ERR_RESPONSE_TOO_BIG,
+						      false);
 			torture_assert_goto(test_context->tctx,
 					    ok,
 					    ok,
@@ -254,7 +288,8 @@ static krb5_error_code torture_krb5_post_recv_test(krb5_context context,
 			ok = torture_check_krb5_error(test_context,
 						      context,
 						      reply,
-						      KRB5KDC_ERR_PREAUTH_REQUIRED);
+						      KRB5KDC_ERR_PREAUTH_REQUIRED,
+						      false);
 			torture_assert_goto(test_context->tctx,
 					    ok,
 					    ok,
@@ -264,7 +299,8 @@ static krb5_error_code torture_krb5_post_recv_test(krb5_context context,
 			ok = torture_check_krb5_error(test_context,
 						      context,
 						      reply,
-						      KRB5KRB_ERR_RESPONSE_TOO_BIG);
+						      KRB5KRB_ERR_RESPONSE_TOO_BIG,
+						      false);
 			torture_assert_goto(test_context->tctx,
 					    ok,
 					    ok,
@@ -288,6 +324,39 @@ static krb5_error_code torture_krb5_post_recv_test(krb5_context context,
 				    "Too many packets");
 		break;
 	case TORTURE_KRB5_TEST_BREAK_PW:
+		if (test_context->recv_packet_count == 0) {
+			ok = torture_check_krb5_error(test_context,
+						      context,
+						      reply,
+						      KRB5KDC_ERR_PREAUTH_REQUIRED,
+						      false);
+			torture_assert_goto(test_context->tctx,
+					    ok,
+					    ok,
+					    out,
+					    "torture_check_krb5_error failed");
+			if (!ok) {
+				goto out;
+			}
+		} else if (test_context->recv_packet_count == 1) {
+			ok = torture_check_krb5_error(test_context,
+						      context,
+						      reply,
+						      KRB5KDC_ERR_PREAUTH_FAILED,
+						      true);
+			torture_assert_goto(test_context->tctx,
+					    ok,
+					    ok,
+					    out,
+					    "torture_check_krb5_error failed");
+		}
+
+		torture_assert_goto(test_context->tctx,
+				    test_context->recv_packet_count < 2,
+				    ok,
+				    out,
+				    "Too many packets");
+		break;
 	case TORTURE_KRB5_TEST_CLOCK_SKEW:
 		break;
 	}
@@ -360,6 +429,8 @@ static bool torture_krb5_as_req_creds(struct torture_context *tctx,
 					  &error_string);
 	torture_assert_int_equal(tctx, code, 0, error_string);
 
+	password = cli_credentials_get_password(credentials);
+
 	switch (test)
 	{
 	case TORTURE_KRB5_TEST_PLAIN:
@@ -381,12 +452,12 @@ static bool torture_krb5_as_req_creds(struct torture_context *tctx,
 #endif
 		break;
 	case TORTURE_KRB5_TEST_BREAK_PW:
+		password = "NOT the password";
+		break;
 	case TORTURE_KRB5_TEST_CLOCK_SKEW:
 		break;
 	}
 
-	password = cli_credentials_get_password(credentials);
-
 	code = krb5_get_init_creds_password(smb_krb5_context->krb5_context,
 					    &my_creds,
 					    principal,
@@ -409,6 +480,12 @@ static bool torture_krb5_as_req_creds(struct torture_context *tctx,
 					 "krb5_get_init_creds_password failed");
 		break;
 	case TORTURE_KRB5_TEST_BREAK_PW:
+		torture_assert_int_equal(tctx,
+					 code,
+					 KRB5KDC_ERR_PREAUTH_FAILED,
+					 "krb5_get_init_creds_password should "
+					 "have failed");
+		return true;
 	case TORTURE_KRB5_TEST_CLOCK_SKEW:
 		break;
 	}
@@ -442,6 +519,13 @@ static bool torture_krb5_as_req_pac_request(struct torture_context *tctx)
 }
 #endif /* HAVE_KRB5_GET_INIT_CREDS_OPT_SET_PAC_REQUEST */
 
+static bool torture_krb5_as_req_break_pw(struct torture_context *tctx)
+{
+	return torture_krb5_as_req_creds(tctx,
+					 cmdline_credentials,
+					 TORTURE_KRB5_TEST_BREAK_PW);
+}
+
 NTSTATUS torture_krb5_init(TALLOC_CTX *ctx)
 {
 	struct torture_suite *suite =
@@ -460,10 +544,10 @@ NTSTATUS torture_krb5_init(TALLOC_CTX *ctx)
 				      torture_krb5_as_req_pac_request);
 #endif
 
-#if 0
 	torture_suite_add_simple_test(kdc_suite, "as-req-break-pw",
 				      torture_krb5_as_req_break_pw);
 
+#if 0
 	torture_suite_add_simple_test(kdc_suite, "as-req-clock-skew",
 				      torture_krb5_as_req_clock_skew);
 
-- 
2.12.2


From e3f67a5efef22e2bf88613fefd0ec557d881370b Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Tue, 5 Jul 2016 16:16:17 +0200
Subject: [PATCH 30/51] s4-torture: Add TORTURE_KRB5_TEST_CLOCK_SKEW test

Signed-off-by: Andreas Schneider <asn at samba.org>
---
 selftest/target/Samba.pm       |  3 ++
 source4/torture/krb5/kdc-mit.c | 62 ++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 63 insertions(+), 2 deletions(-)

diff --git a/selftest/target/Samba.pm b/selftest/target/Samba.pm
index 8b2e4a664b3..1600ed8066a 100644
--- a/selftest/target/Samba.pm
+++ b/selftest/target/Samba.pm
@@ -205,6 +205,9 @@ sub mk_krb5_conf($$)
  # This is especially required by samba3.raw.session krb5 and
  # reauth tests
  clockskew = 5
+ # We are running on the same machine, do not correct
+ # system clock differences
+ kdc_timesync = 0
 
 ";
 
diff --git a/source4/torture/krb5/kdc-mit.c b/source4/torture/krb5/kdc-mit.c
index 1e12a17b3cf..8037ba3c9fa 100644
--- a/source4/torture/krb5/kdc-mit.c
+++ b/source4/torture/krb5/kdc-mit.c
@@ -21,6 +21,7 @@
 
 #include "includes.h"
 #include "system/kerberos.h"
+#include "system/time.h"
 #include "torture/smbtorture.h"
 #include "torture/winbind/proto.h"
 #include "torture/krb5/proto.h"
@@ -358,6 +359,44 @@ static krb5_error_code torture_krb5_post_recv_test(krb5_context context,
 				    "Too many packets");
 		break;
 	case TORTURE_KRB5_TEST_CLOCK_SKEW:
+		if (test_context->recv_packet_count == 0) {
+			ok = torture_check_krb5_error(test_context,
+						      context,
+						      reply,
+						      KRB5KDC_ERR_PREAUTH_REQUIRED,
+						      false);
+			torture_assert_goto(test_context->tctx,
+					    ok,
+					    ok,
+					    out,
+					    "torture_check_krb5_error failed");
+			if (!ok) {
+				goto out;
+			}
+		} else if (test_context->recv_packet_count == 1) {
+			/*
+			 * This only works if kdc_timesync 0 is set in krb5.conf
+			 *
+			 * See commit 5f39a4438eafd693a3eb8366bbc3901efe62e538
+			 * in the MIT Kerberos source tree.
+			 */
+			ok = torture_check_krb5_error(test_context,
+						      context,
+						      reply,
+						      KRB5KRB_AP_ERR_SKEW,
+						      false);
+			torture_assert_goto(test_context->tctx,
+					    ok,
+					    ok,
+					    out,
+					    "torture_check_krb5_error failed");
+		}
+
+		torture_assert_goto(test_context->tctx,
+				    test_context->recv_packet_count < 2,
+				    ok,
+				    out,
+				    "Too many packets");
 		break;
 	}
 
@@ -455,6 +494,12 @@ static bool torture_krb5_as_req_creds(struct torture_context *tctx,
 		password = "NOT the password";
 		break;
 	case TORTURE_KRB5_TEST_CLOCK_SKEW:
+		code = krb5_set_real_time(smb_krb5_context->krb5_context,
+					  time(NULL) + 3600,
+					  0);
+		torture_assert_int_equal(tctx,
+					 code, 0,
+					 "krb5_set_real_time failed");
 		break;
 	}
 
@@ -487,7 +532,12 @@ static bool torture_krb5_as_req_creds(struct torture_context *tctx,
 					 "have failed");
 		return true;
 	case TORTURE_KRB5_TEST_CLOCK_SKEW:
-		break;
+		torture_assert_int_equal(tctx,
+					 code,
+					 KRB5KRB_AP_ERR_SKEW,
+					 "krb5_get_init_creds_password should "
+					 "have failed");
+		return true;
 	}
 
 	krb5_free_cred_contents(smb_krb5_context->krb5_context,
@@ -526,6 +576,13 @@ static bool torture_krb5_as_req_break_pw(struct torture_context *tctx)
 					 TORTURE_KRB5_TEST_BREAK_PW);
 }
 
+static bool torture_krb5_as_req_clock_skew(struct torture_context *tctx)
+{
+	return torture_krb5_as_req_creds(tctx,
+					 cmdline_credentials,
+					 TORTURE_KRB5_TEST_CLOCK_SKEW);
+}
+
 NTSTATUS torture_krb5_init(TALLOC_CTX *ctx)
 {
 	struct torture_suite *suite =
@@ -547,10 +604,11 @@ NTSTATUS torture_krb5_init(TALLOC_CTX *ctx)
 	torture_suite_add_simple_test(kdc_suite, "as-req-break-pw",
 				      torture_krb5_as_req_break_pw);
 
-#if 0
+	/* This only works if kdc_timesync 0 is set in krb5.conf */
 	torture_suite_add_simple_test(kdc_suite, "as-req-clock-skew",
 				      torture_krb5_as_req_clock_skew);
 
+#if 0
 	torture_suite_add_suite(kdc_suite, torture_krb5_canon(kdc_suite));
 #endif
 	torture_suite_add_suite(suite, kdc_suite);
-- 
2.12.2


From 0cff2d611724b3718c448ff92cc72592b65b4662 Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Fri, 1 Jul 2016 12:33:45 +0200
Subject: [PATCH 31/51] s4-torture: Add AES and RC4 enctype checks

Signed-off-by: Andreas Schneider <asn at samba.org>
---
 source4/torture/krb5/kdc-mit.c | 175 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 175 insertions(+)

diff --git a/source4/torture/krb5/kdc-mit.c b/source4/torture/krb5/kdc-mit.c
index 8037ba3c9fa..29cb93d9e62 100644
--- a/source4/torture/krb5/kdc-mit.c
+++ b/source4/torture/krb5/kdc-mit.c
@@ -44,6 +44,9 @@ enum torture_krb5_test {
 	TORTURE_KRB5_TEST_PAC_REQUEST,
 	TORTURE_KRB5_TEST_BREAK_PW,
 	TORTURE_KRB5_TEST_CLOCK_SKEW,
+	TORTURE_KRB5_TEST_AES,
+	TORTURE_KRB5_TEST_RC4,
+	TORTURE_KRB5_TEST_AES_RC4,
 };
 
 struct torture_krb5_context {
@@ -107,6 +110,9 @@ static krb5_error_code torture_krb5_pre_send_test(krb5_context context,
 	case TORTURE_KRB5_TEST_PAC_REQUEST:
 	case TORTURE_KRB5_TEST_BREAK_PW:
 	case TORTURE_KRB5_TEST_CLOCK_SKEW:
+	case TORTURE_KRB5_TEST_AES:
+	case TORTURE_KRB5_TEST_RC4:
+	case TORTURE_KRB5_TEST_AES_RC4:
 		ok = torture_check_krb5_as_req(test_context,
 					       context,
 					       message);
@@ -212,6 +218,30 @@ static bool torture_check_krb5_as_rep(struct torture_krb5_context *test_context,
 	return true;
 }
 
+static bool torture_check_krb5_as_rep_enctype(struct torture_krb5_context *test_context,
+					      krb5_context context,
+					      const krb5_data *reply,
+					      krb5_enctype expected_enctype)
+{
+	krb5_enctype reply_enctype;
+	bool ok;
+
+	ok = torture_check_krb5_as_rep(test_context,
+				       context,
+				       reply);
+	if (!ok) {
+		return false;
+	}
+
+	reply_enctype = test_context->as_rep->enc_part.enctype;
+
+	torture_assert_int_equal(test_context->tctx,
+				 reply_enctype, expected_enctype,
+				 "Ticket encrypted with invalid algorithm");
+
+	return true;
+}
+
 static krb5_error_code torture_krb5_post_recv_test(krb5_context context,
 						   void *data,
 						   krb5_error_code kdc_code,
@@ -398,6 +428,72 @@ static krb5_error_code torture_krb5_post_recv_test(krb5_context context,
 				    out,
 				    "Too many packets");
 		break;
+	case TORTURE_KRB5_TEST_AES:
+		torture_comment(test_context->tctx, "TORTURE_KRB5_TEST_AES\n");
+
+		if (test_context->recv_packet_count == 0) {
+			ok = torture_check_krb5_error(test_context,
+						      context,
+						      reply,
+						      KRB5KDC_ERR_PREAUTH_REQUIRED,
+						      false);
+			if (!ok) {
+				goto out;
+			}
+		} else {
+			ok = torture_check_krb5_as_rep_enctype(test_context,
+							       context,
+							       reply,
+							       ENCTYPE_AES256_CTS_HMAC_SHA1_96);
+			if (!ok) {
+				goto out;
+			}
+		}
+		break;
+	case TORTURE_KRB5_TEST_RC4:
+		torture_comment(test_context->tctx, "TORTURE_KRB5_TEST_RC4\n");
+
+		if (test_context->recv_packet_count == 0) {
+			ok = torture_check_krb5_error(test_context,
+						      context,
+						      reply,
+						      KRB5KDC_ERR_PREAUTH_REQUIRED,
+						      false);
+			if (!ok) {
+				goto out;
+			}
+		} else {
+			ok = torture_check_krb5_as_rep_enctype(test_context,
+							       context,
+							       reply,
+							       ENCTYPE_ARCFOUR_HMAC);
+			if (!ok) {
+				goto out;
+			}
+		}
+		break;
+	case TORTURE_KRB5_TEST_AES_RC4:
+		torture_comment(test_context->tctx, "TORTURE_KRB5_TEST_AES_RC4\n");
+
+		if (test_context->recv_packet_count == 0) {
+			ok = torture_check_krb5_error(test_context,
+						      context,
+						      reply,
+						      KRB5KDC_ERR_PREAUTH_REQUIRED,
+						      false);
+			if (!ok) {
+				goto out;
+			}
+		} else {
+			ok = torture_check_krb5_as_rep_enctype(test_context,
+							       context,
+							       reply,
+							       ENCTYPE_AES256_CTS_HMAC_SHA1_96);
+			if (!ok) {
+				goto out;
+			}
+		}
+		break;
 	}
 
 	code = kdc_code;
@@ -501,6 +597,49 @@ static bool torture_krb5_as_req_creds(struct torture_context *tctx,
 					 code, 0,
 					 "krb5_set_real_time failed");
 		break;
+	case TORTURE_KRB5_TEST_AES: {
+		krb5_enctype etype[] = { ENCTYPE_AES256_CTS_HMAC_SHA1_96 };
+
+		code = krb5_get_init_creds_opt_alloc(smb_krb5_context->krb5_context,
+						     &krb_options);
+		torture_assert_int_equal(tctx,
+					 code, 0,
+					 "krb5_get_init_creds_opt_alloc failed");
+
+		krb5_get_init_creds_opt_set_etype_list(krb_options,
+						       etype,
+						       1);
+		break;
+	}
+	case TORTURE_KRB5_TEST_RC4: {
+		krb5_enctype etype[] = { ENCTYPE_ARCFOUR_HMAC };
+
+		code = krb5_get_init_creds_opt_alloc(smb_krb5_context->krb5_context,
+						     &krb_options);
+		torture_assert_int_equal(tctx,
+					 code, 0,
+					 "krb5_get_init_creds_opt_alloc failed");
+
+		krb5_get_init_creds_opt_set_etype_list(krb_options,
+						       etype,
+						       1);
+		break;
+	}
+	case TORTURE_KRB5_TEST_AES_RC4: {
+		krb5_enctype etype[] = { ENCTYPE_AES256_CTS_HMAC_SHA1_96, ENCTYPE_ARCFOUR_HMAC };
+
+		code = krb5_get_init_creds_opt_alloc(smb_krb5_context->krb5_context,
+						     &krb_options);
+		torture_assert_int_equal(tctx,
+					 code, 0,
+					 "krb5_get_init_creds_opt_alloc failed");
+
+
+		krb5_get_init_creds_opt_set_etype_list(krb_options,
+						       etype,
+						       2);
+		break;
+	}
 	}
 
 	code = krb5_get_init_creds_password(smb_krb5_context->krb5_context,
@@ -519,6 +658,9 @@ static bool torture_krb5_as_req_creds(struct torture_context *tctx,
 	{
 	case TORTURE_KRB5_TEST_PLAIN:
 	case TORTURE_KRB5_TEST_PAC_REQUEST:
+	case TORTURE_KRB5_TEST_AES:
+	case TORTURE_KRB5_TEST_RC4:
+	case TORTURE_KRB5_TEST_AES_RC4:
 		torture_assert_int_equal(tctx,
 					 code,
 					 0,
@@ -583,6 +725,27 @@ static bool torture_krb5_as_req_clock_skew(struct torture_context *tctx)
 					 TORTURE_KRB5_TEST_CLOCK_SKEW);
 }
 
+static bool torture_krb5_as_req_aes(struct torture_context *tctx)
+{
+	return torture_krb5_as_req_creds(tctx,
+					 cmdline_credentials,
+					 TORTURE_KRB5_TEST_AES);
+}
+
+static bool torture_krb5_as_req_rc4(struct torture_context *tctx)
+{
+	return torture_krb5_as_req_creds(tctx,
+					 cmdline_credentials,
+					 TORTURE_KRB5_TEST_RC4);
+}
+
+static bool torture_krb5_as_req_aes_rc4(struct torture_context *tctx)
+{
+	return torture_krb5_as_req_creds(tctx,
+					 cmdline_credentials,
+					 TORTURE_KRB5_TEST_AES_RC4);
+}
+
 NTSTATUS torture_krb5_init(TALLOC_CTX *ctx)
 {
 	struct torture_suite *suite =
@@ -611,6 +774,18 @@ NTSTATUS torture_krb5_init(TALLOC_CTX *ctx)
 #if 0
 	torture_suite_add_suite(kdc_suite, torture_krb5_canon(kdc_suite));
 #endif
+	torture_suite_add_simple_test(kdc_suite,
+				      "as-req-aes",
+				      torture_krb5_as_req_aes);
+
+	torture_suite_add_simple_test(kdc_suite,
+				      "as-req-rc4",
+				      torture_krb5_as_req_rc4);
+
+	torture_suite_add_simple_test(kdc_suite,
+				      "as-req-aes-rc4",
+				      torture_krb5_as_req_aes_rc4);
+
 	torture_suite_add_suite(suite, kdc_suite);
 
 	torture_register_suite(suite);
-- 
2.12.2


From f770ea2febb0c28f820d070463763f69406f3748 Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Wed, 7 Sep 2016 12:32:50 +0200
Subject: [PATCH 32/51] s4-kdc: Add MIT Kerberos specific kpasswd code

Signed-off-by: Andreas Schneider <asn at samba.org>
---
 source4/kdc/kpasswd-service-mit.c | 300 ++++++++++++++++++++++++++++++++++++++
 source4/kdc/wscript_build         |   3 +-
 2 files changed, 301 insertions(+), 2 deletions(-)
 create mode 100644 source4/kdc/kpasswd-service-mit.c

diff --git a/source4/kdc/kpasswd-service-mit.c b/source4/kdc/kpasswd-service-mit.c
new file mode 100644
index 00000000000..eb3a098eb76
--- /dev/null
+++ b/source4/kdc/kpasswd-service-mit.c
@@ -0,0 +1,300 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   Samba kpasswd implementation
+
+   Copyright (c) 2016      Andreas Schneider <asn at samba.org>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "smbd/service_task.h"
+#include "param/param.h"
+#include "auth/auth.h"
+#include "auth/gensec/gensec.h"
+#include "kdc/kdc-server.h"
+#include "kdc/kpasswd_glue.h"
+#include "kdc/kpasswd-service.h"
+#include "kdc/kpasswd-helper.h"
+
+#define RFC3244_VERSION 0xff80
+
+krb5_error_code decode_krb5_setpw_req(const krb5_data *code,
+				      krb5_data **password_out,
+				      krb5_principal *target_out);
+
+static krb5_error_code kpasswd_change_password(struct kdc_server *kdc,
+					       TALLOC_CTX *mem_ctx,
+					       struct auth_session_info *session_info,
+					       DATA_BLOB *password,
+					       DATA_BLOB *kpasswd_reply,
+					       const char **error_string)
+{
+	NTSTATUS status;
+	NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+	enum samPwdChangeReason reject_reason;
+	const char *reject_string = NULL;
+	struct samr_DomInfo1 *dominfo;
+	bool ok;
+
+	status = samdb_kpasswd_change_password(mem_ctx,
+					       kdc->task->lp_ctx,
+					       kdc->task->event_ctx,
+					       kdc->samdb,
+					       session_info,
+					       password,
+					       &reject_reason,
+					       &dominfo,
+					       &reject_string,
+					       &result);
+	if (!NT_STATUS_IS_OK(status)) {
+		ok = kpasswd_make_error_reply(mem_ctx,
+					      KRB5_KPASSWD_ACCESSDENIED,
+					      reject_string,
+					      kpasswd_reply);
+		if (!ok) {
+			*error_string = "Failed to create reply";
+			return KRB5_KPASSWD_HARDERROR;
+		}
+		/* We want to send an an authenticated packet. */
+		return 0;
+	}
+
+	ok = kpasswd_make_pwchange_reply(mem_ctx,
+					 result,
+					 reject_reason,
+					 dominfo,
+					 kpasswd_reply);
+	if (!ok) {
+		*error_string = "Failed to create reply";
+		return KRB5_KPASSWD_HARDERROR;
+	}
+
+	return 0;
+}
+
+static krb5_error_code kpasswd_set_password(struct kdc_server *kdc,
+					    TALLOC_CTX *mem_ctx,
+					    struct auth_session_info *session_info,
+					    DATA_BLOB *decoded_data,
+					    DATA_BLOB *kpasswd_reply,
+					    const char **error_string)
+{
+	krb5_context context = kdc->smb_krb5_context->krb5_context;
+	krb5_data k_dec_data;
+	krb5_data *k_clear_data;
+	krb5_principal target_principal;
+	krb5_error_code code;
+	DATA_BLOB password;
+	char *target_realm = NULL;
+	char *target_name = NULL;
+	char *target_principal_string = NULL;
+	bool is_service_principal = false;
+	bool ok;
+	size_t num_components;
+	enum samPwdChangeReason reject_reason = SAM_PWD_CHANGE_NO_ERROR;
+	struct samr_DomInfo1 *dominfo = NULL;
+	NTSTATUS status;
+
+	k_dec_data.length = decoded_data->length;
+	k_dec_data.data   = (char *)decoded_data->data;
+
+	code = decode_krb5_setpw_req(&k_dec_data, &k_clear_data, &target_principal);
+	if (code != 0) {
+		DBG_WARNING("decode_krb5_setpw_req failed: %s\n",
+			    error_message(code));
+		ok = kpasswd_make_error_reply(mem_ctx,
+					      KRB5_KPASSWD_MALFORMED,
+					      "Failed to decode packet",
+					      kpasswd_reply);
+		if (!ok) {
+			*error_string = "Failed to create reply";
+			return KRB5_KPASSWD_HARDERROR;
+		}
+		return 0;
+	}
+
+	ok = convert_string_talloc_handle(mem_ctx,
+					  lpcfg_iconv_handle(kdc->task->lp_ctx),
+					  CH_UTF8,
+					  CH_UTF16,
+					  (const char *)k_clear_data->data,
+					  k_clear_data->length,
+					  (void **)&password.data,
+					  &password.length);
+	krb5_free_data(context, k_clear_data);
+	if (!ok) {
+		DBG_WARNING("String conversion failed\n");
+		*error_string = "String conversion failed";
+		return KRB5_KPASSWD_HARDERROR;
+	}
+
+	target_realm = smb_krb5_principal_get_realm(context, target_principal);
+	code = krb5_unparse_name_flags(context,
+				       target_principal,
+				       KRB5_PRINCIPAL_UNPARSE_NO_REALM,
+				       &target_name);
+	if (code != 0) {
+		DBG_WARNING("Failed to parse principal\n");
+		*error_string = "String conversion failed";
+		return KRB5_KPASSWD_HARDERROR;
+	}
+
+	if ((target_name != NULL && target_realm == NULL) ||
+	    (target_name == NULL && target_realm != NULL)) {
+		krb5_free_principal(context, target_principal);
+		SAFE_FREE(target_realm);
+		SAFE_FREE(target_name);
+
+		ok = kpasswd_make_error_reply(mem_ctx,
+					      KRB5_KPASSWD_MALFORMED,
+					      "Realm and principal must be "
+					      "both present, or neither present",
+					      kpasswd_reply);
+		if (!ok) {
+			*error_string = "Failed to create reply";
+			return KRB5_KPASSWD_HARDERROR;
+		}
+		return 0;
+	}
+
+	if (target_name != NULL && target_realm != NULL) {
+		SAFE_FREE(target_realm);
+		SAFE_FREE(target_name);
+	} else {
+		krb5_free_principal(context, target_principal);
+		SAFE_FREE(target_realm);
+		SAFE_FREE(target_name);
+
+		return kpasswd_change_password(kdc,
+					       mem_ctx,
+					       session_info,
+					       &password,
+					       kpasswd_reply,
+					       error_string);
+	}
+
+	num_components = krb5_princ_size(context, target_principal);
+	if (num_components >= 2) {
+		is_service_principal = true;
+		code = krb5_unparse_name_flags(context,
+					       target_principal,
+					       KRB5_PRINCIPAL_UNPARSE_SHORT,
+					       &target_principal_string);
+	} else {
+		code = krb5_unparse_name(context,
+					 target_principal,
+					 &target_principal_string);
+	}
+	krb5_free_principal(context, target_principal);
+	if (code != 0) {
+		ok = kpasswd_make_error_reply(mem_ctx,
+					      KRB5_KPASSWD_MALFORMED,
+					      "Failed to parse principal",
+					      kpasswd_reply);
+		if (!ok) {
+			*error_string = "Failed to create reply";
+			return KRB5_KPASSWD_HARDERROR;
+		}
+	}
+
+	status = kpasswd_samdb_set_password(mem_ctx,
+					    kdc->task->event_ctx,
+					    kdc->task->lp_ctx,
+					    session_info,
+					    is_service_principal,
+					    target_principal_string,
+					    &password,
+					    &reject_reason,
+					    &dominfo);
+	if (!NT_STATUS_IS_OK(status)) {
+		DBG_ERR("kpasswd_samdb_set_password failed - %s\n",
+			nt_errstr(status));
+	}
+
+	ok = kpasswd_make_pwchange_reply(mem_ctx,
+					 status,
+					 reject_reason,
+					 dominfo,
+					 kpasswd_reply);
+	if (!ok) {
+		*error_string = "Failed to create reply";
+		return KRB5_KPASSWD_HARDERROR;
+	}
+
+	return 0;
+}
+
+krb5_error_code kpasswd_handle_request(struct kdc_server *kdc,
+				       TALLOC_CTX *mem_ctx,
+				       struct gensec_security *gensec_security,
+				       uint16_t verno,
+				       DATA_BLOB *decoded_data,
+				       DATA_BLOB *kpasswd_reply,
+				       const char **error_string)
+{
+	struct auth_session_info *session_info;
+	NTSTATUS status;
+
+	status = gensec_session_info(gensec_security,
+				     mem_ctx,
+				     &session_info);
+	if (!NT_STATUS_IS_OK(status)) {
+		*error_string = talloc_asprintf(mem_ctx,
+						"gensec_session_info failed - %s",
+						nt_errstr(status));
+		return KRB5_KPASSWD_HARDERROR;
+	}
+
+	switch(verno) {
+	case 1: {
+		DATA_BLOB password;
+		bool ok;
+
+		ok = convert_string_talloc_handle(mem_ctx,
+						  lpcfg_iconv_handle(kdc->task->lp_ctx),
+						  CH_UTF8,
+						  CH_UTF16,
+						  (const char *)decoded_data->data,
+						  decoded_data->length,
+						  (void **)&password.data,
+						  &password.length);
+		if (!ok) {
+			*error_string = "String conversion failed!";
+			DBG_WARNING("%s\n", *error_string);
+			return KRB5_KPASSWD_HARDERROR;
+		}
+
+		return kpasswd_change_password(kdc,
+					       mem_ctx,
+					       session_info,
+					       &password,
+					       kpasswd_reply,
+					       error_string);
+	}
+	case RFC3244_VERSION: {
+		return kpasswd_set_password(kdc,
+					    mem_ctx,
+					    session_info,
+					    decoded_data,
+					    kpasswd_reply,
+					    error_string);
+	}
+	default:
+		return KRB5_KPASSWD_BAD_VERSION;
+	}
+
+	return 0;
+}
diff --git a/source4/kdc/wscript_build b/source4/kdc/wscript_build
index a19932cca50..5e50142dadd 100644
--- a/source4/kdc/wscript_build
+++ b/source4/kdc/wscript_build
@@ -67,8 +67,7 @@ bld.SAMBA_SUBSYSTEM('KDC-SERVER',
                          ldb
                          LIBTSOCKET
                          LIBSAMBA_TSOCKET
-                    ''',
-                    enabled=bld.CONFIG_SET('SAMBA4_USES_HEIMDAL'))
+                    ''')
 
 kpasswd_flavor_src = 'kpasswd-service.c kpasswd-helper.c'
 if bld.CONFIG_SET('SAMBA4_USES_HEIMDAL'):
-- 
2.12.2


From ba378289e783cd8beedeb5812e1719652ae09d73 Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Wed, 7 Sep 2016 12:29:18 +0200
Subject: [PATCH 33/51] waf: Search for MIT kadm-server library

This is needed for plugin registration in the KDC.

Signed-off-by: Andreas Schneider <asn at samba.org>
---
 wscript_configure_system_mitkrb5 | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/wscript_configure_system_mitkrb5 b/wscript_configure_system_mitkrb5
index 39924577431..41cc2dd0ed8 100644
--- a/wscript_configure_system_mitkrb5
+++ b/wscript_configure_system_mitkrb5
@@ -34,6 +34,10 @@ if conf.env.KRB5_CONFIG:
     krb5_define_syslib(conf, "krb5", conf.env['LIB_KRB5'])
 
     conf.CHECK_CFG(path=conf.env.KRB5_CONFIG, args="--cflags --libs",
+                   package="kadm-server", uselib_store="KADM-SERVER")
+    conf.CHECK_FUNCS_IN('kadm5_init', 'kadm5srv_mit')
+
+    conf.CHECK_CFG(path=conf.env.KRB5_CONFIG, args="--cflags --libs",
                    package="kdb", uselib_store="KDB5")
     krb5_define_syslib(conf, "kdb5", conf.env['LIB_KDB5'])
 
-- 
2.12.2


From 1fe9c853c95a6def9988b487e91291567f826325 Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Thu, 8 Sep 2016 09:58:44 +0200
Subject: [PATCH 34/51] s4-kdc: Start the kpasswd service with MIT KDC

Signed-off-by: Andreas Schneider <asn at samba.org>
---
 source4/kdc/kdc-service-mit.c | 219 +++++++++++++++++++++++++++++++++++++++++-
 source4/kdc/wscript_build     |   7 ++
 2 files changed, 225 insertions(+), 1 deletion(-)

diff --git a/source4/kdc/kdc-service-mit.c b/source4/kdc/kdc-service-mit.c
index 719ea48c090..87c0179f461 100644
--- a/source4/kdc/kdc-service-mit.c
+++ b/source4/kdc/kdc-service-mit.c
@@ -3,7 +3,7 @@
 
    Start MIT krb5kdc server within Samba AD
 
-   Copyright (c) 2014      Andreas Schneider <asn at samba.org>
+   Copyright (c) 2014-2016 Andreas Schneider <asn at samba.org>
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -30,11 +30,114 @@
 #include "kdc/kdc-service-mit.h"
 #include "dynconfig.h"
 #include "libds/common/roles.h"
+#include "lib/socket/netif.h"
+#include "samba/session.h"
+#include "dsdb/samdb/samdb.h"
+#include "kdc/samba_kdc.h"
+#include "kdc/kdc-server.h"
+#include "kdc/kpasswd-service.h"
+#include <kadm5/admin.h>
+#include <kdb.h>
 
 #include "source4/kdc/mit_kdc_irpc.h"
 
+/* PROTOTYPES */
 static void mitkdc_server_done(struct tevent_req *subreq);
 
+static int kdc_server_destroy(struct kdc_server *kdc)
+{
+	if (kdc->private_data != NULL) {
+		kadm5_destroy(kdc->private_data);
+	}
+
+	return 0;
+}
+
+static NTSTATUS startup_kpasswd_server(TALLOC_CTX *mem_ctx,
+				       struct kdc_server *kdc,
+				       struct loadparm_context *lp_ctx,
+				       struct interface *ifaces)
+{
+	const struct model_ops *model_ops;
+	int num_interfaces;
+	int i;
+	TALLOC_CTX *tmp_ctx;
+	NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+	uint16_t kpasswd_port;
+	bool done_wildcard = false;
+	bool ok;
+
+	kpasswd_port = lpcfg_kpasswd_port(lp_ctx);
+	if (kpasswd_port == 0) {
+		return NT_STATUS_OK;
+	}
+
+	model_ops = process_model_startup("single");
+	if (model_ops == NULL) {
+		DBG_ERR("Can't find 'single' process model_ops\n");
+		return NT_STATUS_INTERNAL_ERROR;
+	}
+
+	tmp_ctx = talloc_named_const(mem_ctx, 0, "kpasswd");
+	if (tmp_ctx == NULL) {
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	num_interfaces = iface_list_count(ifaces);
+
+	ok = lpcfg_bind_interfaces_only(lp_ctx);
+	if (!ok) {
+		int num_binds = 0;
+		char **wcard;
+
+		wcard = iface_list_wildcard(tmp_ctx);
+		if (wcard == NULL) {
+			status = NT_STATUS_NO_MEMORY;
+			goto out;
+		}
+
+		for (i = 0; wcard[i] != NULL; i++) {
+			status = kdc_add_socket(kdc,
+						model_ops,
+						"kpasswd",
+						wcard[i],
+						kpasswd_port,
+						kpasswd_process,
+						false);
+			if (NT_STATUS_IS_OK(status)) {
+				num_binds++;
+			}
+		}
+		talloc_free(wcard);
+
+		if (num_binds == 0) {
+			status = NT_STATUS_INVALID_PARAMETER_MIX;
+			goto out;
+		}
+
+		done_wildcard = true;
+	}
+
+	for (i = 0; i < num_interfaces; i++) {
+		const char *address = talloc_strdup(tmp_ctx, iface_list_n_ip(ifaces, i));
+
+		status = kdc_add_socket(kdc,
+					model_ops,
+					"kpasswd",
+					address,
+					kpasswd_port,
+					kpasswd_process,
+					done_wildcard);
+		if (NT_STATUS_IS_OK(status)) {
+			goto out;
+		}
+	}
+
+out:
+	talloc_free(tmp_ctx);
+	return status;
+}
+
 /*
  * Startup a copy of the krb5kdc as a child daemon
  */
@@ -42,8 +145,14 @@ void mitkdc_task_init(struct task_server *task)
 {
 	struct tevent_req *subreq;
 	const char * const *kdc_cmd;
+	struct interface *ifaces;
 	const char *kdc_config;
+	struct kdc_server *kdc;
+	krb5_error_code code;
 	NTSTATUS status;
+	kadm5_ret_t ret;
+	kadm5_config_params config;
+	void *server_handle;
 
 	task_server_set_title(task, "task[mitkdc_parent]");
 
@@ -65,6 +174,15 @@ void mitkdc_task_init(struct task_server *task)
 		break;
 	}
 
+	/* Load interfaces for kpasswd */
+	load_interface_list(task, task->lp_ctx, &ifaces);
+	if (iface_list_count(ifaces) == 0) {
+		task_server_terminate(task,
+				      "KDC: no network interfaces configured",
+				      false);
+		return;
+	}
+
 	kdc_config = lpcfg_mit_kdc_config(task->lp_ctx, task);
 	if (kdc_config != NULL && kdc_config[0] != '\0') {
 		/* Do not overwrite the variable if already set! */
@@ -106,6 +224,105 @@ void mitkdc_task_init(struct task_server *task)
 	}
 
 	DEBUG(5,("Started irpc service for kdc_server\n"));
+
+	kdc = talloc_zero(task, struct kdc_server);
+	if (kdc == NULL) {
+		task_server_terminate(task, "KDC: Out of memory", true);
+		return;
+	}
+	talloc_set_destructor(kdc, kdc_server_destroy);
+
+	kdc->task = task;
+
+	kdc->base_ctx = talloc_zero(kdc, struct samba_kdc_base_context);
+	if (kdc->base_ctx == NULL) {
+		task_server_terminate(task, "KDC: Out of memory", true);
+		return;
+	}
+
+	kdc->base_ctx->ev_ctx = task->event_ctx;
+	kdc->base_ctx->lp_ctx = task->lp_ctx;
+
+	initialize_krb5_error_table();
+
+	code = smb_krb5_init_context(kdc,
+				     kdc->task->lp_ctx,
+				     &kdc->smb_krb5_context);
+	if (code != 0) {
+		task_server_terminate(task,
+				      "KDC: Unable to initialized krb5 context",
+				      true);
+		return;
+	}
+
+	code = kadm5_init_krb5_context(&kdc->smb_krb5_context->krb5_context);
+	if (code != 0) {
+		task_server_terminate(task,
+				      "KDC: Unable to init kadm5 krb5_context",
+				      true);
+		return;
+	}
+
+	ZERO_STRUCT(config);
+	config.mask = KADM5_CONFIG_REALM;
+	config.realm = discard_const_p(char, lpcfg_realm(kdc->task->lp_ctx));
+
+	ret = kadm5_init(kdc->smb_krb5_context->krb5_context,
+			 discard_const_p(char, "kpasswd"),
+			 NULL, /* pass */
+			 discard_const_p(char, "kpasswd"),
+			 &config,
+			 KADM5_STRUCT_VERSION,
+			 KADM5_API_VERSION_4,
+			 NULL,
+			 &server_handle);
+	if (ret != 0) {
+		task_server_terminate(task,
+				      "KDC: Initialize kadm5",
+				      true);
+		return;
+	}
+	kdc->private_data = server_handle;
+
+	code = krb5_db_register_keytab(kdc->smb_krb5_context->krb5_context);
+	if (code != 0) {
+		task_server_terminate(task,
+				      "KDC: Unable to KDB",
+				      true);
+		return;
+	}
+
+	kdc->keytab_name = talloc_asprintf(kdc, "KDB:");
+	if (kdc->keytab_name == NULL) {
+		task_server_terminate(task,
+				      "KDC: Out of memory",
+				      true);
+		return;
+	}
+
+	kdc->samdb = samdb_connect(kdc,
+				   kdc->task->event_ctx,
+				   kdc->task->lp_ctx,
+				   system_session(kdc->task->lp_ctx),
+				   0);
+	if (kdc->samdb == NULL) {
+		task_server_terminate(task,
+				      "KDC: Unable to connect to sambdb",
+				      true);
+		return;
+	}
+
+	status = startup_kpasswd_server(kdc,
+				    kdc,
+				    task->lp_ctx,
+				    ifaces);
+	if (!NT_STATUS_IS_OK(status)) {
+		task_server_terminate(task,
+				      "KDC: Unable to start kpasswd server",
+				      true);
+	}
+
+	DEBUG(5,("Started kpasswd service for kdc_server\n"));
 }
 
 /*
diff --git a/source4/kdc/wscript_build b/source4/kdc/wscript_build
index 5e50142dadd..6179e3e6426 100644
--- a/source4/kdc/wscript_build
+++ b/source4/kdc/wscript_build
@@ -37,6 +37,11 @@ if bld.CONFIG_GET('SAMBA_USES_MITKDC'):
                           talloc
                           UTIL_RUNCMD
                           MIT_KDC_IRPC
+                          KDC-SERVER
+                          KPASSWD-SERVICE
+                          com_err
+                          kadm5srv_mit
+                          kdb5
                      ''',
                      internal_module=False)
 
@@ -72,6 +77,8 @@ bld.SAMBA_SUBSYSTEM('KDC-SERVER',
 kpasswd_flavor_src = 'kpasswd-service.c kpasswd-helper.c'
 if bld.CONFIG_SET('SAMBA4_USES_HEIMDAL'):
     kpasswd_flavor_src = kpasswd_flavor_src + ' kpasswd-service-heimdal.c'
+elif bld.CONFIG_GET('SAMBA_USES_MITKDC'):
+    kpasswd_flavor_src = kpasswd_flavor_src + ' kpasswd-service-mit.c'
 
 bld.SAMBA_SUBSYSTEM('KPASSWD-SERVICE',
                     source=kpasswd_flavor_src,
-- 
2.12.2


From 6b7f6fb54110c8e1bee976d719819cefd8bb8424 Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Mon, 5 Sep 2016 18:01:57 +0200
Subject: [PATCH 35/51] testprogs: Add MIT Kerberos specific kpasswd blackbox
 test

Signed-off-by: Andreas Schneider <asn at samba.org>
---
 source4/selftest/tests.py              |   1 +
 testprogs/blackbox/test_kpasswd_mit.sh | 231 +++++++++++++++++++++++++++++++++
 2 files changed, 232 insertions(+)
 create mode 100755 testprogs/blackbox/test_kpasswd_mit.sh

diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py
index b7ac0c5f5f7..75405b9c717 100755
--- a/source4/selftest/tests.py
+++ b/source4/selftest/tests.py
@@ -404,6 +404,7 @@ else:
     plantestsuite("samba4.blackbox.kinit_trust(fl2008r2dc:local)", "fl2008r2dc:local", [os.path.join(bbdir, "test_kinit_trusts_mit.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$TRUST_SERVER', '$TRUST_USERNAME', '$TRUST_PASSWORD', '$TRUST_REALM', '$TRUST_DOMAIN', '$PREFIX', "forest"])
     plantestsuite("samba4.blackbox.kinit_trust(fl2003dc:local)", "fl2003dc:local", [os.path.join(bbdir, "test_kinit_trusts_mit.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$TRUST_SERVER', '$TRUST_USERNAME', '$TRUST_PASSWORD', '$TRUST_REALM', '$TRUST_DOMAIN', '$PREFIX', "external"])
     plantestsuite("samba4.blackbox.export.keytab(ad_dc_ntvfs:local)", "ad_dc_ntvfs:local", [os.path.join(bbdir, "test_export_keytab_mit.sh"), '$SERVER', '$USERNAME', '$REALM', '$DOMAIN', "$PREFIX", smbclient4])
+    plantestsuite("samba4.blackbox.kpasswd(ad_dc_ntvfs:local)", "ad_dc_ntvfs:local", [os.path.join(bbdir, "test_kpasswd_mit.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', "$PREFIX/ad_dc_ntvfs"])
 
 plantestsuite("samba4.blackbox.trust_ntlm", "fl2008r2dc:local", [os.path.join(bbdir, "test_trust_ntlm.sh"), '$SERVER_IP', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$TRUST_USERNAME', '$TRUST_PASSWORD', '$TRUST_REALM', '$TRUST_DOMAIN', 'forest', 'auto', 'NT_STATUS_NO_TRUST_LSA_SECRET'])
 plantestsuite("samba4.blackbox.trust_ntlm", "fl2003dc:local", [os.path.join(bbdir, "test_trust_ntlm.sh"), '$SERVER_IP', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$TRUST_USERNAME', '$TRUST_PASSWORD', '$TRUST_REALM', '$TRUST_DOMAIN', 'external', 'auto', 'NT_STATUS_NO_TRUST_LSA_SECRET'])
diff --git a/testprogs/blackbox/test_kpasswd_mit.sh b/testprogs/blackbox/test_kpasswd_mit.sh
new file mode 100755
index 00000000000..8a0bce449f3
--- /dev/null
+++ b/testprogs/blackbox/test_kpasswd_mit.sh
@@ -0,0 +1,231 @@
+#!/bin/sh
+# Blackbox tests for chainging passwords with kinit and kpasswd
+#
+# Copyright (c) 2006-2007 Jelmer Vernooij <jelmer at samba.org>
+# Copyright (c) 2006-2008 Andrew Bartlett <abartlet at samba.org>
+# Copyright (c) 2016      Andreas Schneider <asn at samba.org>
+
+if [ $# -lt 6 ]; then
+cat <<EOF
+Usage: test_kpasswd_mit.sh SERVER USERNAME PASSWORD REALM DOMAIN PREFIX
+EOF
+exit 1;
+fi
+
+SERVER=$1
+USERNAME=$2
+PASSWORD=$3
+REALM=$4
+DOMAIN=$5
+PREFIX=$6
+shift 6
+failed=0
+
+samba_bindir="$BINDIR"
+
+samba_kinit=kinit
+samba_kpasswd=kpasswd
+
+smbclient="$samba_bindir/smbclient"
+samba_tool="$samba_bindir/samba-tool"
+net_tool="$samba_bindir/net"
+texpect="$samba_bindir/texpect"
+
+newuser="$samba_tool user create"
+SMB_UNC="//$SERVER/tmp"
+
+. `dirname $0`/subunit.sh
+. `dirname $0`/common_test_fns.inc
+
+do_kinit() {
+	principal="$1"
+	password="$2"
+	shift
+	shift
+	echo $password | $samba_kinit $principal
+}
+
+UID_WRAPPER_ROOT=1
+export UID_WRAPPER_ROOT
+
+CONFIG="--configfile=$PREFIX/etc/smb.conf"
+export CONFIG
+
+testit "reset password policies beside of minimum password age of 0 days" \
+	$VALGRIND $samba_tool domain passwordsettings $CONFIG set --complexity=default --history-length=default --min-pwd-length=default --min-pwd-age=0 --max-pwd-age=default || failed=`expr $failed + 1`
+
+TEST_USERNAME="samson"
+TEST_PASSWORD="testPaSS at 00%"
+TEST_PASSWORD_NEW="testPaSS at 01%"
+TEST_PASSWORD_SHORT="secret"
+TEST_PASSWORD_WEAK="Supersecret"
+TEST_PRINCIPAL="$TEST_USERNAME@$REALM"
+
+testit "create user locally" \
+	$VALGRIND $newuser $CONFIG $TEST_USERNAME $TEST_PASSWORD || failed=`expr $failed + 1`
+
+KRB5CCNAME="$PREFIX/tmpuserccache"
+export KRB5CCNAME
+
+testit "kinit with user password" \
+	do_kinit $TEST_PRINCIPAL $TEST_PASSWORD || failed=`expr $failed + 1`
+
+test_smbclient "Test login with user kerberos ccache" \
+	"ls" "$SMB_UNC" -k yes || failed=`expr $failed + 1`
+
+testit "change user password with 'samba-tool user password' (unforced)" \
+	$VALGRIND $samba_tool user password -W$DOMAIN -U$TEST_USERNAME%$TEST_PASSWORD -k no --newpassword=$TEST_PASSWORD_NEW || failed=`expr $failed + 1`
+
+TEST_PASSWORD_OLD=$TEST_PASSWORD
+TEST_PASSWORD=$TEST_PASSWORD_NEW
+TEST_PASSWORD_NEW="testPaSS at 02%"
+
+testit "kinit with user password" \
+	do_kinit $TEST_PRINCIPAL $TEST_PASSWORD || failed=`expr $failed + 1`
+
+test_smbclient "Test login with user kerberos ccache" \
+	"ls" "$SMB_UNC" -k yes || failed=`expr $failed + 1`
+
+###########################################################
+### check that a password mismatch is detected
+###########################################################
+
+cat > $PREFIX/tmpkpasswdscript <<EOF
+expect Password for $TEST_PRINCIPAL
+password ${TEST_PASSWORD}\n
+expect Enter new password
+send ${TEST_PASSWORD_WEAK}\n
+expect Enter it again
+send ${TEST_PASSWORD_NEW}\n
+expect kpasswd: Password mismatch while reading password
+EOF
+
+testit_expect_failure "kpasswd check password mismatch" \
+	$texpect $PREFIX/tmpkpasswdscript $samba_kpasswd $TEST_PRINCIPAL && failed=`expr $failed + 1`
+
+###########################################################
+### check that a short password is rejected
+###########################################################
+
+cat > $PREFIX/tmpkpasswdscript <<EOF
+expect Password for $TEST_PRINCIPAL
+password ${TEST_PASSWORD}\n
+expect Enter new password
+send ${TEST_PASSWORD_SHORT}\n
+expect Enter it again
+send ${TEST_PASSWORD_SHORT}\n
+expect Password change rejected: Password too short, password must be at least 7 characters long
+EOF
+
+testit_expect_failure "kpasswd check short user password" \
+	$texpect $PREFIX/tmpkpasswdscript $samba_kpasswd $TEST_PRINCIPAL && failed=`expr $failed + 1`
+
+###########################################################
+### check that a weak password is rejected
+###########################################################
+
+cat > $PREFIX/tmpkpasswdscript <<EOF
+expect Password for $TEST_PRINCIPAL
+password ${TEST_PASSWORD}\n
+expect Enter new password
+send ${TEST_PASSWORD_WEAK}\n
+expect Enter it again
+send ${TEST_PASSWORD_WEAK}\n
+expect Password change rejected: Password does not meet complexity requirement
+EOF
+
+testit_expect_failure "kpasswd check weak user password" \
+	$texpect $PREFIX/tmpkpasswdscript $samba_kpasswd $TEST_PRINCIPAL && failed=`expr $failed + 1`
+
+###########################################################
+### check that a strong password is accepted
+###########################################################
+
+cat > $PREFIX/tmpkpasswdscript <<EOF
+expect Password for $TEST_PRINCIPAL
+password ${TEST_PASSWORD}\n
+expect Enter new password
+send ${TEST_PASSWORD_NEW}\n
+expect Enter it again
+send ${TEST_PASSWORD_NEW}\n
+expect Password changed.
+EOF
+
+testit "kpasswd change user password" \
+	$texpect $PREFIX/tmpkpasswdscript $samba_kpasswd $TEST_PRINCIPAL|| failed=`expr $failed + 1`
+
+TEST_PASSWORD=$TEST_PASSWORD_NEW
+TEST_PASSWORD_NEW="testPaSS at 03%"
+
+test_smbclient "Test login with user kerberos" 'ls' "$SMB_UNC" -k yes -U$TEST_PRINCIPAL%$TEST_PASSWORD || failed=`expr $failed + 1`
+
+###########################################################
+### Force password change at login
+###########################################################
+
+testit "set password on user locally" \
+	$VALGRIND $samba_tool user setpassword $TEST_USERNAME $CONFIG --newpassword=$TEST_PASSWORD_NEW --must-change-at-next-login || failed=`expr $failed + 1`
+
+TEST_PASSWORD=$TEST_PASSWORD_NEW
+TEST_PASSWORD_NEW="testPaSS at 04%"
+
+cat > $PREFIX/tmpkinitscript <<EOF
+expect Password for $TEST_PRINCIPAL
+password ${TEST_PASSWORD}\n
+expect Password expired
+expect Enter new password
+send ${TEST_PASSWORD_NEW}\n
+expect Enter it again
+send ${TEST_PASSWORD_NEW}\n
+EOF
+
+testit "kinit and change user password" \
+	$texpect $PREFIX/tmpkinitscript $samba_kinit $TEST_PRINCIPAL|| failed=`expr $failed + 1`
+
+TEST_PASSWORD=$TEST_PASSWORD_NEW
+TEST_PASSWORD_NEW="testPaSS at 05%"
+
+test_smbclient "Test login with user kerberos" \
+	"ls" "$SMB_UNC" -k yes -U$TEST_PRINCIPAL%$TEST_PASSWORD || failed=`expr $failed + 1`
+
+###########################################################
+### Test kpasswd service via 'net ads password'
+###########################################################
+
+# NOTE: This call works if it is compiled with Heimdal, because the Heimdal
+# krb5_set_password() implementation falls back to change_password. The MIT
+# function doesn't!
+testit_expect_failure "change user password with 'net ads password', admin: $DOMAIN/$TEST_USERNAME, target: $TEST_PRINCIPAL (will fail)" \
+	$VALGRIND $net_tool ads password -W$DOMAIN -U$TEST_PRINCIPAL%$TEST_PASSWORD $TEST_PRINCIPAL "$TEST_PASSWORD_NEW" && failed=`expr $failed + 1`
+
+#TEST_PASSWORD=$TEST_PASSWORD_NEW
+#TEST_PASSWORD_NEW="testPaSS at 06%"
+
+#test_smbclient "Test login with smbclient (ntlm)" \
+#	"ls" "$SMB_UNC" -k no -U$TEST_PRINCIPAL%$TEST_PASSWORD || failed=`expr $failed + 1`
+
+###########################################################
+### Test kpasswd service via 'net ads password' as admin
+###########################################################
+
+testit "set user password with 'net ads password', admin: $DOMAIN/$USERNAME, target: $TEST_PRINCIPAL" \
+	$VALGRIND $net_tool ads password -W$DOMAIN -U$USERNAME@$REALM%$PASSWORD $TEST_PRINCIPAL "$TEST_PASSWORD_NEW" || failed=`expr $failed + 1`
+
+TEST_PASSWORD=$TEST_PASSWORD_NEW
+TEST_PASSWORD_NEW="testPaSS at 07%"
+
+test_smbclient "Test login with smbclient (ntlm)" \
+	"ls" "$SMB_UNC" -k no -U$TEST_PRINCIPAL%$TEST_PASSWORD || failed=`expr $failed + 1`
+
+###########################################################
+### Cleanup
+###########################################################
+
+testit "reset password policies" \
+	$VALGRIND $samba_tool domain passwordsettings $CONFIG set --complexity=default --history-length=default --min-pwd-length=default --min-pwd-age=default --max-pwd-age=default || failed=`expr $failed + 1`
+
+testit "delete user" \
+	$VALGRIND $samba_tool user delete $TEST_USERNAME -U"$USERNAME%$PASSWORD" $CONFIG -k no  || failed=`expr $failed + 1`
+
+rm -f $PREFIX/tmpuserccache $PREFIX/tmpkpasswdscript $PREFIX/tmpkinitscript
+exit $failed
-- 
2.12.2


From 2eba7f1242bee8f0f86ad4dc25485dd9bcf9c8ac Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Mon, 13 Apr 2015 15:58:14 +0200
Subject: [PATCH 36/51] selftest: Skip s4u2proxy tests, no support yet

Signed-off-by: Andreas Schneider <asn at samba.org>
---
 selftest/skip_mit_kdc | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/selftest/skip_mit_kdc b/selftest/skip_mit_kdc
index b0c901514d5..4a51c98ea0b 100644
--- a/selftest/skip_mit_kdc
+++ b/selftest/skip_mit_kdc
@@ -1,3 +1,5 @@
 # We do not support RODC yet
 .*rodc
 .*RODC
+^samba4.ntvfs.cifs.ntlm.base.unlink
+^samba4.ntvfs.cifs.krb5.base.unlink
-- 
2.12.2


From fa1c91f41caa09ccd316698e41358c25dffed495 Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Mon, 23 Nov 2015 11:44:26 +0100
Subject: [PATCH 37/51] waf: Create kerberos_implementation.py for provisioning

Signed-off-by: Andreas Schneider <asn at samba.org>
---
 .gitignore     |  3 +++
 python/wscript | 45 +++++++++++++++++++++++++++++++++++++++++++++
 wscript        |  1 +
 3 files changed, 49 insertions(+)
 create mode 100644 python/wscript

diff --git a/.gitignore b/.gitignore
index 1a43d43b3b3..f8d4eab2a7c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -65,3 +65,6 @@ semantic.cache
 /.emacs.desktop*
 /.gdb_history
 .clang-format
+
+# generated by configure
+python/samba/provision/kerberos_implementation.py
diff --git a/python/wscript b/python/wscript
new file mode 100644
index 00000000000..714d649219d
--- /dev/null
+++ b/python/wscript
@@ -0,0 +1,45 @@
+#!/usr/bin/env python
+
+import os
+
+def configure(conf):
+    kerberos_py = conf.srcdir + "/python/samba/provision/kerberos_implementation.py"
+
+    f = open(kerberos_py, 'w')
+    try:
+        header = """#
+# Copyright (c) 2016      Andreas Schneider <asn at samba.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+"""
+        f.write(header)
+
+        data = """kdb_modules_dir = "{0}"
+kdc_default_config_dir = "{1}"
+"""
+
+        if conf.env.HEIMDAL_KRB5_CONFIG:
+            f.write(data.format("", ""))
+        else:
+            modulesdir = "%s/krb5/plugins/kdb" % conf.env.LIBDIR
+            paths = [ "/var/kerberos/krb5kdc", "/var/lib/kerberos/krb5kdc" ]
+            kdc_path = None
+            for p in paths:
+                if os.path.exists(p):
+                    kdc_path = p
+
+            f.write(data.format(modulesdir, kdc_path))
+    finally:
+        f.close()
diff --git a/wscript b/wscript
index 57b87850896..2a886e6dd48 100644
--- a/wscript
+++ b/wscript
@@ -210,6 +210,7 @@ def configure(conf):
 
     conf.RECURSE('source3')
     conf.RECURSE('lib/texpect')
+    conf.RECURSE('python')
     if conf.env.with_ctdb:
         conf.RECURSE('ctdb')
     conf.RECURSE('lib/socket')
-- 
2.12.2


From 02b10231a73bb448bfc09fe6bd230ab8ce475c10 Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Mon, 12 Sep 2016 21:52:23 +0200
Subject: [PATCH 38/51] selftest: Add a variable to indicate that selftest is
 running

Signed-off-by: Andreas Schneider <asn at samba.org>
---
 selftest/selftest.pl | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/selftest/selftest.pl b/selftest/selftest.pl
index b00ab486e87..3ab07a7a741 100755
--- a/selftest/selftest.pl
+++ b/selftest/selftest.pl
@@ -324,6 +324,8 @@ my $srcdir_abs = abs_path($srcdir);
 die("using an empty absolute prefix isn't allowed") unless $prefix_abs ne "";
 die("using '/' as absolute prefix isn't allowed") unless $prefix_abs ne "/";
 
+$ENV{SAMBA_SELFTEST} = "1";
+
 $ENV{PREFIX} = $prefix;
 $ENV{PREFIX_ABS} = $prefix_abs;
 $ENV{SRCDIR} = $srcdir;
-- 
2.12.2


From 523cb1fe0d481fb94c5918037b644847619b8b9d Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Tue, 4 Apr 2017 08:10:52 +0200
Subject: [PATCH 39/51] python: Add py_is_heimdal_built() to pyglue

Signed-off-by: Andreas Schneider <asn at samba.org>
---
 python/pyglue.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/python/pyglue.c b/python/pyglue.c
index 2bb6247fdeb..07cde49e16b 100644
--- a/python/pyglue.c
+++ b/python/pyglue.c
@@ -152,6 +152,15 @@ static PyObject *py_is_ntvfs_fileserver_built(PyObject *self)
 #endif
 }
 
+static PyObject *py_is_heimdal_built(PyObject *self)
+{
+#ifdef SAMBA4_USES_HEIMDAL
+	Py_RETURN_TRUE;
+#else
+	Py_RETURN_FALSE;
+#endif
+}
+
 /*
   return the list of interface IPs we have configured
   takes an loadparm context, returns a list of IPs in string form
@@ -307,6 +316,8 @@ static PyMethodDef py_misc_methods[] = {
 		"(for testing) find one string in another with Samba's strstr_m()"},
 	{ "is_ntvfs_fileserver_built", (PyCFunction)py_is_ntvfs_fileserver_built, METH_NOARGS,
 		"is the NTVFS file server built in this installation?" },
+	{ "is_heimdal_built", (PyCFunction)py_is_heimdal_built, METH_NOARGS,
+		"is Samba built with Heimdal Kerberbos?" },
 	{ NULL }
 };
 
-- 
2.12.2


From 77bf283d025aca981707a5cf3b15924f0e966e3d Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Fri, 9 Oct 2015 15:06:52 +0200
Subject: [PATCH 40/51] python: Add provisioning support for MIT KDC in
 samba-tool

Signed-off-by: Andreas Schneider <asn at cryptomilk.org>
---
 python/samba/__init__.py           |   1 +
 python/samba/netcmd/domain.py      |  15 +++++-
 python/samba/provision/__init__.py |  18 ++++---
 python/samba/provision/kerberos.py | 101 +++++++++++++++++++++++++++++++++++++
 4 files changed, 128 insertions(+), 7 deletions(-)
 create mode 100644 python/samba/provision/kerberos.py

diff --git a/python/samba/__init__.py b/python/samba/__init__.py
index 67aa82300f9..6f79b3cc960 100644
--- a/python/samba/__init__.py
+++ b/python/samba/__init__.py
@@ -391,6 +391,7 @@ generate_random_machine_password = _glue.generate_random_machine_password
 strcasecmp_m = _glue.strcasecmp_m
 strstr_m = _glue.strstr_m
 is_ntvfs_fileserver_built = _glue.is_ntvfs_fileserver_built
+is_heimdal_built = _glue.is_heimdal_built
 
 NTSTATUSError = _glue.NTSTATUSError
 HRESULTError = _glue.HRESULTError
diff --git a/python/samba/netcmd/domain.py b/python/samba/netcmd/domain.py
index 4bd99ba6ff5..bfc4772b7b1 100644
--- a/python/samba/netcmd/domain.py
+++ b/python/samba/netcmd/domain.py
@@ -87,6 +87,9 @@ from samba.provision import (
     ProvisioningError
     )
 
+from samba.provision.kerberos_implementation import (
+    kdc_default_config_dir)
+
 from samba.provision.common import (
     FILL_FULL,
     FILL_NT4SYNC,
@@ -263,12 +266,20 @@ class cmd_domain_provision(Command):
                default="auto")
     ]
 
+    kdc_options = [
+        Option("--kdc-config-dir", type="string", metavar="KDC-CONFIG-DIR",
+               help="Set the MIT KDC config directory (default='%s')" % kdc_default_config_dir),
+    ]
+
     if os.getenv('TEST_LDAP', "no") == "yes":
         takes_options.extend(openldap_options)
 
     if samba.is_ntvfs_fileserver_built():
          takes_options.extend(ntvfs_options)
 
+    if not samba.is_heimdal_built():
+        takes_options.extend(kdc_options)
+
     takes_args = []
 
     def run(self, sambaopts=None, versionopts=None,
@@ -304,6 +315,7 @@ class cmd_domain_provision(Command):
             use_xattrs="auto",
             slapd_path=None,
             use_ntvfs=False,
+            kdc_config_dir=None,
             use_rfc2307=None,
             ldap_backend_nosync=None,
             ldap_backend_extra_port=None,
@@ -471,7 +483,8 @@ class cmd_domain_provision(Command):
                   use_rfc2307=use_rfc2307, skip_sysvolacl=False,
                   ldap_backend_extra_port=ldap_backend_extra_port,
                   ldap_backend_forced_uri=ldap_backend_forced_uri,
-                  nosync=ldap_backend_nosync, ldap_dryrun_mode=ldap_dryrun_mode)
+                  nosync=ldap_backend_nosync, ldap_dryrun_mode=ldap_dryrun_mode,
+                  kdcconfdir=kdc_config_dir)
 
         except ProvisioningError, e:
             raise CommandError("Provision failed", e)
diff --git a/python/samba/provision/__init__.py b/python/samba/provision/__init__.py
index f8e4696a2fd..b001c544fb9 100644
--- a/python/samba/provision/__init__.py
+++ b/python/samba/provision/__init__.py
@@ -118,7 +118,7 @@ import samba.registry
 from samba.schema import Schema
 from samba.samdb import SamDB
 from samba.dbchecker import dbcheck
-
+from samba.provision.kerberos import make_kdcconf
 
 DEFAULT_POLICY_GUID = "31B2F340-016D-11D2-945F-00C04FB984F9"
 DEFAULT_DC_POLICY_GUID = "6AC1786C-016F-11D2-945F-00C04FB984F9"
@@ -668,10 +668,9 @@ def guess_names(lp=None, hostname=None, domain=None, dnsdomain=None,
 
     return names
 
-
 def make_smbconf(smbconf, hostname, domain, realm, targetdir,
                  serverrole=None, eadb=False, use_ntvfs=False, lp=None,
-                 global_param=None):
+                 global_param=None, kdcconfdir=None):
     """Create a new smb.conf file based on a couple of basic settings.
     """
     assert smbconf is not None
@@ -732,6 +731,11 @@ def make_smbconf(smbconf, hostname, domain, realm, targetdir,
                 statedir = lp.get("state directory")
             lp.set("xattr_tdb:file", os.path.abspath(os.path.join(statedir, "xattr.tdb")))
 
+    make_kdcconf(realm, domain, kdcconfdir, os.path.dirname(lp.get("log file")))
+    if kdcconfdir is not None:
+        kdcconf = "%s/kdc.conf" % kdcconfdir
+        lp.set("mit kdc config", kdcconf)
+
     shares = {}
     if serverrole == "active directory domain controller":
         shares["sysvol"] = os.path.join(lp.get("state directory"), "sysvol")
@@ -1925,7 +1929,7 @@ def provision_fake_ypserver(logger, samdb, domaindn, netbiosname, nisdomain,
         samdb.transaction_commit()
 
 
-def provision(logger, session_info, smbconf=None,
+def provision(logger, session_info, smbconf=None, kdcconfdir=None,
         targetdir=None, samdb_fill=FILL_FULL, realm=None, rootdn=None,
         domaindn=None, schemadn=None, configdn=None, serverdn=None,
         domain=None, hostname=None, hostip=None, hostip6=None, domainsid=None,
@@ -2009,11 +2013,13 @@ def provision(logger, session_info, smbconf=None,
             make_smbconf(smbconf, hostname, domain, realm,
                          targetdir, serverrole=serverrole,
                          eadb=useeadb, use_ntvfs=use_ntvfs,
-                         lp=lp, global_param=global_param)
+                         lp=lp, global_param=global_param,
+                         kdcconfdir=kdcconfdir)
     else:
         make_smbconf(smbconf, hostname, domain, realm, targetdir,
                      serverrole=serverrole,
-                     eadb=useeadb, use_ntvfs=use_ntvfs, lp=lp, global_param=global_param)
+                     eadb=useeadb, use_ntvfs=use_ntvfs, lp=lp, global_param=global_param,
+                     kdcconfdir=kdcconfdir)
 
     if lp is None:
         lp = samba.param.LoadParm()
diff --git a/python/samba/provision/kerberos.py b/python/samba/provision/kerberos.py
new file mode 100644
index 00000000000..f874ff61567
--- /dev/null
+++ b/python/samba/provision/kerberos.py
@@ -0,0 +1,101 @@
+# Unix SMB/CIFS implementation
+#
+# Backend code for provisioning a Samba AD server
+#
+# Copyright (c) 2015      Andreas Schneider <asn at samba.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from samba.provision.kerberos_implementation import (
+    kdb_modules_dir,
+    kdc_default_config_dir)
+from samba import _glue
+import os
+
+def make_kdcconf(realm, domain, kdcconfdir, logdir):
+
+    if _glue.is_heimdal_built:
+        return
+
+    # Do nothing if kdc.conf has been set
+    if 'KRB5_KDC_PROFILE' in os.environ:
+        return
+
+    # We are in selftest
+    if 'SAMBA_SELFTEST' in os.environ and 'MITKRB5' in os.environ:
+        return
+
+    # If not specified use the default
+    if kdcconfdir is None:
+        kdcconfdir = kdc_default_config_dir
+
+    kdcconf = "%s/kdc.conf" % kdcconfdir
+
+    assert domain is not None
+    domain = domain.upper()
+
+    assert realm is not None
+    realm = realm.upper()
+
+    f = open(kdcconf, 'w')
+    try:
+        f.write("[kdcdefaults]\n")
+
+        f.write("\tkdc_ports = 88\n")
+        f.write("\tkdc_tcp_ports = 88\n")
+        f.write("\tkadmind_port = 464\n")
+        f.write("\n")
+
+        f.write("[realms]\n")
+
+        f.write("\t%s = {\n" % realm)
+        f.write("\t}\n")
+        f.write("\n")
+
+        f.write("\t%s = {\n" % realm.lower())
+        f.write("\t}\n")
+        f.write("\n")
+
+        f.write("\t%s = {\n" % domain)
+        f.write("\t}\n")
+        f.write("\n")
+
+        f.write("[dbmodules]\n")
+
+        f.write("\tdb_modules_dir = %s\n" % kdb_modules_dir)
+        f.write("\n")
+
+        f.write("\t%s = {\n" % realm)
+        f.write("\t\tdb_library = samba\n")
+        f.write("\t}\n")
+        f.write("\n")
+
+        f.write("\t%s = {\n" % realm.lower())
+        f.write("\t\tdb_library = samba\n")
+        f.write("\t}\n")
+        f.write("\n")
+
+        f.write("\t%s = {\n" % domain)
+        f.write("\t\tdb_library = samba\n")
+        f.write("\t}\n")
+        f.write("\n")
+
+        f.write("[logging]\n")
+
+        f.write("\tkdc = FILE:%s/mit_kdc.log\n" % logdir)
+        f.write("\tadmin_server = FILE:%s/mit_kadmin.log\n" % logdir)
+        f.write("\n")
+    finally:
+        f.close()
-- 
2.12.2


From f4519a52c2ae13b20d54fc933983d18d7b4f4047 Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Mon, 23 Nov 2015 15:08:54 +0100
Subject: [PATCH 41/51] waf: Move python build instructions to wscript

Signed-off-by: Andreas Schneider <asn at samba.org>
---
 python/wscript       | 44 ++++++++++++++++++++++++++++++++++++++++++++
 python/wscript_build | 36 ------------------------------------
 2 files changed, 44 insertions(+), 36 deletions(-)
 delete mode 100644 python/wscript_build

diff --git a/python/wscript b/python/wscript
index 714d649219d..687a268412f 100644
--- a/python/wscript
+++ b/python/wscript
@@ -43,3 +43,47 @@ kdc_default_config_dir = "{1}"
             f.write(data.format(modulesdir, kdc_path))
     finally:
         f.close()
+
+def build(bld):
+    bld.SAMBA_LIBRARY('samba_python',
+                      source=[],
+                      deps='''
+                           LIBPYTHON
+                           pytalloc-util
+                           pyrpc_util
+                           ''',
+                      grouping_library=True,
+                      private_library=True,
+                      pyembed=True,
+                      enabled=bld.PYTHON_BUILD_IS_ENABLED())
+
+    bld.SAMBA_SUBSYSTEM('LIBPYTHON',
+                        source='modules.c',
+                        public_deps='',
+                        init_function_sentinel='{NULL,NULL}',
+                        deps='talloc',
+                        pyext=True,
+                        enabled=bld.PYTHON_BUILD_IS_ENABLED())
+
+    for env in bld.gen_python_environments():
+        pytalloc_util = bld.pyembed_libname('pytalloc-util')
+        pyparam_util = bld.pyembed_libname('pyparam_util')
+
+        bld.SAMBA_PYTHON('python_glue',
+                         source='pyglue.c',
+                         deps='''
+                              %s
+                              samba-util
+                              netif
+                              %s
+                              ''' % (pyparam_util, pytalloc_util),
+                         realname='samba/_glue.so')
+
+    if bld.PYTHON_BUILD_IS_ENABLED():
+        for env in bld.gen_python_environments():
+            # install out various python scripts for use by make test
+            bld.SAMBA_SCRIPT('samba_python_files',
+                             pattern='samba/**/*.py',
+                             installdir='python')
+
+            bld.INSTALL_WILDCARD('${PYTHONARCHDIR}', 'samba/**/*.py', flat=False)
diff --git a/python/wscript_build b/python/wscript_build
deleted file mode 100644
index 87da26f710f..00000000000
--- a/python/wscript_build
+++ /dev/null
@@ -1,36 +0,0 @@
-#!/usr/bin/env python
-
-bld.SAMBA_LIBRARY('samba_python',
-	source=[],
-	deps='LIBPYTHON pytalloc-util pyrpc_util',
-	grouping_library=True,
-	private_library=True,
-	pyembed=True,
-	enabled=bld.PYTHON_BUILD_IS_ENABLED())
-
-bld.SAMBA_SUBSYSTEM('LIBPYTHON',
-	source='modules.c',
-	public_deps='',
-	init_function_sentinel='{NULL,NULL}',
-	deps='talloc',
-	pyext=True,
-	enabled=bld.PYTHON_BUILD_IS_ENABLED())
-
-for env in bld.gen_python_environments():
-	pytalloc_util = bld.pyembed_libname('pytalloc-util')
-	pyparam_util = bld.pyembed_libname('pyparam_util')
-
-	bld.SAMBA_PYTHON('python_glue',
-		source='pyglue.c',
-		deps='%s samba-util netif %s' % (pyparam_util, pytalloc_util),
-		realname='samba/_glue.so'
-		)
-
-if bld.PYTHON_BUILD_IS_ENABLED():
-    for env in bld.gen_python_environments():
-	# install out various python scripts for use by make test
-	bld.SAMBA_SCRIPT('samba_python_files',
-	                 pattern='samba/**/*.py',
-	                 installdir='python')
-
-	bld.INSTALL_WILDCARD('${PYTHONARCHDIR}', 'samba/**/*.py', flat=False)
-- 
2.12.2


From 3f5c5656ca2551dba998943ac4261da1b83612b4 Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Tue, 27 Sep 2016 18:53:44 +0200
Subject: [PATCH 42/51] s4-torture: Fix reauth tests with smaller clockskew
 grace time

Signed-off-by: Andreas Schneider <asn at samba.org>
---
 source4/torture/raw/session.c  | 8 ++++----
 source4/torture/smb2/session.c | 4 ++--
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/source4/torture/raw/session.c b/source4/torture/raw/session.c
index 6938c88f95d..26b93cca512 100644
--- a/source4/torture/raw/session.c
+++ b/source4/torture/raw/session.c
@@ -304,8 +304,8 @@ static bool test_session_expire1(struct torture_context *tctx)
 		torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
 						"raw_fileinfo failed");
 
-		torture_comment(tctx, "sleep 5 seconds\n");
-		smb_msleep(5*1000);
+		torture_comment(tctx, "sleep 10 seconds\n");
+		smb_msleep(10*1000);
 	}
 
 	/*
@@ -343,8 +343,8 @@ static bool test_session_expire1(struct torture_context *tctx)
 		torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
 						"raw_fileinfo failed");
 
-		torture_comment(tctx, "sleep 5 seconds\n");
-		smb_msleep(5*1000);
+		torture_comment(tctx, "sleep 10 seconds\n");
+		smb_msleep(10*1000);
 
 		torture_comment(tctx, "query info => EXPIRED\n");
 		ZERO_STRUCT(qfinfo.access_information.out);
diff --git a/source4/torture/smb2/session.c b/source4/torture/smb2/session.c
index e35ec85c6a3..e3c5676a80a 100644
--- a/source4/torture/smb2/session.c
+++ b/source4/torture/smb2/session.c
@@ -1125,8 +1125,8 @@ static bool test_session_expire1(struct torture_context *tctx)
 		torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
 						"smb2_getinfo_file failed");
 
-		torture_comment(tctx, "sleep 5 seconds\n");
-		smb_msleep(5*1000);
+		torture_comment(tctx, "sleep 10 seconds\n");
+		smb_msleep(10*1000);
 
 		torture_comment(tctx, "query info => EXPIRED\n");
 		ZERO_STRUCT(qfinfo.access_information.out);
-- 
2.12.2


From f89ccb843b6b044cd651a6fcf5381a0f32dc7577 Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Fri, 30 Sep 2016 07:41:09 +0200
Subject: [PATCH 43/51] s4-kdc: Fix logging with the KDB driver

Signed-off-by: Andreas Schneider <asn at samba.org>
---
 source4/kdc/mit_samba.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/source4/kdc/mit_samba.c b/source4/kdc/mit_samba.c
index 8a2bfe9b715..0531b017fdb 100644
--- a/source4/kdc/mit_samba.c
+++ b/source4/kdc/mit_samba.c
@@ -76,7 +76,7 @@ int mit_samba_context_init(struct mit_samba_context **_ctx)
 		goto done;
 	}
 
-	setup_logging("mitkdc", DEBUG_STDOUT);
+	setup_logging("mitkdc", DEBUG_DEFAULT_STDOUT);
 
 	/* init s4 configuration */
 	s4_conf_file = lpcfg_configfile(base_ctx.lp_ctx);
-- 
2.12.2


From d1df4c0ab06222a07987bcc9d8cd0b6d649a9c19 Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Thu, 29 Sep 2016 02:03:35 +0200
Subject: [PATCH 44/51] s4-kdc: Implement mit_samba_get_pac()

Signed-off-by: Andreas Schneider <asn at samba.org>
---
 source4/kdc/mit_samba.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++
 source4/kdc/mit_samba.h |  6 +++++
 2 files changed, 74 insertions(+)

diff --git a/source4/kdc/mit_samba.c b/source4/kdc/mit_samba.c
index 0531b017fdb..275a507e86e 100644
--- a/source4/kdc/mit_samba.c
+++ b/source4/kdc/mit_samba.c
@@ -366,6 +366,74 @@ int mit_samba_get_pac_data(struct mit_samba_context *ctx,
 	return 0;
 }
 
+int mit_samba_get_pac(struct mit_samba_context *smb_ctx,
+		      krb5_context context,
+		      krb5_db_entry *client,
+		      krb5_keyblock *client_key,
+		      krb5_pac *pac)
+{
+	TALLOC_CTX *tmp_ctx;
+	DATA_BLOB *logon_info_blob = NULL;
+	DATA_BLOB *upn_dns_info_blob = NULL;
+	DATA_BLOB *cred_ndr = NULL;
+	DATA_BLOB **cred_ndr_ptr = NULL;
+	DATA_BLOB cred_blob = data_blob_null;
+	DATA_BLOB *pcred_blob = NULL;
+	NTSTATUS nt_status;
+	krb5_error_code code;
+	struct samba_kdc_entry *skdc_entry;
+
+	skdc_entry = talloc_get_type_abort(client->e_data,
+					   struct samba_kdc_entry);
+
+	tmp_ctx = talloc_named(smb_ctx,
+			       0,
+			       "mit_samba_get_pac_data_blobs context");
+	if (tmp_ctx == NULL) {
+		return ENOMEM;
+	}
+
+#if 0 /* TODO Find out if this is a pkinit_reply key */
+	/* Check if we have a PREAUTH key */
+	if (client_key != NULL) {
+		cred_ndr_ptr = &cred_ndr;
+	}
+#endif
+
+	nt_status = samba_kdc_get_pac_blobs(tmp_ctx,
+					    skdc_entry,
+					    &logon_info_blob,
+					    cred_ndr_ptr,
+					    &upn_dns_info_blob);
+	if (!NT_STATUS_IS_OK(nt_status)) {
+		talloc_free(tmp_ctx);
+		return EINVAL;
+	}
+
+	if (cred_ndr != NULL) {
+		code = samba_kdc_encrypt_pac_credentials(context,
+							 client_key,
+							 cred_ndr,
+							 tmp_ctx,
+							 &cred_blob);
+		if (code != 0) {
+			talloc_free(tmp_ctx);
+			return code;
+		}
+		pcred_blob = &cred_blob;
+	}
+
+	code = samba_make_krb5_pac(context,
+				   logon_info_blob,
+				   pcred_blob,
+				   upn_dns_info_blob,
+				   NULL,
+				   pac);
+
+	talloc_free(tmp_ctx);
+	return code;
+}
+
 int mit_samba_update_pac_data(struct mit_samba_context *ctx,
 			      krb5_db_entry *client,
 			      DATA_BLOB *pac_data,
diff --git a/source4/kdc/mit_samba.h b/source4/kdc/mit_samba.h
index 277b2e57a93..5be77958dc4 100644
--- a/source4/kdc/mit_samba.h
+++ b/source4/kdc/mit_samba.h
@@ -51,6 +51,12 @@ int mit_samba_get_pac_data(struct mit_samba_context *ctx,
 			   krb5_db_entry *client,
 			   DATA_BLOB *data);
 
+int mit_samba_get_pac(struct mit_samba_context *smb_ctx,
+		      krb5_context context,
+		      krb5_db_entry *client,
+		      krb5_keyblock *client_key,
+		      krb5_pac *pac);
+
 int mit_samba_update_pac_data(struct mit_samba_context *ctx,
 			      krb5_db_entry *client,
 			      DATA_BLOB *pac_data,
-- 
2.12.2


From 000e681e2eac0ccc3f96b974506e5600940f7cf3 Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Thu, 29 Sep 2016 02:04:00 +0200
Subject: [PATCH 45/51] s4-kdc: Use mit_samba_get_pac() in ks_get_pac()

This adds UPN_DNS_INFO to the PAC.

Signed-off-by: Andreas Schneider <asn at samba.org>
---
 source4/kdc/mit-kdb/kdb_samba_policies.c | 30 ++++++++----------------------
 1 file changed, 8 insertions(+), 22 deletions(-)

diff --git a/source4/kdc/mit-kdb/kdb_samba_policies.c b/source4/kdc/mit-kdb/kdb_samba_policies.c
index 396e6fe9d31..8c3a85b1f1f 100644
--- a/source4/kdc/mit-kdb/kdb_samba_policies.c
+++ b/source4/kdc/mit-kdb/kdb_samba_policies.c
@@ -155,11 +155,10 @@ done:
 
 static krb5_error_code ks_get_pac(krb5_context context,
 				  krb5_db_entry *client,
+				  krb5_keyblock *client_key,
 				  krb5_pac *pac)
 {
 	struct mit_samba_context *mit_ctx;
-	DATA_BLOB pac_data;
-	krb5_data data;
 	krb5_error_code code;
 
 	mit_ctx = ks_get_context(context);
@@ -167,27 +166,15 @@ static krb5_error_code ks_get_pac(krb5_context context,
 		return KRB5_KDB_DBNOTINITED;
 	}
 
-	code = mit_samba_get_pac_data(mit_ctx,
-				      client,
-				      &pac_data);
+	code = mit_samba_get_pac(mit_ctx,
+				 context,
+				 client,
+				 client_key,
+				 pac);
 	if (code != 0) {
 		return code;
 	}
 
-	code = krb5_pac_init(context, pac);
-	if (code != 0) {
-		goto done;
-	}
-
-	data = ks_make_data(pac_data.data, pac_data.length);
-
-	code = krb5_pac_add_buffer(context, *pac, PAC_LOGON_INFO, &data);
-	if (code != 0) {
-		goto done;
-	}
-
-done:
-	free(pac_data.data);
 	return code;
 }
 
@@ -332,8 +319,7 @@ krb5_error_code kdb_samba_db_sign_auth_data(krb5_context context,
 	is_as_req = ((flags & KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY) != 0);
 
 	if (is_as_req && (flags & KRB5_KDB_FLAG_INCLUDE_PAC)) {
-
-		code = ks_get_pac(context, client, &pac);
+		code = ks_get_pac(context, client, client_key, &pac);
 		if (code != 0) {
 			goto done;
 		}
@@ -350,7 +336,7 @@ krb5_error_code kdb_samba_db_sign_auth_data(krb5_context context,
 
 	if (pac == NULL && client != NULL) {
 
-		code = ks_get_pac(context, client, &pac);
+		code = ks_get_pac(context, client, client_key, &pac);
 		if (code != 0) {
 			goto done;
 		}
-- 
2.12.2


From 39ec398ed1fe7b57ce51fda4eb1783fdc5063abb Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Thu, 26 Jan 2017 17:04:19 +0100
Subject: [PATCH 46/51] mit-samba: Remove unused mit_samba_get_pac_data()

Signed-off-by: Andreas Schneider <asn at samba.org>
---
 source4/kdc/mit_samba.c | 35 -----------------------------------
 source4/kdc/mit_samba.h |  4 ----
 2 files changed, 39 deletions(-)

diff --git a/source4/kdc/mit_samba.c b/source4/kdc/mit_samba.c
index 275a507e86e..82a6dfddbe1 100644
--- a/source4/kdc/mit_samba.c
+++ b/source4/kdc/mit_samba.c
@@ -331,41 +331,6 @@ int mit_samba_get_nextkey(struct mit_samba_context *ctx,
 	return ret;
 }
 
-int mit_samba_get_pac_data(struct mit_samba_context *ctx,
-			   krb5_db_entry *client,
-			   DATA_BLOB *data)
-{
-	TALLOC_CTX *tmp_ctx;
-	DATA_BLOB *pac_blob;
-	NTSTATUS nt_status;
-	struct samba_kdc_entry *skdc_entry;
-
-	skdc_entry = talloc_get_type_abort(client->e_data,
-					   struct samba_kdc_entry);
-
-	tmp_ctx = talloc_named(ctx, 0, "mit_samba_get_pac_data context");
-	if (!tmp_ctx) {
-		return ENOMEM;
-	}
-
-	nt_status = samba_kdc_get_pac_blob(tmp_ctx, skdc_entry, &pac_blob);
-	if (!NT_STATUS_IS_OK(nt_status)) {
-		talloc_free(tmp_ctx);
-		return EINVAL;
-	}
-
-	data->data = (uint8_t *)malloc(pac_blob->length);
-	if (!data->data) {
-		talloc_free(tmp_ctx);
-		return ENOMEM;
-	}
-	memcpy(data->data, pac_blob->data, pac_blob->length);
-	data->length = pac_blob->length;
-
-	talloc_free(tmp_ctx);
-	return 0;
-}
-
 int mit_samba_get_pac(struct mit_samba_context *smb_ctx,
 		      krb5_context context,
 		      krb5_db_entry *client,
diff --git a/source4/kdc/mit_samba.h b/source4/kdc/mit_samba.h
index 5be77958dc4..37e7d8d5126 100644
--- a/source4/kdc/mit_samba.h
+++ b/source4/kdc/mit_samba.h
@@ -47,10 +47,6 @@ int mit_samba_get_firstkey(struct mit_samba_context *ctx,
 int mit_samba_get_nextkey(struct mit_samba_context *ctx,
 			  krb5_db_entry **_kentry);
 
-int mit_samba_get_pac_data(struct mit_samba_context *ctx,
-			   krb5_db_entry *client,
-			   DATA_BLOB *data);
-
 int mit_samba_get_pac(struct mit_samba_context *smb_ctx,
 		      krb5_context context,
 		      krb5_db_entry *client,
-- 
2.12.2


From 458f5c06bf9765813357730f9863ed65ba324473 Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Thu, 29 Sep 2016 08:38:58 +0200
Subject: [PATCH 47/51] s4-pac-glue: Do not add an empty PAC_TYPE_LOGON_NAME
 with MIT

MIT Kerberos will insert an empty PAC_TYPE_LOGON_NAME during
krb5_pac_sign().

Signed-off-by: Andreas Schneider <asn at samba.org>
---
 source4/kdc/pac-glue.c | 13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)

diff --git a/source4/kdc/pac-glue.c b/source4/kdc/pac-glue.c
index 079030ee5e8..1a862e2a8a3 100644
--- a/source4/kdc/pac-glue.c
+++ b/source4/kdc/pac-glue.c
@@ -420,10 +420,13 @@ krb5_error_code samba_make_krb5_pac(krb5_context context,
 	krb5_data cred_data;
 	krb5_data upn_data;
 	krb5_data deleg_data;
-	krb5_data null_data;
 	krb5_error_code ret;
-
-	ZERO_STRUCT(null_data);
+#ifdef SAMBA4_USES_HEIMDAL
+	krb5_data null_data = {
+		.length = 0,
+		.data = NULL,
+	};
+#endif
 
 	/* The user account may be set not to want the PAC */
 	if (logon_blob == NULL) {
@@ -503,10 +506,13 @@ krb5_error_code samba_make_krb5_pac(krb5_context context,
 		}
 	}
 
+#ifdef SAMBA4_USES_HEIMDAL
 	/*
 	 * null_data will be filled by the generic KDC code in the caller
 	 * here we just add it in order to have it before
 	 * PAC_TYPE_UPN_DNS_INFO
+	 *
+	 * Not needed with MIT Kerberos - asn
 	 */
 	ret = krb5_pac_add_buffer(context, *pac,
 				  PAC_TYPE_LOGON_NAME,
@@ -516,6 +522,7 @@ krb5_error_code samba_make_krb5_pac(krb5_context context,
 		smb_krb5_free_data_contents(context, &deleg_data);
 		return ret;
 	}
+#endif
 
 	if (upn_blob != NULL) {
 		ret = krb5_pac_add_buffer(context, *pac,
-- 
2.12.2


From c17952c89dfd436b45bb369c17f31156ce431ae7 Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Fri, 30 Sep 2016 07:43:31 +0200
Subject: [PATCH 48/51] s4-kdc: Implement mit_samba_get_repac()

Signed-off-by: Andreas Schneider <asn at samba.org>
---
 source4/kdc/mit_samba.c | 382 ++++++++++++++++++++++++++++++++++++++++++++++++
 source4/kdc/mit_samba.h |  10 ++
 2 files changed, 392 insertions(+)

diff --git a/source4/kdc/mit_samba.c b/source4/kdc/mit_samba.c
index 82a6dfddbe1..9e605f05506 100644
--- a/source4/kdc/mit_samba.c
+++ b/source4/kdc/mit_samba.c
@@ -30,6 +30,7 @@
 #include "kdc/sdb.h"
 #include "kdc/sdb_kdb.h"
 #include "auth/kerberos/kerberos.h"
+#include "auth/kerberos/pac_utils.h"
 #include "kdc/samba_kdc.h"
 #include "kdc/pac-glue.h"
 #include "kdc/db-glue.h"
@@ -468,6 +469,387 @@ done:
 	return ret;
 }
 
+int mit_samba_reget_pac(struct mit_samba_context *ctx,
+			krb5_context context,
+			int flags,
+			krb5_const_principal client_principal,
+			krb5_db_entry *client,
+			krb5_db_entry *server,
+			krb5_db_entry *krbtgt,
+			krb5_keyblock *krbtgt_keyblock,
+			krb5_pac *pac)
+{
+	TALLOC_CTX *tmp_ctx;
+	krb5_error_code code;
+	NTSTATUS nt_status;
+	DATA_BLOB *pac_blob = NULL;
+	DATA_BLOB *upn_blob = NULL;
+	DATA_BLOB *deleg_blob = NULL;
+	struct samba_kdc_entry *client_skdc_entry = NULL;
+	struct samba_kdc_entry *krbtgt_skdc_entry;
+	bool is_in_db = false;
+	bool is_untrusted = false;
+	size_t num_types = 0;
+	uint32_t *types = NULL;
+	uint32_t forced_next_type = 0;
+	size_t i = 0;
+	ssize_t logon_info_idx = -1;
+	ssize_t delegation_idx = -1;
+	ssize_t logon_name_idx = -1;
+	ssize_t upn_dns_info_idx = -1;
+	ssize_t srv_checksum_idx = -1;
+	ssize_t kdc_checksum_idx = -1;
+	krb5_pac new_pac = NULL;
+	bool ok;
+
+	if (client != NULL) {
+		client_skdc_entry =
+			talloc_get_type_abort(client->e_data,
+					      struct samba_kdc_entry);
+
+		/* The user account may be set not to want the PAC */
+		ok = samba_princ_needs_pac(client_skdc_entry);
+		if (!ok) {
+			return EINVAL;
+		}
+	}
+
+	if (krbtgt == NULL) {
+		return EINVAL;
+	}
+	krbtgt_skdc_entry =
+		talloc_get_type_abort(krbtgt->e_data,
+				      struct samba_kdc_entry);
+
+	tmp_ctx = talloc_named(ctx, 0, "mit_samba_reget_pac context");
+	if (!tmp_ctx) {
+		return ENOMEM;
+	}
+
+	code = samba_krbtgt_is_in_db(krbtgt_skdc_entry,
+				     &is_in_db,
+				     &is_untrusted);
+	if (code != 0) {
+		goto done;
+	}
+
+	if (is_untrusted) {
+		if (client == NULL) {
+			return KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
+		}
+
+		nt_status = samba_kdc_get_pac_blobs(tmp_ctx,
+						    client_skdc_entry,
+						    &pac_blob,
+						    NULL,
+						    &upn_blob);
+		if (!NT_STATUS_IS_OK(nt_status)) {
+			code = EINVAL;
+			goto done;
+		}
+	} else {
+		struct PAC_SIGNATURE_DATA *pac_srv_sig;
+		struct PAC_SIGNATURE_DATA *pac_kdc_sig;
+
+		pac_blob = talloc_zero(tmp_ctx, DATA_BLOB);
+		if (pac_blob == NULL) {
+			code = ENOMEM;
+			goto done;
+		}
+
+		pac_srv_sig = talloc_zero(tmp_ctx, struct PAC_SIGNATURE_DATA);
+		if (pac_srv_sig == NULL) {
+			code = ENOMEM;
+			goto done;
+		}
+
+		pac_kdc_sig = talloc_zero(tmp_ctx, struct PAC_SIGNATURE_DATA);
+		if (pac_kdc_sig == NULL) {
+			code = ENOMEM;
+			goto done;
+		}
+
+		nt_status = samba_kdc_update_pac_blob(tmp_ctx,
+						      context,
+						      *pac,
+						      pac_blob,
+						      pac_srv_sig,
+						      pac_kdc_sig);
+		if (!NT_STATUS_IS_OK(nt_status)) {
+			DEBUG(0, ("Update PAC blob failed: %s\n",
+				  nt_errstr(nt_status)));
+			code = EINVAL;
+			goto done;
+		}
+
+		if (is_in_db) {
+			/*
+			 * Now check the KDC signature, fetching the correct
+			 * key based on the enc type.
+			 */
+			code = check_pac_checksum(pac_srv_sig->signature,
+						  pac_kdc_sig,
+						  context,
+						  krbtgt_keyblock);
+			if (code != 0) {
+				DBG_INFO("PAC KDC signature failed to verify\n");
+				goto done;
+			}
+		}
+	}
+
+	if (flags & KRB5_KDB_FLAG_CONSTRAINED_DELEGATION) {
+		deleg_blob = talloc_zero(tmp_ctx, DATA_BLOB);
+		if (deleg_blob == NULL) {
+			code = ENOMEM;
+			goto done;
+		}
+
+		nt_status = samba_kdc_update_delegation_info_blob(tmp_ctx,
+								  context,
+								  *pac,
+								  server->princ,
+								  discard_const(client_principal),
+								  deleg_blob);
+		if (!NT_STATUS_IS_OK(nt_status)) {
+			DEBUG(0, ("Update delegation info failed: %s\n",
+				  nt_errstr(nt_status)));
+			code = EINVAL;
+			goto done;
+		}
+	}
+
+	/* Check the types of the given PAC */
+	code = krb5_pac_get_types(context, *pac, &num_types, &types);
+	if (code != 0) {
+		goto done;
+	}
+
+	for (i = 0; i < num_types; i++) {
+		switch (types[i]) {
+		case PAC_TYPE_LOGON_INFO:
+			if (logon_info_idx != -1) {
+				DBG_WARNING("logon type[%u] twice [%zd] and [%zu]: \n",
+					    types[i],
+					    logon_info_idx,
+					    i);
+				SAFE_FREE(types);
+				code = EINVAL;
+				goto done;
+			}
+			logon_info_idx = i;
+			break;
+		case PAC_TYPE_CONSTRAINED_DELEGATION:
+			if (delegation_idx != -1) {
+				DBG_WARNING("logon type[%u] twice [%zd] and [%zu]: \n",
+					    types[i],
+					    delegation_idx,
+					    i);
+				SAFE_FREE(types);
+				code = EINVAL;
+				goto done;
+			}
+			delegation_idx = i;
+			break;
+		case PAC_TYPE_LOGON_NAME:
+			if (logon_name_idx != -1) {
+				DBG_WARNING("logon type[%u] twice [%zd] and [%zu]: \n",
+					    types[i],
+					    logon_name_idx,
+					    i);
+				SAFE_FREE(types);
+				code = EINVAL;
+				goto done;
+			}
+			logon_name_idx = i;
+			break;
+		case PAC_TYPE_UPN_DNS_INFO:
+			if (upn_dns_info_idx != -1) {
+				DBG_WARNING("logon type[%u] twice [%zd] and [%zu]: \n",
+					    types[i],
+					    upn_dns_info_idx,
+					    i);
+				SAFE_FREE(types);
+				code = EINVAL;
+				goto done;
+			}
+			upn_dns_info_idx = i;
+			break;
+		case PAC_TYPE_SRV_CHECKSUM:
+			if (srv_checksum_idx != -1) {
+				DBG_WARNING("logon type[%u] twice [%zd] and [%zu]: \n",
+					    types[i],
+					    srv_checksum_idx,
+					    i);
+				SAFE_FREE(types);
+				code = EINVAL;
+				goto done;
+			}
+			srv_checksum_idx = i;
+			break;
+		case PAC_TYPE_KDC_CHECKSUM:
+			if (kdc_checksum_idx != -1) {
+				DBG_WARNING("logon type[%u] twice [%zd] and [%zu]: \n",
+					    types[i],
+					    kdc_checksum_idx,
+					    i);
+				SAFE_FREE(types);
+				code = EINVAL;
+				goto done;
+			}
+			kdc_checksum_idx = i;
+			break;
+		default:
+			continue;
+		}
+	}
+
+	if (logon_info_idx == -1) {
+		DEBUG(1, ("PAC_TYPE_LOGON_INFO missing\n"));
+		SAFE_FREE(types);
+		code = EINVAL;
+		goto done;
+	}
+	if (logon_name_idx == -1) {
+		DEBUG(1, ("PAC_TYPE_LOGON_NAME missing\n"));
+		SAFE_FREE(types);
+		code = EINVAL;
+		goto done;
+	}
+	if (srv_checksum_idx == -1) {
+		DEBUG(1, ("PAC_TYPE_SRV_CHECKSUM missing\n"));
+		SAFE_FREE(types);
+		code = EINVAL;
+		goto done;
+	}
+	if (kdc_checksum_idx == -1) {
+		DEBUG(1, ("PAC_TYPE_KDC_CHECKSUM missing\n"));
+		SAFE_FREE(types);
+		code = EINVAL;
+		goto done;
+	}
+
+	/* Build an updated PAC */
+	code = krb5_pac_init(context, &new_pac);
+	if (code != 0) {
+		SAFE_FREE(types);
+		goto done;
+	}
+
+	for (i = 0;;) {
+		krb5_data type_data;
+		DATA_BLOB type_blob = data_blob_null;
+		uint32_t type;
+
+		if (forced_next_type != 0) {
+			/*
+			 * We need to inject possible missing types
+			 */
+			type = forced_next_type;
+			forced_next_type = 0;
+		} else if (i < num_types) {
+			type = types[i];
+			i++;
+		} else {
+			break;
+		}
+
+		switch (type) {
+		case PAC_TYPE_LOGON_INFO:
+			type_blob = *pac_blob;
+
+			if (delegation_idx == -1 && deleg_blob != NULL) {
+				/* inject CONSTRAINED_DELEGATION behind */
+				forced_next_type = PAC_TYPE_CONSTRAINED_DELEGATION;
+			}
+			break;
+		case PAC_TYPE_CONSTRAINED_DELEGATION:
+			if (deleg_blob != NULL) {
+				type_blob = *deleg_blob;
+			}
+			break;
+		case PAC_TYPE_CREDENTIAL_INFO:
+			/*
+			 * Note that we copy the credential blob,
+			 * as it's only usable with the PKINIT based
+			 * AS-REP reply key, it's only available on the
+			 * host which did the AS-REQ/AS-REP exchange.
+			 *
+			 * This matches Windows 2008R2...
+			 */
+			break;
+		case PAC_TYPE_LOGON_NAME:
+			/*
+			 * This is generated in the main KDC code
+			 */
+			continue;
+		case PAC_TYPE_UPN_DNS_INFO:
+			/*
+			 * Replace in the RODC case, otherwise
+			 * upn_blob is NULL and we just copy.
+			 */
+			if (upn_blob != NULL) {
+				type_blob = *upn_blob;
+			}
+			break;
+		case PAC_TYPE_SRV_CHECKSUM:
+			/*
+			 * This is generated in the main KDC code
+			 */
+			continue;
+		case PAC_TYPE_KDC_CHECKSUM:
+			/*
+			 * This is generated in the main KDC code
+			 */
+			continue;
+		default:
+			/* just copy... */
+			break;
+		}
+
+		if (type_blob.length != 0) {
+			code = smb_krb5_copy_data_contents(&type_data,
+							   type_blob.data,
+							   type_blob.length);
+			if (code != 0) {
+				SAFE_FREE(types);
+				krb5_pac_free(context, new_pac);
+				goto done;
+			}
+		} else {
+			code = krb5_pac_get_buffer(context,
+						   *pac,
+						   type,
+						   &type_data);
+			if (code != 0) {
+				SAFE_FREE(types);
+				krb5_pac_free(context, new_pac);
+				goto done;
+			}
+		}
+
+		code = krb5_pac_add_buffer(context,
+					   new_pac,
+					   type,
+					   &type_data);
+		smb_krb5_free_data_contents(context, &type_data);
+		if (code != 0) {
+			SAFE_FREE(types);
+			krb5_pac_free(context, new_pac);
+			goto done;
+		}
+	}
+
+	SAFE_FREE(types);
+
+	/* We now replace the pac */
+	krb5_pac_free(context, *pac);
+	*pac = new_pac;
+done:
+	talloc_free(tmp_ctx);
+	return code;
+}
+
 /* provide header, function is exported but there are no public headers */
 
 krb5_error_code encode_krb5_padata_sequence(krb5_pa_data *const *rep, krb5_data **code);
diff --git a/source4/kdc/mit_samba.h b/source4/kdc/mit_samba.h
index 37e7d8d5126..b74a2d7a971 100644
--- a/source4/kdc/mit_samba.h
+++ b/source4/kdc/mit_samba.h
@@ -53,6 +53,16 @@ int mit_samba_get_pac(struct mit_samba_context *smb_ctx,
 		      krb5_keyblock *client_key,
 		      krb5_pac *pac);
 
+int mit_samba_reget_pac(struct mit_samba_context *ctx,
+			krb5_context context,
+			int flags,
+			krb5_const_principal client_principal,
+			krb5_db_entry *client,
+			krb5_db_entry *server,
+			krb5_db_entry *krbtgt,
+			krb5_keyblock *krbtgt_keyblock,
+			krb5_pac *pac);
+
 int mit_samba_update_pac_data(struct mit_samba_context *ctx,
 			      krb5_db_entry *client,
 			      DATA_BLOB *pac_data,
-- 
2.12.2


From 60567c74dead71d0bbbdf3d26676e46d43c2f908 Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Fri, 30 Sep 2016 07:43:47 +0200
Subject: [PATCH 49/51] s4-kdc: Use mit_samba_reget_pac() in ks_verify_pac()

Signed-off-by: Andreas Schneider <asn at samba.org>
---
 source4/kdc/mit-kdb/kdb_samba_policies.c | 50 +++++++++++++++++---------------
 1 file changed, 27 insertions(+), 23 deletions(-)

diff --git a/source4/kdc/mit-kdb/kdb_samba_policies.c b/source4/kdc/mit-kdb/kdb_samba_policies.c
index 8c3a85b1f1f..81140abfd50 100644
--- a/source4/kdc/mit-kdb/kdb_samba_policies.c
+++ b/source4/kdc/mit-kdb/kdb_samba_policies.c
@@ -182,6 +182,8 @@ static krb5_error_code ks_verify_pac(krb5_context context,
 				     unsigned int flags,
 				     krb5_const_principal client_princ,
 				     krb5_db_entry *client,
+				     krb5_db_entry *server,
+				     krb5_db_entry *krbtgt,
 				     krb5_keyblock *server_key,
 				     krb5_keyblock *krbtgt_key,
 				     krb5_timestamp authtime,
@@ -191,9 +193,7 @@ static krb5_error_code ks_verify_pac(krb5_context context,
 	struct mit_samba_context *mit_ctx;
 	krb5_authdata **authdata = NULL;
 	krb5_pac ipac = NULL;
-	DATA_BLOB pac_data = { NULL, 0 };
 	DATA_BLOB logon_data = { NULL, 0 };
-	krb5_data data;
 	krb5_error_code code;
 
 	mit_ctx = ks_get_context(context);
@@ -257,28 +257,23 @@ static krb5_error_code ks_verify_pac(krb5_context context,
 	}
 
 	/* check and update PAC */
-	pac_data.data = authdata[0]->contents;
-	pac_data.length = authdata[0]->length;
-
-	code = mit_samba_update_pac_data(mit_ctx,
-					 client,
-					 &pac_data,
-					 &logon_data);
-	if (code != 0) {
-		goto done;
-	}
-
-	code = krb5_pac_init(context, pac);
+	code = krb5_pac_parse(context,
+			      authdata[0]->contents,
+			      authdata[0]->length,
+			      pac);
 	if (code != 0) {
 		goto done;
 	}
 
-	data = ks_make_data(logon_data.data, logon_data.length);
-
-	code = krb5_pac_add_buffer(context, *pac, PAC_LOGON_INFO, &data);
-	if (code != 0) {
-		goto done;
-	}
+	code = mit_samba_reget_pac(mit_ctx,
+				   context,
+				   flags,
+				   client_princ,
+				   client,
+				   server,
+				   krbtgt,
+				   krbtgt_key,
+				   pac);
 
 done:
 	krb5_free_authdata(context, authdata);
@@ -326,9 +321,17 @@ krb5_error_code kdb_samba_db_sign_auth_data(krb5_context context,
 	}
 
 	if (!is_as_req) {
-		code = ks_verify_pac(context, flags, ks_client_princ, client,
-				server_key, krbtgt_key, authtime,
-				tgt_auth_data, &pac);
+		code = ks_verify_pac(context,
+				     flags,
+				     ks_client_princ,
+				     client,
+				     server,
+				     krbtgt,
+				     server_key,
+				     krbtgt_key,
+				     authtime,
+				     tgt_auth_data,
+				     &pac);
 		if (code != 0) {
 			goto done;
 		}
@@ -350,6 +353,7 @@ krb5_error_code kdb_samba_db_sign_auth_data(krb5_context context,
 	code = krb5_pac_sign(context, pac, authtime, ks_client_princ,
 			server_key, krbtgt_key, &pac_data);
 	if (code != 0) {
+		DBG_ERR("krb5_pac_sign failed: %d\n", code);
 		goto done;
 	}
 
-- 
2.12.2


From 3d85394ca95dc949b6ea68375bb6cfbee07c9304 Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Thu, 26 Jan 2017 17:07:14 +0100
Subject: [PATCH 50/51] mit-samba: Remove obsolete mit_samba_update_pac_data()

Signed-off-by: Andreas Schneider <asn at samba.org>
---
 source4/kdc/mit_samba.c | 69 -------------------------------------------------
 source4/kdc/mit_samba.h | 10 -------
 2 files changed, 79 deletions(-)

diff --git a/source4/kdc/mit_samba.c b/source4/kdc/mit_samba.c
index 9e605f05506..81189018172 100644
--- a/source4/kdc/mit_samba.c
+++ b/source4/kdc/mit_samba.c
@@ -400,75 +400,6 @@ int mit_samba_get_pac(struct mit_samba_context *smb_ctx,
 	return code;
 }
 
-int mit_samba_update_pac_data(struct mit_samba_context *ctx,
-			      krb5_db_entry *client,
-			      DATA_BLOB *pac_data,
-			      DATA_BLOB *logon_data)
-{
-	TALLOC_CTX *tmp_ctx;
-	DATA_BLOB *logon_blob;
-	krb5_error_code code;
-	NTSTATUS nt_status;
-	krb5_pac pac = NULL;
-	int ret;
-	struct samba_kdc_entry *skdc_entry = NULL;
-
-	if (client) {
-		skdc_entry = talloc_get_type_abort(client->e_data,
-						   struct samba_kdc_entry);
-	}
-
-	/* The user account may be set not to want the PAC */
-	if (client && !samba_princ_needs_pac(skdc_entry)) {
-		return EINVAL;
-	}
-
-	tmp_ctx = talloc_named(ctx, 0, "mit_samba_update_pac_data context");
-	if (!tmp_ctx) {
-		return ENOMEM;
-	}
-
-	logon_blob = talloc_zero(tmp_ctx, DATA_BLOB);
-	if (!logon_blob) {
-		ret = ENOMEM;
-		goto done;
-	}
-
-	code = krb5_pac_parse(ctx->context,
-			      pac_data->data, pac_data->length, &pac);
-	if (code) {
-		ret = EINVAL;
-		goto done;
-	}
-
-	/* TODO: An implementation-specific decision will need to be
-	 * made as to when to check the KDC pac signature, and how to
-	 * untrust untrusted RODCs */
-	nt_status = samba_kdc_update_pac_blob(tmp_ctx, ctx->context,
-					      pac, logon_blob, NULL, NULL);
-	if (!NT_STATUS_IS_OK(nt_status)) {
-		DEBUG(0, ("Building PAC failed: %s\n",
-			  nt_errstr(nt_status)));
-		ret = EINVAL;
-		goto done;
-	}
-
-	logon_data->data = (uint8_t *)malloc(logon_blob->length);
-	if (!logon_data->data) {
-		ret = ENOMEM;
-		goto done;
-	}
-	memcpy(logon_data->data, logon_blob->data, logon_blob->length);
-	logon_data->length = logon_blob->length;
-
-	ret = 0;
-
-done:
-	if (pac) krb5_pac_free(ctx->context, pac);
-	talloc_free(tmp_ctx);
-	return ret;
-}
-
 int mit_samba_reget_pac(struct mit_samba_context *ctx,
 			krb5_context context,
 			int flags,
diff --git a/source4/kdc/mit_samba.h b/source4/kdc/mit_samba.h
index b74a2d7a971..df088491ecb 100644
--- a/source4/kdc/mit_samba.h
+++ b/source4/kdc/mit_samba.h
@@ -63,16 +63,6 @@ int mit_samba_reget_pac(struct mit_samba_context *ctx,
 			krb5_keyblock *krbtgt_keyblock,
 			krb5_pac *pac);
 
-int mit_samba_update_pac_data(struct mit_samba_context *ctx,
-			      krb5_db_entry *client,
-			      DATA_BLOB *pac_data,
-			      DATA_BLOB *logon_data);
-
-int mit_samba_update_pac_data(struct mit_samba_context *ctx,
-			      krb5_db_entry *client,
-			      DATA_BLOB *pac_data,
-			      DATA_BLOB *logon_data);
-
 int mit_samba_check_client_access(struct mit_samba_context *ctx,
 				  krb5_db_entry *client,
 				  const char *client_name,
-- 
2.12.2


From 0e470b404091c821f9f8fb9bce088ff795bf4880 Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Fri, 27 Jan 2017 12:11:33 +0100
Subject: [PATCH 51/51] mit_samba: Fix principal lookup for cross domain
 referral

Pair-Programmed-With: Stefan Metzmacher <metze at samba.org>

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Signed-off-by: Andreas Schneider <asn at samba.org>
---
 source4/kdc/mit_samba.c | 51 +++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 43 insertions(+), 8 deletions(-)

diff --git a/source4/kdc/mit_samba.c b/source4/kdc/mit_samba.c
index 81189018172..677e53330a0 100644
--- a/source4/kdc/mit_samba.c
+++ b/source4/kdc/mit_samba.c
@@ -188,6 +188,7 @@ int mit_samba_get_principal(struct mit_samba_context *ctx,
 	krb5_db_entry *kentry;
 	int ret;
 	int sflags = 0;
+	krb5_principal referral_principal = NULL;
 
 	kentry = calloc(1, sizeof(krb5_db_entry));
 	if (kentry == NULL) {
@@ -217,6 +218,8 @@ int mit_samba_get_principal(struct mit_samba_context *ctx,
 	 * backend and we will fail to parse the entry later */
 	sflags |= SDB_F_ADMIN_DATA;
 
+
+fetch_referral_principal:
 	ret = samba_kdc_fetch(ctx->context, ctx->db_ctx,
 			      principal, sflags, 0, &sentry);
 	switch (ret) {
@@ -225,14 +228,43 @@ int mit_samba_get_principal(struct mit_samba_context *ctx,
 	case SDB_ERR_NOENTRY:
 		ret = KRB5_KDB_NOENTRY;
 		goto done;
-	case SDB_ERR_WRONG_REALM:
-		/*
-		 * If we have a wrong realm e.g. if we try get a cross forest
-		 * ticket, we return a ticket with the correct realm. The KDC
-		 * will detect this an return the appropriate return code.
-		 */
-		ret = 0;
-		break;
+	case SDB_ERR_WRONG_REALM: {
+		char *dest_realm = NULL;
+		const char *our_realm = lpcfg_realm(ctx->db_ctx->lp_ctx);
+
+		if (sflags & SDB_F_FOR_AS_REQ) {
+			ret = 0;
+			break;
+		}
+
+		if (referral_principal != NULL) {
+			sdb_free_entry(&sentry);
+			ret = KRB5_KDB_NOENTRY;
+			goto done;
+		}
+
+		dest_realm = smb_krb5_principal_get_realm(ctx->context,
+							  sentry.entry.principal);
+		sdb_free_entry(&sentry);
+		if (dest_realm == NULL) {
+			ret = KRB5_KDB_NOENTRY;
+			goto done;
+		}
+
+		ret = smb_krb5_make_principal(ctx->context,
+					      &referral_principal,
+					      our_realm,
+					      KRB5_TGS_NAME,
+					      dest_realm,
+					      NULL);
+		SAFE_FREE(dest_realm);
+		if (ret != 0) {
+			goto done;
+		}
+
+		principal = referral_principal;
+		goto fetch_referral_principal;
+	}
 	case SDB_ERR_NOT_FOUND_HERE:
 		/* FIXME: RODC support */
 	default:
@@ -244,6 +276,9 @@ int mit_samba_get_principal(struct mit_samba_context *ctx,
 	sdb_free_entry(&sentry);
 
 done:
+	krb5_free_principal(ctx->context, referral_principal);
+	referral_principal = NULL;
+
 	if (ret) {
 		free(kentry);
 	} else {
-- 
2.12.2



More information about the samba-technical mailing list