[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