[PATCH] Implement a more abstracted kpasswd service

Jeremy Allison jra at samba.org
Thu Sep 8 22:26:20 UTC 2016


On Wed, Sep 07, 2016 at 06:02:45PM +0200, Andreas Schneider wrote:
> Hi Andrew,
> 
> I've implemented a working kpasswd service with MIT Kerberos in the meantime. 
> This patchset is the work to cleanup Heimdal code and prepare for later MIT 
> Kerberos code.
> 
> I've started with splitting up the test_passwords.sh test. Now we have a 
> test_password_settings.sh and test_kpasswd_heimdal.sh test.
> 
> The test_kpasswd_heimdal.sh only tests the kpasswd service implementation in 
> different ways. It has some additional tests, like doing a password change 
> with kinit.
> 
> Next I reworked the kpasswd service implementation to be able to share code 
> which is not Kerberos flavor specific.
> 
> The patchset is attached but you can also find it here:
> 
> https://git.samba.org/?p=asn/samba.git;a=shortlog;h=refs/heads/master-kpasswd
> 
> 
> Please review and push if appropriate!

Pushed the first 4 patches as they're obviously correct.

Still looking over the rest !

Cheers,

Jeremy.

> From 114e00019298265090a656a12d3ddfadcbf70059 Mon Sep 17 00:00:00 2001
> From: Andreas Schneider <asn at samba.org>
> Date: Wed, 7 Sep 2016 15:15:00 +0200
> Subject: [PATCH 01/18] util: Fix the documentation of push_utf8_talloc()
> 
> Signed-off-by: Andreas Schneider <asn at samba.org>
> ---
>  lib/util/charset/pull_push.c | 24 ++++++++++++++++--------
>  1 file changed, 16 insertions(+), 8 deletions(-)
> 
> diff --git a/lib/util/charset/pull_push.c b/lib/util/charset/pull_push.c
> index b7a5bcd..cb38471 100644
> --- a/lib/util/charset/pull_push.c
> +++ b/lib/util/charset/pull_push.c
> @@ -46,16 +46,24 @@ bool push_ucs2_talloc(TALLOC_CTX *ctx, smb_ucs2_t **dest, const char *src,
>  }
>  
>  /**
> - * Copy a string from a unix char* src to a UTF-8 destination, allocating a buffer using talloc
> + * @brief Create a UTF-8 string from a unix charset string.
>   *
> - * @param dest always set at least to NULL
> - * @parm converted_size set to the number of bytes occupied by the string in
> - * the destination on success.
> + * The resulting UTF-8 string is talloc'ed.
>   *
> - * @return true if new buffer was correctly allocated, and string was
> - * converted.
> - **/
> -
> + * @param[in]  ctx      The talloc memory context.
> + *
> + * @param[in]  dest     A pointer to store the talloc'ed UTF-8 string.
> + *
> + * @param[in]  src      The unix charset to convert.
> + *
> + * @param[in]  converted_size A pointer to store the length of the talloc'ed
> + *                            UTF-8 string including the nul-termination bytes.
> + *
> + * The destination string should be free'd using talloc_free() if no longer
> + * needed.
> + *
> + * @return True on succcess, false otherwise.
> + */
>  bool push_utf8_talloc(TALLOC_CTX *ctx, char **dest, const char *src,
>  		      size_t *converted_size)
>  {
> -- 
> 2.10.0
> 
> 
> From ce8b32d4b4f911f52b3557a6270a315b363aff00 Mon Sep 17 00:00:00 2001
> From: Andreas Schneider <asn at samba.org>
> Date: Tue, 6 Sep 2016 11:08:04 +0200
> Subject: [PATCH 02/18] dsdb: Do not use free'd memory.
> 
> The msg has already been free'd at this point so we need to print the
> user_dn which gets assigned to msg->dn.
> 
> Signed-off-by: Andreas Schneider <asn at samba.org>
> ---
>  source4/dsdb/common/util.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c
> index 448b20a..d1777b3 100644
> --- a/source4/dsdb/common/util.c
> +++ b/source4/dsdb/common/util.c
> @@ -2339,7 +2339,7 @@ static NTSTATUS samdb_set_password_internal(struct ldb_context *ldb, TALLOC_CTX
>  		status = NT_STATUS_ACCESS_DENIED;
>  	} else if (ret != LDB_SUCCESS) {
>  		DEBUG(1, ("Failed to set password on %s: %s\n",
> -			  ldb_dn_get_linearized(msg->dn),
> +			  ldb_dn_get_linearized(user_dn),
>  			  ldb_errstring(ldb)));
>  		status = NT_STATUS_UNSUCCESSFUL;
>  	}
> -- 
> 2.10.0
> 
> 
> From 57327602cc174d5a321a8f6f423bc831a4e2c23a Mon Sep 17 00:00:00 2001
> From: Andreas Schneider <asn at samba.org>
> Date: Fri, 2 Sep 2016 10:53:41 +0200
> Subject: [PATCH 03/18] Revert "krb5_wrap: Add MIT implmentation of
>  smb_krb5_keyblock_init_contents()"
> 
> This reverts commit c0e861666911d84f2d78cdab370077d9ac192005.
> 
> The krb5_init_keyblock function from MIT allocates the key but we
> operate only on the contents.
> 
> Signed-off-by: Andreas Schneider <asn at samba.org>
> ---
>  lib/krb5_wrap/krb5_samba.c | 16 ----------------
>  1 file changed, 16 deletions(-)
> 
> diff --git a/lib/krb5_wrap/krb5_samba.c b/lib/krb5_wrap/krb5_samba.c
> index 841e3f8..dcd6185 100644
> --- a/lib/krb5_wrap/krb5_samba.c
> +++ b/lib/krb5_wrap/krb5_samba.c
> @@ -1638,22 +1638,6 @@ krb5_error_code smb_krb5_keyblock_init_contents(krb5_context context,
>  {
>  #if defined(HAVE_KRB5_KEYBLOCK_INIT)
>  	return krb5_keyblock_init(context, enctype, data, length, key);
> -#elif defined(HAVE_KRB5_INIT_KEYBLOCK)
> -	krb5_error_code code;
> -
> -	code = krb5_init_keyblock(context,
> -				  enctype,
> -				  length,
> -				  key);
> -	if (code != 0) {
> -		return code;
> -	}
> -
> -	if (length != 0) {
> -		memcpy(KRB5_KEY_DATA(key), data, length);
> -	}
> -
> -	return 0;
>  #else
>  	memset(key, 0, sizeof(krb5_keyblock));
>  	KRB5_KEY_DATA(key) = SMB_MALLOC(length);
> -- 
> 2.10.0
> 
> 
> From 2e7dd98f84f0f31c36ed132b975877e565ecd807 Mon Sep 17 00:00:00 2001
> From: Andreas Schneider <asn at samba.org>
> Date: Tue, 6 Sep 2016 12:09:47 +0200
> Subject: [PATCH 04/18] gensec_krb5: Do not leak memory of target_principal
> 
> CID 1372504
> 
> Signed-off-by: Andreas Schneider <asn at samba.org>
> ---
>  source4/auth/gensec/gensec_krb5.c | 7 ++++---
>  1 file changed, 4 insertions(+), 3 deletions(-)
> 
> diff --git a/source4/auth/gensec/gensec_krb5.c b/source4/auth/gensec/gensec_krb5.c
> index 404ffaf..1dcbb91 100644
> --- a/source4/auth/gensec/gensec_krb5.c
> +++ b/source4/auth/gensec/gensec_krb5.c
> @@ -339,12 +339,16 @@ static NTSTATUS gensec_krb5_common_client_creds(struct gensec_security *gensec_s
>  						    ccache_container->ccache,
>  						    &this_cred.client);
>  			if (ret != 0) {
> +				krb5_free_principal(gensec_krb5_state->smb_krb5_context->krb5_context,
> +						    target_principal);
>  				return NT_STATUS_UNSUCCESSFUL;
>  			}
>  
>  			ret = krb5_copy_principal(gensec_krb5_state->smb_krb5_context->krb5_context,
>  						  target_principal,
>  						  &this_cred.server);
> +			krb5_free_principal(gensec_krb5_state->smb_krb5_context->krb5_context,
> +					    target_principal);
>  			if (ret != 0) {
>  				krb5_free_cred_contents(gensec_krb5_state->smb_krb5_context->krb5_context,
>  							&this_cred);
> @@ -369,9 +373,6 @@ static NTSTATUS gensec_krb5_common_client_creds(struct gensec_security *gensec_s
>  						   in_data_p,
>  						   cred,
>  						   &gensec_krb5_state->enc_ticket);
> -
> -			krb5_free_principal(gensec_krb5_state->smb_krb5_context->krb5_context, 
> -					    target_principal);
>  		}
>  	} else {
>  		ret = krb5_mk_req(gensec_krb5_state->smb_krb5_context->krb5_context, 
> -- 
> 2.10.0
> 
> 
> From dcf520c4294819005c0fa18c73edb31499b6a933 Mon Sep 17 00:00:00 2001
> From: Andreas Schneider <asn at samba.org>
> Date: Wed, 7 Sep 2016 17:17:08 +0200
> Subject: [PATCH 05/18] heimdal: Fix reauthentication after password change
> 
> If the KDC requires a password change kinit will ask after the initial
> authentication for a new password. After the password has been changed
> it does reauthentication and for that it needs to use the new password
> we just set.
> 
> It is needed for the a new kpasswd service test.
> 
> This is already fixed upstream with:
>     911c99375741281adae305f6ec3a3317023eba3e
> 
> Signed-off-by: Andreas Schneider <asn at samba.org>
> ---
>  source4/heimdal/lib/krb5/init_creds_pw.c | 7 ++++---
>  1 file changed, 4 insertions(+), 3 deletions(-)
> 
> diff --git a/source4/heimdal/lib/krb5/init_creds_pw.c b/source4/heimdal/lib/krb5/init_creds_pw.c
> index b6c0a64..a66ad35 100644
> --- a/source4/heimdal/lib/krb5/init_creds_pw.c
> +++ b/source4/heimdal/lib/krb5/init_creds_pw.c
> @@ -1990,6 +1990,7 @@ krb5_get_init_creds_password(krb5_context context,
>  {
>      krb5_init_creds_context ctx;
>      char buf[BUFSIZ];
> +    char buf2[BUFSIZ];
>      krb5_error_code ret;
>      int chpw = 0;
>  
> @@ -2041,8 +2042,6 @@ krb5_get_init_creds_password(krb5_context context,
>  
>  
>      if (ret == KRB5KDC_ERR_KEY_EXPIRED && chpw == 0) {
> -	char buf2[1024];
> -
>  	/* try to avoid recursion */
>  	if (in_tkt_service != NULL && strcmp(in_tkt_service, "kadmin/changepw") == 0)
>  	   goto out;
> @@ -2055,13 +2054,14 @@ krb5_get_init_creds_password(krb5_context context,
>  			       client,
>  			       ctx->password,
>  			       buf2,
> -			       sizeof(buf),
> +			       sizeof(buf2),
>  			       prompter,
>  			       data,
>  			       options);
>  	if (ret)
>  	    goto out;
>  	chpw = 1;
> +	password = buf2;
>  	krb5_init_creds_free(context, ctx);
>  	goto again;
>      }
> @@ -2074,6 +2074,7 @@ krb5_get_init_creds_password(krb5_context context,
>  	krb5_init_creds_free(context, ctx);
>  
>      memset(buf, 0, sizeof(buf));
> +    memset(buf2, 0, sizeof(buf2));
>      return ret;
>  }
>  
> -- 
> 2.10.0
> 
> 
> From c6725c983fadfec91f9e1aa825649b7ad8caa276 Mon Sep 17 00:00:00 2001
> From: Andreas Schneider <asn at samba.org>
> Date: Tue, 6 Sep 2016 08:56:47 +0200
> Subject: [PATCH 06/18] testprogs: Add a common test_smbclient_expect_failure()
>  function
> 
> Signed-off-by: Andreas Schneider <asn at samba.org>
> ---
>  testprogs/blackbox/common_test_fns.inc | 18 ++++++++++++++++++
>  1 file changed, 18 insertions(+)
> 
> diff --git a/testprogs/blackbox/common_test_fns.inc b/testprogs/blackbox/common_test_fns.inc
> index ef21834..aff1aa9 100755
> --- a/testprogs/blackbox/common_test_fns.inc
> +++ b/testprogs/blackbox/common_test_fns.inc
> @@ -18,3 +18,21 @@ test_smbclient() {
>  	fi
>  	return $status
>  }
> +
> +test_smbclient_expect_failure() {
> +	name="$1"
> +	cmd="$2"
> +	unc="$3"
> +	shift
> +	shift
> +	shift
> +	echo "test: $name"
> +	$VALGRIND $smbclient $CONFIGURATION "$unc" -c "$cmd" $@
> +	status=$?
> +	if [ x$status = x0 ]; then
> +		echo "failure: $name"
> +	else
> +		echo "success: $name"
> +	fi
> +	return $status
> +}
> -- 
> 2.10.0
> 
> 
> From aff4324a39605a4fa87252cdb8a4ac89a091ba4f Mon Sep 17 00:00:00 2001
> From: Andreas Schneider <asn at samba.org>
> Date: Tue, 6 Sep 2016 08:55:43 +0200
> Subject: [PATCH 07/18] testprogs: Add a new test_password_settings.sh script
> 
> This test is not Kerberos implementation specific.
> 
> Signed-off-by: Andreas Schneider <asn at samba.org>
> ---
>  source4/selftest/tests.py                    |   1 +
>  testprogs/blackbox/test_password_settings.sh | 211 +++++++++++++++++++++++++++
>  2 files changed, 212 insertions(+)
>  create mode 100755 testprogs/blackbox/test_password_settings.sh
> 
> diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py
> index 2619ecc..037910d 100755
> --- a/source4/selftest/tests.py
> +++ b/source4/selftest/tests.py
> @@ -397,6 +397,7 @@ if have_heimdal_support:
>  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'])
> +plantestsuite("samba4.blackbox.password_settings(ad_dc_ntvfs:local)", "ad_dc_ntvfs:local", [os.path.join(bbdir, "test_password_settings.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', "$PREFIX/ad_dc_ntvfs"])
>  plantestsuite("samba4.blackbox.passwords(ad_dc_ntvfs:local)", "ad_dc_ntvfs:local", [os.path.join(bbdir, "test_passwords.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', "$PREFIX/ad_dc_ntvfs", smbclient4])
>  plantestsuite("samba4.blackbox.cifsdd(ad_dc_ntvfs)", "ad_dc_ntvfs", [os.path.join(samba4srcdir, "client/tests/test_cifsdd.sh"), '$SERVER', '$USERNAME', '$PASSWORD', "$DOMAIN"])
>  plantestsuite("samba4.blackbox.nmblookup(ad_dc_ntvfs)", "ad_dc_ntvfs", [os.path.join(samba4srcdir, "utils/tests/test_nmblookup.sh"), '$NETBIOSNAME', '$NETBIOSALIAS', '$SERVER', '$SERVER_IP', nmblookup4])
> diff --git a/testprogs/blackbox/test_password_settings.sh b/testprogs/blackbox/test_password_settings.sh
> new file mode 100755
> index 0000000..13b7d1b
> --- /dev/null
> +++ b/testprogs/blackbox/test_password_settings.sh
> @@ -0,0 +1,211 @@
> +#!/bin/sh
> +# Blackbox tests for different password settings
> +#
> +# 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_passwords_settings.sh SERVER USERNAME PASSWORD REALM DOMAIN PREFIX
> +EOF
> +exit 1;
> +fi
> +
> +SERVER=$1
> +USERNAME=$2
> +PASSWORD=$3
> +REALM=$4
> +DOMAIN=$5
> +PREFIX=$6
> +shift 7
> +failed=0
> +
> +samba_bindir="$BINDIR"
> +
> +samba_kinit=kinit
> +if test -x $samba_bindir/samba4kinit; then
> +	samba_kinit=$samba_bindir/samba4kinit
> +fi
> +
> +smbclient="$samba_bindir/smbclient"
> +samba_tool="$samba_bindir/samba-tool"
> +smbpasswd="$samba_bindir/smbpasswd"
> +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
> +	if test -x $samba_bindir/samba4kinit; then
> +		echo $password > $PREFIX/tmpuserpassfile
> +		$samba_kinit --password-file=$PREFIX/tmpuserpassfile $principal $@
> +	else
> +		echo $password | $samba_kinit $principal $@
> +	fi
> +}
> +
> +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="$(mktemp -u alice-XXXXXX)"
> +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`
> +
> +###########################################################
> +### Test normal operation as user
> +###########################################################
> +
> +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`
> +
> +###########################################################
> +### Change the users password
> +###########################################################
> +
> +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`
> +
> +#
> +# These tests demonstrate that a credential cache in the environment does not
> +# override a username/password, even an incorrect one, on the command line
> +#
> +
> +testit_expect_failure "Test login with user kerberos ccache, but wrong password specified" \
> +	$VALGRIND $smbclient //$SERVER/tmp -c 'ls' -k yes -U$TEST_PRINCIPAL%invalidpass && failed=`expr $failed + 1`
> +testit_expect_failure "Test login with user kerberos ccache, but old password specified" \
> +	$VALGRIND $smbclient //$SERVER/tmp -c 'ls' -k yes -U$TEST_PRINCIPAL%$TEST_PASSWORD_OLD && failed=`expr $failed + 1`
> +
> +###########################################################
> +### Set the password with smbpasswd
> +###########################################################
> +
> +cat > $PREFIX/tmpsmbpasswdscript <<EOF
> +expect New SMB password:
> +send ${TEST_PASSWORD_NEW}\n
> +expect Retype new SMB password:
> +send ${TEST_PASSWORD_NEW}\n
> +EOF
> +
> +testit "set user password with smbpasswd" \
> +	$texpect $PREFIX/tmpsmbpasswdscript $smbpasswd -L -c $PREFIX/etc/smb.conf $TEST_USERNAME || failed=`expr $failed + 1`
> +
> +TEST_PASSWORD=$TEST_PASSWORD_NEW
> +TEST_PASSWORD_NEW="testPaSS at 03%"
> +
> +test_smbclient "Test login with user (ntlm)" \
> +	"ls" "$SMB_UNC" -k no -U$TEST_PRINCIPAL%$TEST_PASSWORD || failed=`expr $failed + 1`
> +
> +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%"
> +
> +test_smbclient_expect_failure "Test login with user (NT_STATUS_PASSWORD_MUST_CHANGE)" \
> +	"ls" "$SMB_UNC" -k no -U$TEST_PRINCIPAL%$TEST_PASSWORD && failed=`expr $failed + 1`
> +
> +testit "change user password with 'samba-tool user password' (after must change flag set)" \
> +	$VALGRIND $samba_tool user password -W$DOMAIN -U$DOMAIN/$TEST_USERNAME%$TEST_PASSWORD -k no --newpassword=$TEST_PASSWORD_NEW || 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`
> +
> +cat > $PREFIX/tmpsmbpasswdscript <<EOF
> +expect Old SMB password:
> +password ${TEST_PASSWORD}\n
> +expect New SMB password:
> +send ${TEST_PASSWORD_NEW}\n
> +expect Retype new SMB password:
> +send ${TEST_PASSWORD_NEW}\n
> +EOF
> +
> +testit "change user password with smbpasswd (after must change flag set)" \
> +	$texpect $PREFIX/tmpsmbpasswdscript $smbpasswd -r $SERVER  -c $PREFIX/etc/smb.conf -U $TEST_USERNAME || failed=`expr $failed + 1`
> +
> +TEST_PASSWORD=$TEST_PASSWORD_NEW
> +TEST_PASSWORD_NEW="testPaSS at 06%"
> +
> +test_smbclient "Test login with user kerberos" \
> +	"ls" "$SMB_UNC" -k yes -U$TEST_PRINCIPAL%$TEST_PASSWORD || failed=`expr $failed + 1`
> +
> +testit_expect_failure "try to set a non-complex password (command should not succeed)" \
> +	$VALGRIND $samba_tool user password -W$DOMAIN "-U$DOMAIN/$TEST_USERNAME%$TEST_PASSWORD" -k no --newpassword="$TEST_PASSWORD_WEAK" && failed=`expr $failed + 1`
> +
> +testit "allow non-complex passwords" \
> +	$VALGRIND $samba_tool domain passwordsettings set $CONFIG --complexity=off || failed=`expr $failed + 1`
> +
> +testit "try to set a non-complex password (command should succeed)" \
> +	$VALGRIND $samba_tool user password -W$DOMAIN "-U$DOMAIN/$TEST_USERNAME%$TEST_PASSWORD" -k no --newpassword="$TEST_PASSWORD_WEAK" || failed=`expr $failed + 1`
> +
> +TEST_PASSWORD=$TEST_PASSWORD_WEAK
> +
> +test_smbclient "test login with non-complex password" \
> +	"ls" "$SMB_UNC" -k no -U$TEST_PRINCIPAL%$TEST_PASSWORD || failed=`expr $failed + 1`
> +
> +testit_expect_failure "try to set a short password (command should not succeed)" \
> +	$VALGRIND $samba_tool user password -W$DOMAIN "-U$DOMAIN/$TEST_USERNAME%$TEST_PASSWORD" -k no --newpassword="$TEST_PASSWORD_SHORT" && failed=`expr $failed + 1`
> +
> +testit "allow short passwords (length 1)" \
> +	$VALGRIND $samba_tool domain passwordsettings $CONFIG set --min-pwd-length=1 || failed=`expr $failed + 1`
> +
> +testit "try to set a short password (command should succeed)" \
> +	$VALGRIND $samba_tool user password -W$DOMAIN "-U$DOMAIN/$TEST_USERNAME%$TEST_PASSWORD" -k no --newpassword="$TEST_PASSWORD_SHORT" || failed=`expr $failed + 1`
> +
> +TEST_PASSWORD=$TEST_PASSWORD_SHORT
> +TEST_PASSWORD_NEW="testPaSS at 07%"
> +
> +testit "require minimum password age of 1 day" \
> +	$VALGRIND $samba_tool domain passwordsettings $CONFIG set --min-pwd-age=1 || failed=`expr $failed + 1`
> +
> +testit "show password settings" \
> +	$VALGRIND $samba_tool domain passwordsettings $CONFIG show || failed=`expr $failed + 1`
> +
> +testit_expect_failure "try to change password too quickly (command should not succeed)" \
> +	$VALGRIND $samba_tool user password -W$DOMAIN "-U$DOMAIN/$TEST_USERNAME%$TEST_PASSWORD" -k no --newpassword="$TEST_PASSWORD_NEW"  && failed=`expr $failed + 1`
> +
> +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 $TEST_USERNAME" \
> +	$VALGRIND $samba_tool user delete $TEST_USERNAME -U"$USERNAME%$PASSWORD" $CONFIG -k no  || failed=`expr $failed + 1`
> +
> +rm -f $PREFIX/tmpuserpassfile $PREFIX/tmpsmbpasswdscript $PREFIX/tmpuserccache
> +
> +exit $failed
> -- 
> 2.10.0
> 
> 
> From 83f5df454299e99f5c2e4877df3ca598120049d5 Mon Sep 17 00:00:00 2001
> From: Andreas Schneider <asn at samba.org>
> Date: Mon, 5 Sep 2016 15:18:07 +0200
> Subject: [PATCH 08/18] testprogs: Make test_passwords.sh a Heimdal kpasswd
>  test
> 
> Signed-off-by: Andreas Schneider <asn at samba.org>
> ---
>  source4/selftest/tests.py                                         | 2 +-
>  testprogs/blackbox/{test_passwords.sh => test_kpasswd_heimdal.sh} | 0
>  2 files changed, 1 insertion(+), 1 deletion(-)
>  rename testprogs/blackbox/{test_passwords.sh => test_kpasswd_heimdal.sh} (100%)
> 
> diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py
> index 037910d..19a41dc 100755
> --- a/source4/selftest/tests.py
> +++ b/source4/selftest/tests.py
> @@ -393,12 +393,12 @@ if have_heimdal_support:
>      plantestsuite("samba4.blackbox.kinit_trust(fl2008r2dc:local)", "fl2008r2dc: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', "forest", "aes256-cts-hmac-sha1-96"])
>      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", smbclient4])
>  
>  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'])
>  plantestsuite("samba4.blackbox.password_settings(ad_dc_ntvfs:local)", "ad_dc_ntvfs:local", [os.path.join(bbdir, "test_password_settings.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', "$PREFIX/ad_dc_ntvfs"])
> -plantestsuite("samba4.blackbox.passwords(ad_dc_ntvfs:local)", "ad_dc_ntvfs:local", [os.path.join(bbdir, "test_passwords.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', "$PREFIX/ad_dc_ntvfs", smbclient4])
>  plantestsuite("samba4.blackbox.cifsdd(ad_dc_ntvfs)", "ad_dc_ntvfs", [os.path.join(samba4srcdir, "client/tests/test_cifsdd.sh"), '$SERVER', '$USERNAME', '$PASSWORD', "$DOMAIN"])
>  plantestsuite("samba4.blackbox.nmblookup(ad_dc_ntvfs)", "ad_dc_ntvfs", [os.path.join(samba4srcdir, "utils/tests/test_nmblookup.sh"), '$NETBIOSNAME', '$NETBIOSALIAS', '$SERVER', '$SERVER_IP', nmblookup4])
>  plantestsuite("samba4.blackbox.locktest(ad_dc_ntvfs)", "ad_dc_ntvfs", [os.path.join(samba4srcdir, "torture/tests/test_locktest.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$DOMAIN', '$PREFIX'])
> diff --git a/testprogs/blackbox/test_passwords.sh b/testprogs/blackbox/test_kpasswd_heimdal.sh
> similarity index 100%
> rename from testprogs/blackbox/test_passwords.sh
> rename to testprogs/blackbox/test_kpasswd_heimdal.sh
> -- 
> 2.10.0
> 
> 
> From 22485778531a3cd532f5e3225fd511d8bd47abb5 Mon Sep 17 00:00:00 2001
> From: Andreas Schneider <asn at samba.org>
> Date: Tue, 6 Sep 2016 09:31:41 +0200
> Subject: [PATCH 09/18] testprogs: Test only what the Heimdal kpasswd test
>  should test
> 
> The test_password_settings.sh test does test using different password
> settings and is not specific to the kpasswd implementation. This
> test tests the kpasswd service.
> 
> Signed-off-by: Andreas Schneider <asn at samba.org>
> ---
>  source4/selftest/tests.py                  |   2 +-
>  testprogs/blackbox/test_kpasswd_heimdal.sh | 292 ++++++++++++-----------------
>  2 files changed, 123 insertions(+), 171 deletions(-)
> 
> diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py
> index 19a41dc..61d9a82 100755
> --- a/source4/selftest/tests.py
> +++ b/source4/selftest/tests.py
> @@ -393,7 +393,7 @@ if have_heimdal_support:
>      plantestsuite("samba4.blackbox.kinit_trust(fl2008r2dc:local)", "fl2008r2dc: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', "forest", "aes256-cts-hmac-sha1-96"])
>      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", 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"])
>  
>  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"])
> diff --git a/testprogs/blackbox/test_kpasswd_heimdal.sh b/testprogs/blackbox/test_kpasswd_heimdal.sh
> index 61d5461..7e3daed 100755
> --- a/testprogs/blackbox/test_kpasswd_heimdal.sh
> +++ b/testprogs/blackbox/test_kpasswd_heimdal.sh
> @@ -1,9 +1,11 @@
>  #!/bin/sh
> -# Blackbox tests for kinit and kerberos integration with smbclient etc
> +# 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 5 ]; then
> +if [ $# -lt 6 ]; then
>  cat <<EOF
>  Usage: test_passwords.sh SERVER USERNAME PASSWORD REALM DOMAIN PREFIX SMBCLIENT
>  EOF
> @@ -16,41 +18,32 @@ PASSWORD=$3
>  REALM=$4
>  DOMAIN=$5
>  PREFIX=$6
> -smbclient=$7
> -shift 7
> +shift 6
>  failed=0
>  
> -samba4bindir="$BINDIR"
> -samba4kinit=kinit
> -if test -x $BINDIR/samba4kinit; then
> -	samba4kinit=$BINDIR/samba4kinit
> -fi
> +samba_bindir="$BINDIR"
>  
> -samba_tool="$samba4bindir/samba-tool"
> -net_tool="$samba4bindir/net"
> -smbpasswd="$samba4bindir/smbpasswd"
> -texpect="$samba4bindir/texpect"
> -samba4kpasswd=kpasswd
> -if test -x $BINDIR/samba4kpasswd; then
> -	samba4kpasswd=$BINDIR/samba4kpasswd
> -fi
> +smbclient="$samba_bindir/smbclient"
> +samba_kinit=$samba_bindir/samba4kinit
> +samba_kpasswd=$samba_bindir/samba4kpasswd
> +
> +samba_tool="$samba_bindir/samba-tool"
> +net_tool="$samba_bindir/net"
> +texpect="$samba_bindir/texpect"
>  
>  newuser="$samba_tool user create"
> -unc="//$SERVER/tmp"
> +SMB_UNC="//$SERVER/tmp"
>  
>  . `dirname $0`/subunit.sh
>  . `dirname $0`/common_test_fns.inc
>  
>  do_kinit() {
> -	file="$1"
> +	principal="$1"
>  	password="$2"
>  	shift
>  	shift
> -	if test -x $BINDIR/samba4kinit; then
> -		$samba4kinit --password-file=$file --request-pac $@
> -	else
> -		echo $password | $samba4kinit $@
> -	fi
> +	echo $password > $PREFIX/tmppassfile
> +	$samba_kinit --password-file=$PREFIX/tmppassfile $principal $@
>  }
>  
>  UID_WRAPPER_ROOT=1
> @@ -59,207 +52,166 @@ 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`
> +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`
>  
> -USERPASS=testPaSS at 00%
> +TEST_USERNAME="$(mktemp -u alice-XXXXXX)"
> +TEST_PRINCIPAL="$TEST_USERNAME@$REALM"
> +TEST_PASSWORD="testPaSS at 00%"
> +TEST_PASSWORD_NEW="testPaSS at 01%"
> +TEST_PASSWORD_SHORT="secret"
> +TEST_PASSWORD_WEAK="Supersecret"
>  
> -testit "create user locally" $VALGRIND $newuser $CONFIG nettestuser $USERPASS $@ || failed=`expr $failed + 1`
> +testit "create user locally" \
> +	$VALGRIND $newuser $CONFIG $TEST_USERNAME $TEST_PASSWORD || failed=`expr $failed + 1`
>  
>  KRB5CCNAME="$PREFIX/tmpuserccache"
>  export KRB5CCNAME
>  
> -echo $USERPASS > $PREFIX/tmpuserpassfile
> -
> -testit "kinit with user password" do_kinit $PREFIX/tmpuserpassfile $USERPASS nettestuser@$REALM   || failed=`expr $failed + 1`
> +testit "kinit with user password" \
> +	do_kinit $TEST_PRINCIPAL $TEST_PASSWORD || failed=`expr $failed + 1`
>  
> -test_smbclient "Test login with user kerberos ccache" 'ls' "$unc" -k yes || failed=`expr $failed + 1`
> +test_smbclient "Test login with user kerberos ccache" \
> +	"ls" "$SMB_UNC" -k yes || failed=`expr $failed + 1`
>  
> -NEWUSERPASS=testPaSS at 01%
> -testit "change user password with 'samba-tool user password' (unforced)" $VALGRIND $samba_tool user password -W$DOMAIN -U$DOMAIN/nettestuser%$USERPASS  -k no --newpassword=$NEWUSERPASS $@ || 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`
>  
> -echo $NEWUSERPASS > ./tmpuserpassfile
> -testit "kinit with user password" do_kinit ./tmpuserpassfile $NEWUSERPASS nettestuser@$REALM   || failed=`expr $failed + 1`
> +TEST_PASSWORD_OLD=$TEST_PASSWORD
> +TEST_PASSWORD=$TEST_PASSWORD_NEW
> +TEST_PASSWORD_NEW="testPaSS at 02%"
>  
> -test_smbclient "Test login with user kerberos ccache" 'ls' "$unc" -k yes || failed=`expr $failed + 1`
> +testit "kinit with user password" \
> +	do_kinit $TEST_PRINCIPAL $TEST_PASSWORD || failed=`expr $failed + 1`
>  
> -#
> -# These tests demonstrate that a credential cache in the environment does not
> -# override a username/password, even an incorrect one, on the command line
> -#
> +test_smbclient "Test login with user kerberos ccache" \
> +	"ls" "$SMB_UNC" -k yes || failed=`expr $failed + 1`
>  
> -testit_expect_failure  "Test login with user kerberos ccache, but wrong password specified" $VALGRIND $smbclient //$SERVER/tmp -c 'ls' -k yes -Unettestuser@$REALM%wrongpass && failed=`expr $failed + 1`
> -testit_expect_failure  "Test login with user kerberos ccache, but old password specified" $VALGRIND $smbclient //$SERVER/tmp -c 'ls' -k yes -Unettestuser@$REALM%$USERPASS && failed=`expr $failed + 1`
> -
> -
> -USERPASS=$NEWUSERPASS
> -WEAKPASS=testpass1
> -NEWUSERPASS=testPaSS at 02%
> -
> -# password mismatch check doesn't work yet (kpasswd bug, reported to Love)
> -#echo "check that password mismatch gives the right error"
> -#cat > ./tmpkpasswdscript <<EOF
> -#expect Password
> -#password ${USERPASS}\n
> -#expect New password
> -#send ${WEAKPASS}\n
> -#expect New password
> -#send ${NEWUSERPASS}\n
> -#expect password mismatch
> -#EOF
> -#
> -#testit "change user password with kpasswd" $texpect ./tmpkpasswdscript $samba4kpasswd nettestuser@$REALM || failed=`expr $failed + 1`
> +###########################################################
> +### check that a short password is rejected
> +###########################################################
>  
> -
> -echo "check that a weak password is rejected"
> -cat > ./tmpkpasswdscript <<EOF
> +cat > $PREFIX/tmpkpasswdscript <<EOF
>  expect Password
> -password ${USERPASS}\n
> +password ${TEST_PASSWORD}\n
>  expect New password
> -send ${WEAKPASS}\n
> -expect New password
> -send ${WEAKPASS}\n
> -expect Password does not meet complexity requirements
> +send ${TEST_PASSWORD_SHORT}\n
> +expect Verify password
> +send ${TEST_PASSWORD_SHORT}\n
> +expect Password too short
>  EOF
>  
> -testit "change to weak user password with kpasswd" $texpect ./tmpkpasswdscript $samba4kpasswd nettestuser@$REALM || failed=`expr $failed + 1`
> +testit "kpasswd check short user password" \
> +	$texpect $PREFIX/tmpkpasswdscript $samba_kpasswd $TEST_PRINCIPAL || failed=`expr $failed + 1`
> +
> +###########################################################
> +### check that a weak password is rejected
> +###########################################################
>  
>  echo "check that a short password is rejected"
>  cat > ./tmpkpasswdscript <<EOF
>  expect Password
> -password ${USERPASS}\n
> -expect New password
> -send xx1\n
> +password ${TEST_PASSWORD}\n
>  expect New password
> -send xx1\n
> -expect Password too short
> +send $TEST_PASSWORD_WEAK\n
> +expect Verify password
> +send $TEST_PASSWORD_WEAK\n
> +expect Password does not meet complexity requirements
>  EOF
>  
> -testit "change to short user password with kpasswd" $texpect ./tmpkpasswdscript $samba4kpasswd nettestuser@$REALM || failed=`expr $failed + 1`
> +testit "kpasswd check weak user password" \
> +	$texpect $PREFIX/tmpkpasswdscript $samba_kpasswd $TEST_PRINCIPAL || failed=`expr $failed + 1`
>  
> +###########################################################
> +### check that a strong password is accepted
> +###########################################################
>  
> -echo "check that a strong new password is accepted"
>  cat > ./tmpkpasswdscript <<EOF
>  expect Password
> -password ${USERPASS}\n
> +password ${TEST_PASSWORD}\n
>  expect New password
> -send ${NEWUSERPASS}\n
> -expect New password
> -send ${NEWUSERPASS}\n
> +send ${TEST_PASSWORD_NEW}\n
> +expect Verify password
> +send ${TEST_PASSWORD_NEW}\n
>  expect Success
>  EOF
>  
> -testit "change user password with kpasswd" $texpect ./tmpkpasswdscript $samba4kpasswd nettestuser@$REALM || failed=`expr $failed + 1`
> +testit "kpasswd change user password" \
> +	$texpect $PREFIX/tmpkpasswdscript $samba_kpasswd $TEST_PRINCIPAL || failed=`expr $failed + 1`
>  
> -test_smbclient "Test login with user kerberos (unforced)" 'ls' "$unc" -k yes -Unettestuser@$REALM%$NEWUSERPASS || failed=`expr $failed + 1`
> +TEST_PASSWORD=$TEST_PASSWORD_NEW
> +TEST_PASSWORD_NEW="testPaSS at 03%"
>  
> -NEWUSERPASS=testPaSS at 03%
> +###########################################################
> +### Force password change at login
> +###########################################################
>  
> -echo "set password with smbpasswd"
> -cat > ./tmpsmbpasswdscript <<EOF
> -expect New SMB password:
> -send ${NEWUSERPASS}\n
> -expect Retype new SMB password:
> -send ${NEWUSERPASS}\n
> -EOF
> +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`
>  
> -testit "set user password with smbpasswd" $texpect ./tmpsmbpasswdscript $smbpasswd -L -c $PREFIX/etc/smb.conf nettestuser || failed=`expr $failed + 1`
> -USERPASS=$NEWUSERPASS
> +TEST_PASSWORD=$TEST_PASSWORD_NEW
> +TEST_PASSWORD_NEW="testPaSS at 04%"
>  
> -test_smbclient "Test login with user (ntlm)" 'ls' "$unc" -k no -Unettestuser@$REALM%$NEWUSERPASS || failed=`expr $failed + 1`
> +rm -f $PREFIX/tmpuserccache
>  
> -
> -NEWUSERPASS=testPaSS at 04%
> -testit "set password on user locally" $VALGRIND $samba_tool user setpassword nettestuser $CONFIG --newpassword=$NEWUSERPASS --must-change-at-next-login $@ || failed=`expr $failed + 1`
> -USERPASS=$NEWUSERPASS
> -
> -NEWUSERPASS=testPaSS at 05%
> -testit "change user password with 'samba-tool user password' (after must change flag set)" $VALGRIND $samba_tool user password -W$DOMAIN -U$DOMAIN/nettestuser%$USERPASS -k no --newpassword=$NEWUSERPASS $@ || failed=`expr $failed + 1`
> -USERPASS=$NEWUSERPASS
> -
> -NEWUSERPASS=testPaSS at 06%
> -testit "set password on user locally" $VALGRIND $samba_tool user setpassword $CONFIG nettestuser --newpassword=$NEWUSERPASS --must-change-at-next-login $@ || failed=`expr $failed + 1`
> -USERPASS=$NEWUSERPASS
> -
> -NEWUSERPASS=testPaSS at 07%
> -
> -cat > ./tmpkpasswdscript <<EOF
> +cat > $PREFIX/tmpkinitscript <<EOF
>  expect Password
> -password ${USERPASS}\n
> -expect New password
> -send ${NEWUSERPASS}\n
> +password ${TEST_PASSWORD}\n
> +expect Changing password
>  expect New password
> -send ${NEWUSERPASS}\n
> +send ${TEST_PASSWORD_NEW}\n
> +expect Repeat new password
> +send ${TEST_PASSWORD_NEW}\n
>  expect Success
>  EOF
>  
> -testit "change user password with kpasswd (after must change flag set)" $texpect ./tmpkpasswdscript $samba4kpasswd nettestuser@$REALM || failed=`expr $failed + 1`
> -USERPASS=$NEWUSERPASS
> -
> -test_smbclient "Test login with user kerberos" 'ls' "$unc" -k yes -Unettestuser@$REALM%$NEWUSERPASS || failed=`expr $failed + 1`
> -
> -NEWUSERPASS=testPaSS at 08%
> -testit "set password on user locally" $VALGRIND $samba_tool user setpassword $CONFIG nettestuser --newpassword=$NEWUSERPASS --must-change-at-next-login $@ || failed=`expr $failed + 1`
> -USERPASS=$NEWUSERPASS
> -
> -NEWUSERPASS=testPaSS at 09%
> -
> -cat > ./tmpsmbpasswdscript <<EOF
> -expect Old SMB password:
> -password ${USERPASS}\n
> -expect New SMB password:
> -send ${NEWUSERPASS}\n
> -expect Retype new SMB password:
> -send ${NEWUSERPASS}\n
> -EOF
> -
> -testit "change user password with smbpasswd (after must change flag set)" $texpect ./tmpsmbpasswdscript $smbpasswd -r $SERVER  -c $PREFIX/etc/smb.conf -U nettestuser || failed=`expr $failed + 1`
> -
> -USERPASS=$NEWUSERPASS
> -
> -test_smbclient "Test login with user kerberos" 'ls' "$unc" -k yes -Unettestuser@$REALM%$NEWUSERPASS || failed=`expr $failed + 1`
> -
> -NEWUSERPASS=abcdefg
> -testit_expect_failure "try to set a non-complex password (command should not succeed)" $VALGRIND $samba_tool user password -W$DOMAIN "-U$DOMAIN/nettestuser%$USERPASS" -k no --newpassword="$NEWUSERPASS" $@ && failed=`expr $failed + 1`
> -
> -testit "allow non-complex passwords" $VALGRIND $samba_tool domain passwordsettings set $CONFIG --complexity=off || failed=`expr $failed + 1`
> -
> -testit "try to set a non-complex password (command should succeed)" $VALGRIND $samba_tool user password -W$DOMAIN "-U$DOMAIN/nettestuser%$USERPASS" -k no --newpassword="$NEWUSERPASS" $@ || failed=`expr $failed + 1`
> -USERPASS=$NEWUSERPASS
> +testit "kinit and change user password" \
> +	$texpect $PREFIX/tmpkinitscript $samba_kinit $TEST_PRINCIPAL || failed=`expr $failed + 1`
>  
> -test_smbclient "test login with non-complex password" 'ls' "$unc" -k no -Unettestuser@$REALM%$USERPASS || failed=`expr $failed + 1`
> +TEST_PASSWORD=$TEST_PASSWORD_NEW
> +TEST_PASSWORD_NEW="testPaSS at 07%"
>  
> -NEWUSERPASS=abc
> -testit_expect_failure "try to set a short password (command should not succeed)" $VALGRIND $samba_tool user password -W$DOMAIN "-U$DOMAIN/nettestuser%$USERPASS" -k no --newpassword="$NEWUSERPASS" $@ && failed=`expr $failed + 1`
> +test_smbclient "Test login with user (kerberos)" \
> +	"ls" "$SMB_UNC" -k yes -U$TEST_PRINCIPAL%$TEST_PASSWORD || failed=`expr $failed + 1`
>  
> -testit "allow short passwords (length 1)" $VALGRIND $samba_tool domain passwordsettings $CONFIG set --min-pwd-length=1 || failed=`expr $failed + 1`
> +###########################################################
> +### Test kpasswd service via 'net ads password'
> +###########################################################
>  
> -testit "try to set a short password (command should succeed)" $VALGRIND $samba_tool user password -W$DOMAIN "-U$DOMAIN/nettestuser%$USERPASS" -k no --newpassword="$NEWUSERPASS" $@ || failed=`expr $failed + 1`
> -USERPASS="$NEWUSERPASS"
> +# NOTE: This works with heimdal because the krb5_set_password function tries
> +# set_password call first and falls back to change_password if it doesn't
> +# succeed.
> +testit "change user password with 'net ads password', admin: $DOMAIN/$TEST_USERNAME, target: $TEST_PRINCIPAL" \
> +	$VALGRIND $net_tool ads password -W$DOMAIN -U$TEST_PRINCIPAL%$TEST_PASSWORD $TEST_PRINCIPAL "$TEST_PASSWORD_NEW" || failed=`expr $failed + 1`
>  
> -# test kpasswd via net ads password (change variant)
> -NEWUSERPASS="testPaSS at 10%"
> -testit "change user password with 'net ads password', admin: $DOMAIN/nettestuser, target: nettestuser@$REALM" $VALGRIND $net_tool ads password -W$DOMAIN -Unettestuser@$REALM%$USERPASS nettestuser@$REALM "$NEWUSERPASS" $@ || failed=`expr $failed + 1`
> -USERPASS="$NEWUSERPASS"
> +TEST_PASSWORD=$TEST_PASSWORD_NEW
> +TEST_PASSWORD_NEW="testPaSS at 08%"
>  
> -test_smbclient "Test login with smbclient" 'ls' "$unc" -k no -Unettestuser@$REALM%$NEWUSERPASS || failed=`expr $failed + 1`
> +test_smbclient "Test login with smbclient (ntlm)" \
> +	"ls" "$SMB_UNC" -k no -U$TEST_PRINCIPAL%$TEST_PASSWORD || failed=`expr $failed + 1`
>  
> -# test kpasswd via net ads password (admin set variant)
> -NEWUSERPASS="testPaSS at 11%"
> -testit "set user password with 'net ads password', admin: $DOMAIN/$USERNAME, target: nettestuser@$REALM" $VALGRIND $net_tool ads password -W$DOMAIN -U$USERNAME@$REALM%$PASSWORD nettestuser@$REALM "$NEWUSERPASS" $@ || failed=`expr $failed + 1`
> -USERPASS="$NEWUSERPASS"
> +###########################################################
> +### Test kpasswd service via 'net ads password' as admin
> +###########################################################
>  
> -test_smbclient "Test login with smbclient" 'ls' "$unc" -k no -Unettestuser@$REALM%$NEWUSERPASS || failed=`expr $failed + 1`
> +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`
>  
> -testit "require minimum password age of 1 day" $VALGRIND $samba_tool domain passwordsettings $CONFIG set --min-pwd-age=1 || failed=`expr $failed + 1`
> +TEST_PASSWORD=$TEST_PASSWORD_NEW
> +TEST_PASSWORD_NEW="testPaSS at 07%"
>  
> -testit "show password settings" $VALGRIND $samba_tool domain passwordsettings $CONFIG show || failed=`expr $failed + 1`
> +test_smbclient "Test login with smbclient (ntlm)" \
> +	"ls" "$SMB_UNC" -k no -U$TEST_PRINCIPAL%$TEST_PASSWORD || failed=`expr $failed + 1`
>  
> -NEWUSERPASS="testPaSS at 08%"
> -testit_expect_failure "try to change password too quickly (command should not succeed)" $VALGRIND $samba_tool user password -W$DOMAIN "-U$DOMAIN/nettestuser%$USERPASS" -k no --newpassword="$NEWUSERPASS" $@ && 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 "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 "del user" $VALGRIND $samba_tool user delete nettestuser -U"$USERNAME%$PASSWORD" $CONFIG -k no $@ || 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 tmpccfile tmppassfile tmpuserpassfile tmpuserccache tmpkpasswdscript tmpsmbpasswdscript
> +rm -f $PREFIX/tmpuserccache $PREFIX/tmpkpasswdscript $PREFIX/tmpkinitscript
>  exit $failed
> -- 
> 2.10.0
> 
> 
> From 3f802067a4858ae1c0c9ce4faf5fe00534f3d797 Mon Sep 17 00:00:00 2001
> From: Andreas Schneider <asn at samba.org>
> Date: Fri, 2 Sep 2016 11:54:48 +0200
> Subject: [PATCH 10/18] krb5_wrap: Fix smb_krb5_mk_error() with MIT Kerberos
> 
> The server principal is required, so if not set create an obscure one.
> 
> Signed-off-by: Andreas Schneider <asn at samba.org>
> ---
>  lib/krb5_wrap/krb5_samba.c    | 52 +++++++++++++++++++++++++++++++++++--------
>  lib/krb5_wrap/krb5_samba.h    |  2 ++
>  source4/kdc/kdc-server.c      |  2 ++
>  source4/kdc/kpasswd-heimdal.c |  2 ++
>  4 files changed, 49 insertions(+), 9 deletions(-)
> 
> diff --git a/lib/krb5_wrap/krb5_samba.c b/lib/krb5_wrap/krb5_samba.c
> index dcd6185..28884d9 100644
> --- a/lib/krb5_wrap/krb5_samba.c
> +++ b/lib/krb5_wrap/krb5_samba.c
> @@ -206,6 +206,8 @@ krb5_error_code smb_krb5_mk_error(krb5_context context,
>  				  krb5_error_code error_code,
>  				  const char *e_text,
>  				  krb5_data *e_data,
> +				  const krb5_principal client,
> +				  const krb5_principal server,
>  				  krb5_data *enc_err)
>  {
>  	krb5_error_code code = EINVAL;
> @@ -214,27 +216,59 @@ krb5_error_code smb_krb5_mk_error(krb5_context context,
>  			     error_code,
>  			     e_text,
>  			     e_data,
> -			     NULL, /* client */
> -			     NULL, /* server */
> +			     client,
> +			     server,
>  			     NULL, /* client_time */
>  			     NULL, /* client_usec */
>  			     enc_err);
>  #else
> -	krb5_error dec_err = {
> -		.error = error_code,
> -	};
> +	krb5_principal unspec_server = NULL;
> +	krb5_error errpkt;
>  
> +	errpkt.ctime = 0;
> +	errpkt.cusec = 0;
> +
> +	code = krb5_us_timeofday(context,
> +				 &errpkt.stime,
> +				 &errpkt.susec);
> +	if (code != 0) {
> +		return code;
> +	}
> +
> +	errpkt.error = error_code;
> +
> +	errpkt.text.length = 0;
>  	if (e_text != NULL) {
> -		dec_err.text.length = strlen(e_text);
> -		dec_err.text.data = discard_const_p(char, e_text);
> +		errpkt.text.length = strlen(e_text);
> +		errpkt.text.data = discard_const_p(char, e_text);
>  	}
> +
> +	errpkt.e_data.magic = KV5M_DATA;
> +	errpkt.e_data.length = 0;
> +	errpkt.e_data.data = NULL;
>  	if (e_data != NULL) {
> -		dec_err.e_data = *e_data;
> +		errpkt.e_data = *e_data;
> +	}
> +
> +	errpkt.client = client;
> +
> +	if (server != NULL) {
> +		errpkt.server = server;
> +	} else {
> +		code = smb_krb5_make_principal(context,
> +					       &unspec_server,
> +					       "<unspecified realm>",
> +					       NULL);
> +		if (code != 0) {
> +			return code;
> +		}
> +		errpkt.server = unspec_server;
>  	}
>  
>  	code = krb5_mk_error(context,
> -			     &dec_err,
> +			     &errpkt,
>  			     enc_err);
> +	krb5_free_principal(context, unspec_server);
>  #endif
>  	return code;
>  }
> diff --git a/lib/krb5_wrap/krb5_samba.h b/lib/krb5_wrap/krb5_samba.h
> index 64a04b3..71e81ea 100644
> --- a/lib/krb5_wrap/krb5_samba.h
> +++ b/lib/krb5_wrap/krb5_samba.h
> @@ -169,6 +169,8 @@ krb5_error_code smb_krb5_mk_error(krb5_context context,
>  				  krb5_error_code error_code,
>  				  const char *e_text,
>  				  krb5_data *e_data,
> +				  const krb5_principal client,
> +				  const krb5_principal server,
>  				  krb5_data *enc_err);
>  
>  krb5_error_code smb_krb5_get_allowed_etypes(krb5_context context,
> diff --git a/source4/kdc/kdc-server.c b/source4/kdc/kdc-server.c
> index 7854f49..13e338d 100644
> --- a/source4/kdc/kdc-server.c
> +++ b/source4/kdc/kdc-server.c
> @@ -83,6 +83,8 @@ static NTSTATUS kdc_proxy_unavailable_error(struct kdc_server *kdc,
>  				 KRB5KDC_ERR_SVC_UNAVAILABLE,
>  				 NULL,
>  				 NULL,
> +				 NULL,
> +				 NULL,
>  				 &enc_error);
>  	if (code != 0) {
>  		DBG_WARNING("Unable to form krb5 error reply\n");
> diff --git a/source4/kdc/kpasswd-heimdal.c b/source4/kdc/kpasswd-heimdal.c
> index ff2f6af..85d1730 100644
> --- a/source4/kdc/kpasswd-heimdal.c
> +++ b/source4/kdc/kpasswd-heimdal.c
> @@ -81,6 +81,8 @@ static bool kpasswdd_make_unauth_error_reply(struct kdc_server *kdc,
>  				 result_code,
>  				 NULL,
>  				 &k5_error_bytes,
> +				 NULL,
> +				 NULL,
>  				 &k5_error_blob);
>  	if (kret) {
>  		return false;
> -- 
> 2.10.0
> 
> 
> From 039d946af47be16d6b0eea0481f328651c47ef3c Mon Sep 17 00:00:00 2001
> From: Andreas Schneider <asn at samba.org>
> Date: Wed, 7 Sep 2016 14:47:31 +0200
> Subject: [PATCH 11/18] s4-kdc: Move kpasswd_make_error_reply() to a helper
>  file
> 
> Signed-off-by: Andreas Schneider <asn at samba.org>
> ---
>  source4/kdc/kpasswd-heimdal.c | 59 +++++++++++--------------------------
>  source4/kdc/kpasswd-helper.c  | 68 +++++++++++++++++++++++++++++++++++++++++++
>  source4/kdc/kpasswd-helper.h  | 30 +++++++++++++++++++
>  source4/kdc/wscript_build     |  2 +-
>  4 files changed, 116 insertions(+), 43 deletions(-)
>  create mode 100644 source4/kdc/kpasswd-helper.c
>  create mode 100644 source4/kdc/kpasswd-helper.h
> 
> diff --git a/source4/kdc/kpasswd-heimdal.c b/source4/kdc/kpasswd-heimdal.c
> index 85d1730..af8187b 100644
> --- a/source4/kdc/kpasswd-heimdal.c
> +++ b/source4/kdc/kpasswd-heimdal.c
> @@ -33,31 +33,7 @@
>  #include "kdc/kdc-glue.h"
>  #include "dsdb/common/util.h"
>  #include "kdc/kpasswd_glue.h"
> -
> -/* Return true if there is a valid error packet formed in the error_blob */
> -static bool kpasswdd_make_error_reply(struct kdc_server *kdc,
> -				     TALLOC_CTX *mem_ctx,
> -				     uint16_t result_code,
> -				     const char *error_string,
> -				     DATA_BLOB *error_blob)
> -{
> -	char *error_string_utf8;
> -	size_t len;
> -
> -	DEBUG(result_code ? 3 : 10, ("kpasswdd: %s\n", error_string));
> -
> -	if (!push_utf8_talloc(mem_ctx, &error_string_utf8, error_string, &len)) {
> -		return false;
> -	}
> -
> -	*error_blob = data_blob_talloc(mem_ctx, NULL, 2 + len + 1);
> -	if (!error_blob->data) {
> -		return false;
> -	}
> -	RSSVAL(error_blob->data, 0, result_code);
> -	memcpy(error_blob->data + 2, error_string_utf8, len + 1);
> -	return true;
> -}
> +#include "kdc/kpasswd-helper.h"
>  
>  /* Return true if there is a valid error packet formed in the error_blob */
>  static bool kpasswdd_make_unauth_error_reply(struct kdc_server *kdc,
> @@ -70,7 +46,7 @@ static bool kpasswdd_make_unauth_error_reply(struct kdc_server *kdc,
>  	int kret;
>  	DATA_BLOB error_bytes;
>  	krb5_data k5_error_bytes, k5_error_blob;
> -	ret = kpasswdd_make_error_reply(kdc, mem_ctx, result_code, error_string,
> +	ret = kpasswd_make_error_reply(mem_ctx, result_code, error_string,
>  				       &error_bytes);
>  	if (!ret) {
>  		return false;
> @@ -104,13 +80,13 @@ static bool kpasswd_make_pwchange_reply(struct kdc_server *kdc,
>  					DATA_BLOB *error_blob)
>  {
>  	if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
> -		return kpasswdd_make_error_reply(kdc, mem_ctx,
> +		return kpasswd_make_error_reply(mem_ctx,
>  						KRB5_KPASSWD_ACCESSDENIED,
>  						"No such user when changing password",
>  						error_blob);
>  	}
>  	if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
> -		return kpasswdd_make_error_reply(kdc, mem_ctx,
> +		return kpasswd_make_error_reply(mem_ctx,
>  						KRB5_KPASSWD_ACCESSDENIED,
>  						"Not permitted to change password",
>  						error_blob);
> @@ -133,19 +109,19 @@ static bool kpasswd_make_pwchange_reply(struct kdc_server *kdc,
>  			reject_string = "Password change rejected, password changes may not be permitted on this account, or the minimum password age may not have elapsed.";
>  			break;
>  		}
> -		return kpasswdd_make_error_reply(kdc, mem_ctx,
> +		return kpasswd_make_error_reply(mem_ctx,
>  						KRB5_KPASSWD_SOFTERROR,
>  						reject_string,
>  						error_blob);
>  	}
>  	if (!NT_STATUS_IS_OK(status)) {
> -		return kpasswdd_make_error_reply(kdc, mem_ctx,
> +		return kpasswd_make_error_reply(mem_ctx,
>  						 KRB5_KPASSWD_HARDERROR,
>  						 talloc_asprintf(mem_ctx, "failed to set password: %s", nt_errstr(status)),
>  						 error_blob);
>  
>  	}
> -	return kpasswdd_make_error_reply(kdc, mem_ctx, KRB5_KPASSWD_SUCCESS,
> +	return kpasswd_make_error_reply(mem_ctx, KRB5_KPASSWD_SUCCESS,
>  					"Password changed",
>  					error_blob);
>  }
> @@ -179,8 +155,7 @@ static bool kpasswdd_change_password(struct kdc_server *kdc,
>  					       &error_string,
>  					       &result);
>  	if (!NT_STATUS_IS_OK(status)) {
> -		return kpasswdd_make_error_reply(kdc,
> -						 mem_ctx,
> +		return kpasswd_make_error_reply(mem_ctx,
>  						 KRB5_KPASSWD_ACCESSDENIED,
>  						 error_string,
>  						 reply);
> @@ -207,7 +182,7 @@ static bool kpasswd_process_request(struct kdc_server *kdc,
>  	if (!NT_STATUS_IS_OK(gensec_session_info(gensec_security,
>  						 mem_ctx,
>  						 &session_info))) {
> -		return kpasswdd_make_error_reply(kdc, mem_ctx,
> +		return kpasswd_make_error_reply(mem_ctx,
>  						KRB5_KPASSWD_HARDERROR,
>  						"gensec_session_info failed!",
>  						reply);
> @@ -251,7 +226,7 @@ static bool kpasswd_process_request(struct kdc_server *kdc,
>  		ret = decode_ChangePasswdDataMS(input->data, input->length,
>  						&chpw, &len);
>  		if (ret) {
> -			return kpasswdd_make_error_reply(kdc, mem_ctx,
> +			return kpasswd_make_error_reply(mem_ctx,
>  							KRB5_KPASSWD_MALFORMED,
>  							"failed to decode password change structure",
>  							reply);
> @@ -271,7 +246,7 @@ static bool kpasswd_process_request(struct kdc_server *kdc,
>  		if ((chpw.targname && !chpw.targrealm)
>  		    || (!chpw.targname && chpw.targrealm)) {
>  			free_ChangePasswdDataMS(&chpw);
> -			return kpasswdd_make_error_reply(kdc, mem_ctx,
> +			return kpasswd_make_error_reply(mem_ctx,
>  							KRB5_KPASSWD_MALFORMED,
>  							"Realm and principal must be both present, or neither present",
>  							reply);
> @@ -283,7 +258,7 @@ static bool kpasswd_process_request(struct kdc_server *kdc,
>  						       *chpw.targrealm, 0);
>  			if (ret) {
>  				free_ChangePasswdDataMS(&chpw);
> -				return kpasswdd_make_error_reply(kdc, mem_ctx,
> +				return kpasswd_make_error_reply(mem_ctx,
>  								KRB5_KPASSWD_MALFORMED,
>  								"failed to get principal",
>  								reply);
> @@ -291,7 +266,7 @@ static bool kpasswd_process_request(struct kdc_server *kdc,
>  			if (copy_PrincipalName(chpw.targname, &principal->name)) {
>  				free_ChangePasswdDataMS(&chpw);
>  				krb5_free_principal(context, principal);
> -				return kpasswdd_make_error_reply(kdc, mem_ctx,
> +				return kpasswd_make_error_reply(mem_ctx,
>  								KRB5_KPASSWD_MALFORMED,
>  								"failed to extract principal to set",
>  								reply);
> @@ -312,7 +287,7 @@ static bool kpasswd_process_request(struct kdc_server *kdc,
>  
>  			if (krb5_unparse_name_short(context, principal, &set_password_on_princ) != 0) {
>  				krb5_free_principal(context, principal);
> -				return kpasswdd_make_error_reply(kdc, mem_ctx,
> +				return kpasswd_make_error_reply(mem_ctx,
>  								 KRB5_KPASSWD_MALFORMED,
>  								 "krb5_unparse_name failed!",
>  								 reply);
> @@ -320,7 +295,7 @@ static bool kpasswd_process_request(struct kdc_server *kdc,
>  		} else {
>  			if (krb5_unparse_name(context, principal, &set_password_on_princ) != 0) {
>  				krb5_free_principal(context, principal);
> -				return kpasswdd_make_error_reply(kdc, mem_ctx,
> +				return kpasswd_make_error_reply(mem_ctx,
>  								 KRB5_KPASSWD_MALFORMED,
>  								 "krb5_unparse_name failed!",
>  								 reply);
> @@ -331,7 +306,7 @@ static bool kpasswd_process_request(struct kdc_server *kdc,
>  		samdb = samdb_connect(mem_ctx, kdc->task->event_ctx, kdc->task->lp_ctx, session_info, 0);
>  		if (!samdb) {
>  			free(set_password_on_princ);
> -			return kpasswdd_make_error_reply(kdc, mem_ctx,
> +			return kpasswd_make_error_reply(mem_ctx,
>  							 KRB5_KPASSWD_HARDERROR,
>  							 "Unable to open database!",
>  							 reply);
> @@ -399,7 +374,7 @@ static bool kpasswd_process_request(struct kdc_server *kdc,
>  						   reply);
>  	}
>  	default:
> -		return kpasswdd_make_error_reply(kdc, mem_ctx,
> +		return kpasswd_make_error_reply(mem_ctx,
>  						 KRB5_KPASSWD_BAD_VERSION,
>  						 talloc_asprintf(mem_ctx,
>  								 "Protocol version %u not supported",
> diff --git a/source4/kdc/kpasswd-helper.c b/source4/kdc/kpasswd-helper.c
> new file mode 100644
> index 0000000..b4f9e92
> --- /dev/null
> +++ b/source4/kdc/kpasswd-helper.c
> @@ -0,0 +1,68 @@
> +/*
> +   Unix SMB/CIFS implementation.
> +
> +   Samba kpasswd implementation
> +
> +   Copyright (c) 2005      Andrew Bartlett <abartlet at samba.org>
> +   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 "system/kerberos.h"
> +#include "kdc/kpasswd-helper.h"
> +
> +bool kpasswd_make_error_reply(TALLOC_CTX *mem_ctx,
> +			      krb5_error_code error_code,
> +			      const char *error_string,
> +			      DATA_BLOB *error_data)
> +{
> +	bool ok;
> +	char *s;
> +	size_t slen;
> +
> +	if (error_code == 0) {
> +		DBG_DEBUG("kpasswd reply - %s\n", error_string);
> +	} else {
> +		DBG_INFO("kpasswd reply - %s\n", error_string);
> +	}
> +
> +	ok = push_utf8_talloc(mem_ctx, &s, error_string, &slen);
> +	if (!ok) {
> +		return false;
> +	}
> +
> +	/*
> +	 * The string 's' has two terminating nul-bytes which are also
> +	 * reflected by 'slen'. Normally Kerberos doesn't expect that strings
> +	 * are nul-terminated, but Heimdal does!
> +	 */
> +#ifndef SAMBA4_USES_HEIMDAL
> +	slen -= 2;
> +#endif
> +	error_data->length = 2 + slen;
> +	error_data->data = talloc_size(mem_ctx, error_data->length);
> +	if (error_data->data == NULL) {
> +		talloc_free(s);
> +		return false;
> +	}
> +
> +	RSSVAL(error_data->data, 0, error_code);
> +	memcpy(error_data->data + 2, s, slen);
> +
> +	talloc_free(s);
> +
> +	return true;
> +}
> diff --git a/source4/kdc/kpasswd-helper.h b/source4/kdc/kpasswd-helper.h
> new file mode 100644
> index 0000000..74a508c
> --- /dev/null
> +++ b/source4/kdc/kpasswd-helper.h
> @@ -0,0 +1,30 @@
> +/*
> +   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/>.
> +*/
> +
> +#ifndef _KPASSWD_HELPER_H
> +#define _KPASSWD_HELPER_H
> +
> +bool kpasswd_make_error_reply(TALLOC_CTX *mem_ctx,
> +			      krb5_error_code error_code,
> +			      const char *error_string,
> +			      DATA_BLOB *error_data);
> +
> +#endif /* _KPASSWD_HELPER_H */
> diff --git a/source4/kdc/wscript_build b/source4/kdc/wscript_build
> index 230118c..170cc34 100755
> --- a/source4/kdc/wscript_build
> +++ b/source4/kdc/wscript_build
> @@ -7,7 +7,7 @@ else:
>      kdc_include = getattr(bld.env, "CPPPATH_KDC")
>  
>  bld.SAMBA_MODULE('service_kdc',
> -                 source='kdc-heimdal.c kpasswd-heimdal.c',
> +                 source='kdc-heimdal.c kpasswd-helper.c kpasswd-heimdal.c',
>                   subsystem='service',
>                   init_function='server_service_kdc_init',
>                   deps='''
> -- 
> 2.10.0
> 
> 
> From d3dd4155260fc048a81684ddf60cfbe3e801adbc Mon Sep 17 00:00:00 2001
> From: Andreas Schneider <asn at samba.org>
> Date: Wed, 7 Sep 2016 14:57:59 +0200
> Subject: [PATCH 12/18] s4-kdc: Move kpasswd_make_pwchange_reply() to a helper
>  file
> 
> Signed-off-by: Andreas Schneider <asn at samba.org>
> ---
>  source4/kdc/kpasswd-heimdal.c | 63 +++-----------------------------
>  source4/kdc/kpasswd-helper.c  | 84 +++++++++++++++++++++++++++++++++++++++++++
>  source4/kdc/kpasswd-helper.h  |  6 ++++
>  3 files changed, 94 insertions(+), 59 deletions(-)
> 
> diff --git a/source4/kdc/kpasswd-heimdal.c b/source4/kdc/kpasswd-heimdal.c
> index af8187b..49fc755 100644
> --- a/source4/kdc/kpasswd-heimdal.c
> +++ b/source4/kdc/kpasswd-heimdal.c
> @@ -72,60 +72,6 @@ static bool kpasswdd_make_unauth_error_reply(struct kdc_server *kdc,
>  	return true;
>  }
>  
> -static bool kpasswd_make_pwchange_reply(struct kdc_server *kdc,
> -					TALLOC_CTX *mem_ctx,
> -					NTSTATUS status,
> -					enum samPwdChangeReason reject_reason,
> -					struct samr_DomInfo1 *dominfo,
> -					DATA_BLOB *error_blob)
> -{
> -	if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
> -		return kpasswd_make_error_reply(mem_ctx,
> -						KRB5_KPASSWD_ACCESSDENIED,
> -						"No such user when changing password",
> -						error_blob);
> -	}
> -	if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
> -		return kpasswd_make_error_reply(mem_ctx,
> -						KRB5_KPASSWD_ACCESSDENIED,
> -						"Not permitted to change password",
> -						error_blob);
> -	}
> -	if (dominfo && NT_STATUS_EQUAL(status, NT_STATUS_PASSWORD_RESTRICTION)) {
> -		const char *reject_string;
> -		switch (reject_reason) {
> -		case SAM_PWD_CHANGE_PASSWORD_TOO_SHORT:
> -			reject_string = talloc_asprintf(mem_ctx, "Password too short, password must be at least %d characters long.",
> -							dominfo->min_password_length);
> -			break;
> -		case SAM_PWD_CHANGE_NOT_COMPLEX:
> -			reject_string = "Password does not meet complexity requirements";
> -			break;
> -		case SAM_PWD_CHANGE_PWD_IN_HISTORY:
> -			reject_string = talloc_asprintf(mem_ctx, "Password is already in password history.  New password must not match any of your %d previous passwords.",
> -							dominfo->password_history_length);
> -			break;
> -		default:
> -			reject_string = "Password change rejected, password changes may not be permitted on this account, or the minimum password age may not have elapsed.";
> -			break;
> -		}
> -		return kpasswd_make_error_reply(mem_ctx,
> -						KRB5_KPASSWD_SOFTERROR,
> -						reject_string,
> -						error_blob);
> -	}
> -	if (!NT_STATUS_IS_OK(status)) {
> -		return kpasswd_make_error_reply(mem_ctx,
> -						 KRB5_KPASSWD_HARDERROR,
> -						 talloc_asprintf(mem_ctx, "failed to set password: %s", nt_errstr(status)),
> -						 error_blob);
> -
> -	}
> -	return kpasswd_make_error_reply(mem_ctx, KRB5_KPASSWD_SUCCESS,
> -					"Password changed",
> -					error_blob);
> -}
> -
>  /*
>     A user password change
>  
> @@ -161,8 +107,7 @@ static bool kpasswdd_change_password(struct kdc_server *kdc,
>  						 reply);
>  	}
>  
> -	return kpasswd_make_pwchange_reply(kdc,
> -					   mem_ctx,
> +	return kpasswd_make_pwchange_reply(mem_ctx,
>  					   result,
>  					   reject_reason,
>  					   dominfo,
> @@ -321,7 +266,7 @@ static bool kpasswd_process_request(struct kdc_server *kdc,
>  		if (ret != LDB_SUCCESS) {
>  			free(set_password_on_princ);
>  			status = NT_STATUS_TRANSACTION_ABORTED;
> -			return kpasswd_make_pwchange_reply(kdc, mem_ctx,
> +			return kpasswd_make_pwchange_reply(mem_ctx,
>  							   status,
>  							   SAM_PWD_CHANGE_NO_ERROR,
>  							   NULL,
> @@ -340,7 +285,7 @@ static bool kpasswd_process_request(struct kdc_server *kdc,
>  		free(set_password_on_princ);
>  		if (!NT_STATUS_IS_OK(status)) {
>  			ldb_transaction_cancel(samdb);
> -			return kpasswd_make_pwchange_reply(kdc, mem_ctx,
> +			return kpasswd_make_pwchange_reply(mem_ctx,
>  							   status,
>  							   SAM_PWD_CHANGE_NO_ERROR,
>  							   NULL,
> @@ -367,7 +312,7 @@ static bool kpasswd_process_request(struct kdc_server *kdc,
>  		} else {
>  			ldb_transaction_cancel(samdb);
>  		}
> -		return kpasswd_make_pwchange_reply(kdc, mem_ctx,
> +		return kpasswd_make_pwchange_reply(mem_ctx,
>  						   status,
>  						   reject_reason,
>  						   dominfo,
> diff --git a/source4/kdc/kpasswd-helper.c b/source4/kdc/kpasswd-helper.c
> index b4f9e92..8f6870d 100644
> --- a/source4/kdc/kpasswd-helper.c
> +++ b/source4/kdc/kpasswd-helper.c
> @@ -22,6 +22,7 @@
>  
>  #include "includes.h"
>  #include "system/kerberos.h"
> +#include "librpc/gen_ndr/samr.h"
>  #include "kdc/kpasswd-helper.h"
>  
>  bool kpasswd_make_error_reply(TALLOC_CTX *mem_ctx,
> @@ -66,3 +67,86 @@ bool kpasswd_make_error_reply(TALLOC_CTX *mem_ctx,
>  
>  	return true;
>  }
> +
> +bool kpasswd_make_pwchange_reply(TALLOC_CTX *mem_ctx,
> +				 NTSTATUS status,
> +				 enum samPwdChangeReason reject_reason,
> +				 struct samr_DomInfo1 *dominfo,
> +				 DATA_BLOB *error_blob)
> +{
> +	const char *reject_string = NULL;
> +
> +	if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
> +		return kpasswd_make_error_reply(mem_ctx,
> +						KRB5_KPASSWD_ACCESSDENIED,
> +						"No such user when changing password",
> +						error_blob);
> +	} else if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
> +		return kpasswd_make_error_reply(mem_ctx,
> +						KRB5_KPASSWD_ACCESSDENIED,
> +						"Not permitted to change password",
> +						error_blob);
> +	}
> +	if (dominfo != NULL &&
> +	    NT_STATUS_EQUAL(status, NT_STATUS_PASSWORD_RESTRICTION)) {
> +		switch (reject_reason) {
> +		case SAM_PWD_CHANGE_PASSWORD_TOO_SHORT:
> +			reject_string =
> +				talloc_asprintf(mem_ctx,
> +						"Password too short, password "
> +						"must be at least %d characters "
> +						"long.",
> +						dominfo->min_password_length);
> +			if (reject_string == NULL) {
> +				reject_string = "Password too short";
> +			}
> +			break;
> +		case SAM_PWD_CHANGE_NOT_COMPLEX:
> +			reject_string = "Password does not meet complexity "
> +					"requirements";
> +			break;
> +		case SAM_PWD_CHANGE_PWD_IN_HISTORY:
> +			reject_string =
> +				talloc_asprintf(mem_ctx,
> +						"Password is already in password "
> +						"history. New password must not "
> +						"match any of your %d previous "
> +						"passwords.",
> +						dominfo->password_history_length);
> +			if (reject_string == NULL) {
> +				reject_string = "Password is already in password "
> +						"history";
> +			}
> +			break;
> +		default:
> +			reject_string = "Password change rejected, password "
> +					"changes may not be permitted on this "
> +					"account, or the minimum password age "
> +					"may not have elapsed.";
> +			break;
> +		}
> +
> +		return kpasswd_make_error_reply(mem_ctx,
> +						KRB5_KPASSWD_SOFTERROR,
> +						reject_string,
> +						error_blob);
> +	}
> +
> +	if (!NT_STATUS_IS_OK(status)) {
> +		reject_string = talloc_asprintf(mem_ctx,
> +						"Failed to set password: %s",
> +						nt_errstr(status));
> +		if (reject_string == NULL) {
> +			reject_string = "Failed to set password";
> +		}
> +		return kpasswd_make_error_reply(mem_ctx,
> +						KRB5_KPASSWD_HARDERROR,
> +						reject_string,
> +						error_blob);
> +	}
> +
> +	return kpasswd_make_error_reply(mem_ctx,
> +					KRB5_KPASSWD_SUCCESS,
> +					"Password changed",
> +					error_blob);
> +}
> diff --git a/source4/kdc/kpasswd-helper.h b/source4/kdc/kpasswd-helper.h
> index 74a508c..d2ff1e3 100644
> --- a/source4/kdc/kpasswd-helper.h
> +++ b/source4/kdc/kpasswd-helper.h
> @@ -27,4 +27,10 @@ bool kpasswd_make_error_reply(TALLOC_CTX *mem_ctx,
>  			      const char *error_string,
>  			      DATA_BLOB *error_data);
>  
> +bool kpasswd_make_pwchange_reply(TALLOC_CTX *mem_ctx,
> +				 NTSTATUS status,
> +				 enum samPwdChangeReason reject_reason,
> +				 struct samr_DomInfo1 *dominfo,
> +				 DATA_BLOB *error_blob);
> +
>  #endif /* _KPASSWD_HELPER_H */
> -- 
> 2.10.0
> 
> 
> From 5b2a0de8b673aa2db62a1991f162a9eba3267f2f Mon Sep 17 00:00:00 2001
> From: Andreas Schneider <asn at samba.org>
> Date: Wed, 7 Sep 2016 15:07:49 +0200
> Subject: [PATCH 13/18] s4-kdc: Add a kpasswd_samdb_set_password() helper
>  function
> 
> Signed-off-by: Andreas Schneider <asn at samba.org>
> ---
>  source4/kdc/kpasswd-helper.c | 83 ++++++++++++++++++++++++++++++++++++++++++++
>  source4/kdc/kpasswd-helper.h | 10 ++++++
>  2 files changed, 93 insertions(+)
> 
> diff --git a/source4/kdc/kpasswd-helper.c b/source4/kdc/kpasswd-helper.c
> index 8f6870d..0794794 100644
> --- a/source4/kdc/kpasswd-helper.c
> +++ b/source4/kdc/kpasswd-helper.c
> @@ -23,6 +23,8 @@
>  #include "includes.h"
>  #include "system/kerberos.h"
>  #include "librpc/gen_ndr/samr.h"
> +#include "dsdb/samdb/samdb.h"
> +#include "auth/auth.h"
>  #include "kdc/kpasswd-helper.h"
>  
>  bool kpasswd_make_error_reply(TALLOC_CTX *mem_ctx,
> @@ -150,3 +152,84 @@ bool kpasswd_make_pwchange_reply(TALLOC_CTX *mem_ctx,
>  					"Password changed",
>  					error_blob);
>  }
> +
> +NTSTATUS kpasswd_samdb_set_password(TALLOC_CTX *mem_ctx,
> +				    struct tevent_context *event_ctx,
> +				    struct loadparm_context *lp_ctx,
> +				    struct auth_session_info *session_info,
> +				    bool is_service_principal,
> +				    const char *target_principal_name,
> +				    DATA_BLOB *password,
> +				    enum samPwdChangeReason *reject_reason,
> +				    struct samr_DomInfo1 **dominfo)
> +{
> +	NTSTATUS status;
> +	struct ldb_context *samdb;
> +	struct ldb_dn *target_dn = NULL;
> +	int rc;
> +
> +	samdb = samdb_connect(mem_ctx,
> +			      event_ctx,
> +			      lp_ctx,
> +			      session_info,
> +			      0);
> +	if (samdb == NULL) {
> +		return NT_STATUS_INTERNAL_DB_CORRUPTION;
> +	}
> +
> +	DBG_INFO("%s\\%s (%s) is changing password of %s\n",
> +		 session_info->info->domain_name,
> +		 session_info->info->account_name,
> +		 dom_sid_string(mem_ctx,
> +				&session_info->security_token->sids[PRIMARY_USER_SID_INDEX]),
> +		 target_principal_name);
> +
> +	rc = ldb_transaction_start(samdb);
> +	if (rc != LDB_SUCCESS) {
> +		return NT_STATUS_TRANSACTION_ABORTED;
> +	}
> +
> +	if (is_service_principal) {
> +		status = crack_service_principal_name(samdb,
> +						      mem_ctx,
> +						      target_principal_name,
> +						      &target_dn,
> +						      NULL);
> +	} else {
> +		status = crack_user_principal_name(samdb,
> +						   mem_ctx,
> +						   target_principal_name,
> +						   &target_dn,
> +						   NULL);
> +	}
> +	if (!NT_STATUS_IS_OK(status)) {
> +		ldb_transaction_cancel(samdb);
> +		return status;
> +	}
> +
> +	status = samdb_set_password(samdb,
> +				    mem_ctx,
> +				    target_dn,
> +				    NULL, /* domain_dn */
> +				    password,
> +				    NULL, /* lmNewHash */
> +				    NULL, /* ntNewHash */
> +				    NULL, /* lmOldHash */
> +				    NULL, /* ntOldHash */
> +				    reject_reason,
> +				    dominfo);
> +	if (NT_STATUS_IS_OK(status)) {
> +		rc = ldb_transaction_commit(samdb);
> +		if (rc != LDB_SUCCESS) {
> +			DBG_WARNING("Failed to commit transaction to "
> +				    "set password on %s: %s\n",
> +				    ldb_dn_get_linearized(target_dn),
> +				    ldb_errstring(samdb));
> +			return NT_STATUS_TRANSACTION_ABORTED;
> +		}
> +	} else {
> +		ldb_transaction_cancel(samdb);
> +	}
> +
> +	return status;
> +}
> diff --git a/source4/kdc/kpasswd-helper.h b/source4/kdc/kpasswd-helper.h
> index d2ff1e3..8fad81e 100644
> --- a/source4/kdc/kpasswd-helper.h
> +++ b/source4/kdc/kpasswd-helper.h
> @@ -33,4 +33,14 @@ bool kpasswd_make_pwchange_reply(TALLOC_CTX *mem_ctx,
>  				 struct samr_DomInfo1 *dominfo,
>  				 DATA_BLOB *error_blob);
>  
> +NTSTATUS kpasswd_samdb_set_password(TALLOC_CTX *mem_ctx,
> +				    struct tevent_context *event_ctx,
> +				    struct loadparm_context *lp_ctx,
> +				    struct auth_session_info *session_info,
> +				    bool is_service_principal,
> +				    const char *target_principal_name,
> +				    DATA_BLOB *password,
> +				    enum samPwdChangeReason *reject_reason,
> +				    struct samr_DomInfo1 **dominfo);
> +
>  #endif /* _KPASSWD_HELPER_H */
> -- 
> 2.10.0
> 
> 
> From a88f28fcfc259aa4800db4a2074d0d4c8905030b Mon Sep 17 00:00:00 2001
> From: Andreas Schneider <asn at samba.org>
> Date: Wed, 7 Sep 2016 12:30:21 +0200
> Subject: [PATCH 14/18] s4-kdc: Allow to set the keytab_name in the kdc_server
>  structure
> 
> Signed-off-by: Andreas Schneider <asn at samba.org>
> ---
>  source4/kdc/kdc-server.h | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/source4/kdc/kdc-server.h b/source4/kdc/kdc-server.h
> index 47e6c68..fd883c2 100644
> --- a/source4/kdc/kdc-server.h
> +++ b/source4/kdc/kdc-server.h
> @@ -40,6 +40,7 @@ struct kdc_server {
>  	struct ldb_context *samdb;
>  	bool am_rodc;
>  	uint32_t proxy_timeout;
> +	const char *keytab_name;
>  	void *private_data;
>  };
>  
> -- 
> 2.10.0
> 
> 
> From 05f99762c0a943f317f348b2e9419110c1eb1bb9 Mon Sep 17 00:00:00 2001
> From: Andreas Schneider <asn at samba.org>
> Date: Wed, 7 Sep 2016 12:32:14 +0200
> Subject: [PATCH 15/18] s4-kdc: Add a new kpasswd service implementation
> 
> This function is intended to be be passed to kdc_add_socket(). The
> function kpasswd_handle_request() which is called by kpasswd_process()
> is Kerberos implementation specific and should be implemented in a
> kpasswd-service-<kerberos flavour>.c file.
> 
> Signed-off-by: Andreas Schneider <asn at samba.org>
> ---
>  source4/kdc/kpasswd-service.c | 348 ++++++++++++++++++++++++++++++++++++++++++
>  source4/kdc/kpasswd-service.h |  43 ++++++
>  source4/kdc/wscript_build     |   9 ++
>  3 files changed, 400 insertions(+)
>  create mode 100644 source4/kdc/kpasswd-service.c
>  create mode 100644 source4/kdc/kpasswd-service.h
> 
> diff --git a/source4/kdc/kpasswd-service.c b/source4/kdc/kpasswd-service.c
> new file mode 100644
> index 0000000..2a8d691
> --- /dev/null
> +++ b/source4/kdc/kpasswd-service.c
> @@ -0,0 +1,348 @@
> +/*
> +   Unix SMB/CIFS implementation.
> +
> +   Samba kpasswd implementation
> +
> +   Copyright (c) 2005      Andrew Bartlett <abartlet at samba.org>
> +   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 "tsocket/tsocket.h"
> +#include "auth/credentials/credentials.h"
> +#include "auth/auth.h"
> +#include "auth/gensec/gensec.h"
> +#include "kdc/kdc-server.h"
> +#include "kdc/kpasswd-service.h"
> +#include "kdc/kpasswd-helper.h"
> +
> +#define HEADER_LEN 6
> +#ifndef RFC3244_VERSION
> +#define RFC3244_VERSION 0xff80
> +#endif
> +
> +kdc_code kpasswd_process(struct kdc_server *kdc,
> +			 TALLOC_CTX *mem_ctx,
> +			 DATA_BLOB *request,
> +			 DATA_BLOB *reply,
> +			 struct tsocket_address *remote_addr,
> +			 struct tsocket_address *local_addr,
> +			 int datagram)
> +{
> +	uint16_t len;
> +	uint16_t verno;
> +	uint16_t ap_req_len;
> +	uint16_t enc_data_len;
> +	DATA_BLOB ap_req_blob;
> +	DATA_BLOB ap_rep_blob = data_blob_null;
> +	DATA_BLOB enc_data_blob = data_blob_null;
> +	DATA_BLOB dec_data_blob;
> +	DATA_BLOB kpasswd_dec_reply;
> +	const char *error_string = NULL;
> +	krb5_error_code error_code = 0;
> +	struct cli_credentials *server_credentials;
> +	struct gensec_security *gensec_security;
> +#ifndef SAMBA4_USES_HEIMDAL
> +	struct sockaddr_storage remote_ss;
> +#endif
> +	struct sockaddr_storage local_ss;
> +	ssize_t socklen;
> +	TALLOC_CTX *tmp_ctx;
> +	kdc_code rc = KDC_ERROR;
> +	krb5_error_code code = 0;
> +	NTSTATUS status;
> +	int rv;
> +	bool is_inet;
> +	bool ok;
> +
> +	if (kdc->am_rodc) {
> +		return KDC_PROXY_REQUEST;
> +	}
> +
> +	tmp_ctx = talloc_new(mem_ctx);
> +	if (tmp_ctx == NULL) {
> +		return KDC_ERROR;
> +	}
> +
> +	is_inet = tsocket_address_is_inet(remote_addr, "ip");
> +	if (!is_inet) {
> +		DBG_WARNING("Invalid remote IP address");
> +		goto done;
> +	}
> +
> +#ifndef SAMBA4_USES_HEIMDAL
> +	/*
> +	 * FIXME: Heimdal fails to to do a krb5_rd_req() in gensec_krb5 if we
> +	 * set the remote address.
> +	 */
> +
> +	/* remote_addr */
> +	socklen = tsocket_address_bsd_sockaddr(remote_addr,
> +					       (struct sockaddr *)&remote_ss,
> +					       sizeof(struct sockaddr_storage));
> +	if (socklen < 0) {
> +		DBG_WARNING("Invalid remote IP address");
> +		goto done;
> +	}
> +#endif
> +
> +	/* local_addr */
> +	socklen = tsocket_address_bsd_sockaddr(local_addr,
> +					       (struct sockaddr *)&local_ss,
> +					       sizeof(struct sockaddr_storage));
> +	if (socklen < 0) {
> +		DBG_WARNING("Invalid local IP address");
> +		goto done;
> +	}
> +
> +	if (request->length <= HEADER_LEN) {
> +		DBG_WARNING("Request truncated\n");
> +		goto done;
> +	}
> +
> +	len = RSVAL(request->data, 0);
> +	if (request->length != len) {
> +		DBG_WARNING("Request length does not match\n");
> +		goto done;
> +	}
> +
> +	verno = RSVAL(request->data, 2);
> +	if (verno != 1 && verno != RFC3244_VERSION) {
> +		DBG_WARNING("Unsupported version: 0x%04x\n", verno);
> +	}
> +
> +	ap_req_len = RSVAL(request->data, 4);
> +	if ((ap_req_len >= len) || ((ap_req_len + HEADER_LEN) >= len)) {
> +		DBG_WARNING("AP_REQ truncated\n");
> +		goto done;
> +	}
> +
> +	ap_req_blob = data_blob_const(&request->data[HEADER_LEN], ap_req_len);
> +
> +	enc_data_len = len - ap_req_len;
> +	enc_data_blob = data_blob_const(&request->data[HEADER_LEN + ap_req_len],
> +					enc_data_len);
> +
> +	server_credentials = cli_credentials_init(tmp_ctx);
> +	if (server_credentials == NULL) {
> +		DBG_ERR("Failed to initialize server credentials!\n");
> +		goto done;
> +	}
> +
> +	/*
> +	 * We want the credentials subsystem to use the krb5 context we already
> +	 * have, rather than a new context.
> +	 *
> +	 * On this context the KDB plugin has been loaded, so we can access
> +	 * dsdb.
> +	 */
> +	status = cli_credentials_set_krb5_context(server_credentials,
> +						  kdc->smb_krb5_context);
> +	if (!NT_STATUS_IS_OK(status)) {
> +		goto done;
> +	}
> +
> +	cli_credentials_set_conf(server_credentials, kdc->task->lp_ctx);
> +
> +	ok = cli_credentials_set_username(server_credentials,
> +					  "kadmin/changepw",
> +					  CRED_SPECIFIED);
> +	if (!ok) {
> +		goto done;
> +	}
> +
> +	rv = cli_credentials_set_keytab_name(server_credentials,
> +					     kdc->task->lp_ctx,
> +					     kdc->keytab_name,
> +					     CRED_SPECIFIED);
> +	if (rv != 0) {
> +		DBG_ERR("Failed to set credentials keytab name\n");
> +		goto done;
> +	}
> +
> +	status = samba_server_gensec_start(tmp_ctx,
> +					   kdc->task->event_ctx,
> +					   kdc->task->msg_ctx,
> +					   kdc->task->lp_ctx,
> +					   server_credentials,
> +					   "kpasswd",
> +					   &gensec_security);
> +	if (!NT_STATUS_IS_OK(status)) {
> +		goto done;
> +	}
> +
> +	status = gensec_set_local_address(gensec_security, local_addr);
> +	if (!NT_STATUS_IS_OK(status)) {
> +		goto done;
> +	}
> +
> +#ifndef SAMBA4_USES_HEIMDAL
> +	status = gensec_set_remote_address(gensec_security, remote_addr);
> +	if (!NT_STATUS_IS_OK(status)) {
> +		goto done;
> +	}
> +#endif
> +
> +	/* We want the GENSEC wrap calls to generate PRIV tokens */
> +	gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
> +
> +	/* Use the krb5 gesec mechanism so we can load DB modules */
> +	status = gensec_start_mech_by_name(gensec_security, "krb5");
> +	if (!NT_STATUS_IS_OK(status)) {
> +		goto done;
> +	}
> +
> +	/* Accept the AP-REQ and generate the AP-REP we need for the reply */
> +	status = gensec_update_ev(gensec_security,
> +				  tmp_ctx,
> +				  kdc->task->event_ctx,
> +				  ap_req_blob,
> +				  &ap_rep_blob);
> +	if (!NT_STATUS_IS_OK(status) &&
> +	    !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
> +		ap_rep_blob = data_blob_null;
> +		error_code = KRB5_KPASSWD_HARDERROR;
> +		error_string = talloc_asprintf(tmp_ctx,
> +					       "gensec_update failed - %s\n",
> +					       nt_errstr(status));
> +		DBG_ERR("%s", error_string);
> +		goto reply;
> +	}
> +
> +	status = gensec_unwrap(gensec_security,
> +			       tmp_ctx,
> +			       &enc_data_blob,
> +			       &dec_data_blob);
> +	if (!NT_STATUS_IS_OK(status)) {
> +		ap_rep_blob = data_blob_null;
> +		error_code = KRB5_KPASSWD_HARDERROR;
> +		error_string = talloc_asprintf(tmp_ctx,
> +					       "gensec_unwrap failed - %s\n",
> +					       nt_errstr(status));
> +		DBG_ERR("%s", error_string);
> +		goto reply;
> +	}
> +
> +	code = kpasswd_handle_request(kdc,
> +				      tmp_ctx,
> +				      gensec_security,
> +				      verno,
> +				      &dec_data_blob,
> +				      &kpasswd_dec_reply,
> +				      &error_string);
> +	if (code != 0) {
> +		error_code = code;
> +		goto reply;
> +	}
> +
> +	status = gensec_wrap(gensec_security,
> +			     tmp_ctx,
> +			     &kpasswd_dec_reply,
> +			     &enc_data_blob);
> +	if (!NT_STATUS_IS_OK(status)) {
> +		error_code = KRB5_KPASSWD_HARDERROR;
> +		error_string = talloc_asprintf(tmp_ctx,
> +					       "gensec_wrap failed - %s\n",
> +					       nt_errstr(status));
> +		DBG_ERR("%s", error_string);
> +		goto reply;
> +	}
> +
> +reply:
> +	if (error_code != 0) {
> +		krb5_data k_enc_data;
> +		krb5_data k_dec_data;
> +		const char *principal_string;
> +		krb5_principal server_principal;
> +
> +		if (error_string == NULL) {
> +			DBG_ERR("Invalid error string! This should not happen\n");
> +			goto done;
> +		}
> +
> +		ok = kpasswd_make_error_reply(tmp_ctx,
> +					      error_code,
> +					      error_string,
> +					      &dec_data_blob);
> +		if (!ok) {
> +			DBG_ERR("Failed to create error reply\n");
> +			goto done;
> +		}
> +
> +		k_dec_data.length = dec_data_blob.length;
> +		k_dec_data.data   = (char *)dec_data_blob.data;
> +
> +		principal_string = cli_credentials_get_principal(server_credentials,
> +								 tmp_ctx);
> +		if (principal_string == NULL) {
> +			goto done;
> +		}
> +
> +		code = smb_krb5_parse_name(kdc->smb_krb5_context->krb5_context,
> +					   principal_string,
> +					   &server_principal);
> +		if (code != 0) {
> +			DBG_ERR("Failed to create principal: %s\n",
> +				error_message(code));
> +			goto done;
> +		}
> +
> +		code = smb_krb5_mk_error(kdc->smb_krb5_context->krb5_context,
> +					 error_code,
> +					 NULL, /* e_text */
> +					 &k_dec_data,
> +					 NULL, /* client */
> +					 server_principal,
> +					 &k_enc_data);
> +		krb5_free_principal(kdc->smb_krb5_context->krb5_context,
> +				    server_principal);
> +		if (code != 0) {
> +			DBG_ERR("Failed to create krb5 error reply: %s\n",
> +				error_message(code));
> +			goto done;
> +		}
> +
> +		enc_data_blob = data_blob_talloc(tmp_ctx,
> +						 k_enc_data.data,
> +						 k_enc_data.length);
> +		if (enc_data_blob.data == NULL) {
> +			DBG_ERR("Failed to allocate memory for error reply\n");
> +			goto done;
> +		}
> +	}
> +
> +	*reply = data_blob_talloc(mem_ctx,
> +				  NULL,
> +				  HEADER_LEN + ap_rep_blob.length + enc_data_blob.length);
> +	if (reply->data == NULL) {
> +		goto done;
> +	}
> +	RSSVAL(reply->data, 0, reply->length);
> +	RSSVAL(reply->data, 2, 1);
> +	RSSVAL(reply->data, 4, ap_rep_blob.length);
> +	memcpy(reply->data + HEADER_LEN,
> +	       ap_rep_blob.data,
> +	       ap_rep_blob.length);
> +	memcpy(reply->data + HEADER_LEN + ap_rep_blob.length,
> +	       enc_data_blob.data,
> +	       enc_data_blob.length);
> +
> +	rc = KDC_OK;
> +done:
> +	talloc_free(tmp_ctx);
> +	return rc;
> +}
> diff --git a/source4/kdc/kpasswd-service.h b/source4/kdc/kpasswd-service.h
> new file mode 100644
> index 0000000..845d680
> --- /dev/null
> +++ b/source4/kdc/kpasswd-service.h
> @@ -0,0 +1,43 @@
> +/*
> +   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/>.
> +*/
> +
> +#ifndef _KPASSWD_SERVICE_H
> +#define _KPASSWD_SERVICE_H
> +
> +struct gensec_security;
> +
> +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);
> +
> +kdc_code kpasswd_process(struct kdc_server *kdc,
> +			 TALLOC_CTX *mem_ctx,
> +			 DATA_BLOB *request,
> +			 DATA_BLOB *reply,
> +			 struct tsocket_address *remote_addr,
> +			 struct tsocket_address *local_addr,
> +			 int datagram);
> +
> +#endif /* _KPASSWD_SERVICE_H */
> diff --git a/source4/kdc/wscript_build b/source4/kdc/wscript_build
> index 170cc34..99678ea 100755
> --- a/source4/kdc/wscript_build
> +++ b/source4/kdc/wscript_build
> @@ -54,6 +54,15 @@ bld.SAMBA_SUBSYSTEM('KDC-SERVER',
>                      ''',
>                      enabled=bld.CONFIG_SET('SAMBA4_USES_HEIMDAL'))
>  
> +bld.SAMBA_SUBSYSTEM('KPASSWD-SERVICE',
> +                    source='kpasswd-service.c kpasswd-helper.c',
> +                    includes=kdc_include,
> +                    deps='''
> +                         krb5samba
> +                         samba_server_gensec
> +                         KPASSWD_GLUE
> +                         ''')
> +
>  bld.SAMBA_SUBSYSTEM('KDC-GLUE',
>  	source='kdc-glue.c',
>          includes=kdc_include,
> -- 
> 2.10.0
> 
> 
> From 91788579ec046d0d5d2f55a1a0b5ac56c997b27d Mon Sep 17 00:00:00 2001
> From: Andreas Schneider <asn at samba.org>
> Date: Wed, 7 Sep 2016 16:03:15 +0200
> Subject: [PATCH 16/18] s4-kdc: Add new kpasswd service Heimdal backend
> 
> Signed-off-by: Andreas Schneider <asn at samba.org>
> ---
>  source4/kdc/kpasswd-service-heimdal.c | 296 ++++++++++++++++++++++++++++++++++
>  source4/kdc/wscript_build             |   6 +-
>  2 files changed, 301 insertions(+), 1 deletion(-)
>  create mode 100644 source4/kdc/kpasswd-service-heimdal.c
> 
> diff --git a/source4/kdc/kpasswd-service-heimdal.c b/source4/kdc/kpasswd-service-heimdal.c
> new file mode 100644
> index 0000000..c5a40ef
> --- /dev/null
> +++ b/source4/kdc/kpasswd-service-heimdal.c
> @@ -0,0 +1,296 @@
> +/*
> +   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"
> +
> +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_error_code code;
> +	krb5_principal target_principal;
> +	ChangePasswdDataMS chpw;
> +	size_t chpw_len;
> +	DATA_BLOB password;
> +	enum samPwdChangeReason reject_reason = SAM_PWD_CHANGE_NO_ERROR;
> +	struct samr_DomInfo1 *dominfo = NULL;
> +	char *target_principal_string = NULL;
> +	bool is_service_principal = false;
> +	NTSTATUS status;
> +	bool ok;
> +
> +	code = decode_ChangePasswdDataMS(decoded_data->data,
> +					 decoded_data->length,
> +					 &chpw,
> +					 &chpw_len);
> +	if (code != 0) {
> +		DBG_WARNING("decode_ChangePasswdDataMS failed\n");
> +		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 *)chpw.newpasswd.data,
> +					  chpw.newpasswd.length,
> +					  (void **)&password.data,
> +					  &password.length);
> +	if (!ok) {
> +		free_ChangePasswdDataMS(&chpw);
> +		DBG_WARNING("String conversion failed\n");
> +		*error_string = "String conversion failed";
> +		return KRB5_KPASSWD_HARDERROR;
> +	}
> +
> +	if ((chpw.targname != NULL && chpw.targrealm == NULL) ||
> +	    (chpw.targname == NULL && chpw.targrealm != NULL)) {
> +		free_ChangePasswdDataMS(&chpw);
> +		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 (chpw.targname != NULL && chpw.targrealm != NULL) {
> +		code = krb5_build_principal_ext(context,
> +					       &target_principal,
> +					       strlen(*chpw.targrealm),
> +					       *chpw.targrealm,
> +					       0);
> +		if (code != 0) {
> +			free_ChangePasswdDataMS(&chpw);
> +			return kpasswd_make_error_reply(mem_ctx,
> +							KRB5_KPASSWD_MALFORMED,
> +							"Failed to parse principal",
> +							kpasswd_reply);
> +		}
> +		code = copy_PrincipalName(chpw.targname,
> +					  &target_principal->name);
> +		if (code != 0) {
> +			free_ChangePasswdDataMS(&chpw);
> +			krb5_free_principal(context, target_principal);
> +			return kpasswd_make_error_reply(mem_ctx,
> +							KRB5_KPASSWD_MALFORMED,
> +							"Failed to parse principal",
> +							kpasswd_reply);
> +		}
> +	} else {
> +		free_ChangePasswdDataMS(&chpw);
> +		return kpasswd_change_password(kdc,
> +					       mem_ctx,
> +					       session_info,
> +					       &password,
> +					       kpasswd_reply,
> +					       error_string);
> +	}
> +	free_ChangePasswdDataMS(&chpw);
> +
> +	if (target_principal->name.name_string.len >= 2) {
> +		is_service_principal = true;
> +
> +		code = krb5_unparse_name_short(context,
> +					       target_principal,
> +					       &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 KRB5_KPASSWD_VERS_CHANGEPW: {
> +		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 KRB5_KPASSWD_VERS_SETPW: {
> +		return kpasswd_set_password(kdc,
> +					    mem_ctx,
> +					    session_info,
> +					    decoded_data,
> +					    kpasswd_reply,
> +					    error_string);
> +	}
> +	default:
> +		*error_string = talloc_asprintf(mem_ctx,
> +						"Protocol version %u not supported",
> +						verno);
> +		return KRB5_KPASSWD_BAD_VERSION;
> +	}
> +
> +	return 0;
> +}
> diff --git a/source4/kdc/wscript_build b/source4/kdc/wscript_build
> index 99678ea..18eae90 100755
> --- a/source4/kdc/wscript_build
> +++ b/source4/kdc/wscript_build
> @@ -54,8 +54,12 @@ bld.SAMBA_SUBSYSTEM('KDC-SERVER',
>                      ''',
>                      enabled=bld.CONFIG_SET('SAMBA4_USES_HEIMDAL'))
>  
> +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'
> +
>  bld.SAMBA_SUBSYSTEM('KPASSWD-SERVICE',
> -                    source='kpasswd-service.c kpasswd-helper.c',
> +                    source=kpasswd_flavor_src,
>                      includes=kdc_include,
>                      deps='''
>                           krb5samba
> -- 
> 2.10.0
> 
> 
> From 78fb521f42cb58d33ce3ae87985ffff80d0edfe1 Mon Sep 17 00:00:00 2001
> From: Andreas Schneider <asn at samba.org>
> Date: Wed, 7 Sep 2016 16:38:06 +0200
> Subject: [PATCH 17/18] s4-kdc: Switch to the new kpasswd service
>  implementation
> 
> Signed-off-by: Andreas Schneider <asn at samba.org>
> ---
>  source4/kdc/kdc-heimdal.c | 13 +++++++++++--
>  source4/kdc/wscript_build |  3 ++-
>  2 files changed, 13 insertions(+), 3 deletions(-)
> 
> diff --git a/source4/kdc/kdc-heimdal.c b/source4/kdc/kdc-heimdal.c
> index be45073..f2927e5 100644
> --- a/source4/kdc/kdc-heimdal.c
> +++ b/source4/kdc/kdc-heimdal.c
> @@ -33,6 +33,7 @@
>  #include "kdc/kdc-proxy.h"
>  #include "kdc/kdc-glue.h"
>  #include "kdc/pac-glue.h"
> +#include "kdc/kpasswd-service.h"
>  #include "dsdb/samdb/samdb.h"
>  #include "auth/session.h"
>  #include "libds/common/roles.h"
> @@ -151,7 +152,7 @@ static NTSTATUS kdc_startup_interfaces(struct kdc_server *kdc, struct loadparm_c
>  			if (kpasswd_port) {
>  				status = kdc_add_socket(kdc, model_ops,
>  							"kpasswd", wcard[i], kpasswd_port,
> -							kpasswdd_process, false);
> +							kpasswd_process, false);
>  				if (NT_STATUS_IS_OK(status)) {
>  					num_binds++;
>  				}
> @@ -177,7 +178,7 @@ static NTSTATUS kdc_startup_interfaces(struct kdc_server *kdc, struct loadparm_c
>  		if (kpasswd_port) {
>  			status = kdc_add_socket(kdc, model_ops,
>  						"kpasswd", address, kpasswd_port,
> -						kpasswdd_process, done_wildcard);
> +						kpasswd_process, done_wildcard);
>  			NT_STATUS_NOT_OK_RETURN(status);
>  		}
>  	}
> @@ -411,6 +412,14 @@ static void kdc_task_init(struct task_server *task)
>  		return;
>  	}
>  
> +	kdc->keytab_name = talloc_asprintf(kdc, "HDB:samba4&%p", kdc->base_ctx);
> +	if (kdc->keytab_name == NULL) {
> +		task_server_terminate(task,
> +				      "kdc: Failed to set keytab name",
> +				      true);
> +		return;
> +	}
> +
>  	/* Register WinDC hooks */
>  	ret = krb5_plugin_register(kdc->smb_krb5_context->krb5_context,
>  				   PLUGIN_TYPE_DATA, "windc",
> diff --git a/source4/kdc/wscript_build b/source4/kdc/wscript_build
> index 18eae90..24d89f4 100755
> --- a/source4/kdc/wscript_build
> +++ b/source4/kdc/wscript_build
> @@ -7,7 +7,7 @@ else:
>      kdc_include = getattr(bld.env, "CPPPATH_KDC")
>  
>  bld.SAMBA_MODULE('service_kdc',
> -                 source='kdc-heimdal.c kpasswd-helper.c kpasswd-heimdal.c',
> +                 source='kdc-heimdal.c',
>                   subsystem='service',
>                   init_function='server_service_kdc_init',
>                   deps='''
> @@ -20,6 +20,7 @@ bld.SAMBA_MODULE('service_kdc',
>                        PAC_GLUE
>                        KDC-GLUE
>                        KDC-SERVER
> +                      KPASSWD-SERVICE
>                        KPASSWD_GLUE
>                   ''',
>                   internal_module=False)
> -- 
> 2.10.0
> 
> 
> From 9b9234203bf078dee6accac074ce38a986795197 Mon Sep 17 00:00:00 2001
> From: Andreas Schneider <asn at samba.org>
> Date: Wed, 7 Sep 2016 17:47:24 +0200
> Subject: [PATCH 18/18] s4-kdc: Remove obsolete kpasswdd heimdal implementation
> 
> Signed-off-by: Andreas Schneider <asn at samba.org>
> ---
>  source4/kdc/kdc-heimdal.c | 469 ----------------------------------------------
>  1 file changed, 469 deletions(-)
>  delete mode 100644 source4/kdc/kdc-heimdal.c
> 
> diff --git a/source4/kdc/kdc-heimdal.c b/source4/kdc/kdc-heimdal.c
> deleted file mode 100644
> index f2927e5..0000000
> --- a/source4/kdc/kdc-heimdal.c
> +++ /dev/null
> @@ -1,469 +0,0 @@
> -/*
> -   Unix SMB/CIFS implementation.
> -
> -   KDC Server startup
> -
> -   Copyright (C) Andrew Bartlett <abartlet at samba.org> 2005-2008
> -   Copyright (C) Andrew Tridgell	2005
> -   Copyright (C) Stefan Metzmacher	2005
> -
> -   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/process_model.h"
> -#include "lib/tsocket/tsocket.h"
> -#include "lib/messaging/irpc.h"
> -#include "librpc/gen_ndr/ndr_irpc.h"
> -#include "librpc/gen_ndr/ndr_krb5pac.h"
> -#include "lib/socket/netif.h"
> -#include "param/param.h"
> -#include "kdc/kdc-server.h"
> -#include "kdc/kdc-proxy.h"
> -#include "kdc/kdc-glue.h"
> -#include "kdc/pac-glue.h"
> -#include "kdc/kpasswd-service.h"
> -#include "dsdb/samdb/samdb.h"
> -#include "auth/session.h"
> -#include "libds/common/roles.h"
> -#include <kdc.h>
> -#include <hdb.h>
> -
> -NTSTATUS server_service_kdc_init(void);
> -
> -extern struct krb5plugin_windc_ftable windc_plugin_table;
> -
> -/**
> -   Wrapper for krb5_kdc_process_krb5_request, converting to/from Samba
> -   calling conventions
> -*/
> -
> -static kdc_code kdc_process(struct kdc_server *kdc,
> -			    TALLOC_CTX *mem_ctx,
> -			    DATA_BLOB *input,
> -			    DATA_BLOB *reply,
> -			    struct tsocket_address *peer_addr,
> -			    struct tsocket_address *my_addr,
> -			    int datagram_reply)
> -{
> -	int ret;
> -	char *pa;
> -	struct sockaddr_storage ss;
> -	krb5_data k5_reply;
> -	krb5_kdc_configuration *kdc_config =
> -		(krb5_kdc_configuration *)kdc->private_data;
> -
> -	krb5_data_zero(&k5_reply);
> -
> -	krb5_kdc_update_time(NULL);
> -
> -	ret = tsocket_address_bsd_sockaddr(peer_addr, (struct sockaddr *) &ss,
> -				sizeof(struct sockaddr_storage));
> -	if (ret < 0) {
> -		return KDC_ERROR;
> -	}
> -	pa = tsocket_address_string(peer_addr, mem_ctx);
> -	if (pa == NULL) {
> -		return KDC_ERROR;
> -	}
> -
> -	DEBUG(10,("Received KDC packet of length %lu from %s\n",
> -				(long)input->length - 4, pa));
> -
> -	ret = krb5_kdc_process_krb5_request(kdc->smb_krb5_context->krb5_context,
> -					    kdc_config,
> -					    input->data, input->length,
> -					    &k5_reply,
> -					    pa,
> -					    (struct sockaddr *) &ss,
> -					    datagram_reply);
> -	if (ret == -1) {
> -		*reply = data_blob(NULL, 0);
> -		return KDC_ERROR;
> -	}
> -
> -	if (ret == HDB_ERR_NOT_FOUND_HERE) {
> -		*reply = data_blob(NULL, 0);
> -		return KDC_PROXY_REQUEST;
> -	}
> -
> -	if (k5_reply.length) {
> -		*reply = data_blob_talloc(mem_ctx, k5_reply.data, k5_reply.length);
> -		krb5_data_free(&k5_reply);
> -	} else {
> -		*reply = data_blob(NULL, 0);
> -	}
> -	return KDC_OK;
> -}
> -
> -/*
> -  setup our listening sockets on the configured network interfaces
> -*/
> -static NTSTATUS kdc_startup_interfaces(struct kdc_server *kdc, struct loadparm_context *lp_ctx,
> -				       struct interface *ifaces)
> -{
> -	const struct model_ops *model_ops;
> -	int num_interfaces;
> -	TALLOC_CTX *tmp_ctx = talloc_new(kdc);
> -	NTSTATUS status;
> -	int i;
> -	uint16_t kdc_port = lpcfg_krb5_port(lp_ctx);
> -	uint16_t kpasswd_port = lpcfg_kpasswd_port(lp_ctx);
> -	bool done_wildcard = false;
> -
> -	/* within the kdc task we want to be a single process, so
> -	   ask for the single process model ops and pass these to the
> -	   stream_setup_socket() call. */
> -	model_ops = process_model_startup("single");
> -	if (!model_ops) {
> -		DEBUG(0,("Can't find 'single' process model_ops\n"));
> -		return NT_STATUS_INTERNAL_ERROR;
> -	}
> -
> -	num_interfaces = iface_list_count(ifaces);
> -
> -	/* if we are allowing incoming packets from any address, then
> -	   we need to bind to the wildcard address */
> -	if (!lpcfg_bind_interfaces_only(lp_ctx)) {
> -		int num_binds = 0;
> -		char **wcard = iface_list_wildcard(kdc);
> -		NT_STATUS_HAVE_NO_MEMORY(wcard);
> -		for (i=0; wcard[i]; i++) {
> -			if (kdc_port) {
> -				status = kdc_add_socket(kdc, model_ops,
> -							"kdc", wcard[i], kdc_port,
> -							kdc_process, false);
> -				if (NT_STATUS_IS_OK(status)) {
> -					num_binds++;
> -				}
> -			}
> -
> -			if (kpasswd_port) {
> -				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) {
> -			return NT_STATUS_INVALID_PARAMETER_MIX;
> -		}
> -		done_wildcard = true;
> -	}
> -
> -	for (i=0; i<num_interfaces; i++) {
> -		const char *address = talloc_strdup(tmp_ctx, iface_list_n_ip(ifaces, i));
> -
> -		if (kdc_port) {
> -			status = kdc_add_socket(kdc, model_ops,
> -						"kdc", address, kdc_port,
> -						kdc_process, done_wildcard);
> -			NT_STATUS_NOT_OK_RETURN(status);
> -		}
> -
> -		if (kpasswd_port) {
> -			status = kdc_add_socket(kdc, model_ops,
> -						"kpasswd", address, kpasswd_port,
> -						kpasswd_process, done_wildcard);
> -			NT_STATUS_NOT_OK_RETURN(status);
> -		}
> -	}
> -
> -	talloc_free(tmp_ctx);
> -
> -	return NT_STATUS_OK;
> -}
> -
> -static NTSTATUS kdc_check_generic_kerberos(struct irpc_message *msg,
> -				 struct kdc_check_generic_kerberos *r)
> -{
> -	struct PAC_Validate pac_validate;
> -	DATA_BLOB srv_sig;
> -	struct PAC_SIGNATURE_DATA kdc_sig;
> -	struct kdc_server *kdc = talloc_get_type(msg->private_data, struct kdc_server);
> -	krb5_kdc_configuration *kdc_config =
> -		(krb5_kdc_configuration *)kdc->private_data;
> -	enum ndr_err_code ndr_err;
> -	int ret;
> -	hdb_entry_ex ent;
> -	krb5_principal principal;
> -
> -
> -	/* 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;
> -	}
> -
> -	srv_sig = data_blob_const(pac_validate.ChecksumAndSignature.data,
> -				  pac_validate.ChecksumLength);
> -
> -	ret = krb5_make_principal(kdc->smb_krb5_context->krb5_context, &principal,
> -				  lpcfg_realm(kdc->task->lp_ctx),
> -				  "krbtgt", lpcfg_realm(kdc->task->lp_ctx),
> -				  NULL);
> -
> -	if (ret != 0) {
> -		return NT_STATUS_NO_MEMORY;
> -	}
> -
> -	ret = kdc_config->db[0]->hdb_fetch_kvno(kdc->smb_krb5_context->krb5_context,
> -						 kdc_config->db[0],
> -						 principal,
> -						 HDB_F_GET_KRBTGT | HDB_F_DECRYPT,
> -						 0,
> -						 &ent);
> -
> -	if (ret != 0) {
> -		hdb_free_entry(kdc->smb_krb5_context->krb5_context, &ent);
> -		krb5_free_principal(kdc->smb_krb5_context->krb5_context, principal);
> -
> -		return NT_STATUS_LOGON_FAILURE;
> -	}
> -
> -	kdc_sig.type = pac_validate.SignatureType;
> -	kdc_sig.signature = data_blob_const(&pac_validate.ChecksumAndSignature.data[pac_validate.ChecksumLength],
> -					    pac_validate.SignatureLength);
> -
> -	ret = kdc_check_pac(kdc->smb_krb5_context->krb5_context, srv_sig, &kdc_sig, &ent);
> -
> -	hdb_free_entry(kdc->smb_krb5_context->krb5_context, &ent);
> -	krb5_free_principal(kdc->smb_krb5_context->krb5_context, principal);
> -
> -	if (ret != 0) {
> -		return NT_STATUS_LOGON_FAILURE;
> -	}
> -
> -	return NT_STATUS_OK;
> -}
> -
> -
> -/*
> -  startup the kdc task
> -*/
> -static void kdc_task_init(struct task_server *task)
> -{
> -	struct kdc_server *kdc;
> -	krb5_kdc_configuration *kdc_config = NULL;
> -	NTSTATUS status;
> -	krb5_error_code ret;
> -	struct interface *ifaces;
> -	int ldb_ret;
> -
> -	switch (lpcfg_server_role(task->lp_ctx)) {
> -	case ROLE_STANDALONE:
> -		task_server_terminate(task, "kdc: no KDC required in standalone configuration", false);
> -		return;
> -	case ROLE_DOMAIN_MEMBER:
> -		task_server_terminate(task, "kdc: no KDC required in member server configuration", false);
> -		return;
> -	case ROLE_DOMAIN_PDC:
> -	case ROLE_DOMAIN_BDC:
> -		task_server_terminate(task, "Cannot start KDC as a 'classic Samba' DC", true);
> -		return;
> -	case ROLE_ACTIVE_DIRECTORY_DC:
> -		/* Yes, we want a KDC */
> -		break;
> -	}
> -
> -	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;
> -	}
> -
> -	task_server_set_title(task, "task[kdc]");
> -
> -	kdc = talloc_zero(task, struct kdc_server);
> -	if (kdc == NULL) {
> -		task_server_terminate(task, "kdc: out of memory", true);
> -		return;
> -	}
> -
> -	kdc->task = task;
> -
> -
> -	/* get a samdb connection */
> -	kdc->samdb = samdb_connect(kdc, kdc->task->event_ctx, kdc->task->lp_ctx,
> -				   system_session(kdc->task->lp_ctx), 0);
> -	if (!kdc->samdb) {
> -		DEBUG(1,("kdc_task_init: unable to connect to samdb\n"));
> -		task_server_terminate(task, "kdc: krb5_init_context samdb connect failed", true);
> -		return;
> -	}
> -
> -	ldb_ret = samdb_rodc(kdc->samdb, &kdc->am_rodc);
> -	if (ldb_ret != LDB_SUCCESS) {
> -		DEBUG(1, ("kdc_task_init: Cannot determine if we are an RODC: %s\n",
> -			  ldb_errstring(kdc->samdb)));
> -		task_server_terminate(task, "kdc: krb5_init_context samdb RODC connect failed", true);
> -		return;
> -	}
> -
> -	kdc->proxy_timeout = lpcfg_parm_int(kdc->task->lp_ctx, NULL, "kdc", "proxy timeout", 5);
> -
> -	initialize_krb5_error_table();
> -
> -	ret = smb_krb5_init_context(kdc, task->lp_ctx, &kdc->smb_krb5_context);
> -	if (ret) {
> -		DEBUG(1,("kdc_task_init: krb5_init_context failed (%s)\n",
> -			 error_message(ret)));
> -		task_server_terminate(task, "kdc: krb5_init_context failed", true);
> -		return;
> -	}
> -
> -	krb5_add_et_list(kdc->smb_krb5_context->krb5_context, initialize_hdb_error_table_r);
> -
> -	ret = krb5_kdc_get_config(kdc->smb_krb5_context->krb5_context,
> -				  &kdc_config);
> -	if(ret) {
> -		task_server_terminate(task, "kdc: failed to get KDC configuration", true);
> -		return;
> -	}
> -
> -	kdc_config->logf = (krb5_log_facility *)kdc->smb_krb5_context->pvt_log_data;
> -	kdc_config->db = talloc(kdc, struct HDB *);
> -	if (!kdc_config->db) {
> -		task_server_terminate(task, "kdc: out of memory", true);
> -		return;
> -	}
> -	kdc_config->num_db = 1;
> -
> -	/*
> -	 * This restores the behavior before
> -	 * commit 255e3e18e00f717d99f3bc57c8a8895ff624f3c3
> -	 * s4:heimdal: import lorikeet-heimdal-201107150856
> -	 * (commit 48936803fae4a2fb362c79365d31f420c917b85b)
> -	 *
> -	 * as_use_strongest_session_key,preauth_use_strongest_session_key
> -	 * and tgs_use_strongest_session_key are input to the
> -	 * _kdc_find_etype() function. The old bahavior is in
> -	 * the use_strongest_session_key=FALSE code path.
> -	 * (The only remaining difference in _kdc_find_etype()
> -	 *  is the is_preauth parameter.)
> -	 *
> -	 * The old behavior in the _kdc_get_preferred_key()
> -	 * function is use_strongest_server_key=TRUE.
> -	 */
> -	kdc_config->as_use_strongest_session_key = false;
> -	kdc_config->preauth_use_strongest_session_key = false;
> -	kdc_config->tgs_use_strongest_session_key = false;
> -	kdc_config->use_strongest_server_key = true;
> -
> -	/* Register hdb-samba4 hooks for use as a keytab */
> -
> -	kdc->base_ctx = talloc_zero(kdc, struct samba_kdc_base_context);
> -	if (!kdc->base_ctx) {
> -		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;
> -
> -	status = hdb_samba4_create_kdc(kdc->base_ctx,
> -				       kdc->smb_krb5_context->krb5_context,
> -				       &kdc_config->db[0]);
> -	if (!NT_STATUS_IS_OK(status)) {
> -		task_server_terminate(task, "kdc: hdb_samba4_create_kdc (setup KDC database) failed", true);
> -		return;
> -	}
> -
> -	ret = krb5_plugin_register(kdc->smb_krb5_context->krb5_context,
> -				   PLUGIN_TYPE_DATA, "hdb",
> -				   &hdb_samba4_interface);
> -	if(ret) {
> -		task_server_terminate(task, "kdc: failed to register hdb plugin", true);
> -		return;
> -	}
> -
> -	ret = krb5_kt_register(kdc->smb_krb5_context->krb5_context, &hdb_kt_ops);
> -	if(ret) {
> -		task_server_terminate(task, "kdc: failed to register keytab plugin", true);
> -		return;
> -	}
> -
> -	kdc->keytab_name = talloc_asprintf(kdc, "HDB:samba4&%p", kdc->base_ctx);
> -	if (kdc->keytab_name == NULL) {
> -		task_server_terminate(task,
> -				      "kdc: Failed to set keytab name",
> -				      true);
> -		return;
> -	}
> -
> -	/* Register WinDC hooks */
> -	ret = krb5_plugin_register(kdc->smb_krb5_context->krb5_context,
> -				   PLUGIN_TYPE_DATA, "windc",
> -				   &windc_plugin_table);
> -	if(ret) {
> -		task_server_terminate(task, "kdc: failed to register windc plugin", true);
> -		return;
> -	}
> -
> -	ret = krb5_kdc_windc_init(kdc->smb_krb5_context->krb5_context);
> -
> -	if(ret) {
> -		task_server_terminate(task, "kdc: failed to init windc plugin", true);
> -		return;
> -	}
> -
> -	ret = krb5_kdc_pkinit_config(kdc->smb_krb5_context->krb5_context, kdc_config);
> -
> -	if(ret) {
> -		task_server_terminate(task, "kdc: failed to init kdc pkinit subsystem", true);
> -		return;
> -	}
> -	kdc->private_data = kdc_config;
> -
> -	/* start listening on the configured network interfaces */
> -	status = kdc_startup_interfaces(kdc, task->lp_ctx, ifaces);
> -	if (!NT_STATUS_IS_OK(status)) {
> -		task_server_terminate(task, "kdc failed to setup interfaces", true);
> -		return;
> -	}
> -
> -	status = IRPC_REGISTER(task->msg_ctx, irpc, KDC_CHECK_GENERIC_KERBEROS,
> -			       kdc_check_generic_kerberos, kdc);
> -	if (!NT_STATUS_IS_OK(status)) {
> -		task_server_terminate(task, "kdc failed to setup monitoring", true);
> -		return;
> -	}
> -
> -	irpc_add_name(task->msg_ctx, "kdc_server");
> -}
> -
> -
> -/* called at smbd startup - register ourselves as a server service */
> -NTSTATUS server_service_kdc_init(void)
> -{
> -	return register_server_service("kdc", kdc_task_init);
> -}
> -- 
> 2.10.0
> 




More information about the samba-technical mailing list