[PATCHSET] Samba AD with MIT Kerberos

Andreas Schneider asn at samba.org
Thu Apr 20 14:13:25 UTC 2017


On Wednesday, 19 April 2017 11:26:29 CEST Andrew Bartlett wrote:
> The configure --help output does not explain the changed behaviour, it
> still says:
> 
>   --with-system-mitkrb5
>             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
> 

Fixed, and also changed the test of the --without-ad-dc option. We need to 
stop referring to Samba4 and Samba3 and use Samba AD and Samba FS!

> In this patch, the comment in the code still says 1 second:
> 
> commit 0711cd66419989fb6a22f4a6e7b67855981892c6
> Author: Andreas Schneider <asn at samba.org>
> Date:   Mon Sep 26 18:51:33 2016 +0200
> 
>     selftest: Set clockskew grace time to 5 seconds
>     
>     Signed-off-by: Andreas Schneider <asn at samba.org>
> 
> diff --git a/selftest/target/Samba.pm b/selftest/target/Samba.pm
> index 3e5a7c3..e6f5ef8 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
> 

Fixed.

> 
> When building on MIT 1.14.4 (on my Fedora laptop), I get:
> 
> ERROR: MIT krb5 build requires at least 1.14.4. 1.15.1 is found and
> cannot be used
> ERROR: You may try to build with embedded Heimdal Kerebros by not
> specifying --with-system-mitkrb5

OK, the printed versions are in the wrong order, fixed.

> This is different to master, and is what caused the earlier autobuild
> failure I mentioned on ubuntu 14.04 (in the Catalyst Cloud).  What I
> can't find is which commit changed the AD DC to be on with --with-
> system-mitkrb5.
> 
> Additionally specifying --without-ad-dc doesn't help, and isn't
> suggested in any case.  I think the default for --with-system-mitkrb5
> should be --without-ad-dc for now.

Fixed, we need integer comparsion for versions and not strings.

 def parse_version(v):
-    return tuple(map(str, (v.split("."))))
+    return tuple(map(int, (v.split("."))))

This explains a lot :)

> commit 6e48c4ad9718f3ee6fbf78f7236105f2dfd9bdab
> Author: Andreas Schneider <asn at samba.org>
> Date:   Fri Oct 9 15:06:52 2015 +0200
> 
>     python: Add provisioning support for MIT KDC in samba-tool
>     
>     Signed-off-by: Andreas Schneider <asn at cryptomilk.org>
> In these provision changes, you directly import _glue into domain.py
> and python/samba/provision/kerberos.py.  Instead you should do like
> with_ntvfs_fileserver, and go via samba/__init__.py.
> 
> eg
> python/samba/__init__.py:is_ntvfs_fileserver_built =
> _glue.is_ntvfs_fileserver_built

Fixed.

> It also seems to partially revert:
> 
> commit 04d8e0605f27d1fe57de05a9dba749ce36f7e004
> Author: Andreas Schneider <asn at samba.org>
> Date:   Mon Nov 23 11:44:26 2015 +0100
> 
>     waf: Create kerberos_implementation.py for provisioning
>     
>     Signed-off-by: Andreas Schneider <asn at samba.org>
> 
> We are getting closer, but some details still remain to get this right.
>  I wish you the very best with the last few details.  Otherwise, I hope
> we can find some time to knock this off at SambaXP.

Fixed.

Thanks for the review!


Updated patchset attached.


	Andreas


-- 
Andreas Schneider                   GPG-ID: CC014E3D
Samba Team                             asn at samba.org
www.samba.org
-------------- next part --------------
From dd412e20d675ea236514f5ae9e1eacf5e4058c96 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 0663d89becf6f794096a8485b49752b820c7232d 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 442838ae63b28e0b0f5ec22a019fc1f8697bdcd6 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 ed8c808d7fa62e4af71cd855685559d04485555e 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 f9e835bc5c3..d382758168b 100755
--- a/source4/scripting/bin/samba_dnsupdate
+++ b/source4/scripting/bin/samba_dnsupdate
@@ -662,10 +662,13 @@ if opts.update_cache:
 else:
     dns_update_cache = lp.private_path('dns_update_cache')
 
-# use our private krb5.conf to avoid problems with the wrong domain
-# bind9 nsupdate wants the default domain set
-krb5conf = lp.private_path('krb5.conf')
-os.environ['KRB5_CONFIG'] = krb5conf
+krb5conf = None
+# only change the krb5.conf if we are not in selftest
+if 'SOCKET_WRAPPER_DIR' not in os.environ:
+    # use our private krb5.conf to avoid problems with the wrong domain
+    # bind9 nsupdate wants the default domain set
+    krb5conf = lp.private_path('krb5.conf')
+    os.environ['KRB5_CONFIG'] = krb5conf
 
 file = open(dns_update_list, "r")
 
