torture: Start a new testsuite for krb5 and KDC behaviour
authorAndrew Bartlett <abartlet@samba.org>
Mon, 5 Jan 2015 01:54:45 +0000 (14:54 +1300)
committerAndrew Bartlett <abartlet@samba.org>
Fri, 23 Jan 2015 04:42:07 +0000 (05:42 +0100)
Pair-programmed-with: Garming Sam <garming@catalyst.net.nz>
Signed-off-by: Garming Sam <garming@catalyst.net.nz>
Signed-off-by: Andrew Bartlett <abartlet@samba.org>
source4/auth/kerberos/krb5_init_context.c
source4/auth/kerberos/krb5_init_context.h
source4/selftest/tests.py
source4/torture/krb5/kdc.c [new file with mode: 0644]
source4/torture/krb5/wscript_build [new file with mode: 0644]
source4/torture/wscript_build

index 4404b6734c0fcfbb1807f2a1af24d6e0d73550ec..e8a1a6cc2ea9d5ba252de441e0695383f1291c49 100644 (file)
@@ -210,46 +210,31 @@ static void smb_krb5_socket_handler(struct tevent_context *ev, struct tevent_fd
        }
 }
 
-krb5_error_code smb_krb5_send_and_recv_func(krb5_context context,
-                                           void *data,
-                                           krb5_krbhst_info *hi,
-                                           time_t timeout,
-                                           const krb5_data *send_buf,
-                                           krb5_data *recv_buf)
+static krb5_error_code smb_krb5_send_and_recv_func_int(krb5_context context,
+                                                      struct tevent_context *ev,
+                                                      krb5_krbhst_info *hi,
+                                                      struct addrinfo *ai,
+                                                      krb5_send_to_kdc_func func,
+                                                      void *data,
+                                                      time_t timeout,
+                                                      const krb5_data *send_buf,
+                                                      krb5_data *recv_buf)
 {
        krb5_error_code ret;
        NTSTATUS status;
        const char *name;
-       struct addrinfo *ai, *a;
+       struct addrinfo *a;
        struct smb_krb5_socket *smb_krb5;
 
        DATA_BLOB send_blob;
 
-       struct tevent_context *ev;
        TALLOC_CTX *tmp_ctx = talloc_new(NULL);
        if (!tmp_ctx) {
                return ENOMEM;
        }
 
-       if (!data) {
-               /* If no event context was available, then create one for this loop */
-               ev = samba_tevent_context_init(tmp_ctx);
-               if (!ev) {
-                       talloc_free(tmp_ctx);
-                       return ENOMEM;
-               }
-       } else {
-               ev = talloc_get_type_abort(data, struct tevent_context);
-       }
-
        send_blob = data_blob_const(send_buf->data, send_buf->length);
 
-       ret = krb5_krbhst_get_addrinfo(context, hi, &ai);
-       if (ret) {
-               talloc_free(tmp_ctx);
-               return ret;
-       }
-
        for (a = ai; a; a = a->ai_next) {
                struct socket_address *remote_addr;
                smb_krb5 = talloc(tmp_ctx, struct smb_krb5_socket);
@@ -359,18 +344,20 @@ krb5_error_code smb_krb5_send_and_recv_func(krb5_context context,
                                return EINVAL;
                        }
 
-                       /* After each and every event loop, reset the
-                        * send_to_kdc pointers to what they were when
-                        * we entered this loop.  That way, if a
-                        * nested event has invalidated them, we put
-                        * it back before we return to the heimdal
-                        * code */
-                       ret = krb5_set_send_to_kdc_func(context,
-                                                       smb_krb5_send_and_recv_func,
-                                                       data);
-                       if (ret != 0) {
-                               talloc_free(tmp_ctx);
-                               return ret;
+                        if (func) {
+                               /* After each and every event loop, reset the
+                                * send_to_kdc pointers to what they were when
+                                * we entered this loop.  That way, if a
+                                * nested event has invalidated them, we put
+                                * it back before we return to the heimdal
+                                * code */
+                               ret = krb5_set_send_to_kdc_func(context,
+                                                               func,
+                                                               data);
+                               if (ret != 0) {
+                                       talloc_free(tmp_ctx);
+                                       return ret;
+                               }
                        }
                }
                if (NT_STATUS_EQUAL(smb_krb5->status, NT_STATUS_IO_TIMEOUT)) {
@@ -407,6 +394,68 @@ krb5_error_code smb_krb5_send_and_recv_func(krb5_context context,
        }
        return KRB5_KDC_UNREACH;
 }
+
+krb5_error_code smb_krb5_send_and_recv_func(krb5_context context,
+                                           void *data,
+                                           krb5_krbhst_info *hi,
+                                           time_t timeout,
+                                           const krb5_data *send_buf,
+                                           krb5_data *recv_buf)
+{
+       krb5_error_code ret;
+       struct addrinfo *ai;
+
+       struct tevent_context *ev;
+       TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+       if (!tmp_ctx) {
+               return ENOMEM;
+       }
+
+       if (!data) {
+               /* If no event context was available, then create one for this loop */
+               ev = samba_tevent_context_init(tmp_ctx);
+               if (!ev) {
+                       talloc_free(tmp_ctx);
+                       return ENOMEM;
+               }
+       } else {
+               ev = talloc_get_type_abort(data, struct tevent_context);
+       }
+
+       ret = krb5_krbhst_get_addrinfo(context, hi, &ai);
+       if (ret) {
+               talloc_free(tmp_ctx);
+               return ret;
+       }
+       return smb_krb5_send_and_recv_func_int(context, ev, hi, ai, smb_krb5_send_and_recv_func, data, timeout, send_buf, recv_buf);
+}
+
+krb5_error_code smb_krb5_send_and_recv_func_forced(krb5_context context,
+                                                  void *data, /* struct addrinfo */
+                                                  krb5_krbhst_info *hi,
+                                                  time_t timeout,
+                                                  const krb5_data *send_buf,
+                                                  krb5_data *recv_buf)
+{
+       struct addrinfo *ai = data;
+
+       struct tevent_context *ev;
+       TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+       if (!tmp_ctx) {
+               return ENOMEM;
+       }
+
+       /* If no event context was available, then create one for this loop */
+       ev = samba_tevent_context_init(tmp_ctx);
+       if (!ev) {
+               talloc_free(tmp_ctx);
+               return ENOMEM;
+       }
+
+       /* No need to pass in send_and_recv functions, we won't nest on this private event loop */
+       return smb_krb5_send_and_recv_func_int(context, ev, hi, ai, NULL, NULL,
+                                              timeout, send_buf, recv_buf);
+}
 #endif
 
 krb5_error_code
index 3c32069ba2fdf34e4e22577deafad34094c697e1..6c997c5fa563e69077abb88c24ffbb02acf51ed8 100644 (file)
@@ -45,6 +45,12 @@ krb5_error_code smb_krb5_send_and_recv_func(krb5_context context,
                                            time_t timeout,
                                            const krb5_data *send_buf,
                                            krb5_data *recv_buf);
+krb5_error_code smb_krb5_send_and_recv_func_forced(krb5_context context,
+                                                  void *data, /* struct addrinfo */
+                                                  krb5_krbhst_info *hi,
+                                                  time_t timeout,
+                                                  const krb5_data *send_buf,
+                                                  krb5_data *recv_buf);
 krb5_error_code smb_krb5_context_set_event_ctx(struct smb_krb5_context *smb_krb5_context,
                                               struct tevent_context *ev,
                                               struct tevent_context **previous_ev);
index a991e1271f4382f4cf4d5df1ffa5b3e0a74c166e..5208774d702af13c4d87d105c02fe9bc02b7bca8 100755 (executable)
@@ -548,6 +548,10 @@ for env in ['vampire_dc', 'promoted_dc']:
 for env in ["dc", "s4member", "rodc", "promoted_dc", "plugin_s4_dc", "s3member"]:
     plantestsuite("samba.blackbox.wbinfo(%s:local)" % env, "%s:local" % env, [os.path.join(samba4srcdir, "../nsswitch/tests/test_wbinfo.sh"), '$DOMAIN', '$DC_USERNAME', '$DC_PASSWORD', env])
 
+for env in ["dc", "rodc", "promoted_dc", "plugin_s4_dc"]:
+    plansmbtorture4testsuite('krb5.kdc', env, ['ncacn_np:$SERVER', "-k", "yes", '-U$USERNAME@$REALM%$PASSWORD', '--workgroup=$DOMAIN'])
+
+
 # TODO: Verifying the databases really should be a part of the
 # environment teardown.
 # check the databases are all OK. PLEASE LEAVE THIS AS THE LAST TEST
diff --git a/source4/torture/krb5/kdc.c b/source4/torture/krb5/kdc.c
new file mode 100644 (file)
index 0000000..9dcee40
--- /dev/null
@@ -0,0 +1,118 @@
+/* 
+   Unix SMB/CIFS implementation.
+
+   Validate the krb5 pac generation routines
+   
+   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2015
+
+   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 "torture/smbtorture.h"
+#include "torture/winbind/proto.h"
+#include "auth/credentials/credentials.h"
+#include "lib/cmdline/popt_common.h"
+#include "source4/auth/kerberos/kerberos.h"
+#include "source4/auth/kerberos/kerberos_util.h"
+#include "lib/util/util_net.h"
+
+static bool torture_krb5_init_context(struct torture_context *tctx,
+                                     struct smb_krb5_context **smb_krb5_context)
+{
+       const char *host = torture_setting_string(tctx, "host", NULL);
+       krb5_error_code k5ret;
+       bool ok;
+       struct addrinfo *server;
+       
+       k5ret = smb_krb5_init_context(tctx, tctx->lp_ctx, smb_krb5_context);
+       torture_assert_int_equal(tctx, k5ret, 0, "smb_krb5_init_context failed");
+
+       ok = interpret_string_addr_internal(&server, host, AI_NUMERICHOST);
+       torture_assert(tctx, ok, "Failed to parse target server");
+
+       set_sockaddr_port(server->ai_addr, 88);
+
+       k5ret = krb5_set_send_to_kdc_func((*smb_krb5_context)->krb5_context,
+                                         smb_krb5_send_and_recv_func_forced,
+                                         server);
+       torture_assert_int_equal(tctx, k5ret, 0, "krb5_set_send_to_kdc_func failed");
+       return true;
+}
+
+static bool torture_krb5_as_req_1(struct torture_context *tctx)
+{
+       krb5_error_code k5ret;
+       bool ok;
+       krb5_creds my_creds;
+       krb5_principal principal;
+       struct smb_krb5_context *smb_krb5_context;
+       enum credentials_obtained obtained;
+       const char *error_string;
+       const char *password = cli_credentials_get_password(cmdline_credentials);
+       
+       ok = torture_krb5_init_context(tctx, &smb_krb5_context);
+       torture_assert(tctx, ok, "torture_krb5_init_context failed");
+       
+       k5ret = principal_from_credentials(tctx, cmdline_credentials, smb_krb5_context, &principal, &obtained,  &error_string);
+       torture_assert_int_equal(tctx, k5ret, 0, error_string);
+
+       k5ret = krb5_get_init_creds_password(smb_krb5_context->krb5_context, &my_creds, principal,
+                                            password, NULL, NULL, 0,
+                                            NULL, NULL);
+       torture_assert_int_equal(tctx, k5ret, 0, "krb5_get_init_creds_password failed");
+
+       torture_assert_int_equal(tctx,
+                                krb5_principal_get_type(smb_krb5_context->krb5_context,
+                                                        my_creds.client), KRB5_NT_PRINCIPAL,
+                                "smb_krb5_init_context gave incorrect client->name.name_type");
+
+       torture_assert(tctx, krb5_principal_compare(smb_krb5_context->krb5_context,
+                                                   principal, my_creds.client),
+                      "krb5_get_init_creds_password returned a different principal");
+       
+       torture_assert_int_equal(tctx,
+                                krb5_principal_get_type(smb_krb5_context->krb5_context,
+                                                        my_creds.server), KRB5_NT_SRV_INST,
+                                "smb_krb5_init_context gave incorrect client->name.name_type");
+
+       torture_assert_str_equal(tctx, krb5_principal_get_comp_string(smb_krb5_context->krb5_context,
+                                                                     my_creds.server, 0),
+                                "krbtgt",
+                                "smb_krb5_init_context gave incorrect my_creds.server->name.name_string[0]");
+
+       k5ret = krb5_free_cred_contents(smb_krb5_context->krb5_context, &my_creds);
+       torture_assert_int_equal(tctx, k5ret, 0, "krb5_free_creds failed");
+
+       return true;
+}
+
+NTSTATUS torture_krb5_init(void);
+NTSTATUS torture_krb5_init(void)
+{
+       struct torture_suite *suite = torture_suite_create(talloc_autofree_context(), "krb5");
+       struct torture_suite *kdc_suite = torture_suite_create(suite, "kdc");
+       suite->description = talloc_strdup(suite, "Kerberos tests");
+       kdc_suite->description = talloc_strdup(kdc_suite, "Kerberos KDC tests");
+
+       torture_suite_add_simple_test(kdc_suite, "as-req-1", 
+                                     torture_krb5_as_req_1);
+
+       torture_suite_add_suite(suite, kdc_suite);
+
+       torture_register_suite(suite);
+       return NT_STATUS_OK;
+}
diff --git a/source4/torture/krb5/wscript_build b/source4/torture/krb5/wscript_build
new file mode 100644 (file)
index 0000000..963c3a3
--- /dev/null
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+if bld.CONFIG_SET('AD_DC_BUILD_IS_ENABLED'):
+      bld.SAMBA_MODULE('TORTURE_KRB5',
+                       source='kdc.c',
+                       autoproto='proto.h',
+                       subsystem='smbtorture',
+                       init_function='torture_krb5_init',
+                       deps='authkrb5 popt POPT_CREDENTIALS torture KERBEROS_UTIL',
+                       internal_module=True
+                 )
+      
index aa5784a4da2d46eed991bb510fc40275316a8e4b..bbb9e9a8213e0f3f9de6f8e99e14c7791da1b868 100755 (executable)
@@ -89,6 +89,7 @@ bld.SAMBA_MODULE('TORTURE_AUTH',
        )
 
 bld.RECURSE('local')
+bld.RECURSE('krb5')
 
 bld.SAMBA_MODULE('TORTURE_NBENCH',
        source='nbench/nbio.c nbench/nbench.c',