diff options
author | Andreas Schneider <asn@samba.org> | 2016-05-13 09:36:34 +0200 |
---|---|---|
committer | Andreas Schneider <asn@cryptomilk.org> | 2017-04-29 23:31:10 +0200 |
commit | 7ad7fca68361617a43d8a7b5129430531fa5ca7f (patch) | |
tree | b17c7c3d18bd72c8a7bbf5394988f024e4170d6d /source4/torture/krb5/kdc-mit.c | |
parent | 6ffef6f5ae90e9c060494c338b0ec0eff4a68146 (diff) | |
download | samba-7ad7fca68361617a43d8a7b5129430531fa5ca7f.tar.gz |
s4-torture: Add KDC test harness and first test
Signed-off-by: Andreas Schneider <asn@samba.org>
Reviewed-by: Andrew Bartlet <abartlet@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
Diffstat (limited to 'source4/torture/krb5/kdc-mit.c')
-rw-r--r-- | source4/torture/krb5/kdc-mit.c | 347 |
1 files changed, 343 insertions, 4 deletions
diff --git a/source4/torture/krb5/kdc-mit.c b/source4/torture/krb5/kdc-mit.c index 882627eb6f3..dfb32019ceb 100644 --- a/source4/torture/krb5/kdc-mit.c +++ b/source4/torture/krb5/kdc-mit.c @@ -1,4 +1,3 @@ - /* Unix SMB/CIFS implementation. @@ -31,13 +30,339 @@ #include "source4/auth/kerberos/kerberos_util.h" #include "lib/util/util_net.h" -static bool test_skip(struct torture_context *tctx) +#define krb5_is_app_tag(dat,tag) \ + ((dat != NULL) && (dat)->length && \ + ((((dat)->data[0] & ~0x20) == ((tag) | 0x40)))) + +#define krb5_is_as_req(dat) krb5_is_app_tag(dat, 10) +#define krb5_is_as_rep(dat) krb5_is_app_tag(dat, 11) +#define krb5_is_krb_error(dat) krb5_is_app_tag(dat, 30) + +enum torture_krb5_test { + TORTURE_KRB5_TEST_PLAIN, + TORTURE_KRB5_TEST_PAC_REQUEST, + TORTURE_KRB5_TEST_BREAK_PW, + TORTURE_KRB5_TEST_CLOCK_SKEW, +}; + +struct torture_krb5_context { + struct torture_context *tctx; + krb5_context krb5_context; + enum torture_krb5_test test; + int recv_packet_count; + krb5_kdc_req *as_req; + krb5_kdc_rep *as_rep; +}; + +krb5_error_code decode_krb5_error(const krb5_data *output, krb5_error **rep); + +krb5_error_code decode_krb5_as_req(const krb5_data *output, krb5_kdc_req **req); +krb5_error_code decode_krb5_as_rep(const krb5_data *output, krb5_kdc_rep **rep); + +void krb5_free_kdc_req(krb5_context ctx, krb5_kdc_req *req); +void krb5_free_kdc_rep(krb5_context ctx, krb5_kdc_rep *rep); + +static bool torture_check_krb5_as_req(struct torture_krb5_context *test_context, + krb5_context context, + const krb5_data *message) +{ + krb5_error_code code; + int nktypes; + + code = decode_krb5_as_req(message, &test_context->as_req); + torture_assert_int_equal(test_context->tctx, + code, 0, + "decode_as_req failed"); + torture_assert_int_equal(test_context->tctx, + test_context->as_req->msg_type, + KRB5_AS_REQ, + "Not a AS REQ"); + + nktypes = test_context->as_req->nktypes; + torture_assert_int_not_equal(test_context->tctx, + nktypes, 0, + "No keytypes"); + + return true; +} + +static krb5_error_code torture_krb5_pre_send_test(krb5_context context, + void *data, + const krb5_data *realm, + const krb5_data *message, + krb5_data **new_message_out, + krb5_data **new_reply_out) +{ + bool ok; + struct torture_krb5_context *test_context = + (struct torture_krb5_context *)data; + + switch (test_context->test) + { + case TORTURE_KRB5_TEST_PLAIN: + case TORTURE_KRB5_TEST_PAC_REQUEST: + case TORTURE_KRB5_TEST_BREAK_PW: + case TORTURE_KRB5_TEST_CLOCK_SKEW: + ok = torture_check_krb5_as_req(test_context, + context, + message); + if (!ok) { + return KRB5KDC_ERR_BADOPTION; + } + break; + } + + return 0; +} + +/* + * We need these function to validate packets because our torture macros + * do a 'return false' on error. + */ +static bool torture_check_krb5_error(struct torture_krb5_context *test_context, + krb5_context context, + const krb5_data *reply, + krb5_error_code error_code) + { - torture_skip(tctx, "Skip kdc tests with MIT Kerberos"); + krb5_error *krb_error; + krb5_error_code code; + + code = decode_krb5_error(reply, &krb_error); + torture_assert_int_equal(test_context->tctx, + code, + 0, + "decode_krb5_error failed"); + + torture_assert_int_equal(test_context->tctx, + krb_error->error, + error_code - KRB5KDC_ERR_NONE, + "Got wrong error code"); + + krb5_free_error(context, krb_error); return true; } +static bool torture_check_krb5_as_rep(struct torture_krb5_context *test_context, + krb5_context context, + const krb5_data *reply) +{ + krb5_error_code code; + bool ok; + + code = decode_krb5_as_rep(reply, &test_context->as_rep); + torture_assert_int_equal(test_context->tctx, + code, + 0, + "decode_krb5_as_rep failed"); + + torture_assert(test_context->tctx, + test_context->as_rep->ticket->enc_part.kvno, + "No KVNO set"); + + ok = torture_setting_bool(test_context->tctx, + "expect_cached_at_rodc", + false); + if (ok) { + torture_assert_int_not_equal(test_context->tctx, + test_context->as_rep->ticket->enc_part.kvno & 0xFFFF0000, + 0, + "Did not get a RODC number in the KVNO"); + } else { + torture_assert_int_equal(test_context->tctx, + test_context->as_rep->ticket->enc_part.kvno & 0xFFFF0000, + 0, + "Unexpecedly got a RODC number in the KVNO"); + } + + return true; +} + +static krb5_error_code torture_krb5_post_recv_test(krb5_context context, + void *data, + krb5_error_code kdc_code, + const krb5_data *realm, + const krb5_data *message, + const krb5_data *reply, + krb5_data **new_reply_out) +{ + struct torture_krb5_context *test_context = + (struct torture_krb5_context *)data; + krb5_error_code code; + bool ok = true; + + torture_comment(test_context->tctx, + "PACKET COUNT = %d\n", + test_context->recv_packet_count); + + torture_comment(test_context->tctx, + "KRB5_AS_REP = %d\n", + krb5_is_as_req(reply)); + + torture_comment(test_context->tctx, + "KRB5_ERROR = %d\n", + krb5_is_krb_error(reply)); + + torture_comment(test_context->tctx, + "KDC ERROR CODE = %d\n", + kdc_code); + + switch (test_context->test) + { + case TORTURE_KRB5_TEST_PLAIN: + if (test_context->recv_packet_count == 0) { + ok = torture_check_krb5_error(test_context, + context, + reply, + KRB5KDC_ERR_PREAUTH_REQUIRED); + torture_assert_goto(test_context->tctx, + ok, + ok, + out, + "torture_check_krb5_error failed"); + } else { + ok = torture_check_krb5_as_rep(test_context, + context, + reply); + torture_assert_goto(test_context->tctx, + ok, + ok, + out, + "torture_check_krb5_as_rep failed"); + } + + torture_assert_goto(test_context->tctx, + test_context->recv_packet_count < 2, + ok, + out, + "Too many packets"); + + break; + case TORTURE_KRB5_TEST_PAC_REQUEST: + case TORTURE_KRB5_TEST_BREAK_PW: + case TORTURE_KRB5_TEST_CLOCK_SKEW: + break; + } + + code = kdc_code; +out: + if (!ok) { + code = EINVAL; + } + + /* Cleanup */ + krb5_free_kdc_req(test_context->krb5_context, test_context->as_req); + krb5_free_kdc_rep(test_context->krb5_context, test_context->as_rep); + + test_context->recv_packet_count++; + + return code; +} + +static bool torture_krb5_init_context(struct torture_context *tctx, + enum torture_krb5_test test, + struct smb_krb5_context **smb_krb5_context) +{ + krb5_error_code code; + + struct torture_krb5_context *test_context = talloc_zero(tctx, + struct torture_krb5_context); + torture_assert(tctx, test_context != NULL, "Failed to allocate"); + + test_context->test = test; + test_context->tctx = tctx; + + code = smb_krb5_init_context(tctx, tctx->lp_ctx, smb_krb5_context); + torture_assert_int_equal(tctx, code, 0, "smb_krb5_init_context failed"); + + test_context->krb5_context = (*smb_krb5_context)->krb5_context; + + krb5_set_kdc_send_hook((*smb_krb5_context)->krb5_context, + torture_krb5_pre_send_test, + test_context); + + krb5_set_kdc_recv_hook((*smb_krb5_context)->krb5_context, + torture_krb5_post_recv_test, + test_context); + + return true; +} +static bool torture_krb5_as_req_creds(struct torture_context *tctx, + struct cli_credentials *credentials, + enum torture_krb5_test test) +{ + krb5_get_init_creds_opt *krb_options = NULL; + struct smb_krb5_context *smb_krb5_context; + enum credentials_obtained obtained; + const char *error_string; + const char *password; + krb5_principal principal; + krb5_error_code code; + krb5_creds my_creds; + bool ok; + + ok = torture_krb5_init_context(tctx, test, &smb_krb5_context); + torture_assert(tctx, ok, "torture_krb5_init_context failed"); + + code = principal_from_credentials(tctx, + credentials, + smb_krb5_context, + &principal, + &obtained, + &error_string); + torture_assert_int_equal(tctx, code, 0, error_string); + + switch (test) + { + case TORTURE_KRB5_TEST_PLAIN: + case TORTURE_KRB5_TEST_PAC_REQUEST: + case TORTURE_KRB5_TEST_BREAK_PW: + case TORTURE_KRB5_TEST_CLOCK_SKEW: + break; + } + + password = cli_credentials_get_password(credentials); + + code = krb5_get_init_creds_password(smb_krb5_context->krb5_context, + &my_creds, + principal, + password, + NULL, + NULL, + 0, + NULL, + krb_options); + krb5_get_init_creds_opt_free(smb_krb5_context->krb5_context, + krb_options); + + switch (test) + { + case TORTURE_KRB5_TEST_PLAIN: + case TORTURE_KRB5_TEST_PAC_REQUEST: + torture_assert_int_equal(tctx, + code, + 0, + "krb5_get_init_creds_password failed"); + break; + case TORTURE_KRB5_TEST_BREAK_PW: + case TORTURE_KRB5_TEST_CLOCK_SKEW: + break; + } + + krb5_free_cred_contents(smb_krb5_context->krb5_context, + &my_creds); + + return true; +} + +static bool torture_krb5_as_req_cmdline(struct torture_context *tctx) +{ + return torture_krb5_as_req_creds(tctx, + cmdline_credentials, + TORTURE_KRB5_TEST_PLAIN); +} + NTSTATUS torture_krb5_init(TALLOC_CTX *ctx) { struct torture_suite *suite = @@ -46,8 +371,22 @@ NTSTATUS torture_krb5_init(TALLOC_CTX *ctx) suite->description = talloc_strdup(suite, "Kerberos tests"); kdc_suite->description = talloc_strdup(kdc_suite, "Kerberos KDC tests"); - torture_suite_add_simple_test(kdc_suite, "skip", test_skip); + torture_suite_add_simple_test(kdc_suite, + "as-req-cmdline", + torture_krb5_as_req_cmdline); + +#if 0 + torture_suite_add_simple_test(kdc_suite, "as-req-pac-request", + torture_krb5_as_req_pac_request); + + torture_suite_add_simple_test(kdc_suite, "as-req-break-pw", + torture_krb5_as_req_break_pw); + + torture_suite_add_simple_test(kdc_suite, "as-req-clock-skew", + torture_krb5_as_req_clock_skew); + torture_suite_add_suite(kdc_suite, torture_krb5_canon(kdc_suite)); +#endif torture_suite_add_suite(suite, kdc_suite); torture_register_suite(suite); |