-- 
2.12.2


From 57f9bfd1fdae5aa7d0af1c51ddd1b9c59b961429 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 c32f6019a0baa4852d3fca906681ce1be6dc547a 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                          |  4 ++--
 wscript_configure_system_mitkrb5 | 27 ++++++++++++++++++---------
 2 files changed, 20 insertions(+), 11 deletions(-)

diff --git a/wscript b/wscript
index de85591223c..a7c4f4c31b9 100644
--- a/wscript
+++ b/wscript
@@ -48,12 +48,12 @@ def set_options(opt):
     opt.samba_add_onoff_option('pthreadpool', with_name="enable", without_name="disable", default=True)
 
     opt.add_option('--with-system-mitkrb5',
-                   help='enable system MIT krb5 build (includes Samba 4 client and Samba 3 code base).'+
+                   help='build Samba with system MIT Kerberos. ' +
                         'You may specify list of paths where Kerberos is installed (e.g. /usr/local /usr/kerberos) to search krb5-config',
                    action='callback', callback=system_mitkrb5_callback, dest='with_system_mitkrb5', default=False)
 
     opt.add_option('--without-ad-dc',
-                   help='disable AD DC functionality (enables Samba 4 client and Samba 3 code base).',
+                   help='disable AD DC functionality (enables only Samba FS (File Server, Winbind, NMBD) and client utilities.',
                    action='store_true', dest='without_ad_dc', default=False)
 
     opt.add_option('--with-ntvfs-fileserver',
diff --git a/wscript_configure_system_mitkrb5 b/wscript_configure_system_mitkrb5
index d3e8ebf0dcd..1aef46af9f1 100644
--- a/wscript_configure_system_mitkrb5
+++ b/wscript_configure_system_mitkrb5
@@ -3,6 +3,14 @@ import Logs, Options, sys
 # Check for kerberos
 have_gssapi=False
 
+# Requried versions
+krb5_required_version = "1.9"
+if conf.CONFIG_SET('AD_DC_BUILD_IS_ENABLED'):
+    krb5_required_version = "1.15.1"
+
+def parse_version(v):
+    return tuple(map(int, (v.split("."))))
+
 def krb5_define_syslib(conf, lib, deps):
     found = 'FOUND_SYSTEMLIB_' + lib
     if found in conf.env:
@@ -44,19 +52,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_required_version, krb5_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 73ce0e0975131cd79cc905ffebeb93978e70ffc5 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 ba1856837fb230200cc0e8ad3eea302eb8ec5303 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 a7c4f4c31b9..032f2ae5fd2 100644
--- a/wscript
+++ b/wscript
@@ -51,6 +51,11 @@ def set_options(opt):
                    help='build Samba with system MIT Kerberos. ' +
                         'You may specify list of paths where Kerberos is installed (e.g. /usr/local /usr/kerberos) to search krb5-config',
                    action='callback', callback=system_mitkrb5_callback, dest='with_system_mitkrb5', default=False)
+    opt.add_option('--with-system-mitkdc',
+                   help=('Specify the path to the krb5kdc binary from MIT Kerberos'),
+                   type="string",
+                   dest='with_system_mitkdc',
+                   default=None)
 
     opt.add_option('--without-ad-dc',
                    help='disable AD DC functionality (enables only Samba FS (File Server, Winbind, NMBD) and client utilities.',
diff --git a/wscript_configure_system_mitkrb5 b/wscript_configure_system_mitkrb5
index 1aef46af9f1..25296e420f6 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 a6969fb49f28899e3b7603afbbd539af9b80d5d7 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 c8a8b6d95c4..860f3e2c96c 100644
--- a/lib/param/loadparm.c
+++ b/lib/param/loadparm.c
@@ -2732,6 +2732,11 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx)
 	lpcfg_do_global_parameter_var(lp_ctx, "spn update command", "%s/samba_spnupdate", dyn_SCRIPTSBINDIR);
 	lpcfg_do_global_parameter_var(lp_ctx, "samba kcc command",
 					"%s/samba_kcc", dyn_SCRIPTSBINDIR);
+#ifdef MIT_KDC_PATH
+	lpcfg_do_global_parameter_var(lp_ctx,
+				      "mit kdc command",
+				      MIT_KDC_PATH);
+#endif
 	lpcfg_do_global_parameter(lp_ctx, "template shell", "/bin/false");
 	lpcfg_do_global_parameter(lp_ctx, "template homedir", "/home/%D/%U");
 
diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c
index 3c597ec2f40..91ecba88ad8 100644
--- a/source3/param/loadparm.c
+++ b/source3/param/loadparm.c
@@ -900,6 +900,10 @@ static void init_globals(struct loadparm_context *lp_ctx, bool reinit_globals)
 	Globals.samba_kcc_command = str_list_make_v3_const(NULL, s, NULL);
 	TALLOC_FREE(s);
 
