[PATCHSET] Samba AD with MIT Kerberos

Andreas Schneider asn at samba.org
Mon Apr 10 05:59:59 UTC 2017


On Friday, 7 April 2017 11:50:21 CEST Andreas Schneider via samba-technical 
wrote:
> > Presumably sn-devel would show likewise, but I try to avoid burning
> > cycles on that box.
> 
> Hi Andrew,
> 
> I run the test.
> 
> Ubuntu 14.04 (same as autobuild)
> master-mit-kdc branch built with Heimdal
> 
> asn at u1404:~/workspace/projects/samba> make -j test
> TESTS="samba4.blackbox.upgradeprovision.alpha13"
> 
> [1(0)/1 at 0s] samba4.blackbox.upgradeprovision.alpha13
> 
> ALL OK (15 tests in 1 testsuites)
> 
> 
> This still looks like a configure/gcc issue on your box ... :-)
> 
> 
> Cheers,
> 
> 	Andreas


Rebased patchset on latest auth subsystem changes attached.


Cheers,


	Andreas

-- 
Andreas Schneider                   GPG-ID: CC014E3D
Samba Team                             asn at samba.org
www.samba.org
-------------- next part --------------
From 88ab3286bef5f2082b3feacc9a9571444c623b55 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/50] 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 5032fb8cfd7f4346a2f285a931d3858e111e7fb2 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/50] 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..4c45b78f774 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 [ ${kase} = "samba4kinit" ]; then
+		kpassfile=$(mktemp)
+		echo $password > ${kpassfile}
+		$kinit_tool --password-file=$PREFIX/tmpuserpassfile $principal $@
+		rm -f ${kpassfile}
+	else
+		echo $password | $kinit_tool $principal $@
+	fi
+}
-- 
2.12.2


From cf3e435ed8c192e99f3ea0d0271188343f7b507a 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/50] 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..853d6be789e 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
+	samba4kinit=${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 5b6297a78145a6d0f190e4ff4a01c261df83c98f 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/50] 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 06877038e1f..ca0ccafe515 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 bf62cab7a5d45445a076dd27ba144a9abd01e803 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/50] 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 610267fc0744b1afcb3d4f0b09a4fdb1b2280144 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/50] 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_configure_system_mitkrb5 | 27 ++++++++++++++++++---------
 1 file changed, 18 insertions(+), 9 deletions(-)

diff --git a/wscript_configure_system_mitkrb5 b/wscript_configure_system_mitkrb5
index d3e8ebf0dcd..1fb28092e54 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(str, (v.split("."))))
+
 def krb5_define_syslib(conf, lib, deps):
     found = 'FOUND_SYSTEMLIB_' + lib
     if found in conf.env:
@@ -44,19 +52,20 @@ 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_version, krb5_required_version))
             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 29a19e1dddd5d47a86c84630030b36ca6ee12dfd 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/50] 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 07886326dd9837ab1ef695f7271a48bc6f120ed4 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/50] 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 3e4a0cdb6d4..44aa602cbc4 100644
--- a/wscript
+++ b/wscript
@@ -51,6 +51,11 @@ def set_options(opt):
                    help='enable system MIT krb5 build (includes Samba 4 client and Samba 3 code base).'+
                         '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 Samba 4 client and Samba 3 code base).',
diff --git a/wscript_configure_system_mitkrb5 b/wscript_configure_system_mitkrb5
index 1fb28092e54..a520238a46b 100644
--- a/wscript_configure_system_mitkrb5
+++ b/wscript_configure_system_mitkrb5
@@ -290,3 +290,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 260caf9f782289828a8714805b204e3333c19989 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/50] 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 cedf8facb8d..910229573a7 100644
--- a/lib/param/loadparm.c
+++ b/lib/param/loadparm.c
@@ -2696,6 +2696,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 57220a64282..484edd4e540 100644
--- a/source3/param/loadparm.c
+++ b/source3/param/loadparm.c
@@ -897,6 +897,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 975e52bd305978ea134718d2ede130629e15869b 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/50] 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..5ac191d3ba0
--- /dev/null
+++ b/source4/kdc/kdc-service-mit.c
@@ -0,0 +1,120 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   run s3 file server within Samba4
+
+   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(void);
+
+NTSTATUS server_service_mitkdc_init(void)
+{
+	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..2c06484705e
--- /dev/null
+++ b/source4/kdc/kdc-service-mit.h
@@ -0,0 +1,27 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   run s3 file server within Samba4
+
+   Copyright (C) Andrew Tridgell	2011
+
+   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 137225e1f40ac40f54f450c906b9ed343726fc5a 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/50] 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 | 190 +++++++++++++++++++++++++++++++++++++++++++++
 source4/kdc/mit_kdc_irpc.h |  20 +++++
 source4/kdc/wscript_build  |  14 ++++
 3 files changed, 224 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..63ae75e578e