+#ifdef MIT_KDC_PATH
+	Globals.mit_kdc_command = str_list_make_v3_const(NULL, MIT_KDC_PATH, NULL);
+#endif
+
 	s = talloc_asprintf(talloc_tos(), "%s/samba_dnsupdate", get_dyn_SCRIPTSBINDIR());
 	if (s == NULL) {
 		smb_panic("init_globals: ENOMEM");
-- 
2.12.2


From c6ed81986c89daf12baed312a5c4cf3a7a6773b5 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 8065b158ccc5fb970dd75ea7a9d0158773638427 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 318cb1af093462d8d57003a28e3bd65cdf1bc7a9 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 1b70f56248d9ca11d6fa7ba7ff9139debb830676 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 e0dae22631680b8c9248061ab181369d7eb8987b 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 032f2ae5fd2..57b87850896 100644
--- a/wscript
+++ b/wscript
@@ -190,17 +190,15 @@ def configure(conf):
         if Options.options.with_pam:
             conf.RECURSE('lib/pam_wrapper')
         if Options.options.with_ntvfs_fileserver != False:
-            if not (Options.options.without_ad_dc or Options.options.with_system_mitkrb5):
+            if not (Options.options.without_ad_dc):
                 conf.DEFINE('WITH_NTVFS_FILESERVER', 1)
         if Options.options.with_ntvfs_fileserver == False:
-            if not (Options.options.without_ad_dc or Options.options.with_system_mitkrb5):
+            if not (Options.options.without_ad_dc):
                 raise Utils.WafError('--without-ntvfs-fileserver conflicts with --enable-selftest while building the AD DC')
 
     if Options.options.with_ntvfs_fileserver == True:
         if Options.options.without_ad_dc:
             raise Utils.WafError('--with-ntvfs-fileserver conflicts with --without-ad-dc')
-        if Options.options.with_system_mitkrb5:
-            raise Utils.WafError('--with-ntvfs-fileserver conflicts with --with-system-mitkrb5')
         conf.DEFINE('WITH_NTVFS_FILESERVER', 1)
 
     if Options.options.with_pthreadpool:
-- 
2.12.2


From a56441087253b07e0668bc034b4db2a0ed581111 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 443d6579820d683afa69d72fbe16b04a0eaf1a61 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 e5b313aa30150d39d8617d94c2f1fc3cc3e18b22 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 f614028e18c1bc15a09f4a44d82d3a9241fa2331 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..8b2e4a664b3 100644
--- a/selftest/target/Samba.pm
+++ b/selftest/target/Samba.pm
@@ -201,6 +201,10 @@ sub mk_krb5_conf($$)
  ticket_lifetime = 24h
  forwardable = yes
  allow_weak_crypto = yes
+ # Set the grace clocskew to 5 seconds
+ # This is especially required by samba3.raw.session krb5 and
+ # reauth tests
+ clockskew = 5
 
 ";
 
-- 
2.12.2


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


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


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


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


From cdadb8514849799ad2df0a420cc3a5932295366b 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 766161b66a3b1c74ada64e51006f8edc0691c561 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 | 45 +++++++++++++++++++++++++++++++++++++++++++++
 wscript        |  1 +
 3 files changed, 49 insertions(+)
 create mode 100644 python/wscript

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


From 6dad8360a64104447a5e0388d6bb68f51f7c6a33 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 0a56503828d5cf85bfc70437c363291d62e176b8 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 187d96cd42022636590ab68c978b40ee9d20f373 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/__init__.py           |   1 +
 python/samba/netcmd/domain.py      |  15 +++++-
 python/samba/provision/__init__.py |  18 ++++---
 python/samba/provision/kerberos.py | 101 +++++++++++++++++++++++++++++++++++++
 4 files changed, 128 insertions(+), 7 deletions(-)
 create mode 100644 python/samba/provision/kerberos.py

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


From f9b590d375787c62d4b729ac443204fb2fc7eae1 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 ee54c91a94024d11552bebd2266177ba7ed25807 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 54252d1bbdfa66eb70c4777ec28c91b7244a6ef0 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 53f08e72e89fc29cd016cd8e147a348042923f9a 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 1a68e1636b5d673abce8d0d711db5ab8f6a3d101 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 6ae52d64ddb6dd2d4985e10336d0f76ffcc0b0f9 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 017cb63552acc5c5c6ce4e387837939ee59dba11 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 f69a8f4dfe1c7fe9fa033166c072fa5d6b2316f3 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 ecddf2ea68f522dbc5738fd94a53ca5339024c2e 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 b9c9e56a51e090bc7949a28f8dfd428b0fbb0adc 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 c08c82e430590e391e807021c74e71834c5b20c7 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