--- /dev/null
+++ b/source4/kdc/mit_kdc_irpc.c
@@ -0,0 +1,190 @@
+/*
+ * 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);
+	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 0140ff544a2dc94383a8e9ea67f20ffa2860a20d 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/50] 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 5ac191d3ba0..10b9e5f0e82 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 8823083a24ec32bb68abeb0690fe52bb35cafa32 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/50] 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 10b9e5f0e82..a1cdd3a4471 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 d26644ba36d56ee5336de35e95eb107c25d03160 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/50] 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 44aa602cbc4..0ba46cecb02 100644
--- a/wscript
+++ b/wscript
@@ -183,17 +183,15 @@ def configure(conf):
         conf.RECURSE('lib/socket_wrapper')
         conf.RECURSE('lib/uid_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 f07bdb7c995b2af859fb676405f61d5116cb7846 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/50] 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 a0cc67dfef4e11d530f4926b31a7a6ff0364a392 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/50] 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 79236ecaa68e6fe6211ff939d748dc950aeaab0f 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/50] 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 818d393a826587416b93836d2680cb6f2a231458 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/50] 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..e6f5ef8c0d2 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 1 second
+ # This is especially required by samba3.raw.session krb5 and
+ # reauth tests
+ clockskew = 5
 
 ";
 
-- 
2.12.2


From b4e4277450a66eb73d5dd95a31ed28ee21dca4c3 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/50] 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 50dc9e4c43050ff31380913932688f4cab6f51f0 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/50] 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 81ec270929ec8f4dc8311d9b68faffededfeb0db 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/50] 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 5008026dfbb0ada36a6e056cbfcd2c7dfd1249f3 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/50] 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 953cda606821abee0e662fc97b213bb23ebfc448 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/50] 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 623aca74c41..af1b7eb886c 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 c704aa8014c5544da61ac67b025dbe84529961dd 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/50] 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 af1b7eb886c..07533307e66 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 2365451a53f08cfd7b68dac8a7bce7afb5eefc79 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/50] 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 07533307e66..3410cead9d1 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 a82fa411848b8effc065496a356279b3eed25dd8 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 26/50] 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 88bff0b0ee4..0b2b8651c79 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(void)
 {
 	struct torture_suite *suite =
@@ -46,8 +371,22 @@ NTSTATUS torture_krb5_init(void)
 	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 138c05cbaf25ade5e4b6193a4f92b688b12cefbe 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 27/50] 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 0b2b8651c79..9b7b6eed4fc 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(void)
 {
 	struct torture_suite *suite =
@@ -375,10 +454,13 @@ NTSTATUS torture_krb5_init(void)
 				      "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 590d8db415d4135dbe282d94ae367d164d5f6dde 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 28/50] 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 9b7b6eed4fc..885b6e40f1b 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(void)
 {
 	struct torture_suite *suite =
@@ -460,10 +544,10 @@ NTSTATUS torture_krb5_init(void)
 				      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 5eb8125931a70b1f5ac5e943fa204e007bcec3fe 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 29/50] 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 e6f5ef8c0d2..a5cd8b6aa5f 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 885b6e40f1b..1edaa291689 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(void)
 {
 	struct torture_suite *suite =
@@ -547,10 +604,11 @@ NTSTATUS torture_krb5_init(void)
 	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 809ba25e7285a607bafbed2ad4728e76f886325a 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 30/50] 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 1edaa291689..a4997357c7e 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(void)
 {
 	struct torture_suite *suite =
@@ -611,6 +774,18 @@ NTSTATUS torture_krb5_init(void)
 #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 1fcbf40b6b4196be6d31f575456558a59f8a95c0 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 31/50] 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 359be43768797dce4597eb76b9fed4167353e069 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 32/50] 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 a520238a46b..6f9330deb2a 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 e6dafa29646ea4e7793fd66605916cc765f63e4b 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 33/50] s4-kdc: Start the kpasswd service with MIT KDC

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

diff --git a/source4/kdc/kdc-service-mit.c b/source4/kdc/kdc-service-mit.c
index a1cdd3a4471..780822b7fb0 100644
--- a/source4/kdc/kdc-service-mit.c
+++ b/source4/kdc/kdc-service-mit.c
@@ -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_new(mem_ctx);
+	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 ce323e3b877bfae6c1c1b28d76d04109f1c9e25c 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 34/50] 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 3410cead9d1..a99cd6e7ec9 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 7455d140deb418007895e46a8e572ec3f5f1a6be 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 35/50] 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 e84bda518054d8282c4ac281cfd9a301dac3aa1a 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 36/50] waf: Create kerberos_implementation.py for provisioning

Signed-off-by: Andreas Schneider <asn at samba.org>
---
 .gitignore     |  3 +++
 python/wscript | 46 ++++++++++++++++++++++++++++++++++++++++++++++
 wscript        |  1 +
 3 files changed, 50 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..f85bb6c784a
--- /dev/null
+++ b/python/wscript
@@ -0,0 +1,46 @@
+#!/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 = """krb5_implementation = "{0}"
+kdb_modules_dir = "{1}"
+kdc_default_config_dir = "{2}"
+"""
+
+        if conf.env.HEIMDAL_KRB5_CONFIG:
+            f.write(data.format("HEIMDAL", "", ""))
+        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("MIT", modulesdir, kdc_path))
+    finally:
+        f.close()
diff --git a/wscript b/wscript
index 0ba46cecb02..499c79f14d0 100644
--- a/wscript
+++ b/wscript
@@ -203,6 +203,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 d054dced99b1e92c9801cffd6d47185f225e87f4 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 37/50] 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 ebacc553cc48edc5126a06ccbedfc2178e3d7398 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 38/50] 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 53b0fd0b0cbfc342deeac51031b055b5b021e60d 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 39/50] python: Add provisioning support for MIT KDC in
 samba-tool

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

diff --git a/python/samba/netcmd/domain.py b/python/samba/netcmd/domain.py
index 4bd99ba6ff5..20d0c8cf4be 100644
--- a/python/samba/netcmd/domain.py
+++ b/python/samba/netcmd/domain.py
@@ -33,6 +33,7 @@ import tempfile
 import logging
 import subprocess
 import time
+from samba import _glue
 from samba import ntstatus
 from samba import NTSTATUSError
 from samba import werror
@@ -87,6 +88,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 +267,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 _glue.is_heimdal_built:
+        takes_options.extend(kdc_options)
+
     takes_args = []
 
     def run(self, sambaopts=None, versionopts=None,
@@ -304,6 +316,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 +484,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()
diff --git a/python/wscript b/python/wscript
index f85bb6c784a..714d649219d 100644
--- a/python/wscript
+++ b/python/wscript
@@ -26,13 +26,12 @@ def configure(conf):
 """
         f.write(header)
 
-        data = """krb5_implementation = "{0}"
-kdb_modules_dir = "{1}"
-kdc_default_config_dir = "{2}"
+        data = """kdb_modules_dir = "{0}"
+kdc_default_config_dir = "{1}"
 """
 
         if conf.env.HEIMDAL_KRB5_CONFIG:
-            f.write(data.format("HEIMDAL", "", ""))
+            f.write(data.format("", ""))
         else:
             modulesdir = "%s/krb5/plugins/kdb" % conf.env.LIBDIR
             paths = [ "/var/kerberos/krb5kdc", "/var/lib/kerberos/krb5kdc" ]
@@ -41,6 +40,6 @@ kdc_default_config_dir = "{2}"
                 if os.path.exists(p):
                     kdc_path = p
 
-            f.write(data.format("MIT", modulesdir, kdc_path))
+            f.write(data.format(modulesdir, kdc_path))
     finally:
         f.close()
-- 
2.12.2


From 23ac4b63f6e6bc62d56e2a248187dbc875eb5d4e 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 40/50] 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 ae3c9ceb6577361e006bfc0bf9bf6bcdc0d268ad 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 41/50] 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 d9bb19b4757bb239d0d9cc3e73f2fc6c07518fd4 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 42/50] 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 8b29d07b42bf64cef867878d3881ffcede82c9b3 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 43/50] 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 14030a83324fc3a3b5154c049a994de05465dad0 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 44/50] 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 915632c5a172a05dcd97d094550d46baf22399cb 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 45/50] 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 d3d0c46773baf0dc97ff33faf60437171031559c 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 46/50] 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 197bc3a81a5e744c92dd0ebab10bbd3afd816294 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 47/50] 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 715a26d83f29c211b94832ff3694cf9cbfb93251 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 48/50] 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 1ce8de371eb808f298a132229667a01bd67b81f6 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 49/50] 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 27fc570a5b172a5af65d376bc2f8552a4fd263c4 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 50/50] 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