2 Unix SMB/CIFS implementation.
4 Validate the krb5 pac generation routines
6 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2015
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "system/kerberos.h"
25 #include "torture/smbtorture.h"
26 #include "torture/krb5/proto.h"
27 #include "auth/credentials/credentials.h"
28 #include "lib/cmdline/cmdline.h"
29 #include "source4/auth/kerberos/kerberos.h"
30 #include "source4/auth/kerberos/kerberos_util.h"
31 #include "lib/util/util_net.h"
32 #include "auth/auth.h"
33 #include "auth/auth_sam_reply.h"
34 #include "auth/gensec/gensec.h"
35 #include "param/param.h"
39 #define TEST_CANONICALIZE 0x0000001
40 #define TEST_ENTERPRISE 0x0000002
41 #define TEST_UPPER_USERNAME 0x0000008
42 #define TEST_WIN2K 0x0000020
43 #define TEST_UPN 0x0000040
44 #define TEST_S4U2SELF 0x0000080
45 #define TEST_REMOVEDOLLAR 0x0000100
46 #define TEST_AS_REQ_SPN 0x0000200
47 #define TEST_ALL 0x00003FF
50 const char *test_name
;
52 const char *real_realm
;
53 const char *real_domain
;
55 const char *real_username
;
61 bool other_upn_suffix
;
66 const char *krb5_service
;
67 const char *krb5_hostname
;
70 struct torture_krb5_context
{
71 struct smb_krb5_context
*smb_krb5_context
;
72 struct torture_context
*tctx
;
73 struct addrinfo
*server
;
74 struct test_data
*test_data
;
79 const char *principal_name
;
83 * A helper function which avoids touching the local databases to
84 * generate the session info, as we just want to verify the principal
85 * name that we found in the ticket not the full local token
87 static NTSTATUS
test_generate_session_info_pac(struct auth4_context
*auth_ctx
,
89 struct smb_krb5_context
*smb_krb5_context
,
91 const char *principal_name
,
92 const struct tsocket_address
*remote_address
,
93 uint32_t session_info_flags
,
94 struct auth_session_info
**session_info
)
97 struct auth_user_info_dc
*user_info_dc
;
99 struct pac_data
*pac_data
;
101 if (pac_blob
== NULL
) {
102 DBG_ERR("pac_blob missing\n");
103 return NT_STATUS_NO_IMPERSONATION_TOKEN
;
106 tmp_ctx
= talloc_named(mem_ctx
, 0, "gensec_gssapi_session_info context");
107 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx
);
109 auth_ctx
->private_data
= pac_data
= talloc_zero(auth_ctx
, struct pac_data
);
111 pac_data
->principal_name
= talloc_strdup(pac_data
, principal_name
);
112 if (!pac_data
->principal_name
) {
113 talloc_free(tmp_ctx
);
114 return NT_STATUS_NO_MEMORY
;
117 nt_status
= kerberos_pac_blob_to_user_info_dc(tmp_ctx
,
119 smb_krb5_context
->krb5_context
,
120 &user_info_dc
, NULL
, NULL
);
121 if (!NT_STATUS_IS_OK(nt_status
)) {
122 talloc_free(tmp_ctx
);
126 if (!(user_info_dc
->info
->user_flags
& NETLOGON_GUEST
)) {
127 session_info_flags
|= AUTH_SESSION_INFO_AUTHENTICATED
;
130 session_info_flags
|= AUTH_SESSION_INFO_SIMPLE_PRIVILEGES
;
131 nt_status
= auth_generate_session_info(mem_ctx
,
134 user_info_dc
, session_info_flags
,
136 if (!NT_STATUS_IS_OK(nt_status
)) {
137 talloc_free(tmp_ctx
);
141 talloc_free(tmp_ctx
);
145 /* Check to see if we can pass the PAC across to the NETLOGON server for validation */
147 /* Also happens to be a really good one-step verification of our Kerberos stack */
149 static bool test_accept_ticket(struct torture_context
*tctx
,
150 struct cli_credentials
*credentials
,
151 const char *principal
,
152 DATA_BLOB client_to_server
)
155 struct gensec_security
*gensec_server_context
;
156 DATA_BLOB server_to_client
;
157 struct auth4_context
*auth_context
;
158 struct auth_session_info
*session_info
;
159 struct pac_data
*pac_data
;
160 TALLOC_CTX
*tmp_ctx
= talloc_new(tctx
);
162 torture_assert(tctx
, tmp_ctx
!= NULL
, "talloc_new() failed");
164 auth_context
= talloc_zero(tmp_ctx
, struct auth4_context
);
165 torture_assert(tctx
, auth_context
!= NULL
, "talloc_new() failed");
167 auth_context
->generate_session_info_pac
= test_generate_session_info_pac
;
169 status
= gensec_server_start(tctx
,
170 lpcfg_gensec_settings(tctx
, tctx
->lp_ctx
),
171 auth_context
, &gensec_server_context
);
172 torture_assert_ntstatus_ok(tctx
, status
, "gensec_server_start (server) failed");
174 status
= gensec_set_credentials(gensec_server_context
, credentials
);
175 torture_assert_ntstatus_ok(tctx
, status
, "gensec_set_credentials (server) failed");
177 status
= gensec_start_mech_by_name(gensec_server_context
, "krb5");
178 torture_assert_ntstatus_ok(tctx
, status
, "gensec_start_mech_by_name (server) failed");
180 server_to_client
= data_blob(NULL
, 0);
182 /* Do a client-server update dance */
183 status
= gensec_update(gensec_server_context
, tmp_ctx
, client_to_server
, &server_to_client
);
184 torture_assert_ntstatus_ok(tctx
, status
, "gensec_update (server) failed");
186 /* Extract the PAC using Samba's code */
188 status
= gensec_session_info(gensec_server_context
, gensec_server_context
, &session_info
);
189 torture_assert_ntstatus_ok(tctx
, status
, "gensec_session_info failed");
191 pac_data
= talloc_get_type(auth_context
->private_data
, struct pac_data
);
193 torture_assert(tctx
, pac_data
!= NULL
, "gensec_update failed to fill in pac_data in auth_context");
194 torture_assert(tctx
, pac_data
->principal_name
!= NULL
, "principal_name not present");
195 torture_assert_str_equal(tctx
, pac_data
->principal_name
, principal
, "wrong principal name");
200 * This function is set in torture_krb5_init_context_canon as krb5
201 * send_and_recv function. This allows us to override what server the
202 * test is aimed at, and to inspect the packets just before they are
203 * sent to the network, and before they are processed on the recv
207 static krb5_error_code
test_krb5_send_to_realm_canon_override(struct smb_krb5_context
*smb_krb5_context
,
208 void *data
, /* struct torture_krb5_context */
209 krb5_const_realm realm
,
211 const krb5_data
*send_buf
,
214 krb5_error_code k5ret
;
216 struct torture_krb5_context
*test_context
217 = talloc_get_type_abort(data
, struct torture_krb5_context
);
219 SMB_ASSERT(smb_krb5_context
== test_context
->smb_krb5_context
);
221 k5ret
= smb_krb5_send_and_recv_func_forced_tcp(smb_krb5_context
,
222 test_context
->server
,
230 test_context
->packet_count
++;
235 static int test_context_destructor(struct torture_krb5_context
*test_context
)
237 freeaddrinfo(test_context
->server
);
242 static bool torture_krb5_init_context_canon(struct torture_context
*tctx
,
243 struct test_data
*test_data
,
244 struct torture_krb5_context
**torture_krb5_context
)
246 const char *host
= torture_setting_string(tctx
, "host", NULL
);
247 krb5_error_code k5ret
;
250 struct torture_krb5_context
*test_context
= talloc_zero(tctx
, struct torture_krb5_context
);
251 torture_assert(tctx
, test_context
!= NULL
, "Failed to allocate");
253 test_context
->test_data
= test_data
;
254 test_context
->tctx
= tctx
;
256 k5ret
= smb_krb5_init_context(test_context
, tctx
->lp_ctx
, &test_context
->smb_krb5_context
);
257 torture_assert_int_equal(tctx
, k5ret
, 0, "smb_krb5_init_context failed");
259 ok
= interpret_string_addr_internal(&test_context
->server
, host
, AI_NUMERICHOST
);
260 torture_assert(tctx
, ok
, "Failed to parse target server");
262 talloc_set_destructor(test_context
, test_context_destructor
);
264 set_sockaddr_port(test_context
->server
->ai_addr
, 88);
266 k5ret
= smb_krb5_set_send_to_kdc_func(test_context
->smb_krb5_context
,
267 test_krb5_send_to_realm_canon_override
,
268 NULL
, /* send_to_kdc */
270 torture_assert_int_equal(tctx
, k5ret
, 0, "krb5_set_send_to_kdc_func failed");
271 *torture_krb5_context
= test_context
;
276 static bool torture_krb5_as_req_canon(struct torture_context
*tctx
, const void *tcase_data
)
278 krb5_error_code k5ret
;
279 krb5_get_init_creds_opt
*krb_options
= NULL
;
280 struct test_data
*test_data
= talloc_get_type_abort(tcase_data
, struct test_data
);
281 krb5_principal principal
;
282 krb5_principal krbtgt_other
;
283 krb5_principal expected_principal
;
284 const char *principal_string
= NULL
;
285 char *krbtgt_other_string
;
287 const char *expected_principal_string
= NULL
;
288 char *expected_unparse_principal_string
;
289 int expected_principal_flags
;
290 char *got_principal_string
;
291 char *assertion_message
;
292 const char *password
= cli_credentials_get_password(
293 samba_cmdline_get_creds());
294 krb5_context k5_context
;
295 struct torture_krb5_context
*test_context
;
298 krb5_creds
*server_creds
;
300 krb5_auth_context auth_context
;
302 krb5_data in_data
, enc_ticket
;
303 krb5_get_creds_opt opt
;
305 const char *spn
= NULL
;
306 const char *spn_real_realm
= NULL
;
307 const char *upn
= torture_setting_string(tctx
, "krb5-upn", "");
308 test_data
->krb5_service
= torture_setting_string(tctx
, "krb5-service", "host");
309 test_data
->krb5_hostname
= torture_setting_string(tctx
, "krb5-hostname", "");
312 * If we have not passed a UPN on the command line,
313 * then skip the UPN tests.
315 if (test_data
->upn
&& upn
[0] == '\0') {
316 torture_skip(tctx
, "This test needs a UPN specified as --option=torture:krb5-upn=user@example.com to run");
320 * If we have not passed a SPN on the command line,
321 * then skip the SPN tests.
323 if (test_data
->as_req_spn
&& test_data
->krb5_hostname
[0] == '\0') {
324 torture_skip(tctx
, "This test needs a hostname specified as --option=torture:krb5-hostname=hostname.example.com and optionally --option=torture:krb5-service=service (defaults to host) to run");
327 if (test_data
->removedollar
&&
328 !torture_setting_bool(tctx
, "run_removedollar_test", false))
330 torture_skip(tctx
, "--option=torture:run_removedollar_test=true not specified");
333 test_data
->realm
= test_data
->real_realm
;
335 if (test_data
->upn
) {
337 test_data
->username
= talloc_strdup(test_data
, upn
);
338 p
= strchr(test_data
->username
, '@');
344 * Test the UPN behaviour carefully. We can
345 * test in two different modes, depending on
346 * what UPN has been set up for us.
348 * If the UPN is in our realm, then we do all the tests with this name also.
350 * If the UPN is not in our realm, then we
351 * expect the tests that replace the realm to
352 * fail (as it won't match)
354 if (strcasecmp(p
, test_data
->real_realm
) != 0) {
355 test_data
->other_upn_suffix
= true;
357 test_data
->other_upn_suffix
= false;
361 * This lets us test the combination of the UPN prefix
362 * with a valid domain, without adding even more
365 test_data
->realm
= p
;
368 ok
= torture_krb5_init_context_canon(tctx
, test_data
, &test_context
);
369 torture_assert(tctx
, ok
, "torture_krb5_init_context failed");
370 k5_context
= test_context
->smb_krb5_context
->krb5_context
;
372 test_data
->realm
= strupper_talloc(test_data
, test_data
->realm
);
373 if (test_data
->upper_username
) {
374 test_data
->username
= strupper_talloc(test_data
, test_data
->username
);
376 test_data
->username
= talloc_strdup(test_data
, test_data
->username
);
379 if (test_data
->removedollar
) {
382 p
= strchr_m(test_data
->username
, '$');
383 torture_assert(tctx
, p
!= NULL
, talloc_asprintf(tctx
,
384 "username[%s] contains no '$'\n",
385 test_data
->username
));
389 spn
= talloc_asprintf(test_data
, "%s/%s@%s",
390 test_data
->krb5_service
,
391 test_data
->krb5_hostname
,
394 spn_real_realm
= talloc_asprintf(test_data
, "%s/%s@%s",
395 test_data
->krb5_service
,
396 test_data
->krb5_hostname
,
397 test_data
->real_realm
);
399 if (!test_data
->canonicalize
&& test_data
->enterprise
) {
401 "This test combination "
402 "is skipped intentionally");
405 if (test_data
->as_req_spn
) {
406 if (test_data
->enterprise
) {
408 "This test combination "
409 "is skipped intentionally");
411 principal_string
= spn
;
413 principal_string
= talloc_asprintf(test_data
,
420 test_data
->spn_is_upn
421 = (strcasecmp(upn
, spn
) == 0);
424 * If we are set to canonicalize, we get back the fixed UPPER
425 * case realm, and the real username (ie matching LDAP
428 * Otherwise, if we are set to enterprise, we
429 * get back the whole principal as-sent
431 * Finally, if we are not set to canonicalize, we get back the
432 * fixed UPPER case realm, but the as-sent username
434 if (test_data
->as_req_spn
&& !test_data
->spn_is_upn
) {
435 expected_principal_string
= spn
;
436 } else if (test_data
->canonicalize
) {
437 expected_principal_string
= talloc_asprintf(test_data
,
439 test_data
->real_username
,
440 test_data
->real_realm
);
441 } else if (test_data
->as_req_spn
&& test_data
->spn_is_upn
) {
442 expected_principal_string
= spn_real_realm
;
444 expected_principal_string
= talloc_asprintf(test_data
,
447 test_data
->real_realm
);
450 if (test_data
->enterprise
) {
451 principal_flags
= KRB5_PRINCIPAL_PARSE_ENTERPRISE
;
453 if (test_data
->upn
&& test_data
->other_upn_suffix
) {
454 torture_skip(tctx
, "UPN test for UPN with other UPN suffix only runs with enterprise principals");
459 if (test_data
->canonicalize
) {
460 expected_principal_flags
= 0;
462 expected_principal_flags
= principal_flags
;
465 torture_assert_int_equal(tctx
,
466 krb5_parse_name_flags(k5_context
,
470 0, "krb5_parse_name_flags failed");
471 torture_assert_int_equal(tctx
,
472 krb5_parse_name_flags(k5_context
,
473 expected_principal_string
,
474 expected_principal_flags
,
475 &expected_principal
),
476 0, "krb5_parse_name_flags failed");
478 if (test_data
->as_req_spn
) {
479 if (test_data
->upn
) {
480 krb5_principal_set_type(k5_context
,
483 krb5_principal_set_type(k5_context
,
487 krb5_principal_set_type(k5_context
,
490 krb5_principal_set_type(k5_context
,
496 torture_assert_int_equal(tctx
,
497 krb5_unparse_name(k5_context
,
499 &expected_unparse_principal_string
),
500 0, "krb5_unparse_name failed");
502 * Prepare a AS-REQ and run the TEST_AS_REQ tests
506 test_context
->packet_count
= 0;
509 * Set the canonicalize flag if this test requires it
511 torture_assert_int_equal(tctx
,
512 krb5_get_init_creds_opt_alloc(k5_context
, &krb_options
),
513 0, "krb5_get_init_creds_opt_alloc failed");
515 torture_assert_int_equal(tctx
,
516 krb5_get_init_creds_opt_set_canonicalize(k5_context
,
518 test_data
->canonicalize
),
519 0, "krb5_get_init_creds_opt_set_canonicalize failed");
521 torture_assert_int_equal(tctx
,
522 krb5_get_init_creds_opt_set_win2k(k5_context
,
525 0, "krb5_get_init_creds_opt_set_win2k failed");
527 k5ret
= krb5_get_init_creds_password(k5_context
, &my_creds
, principal
,
528 password
, NULL
, NULL
, 0,
531 if (test_context
->test_data
->as_req_spn
532 && !test_context
->test_data
->spn_is_upn
) {
533 torture_assert_int_equal(tctx
, k5ret
,
534 KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN
,
535 "Got wrong error_code from "
536 "krb5_get_init_creds_password");
537 /* We can't proceed with more checks */
540 assertion_message
= talloc_asprintf(tctx
,
541 "krb5_get_init_creds_password for %s failed: %s",
543 smb_get_krb5_error_message(k5_context
, k5ret
, tctx
));
544 torture_assert_int_equal(tctx
, k5ret
, 0, assertion_message
);
548 test_context
->packet_count
> 1,
549 "Expected krb5_get_init_creds_password to send more packets");
552 * Assert that the reply was with the correct type of
553 * principal, depending on the flags we set
555 if (test_data
->canonicalize
== false && test_data
->as_req_spn
) {
556 torture_assert_int_equal(tctx
,
557 krb5_principal_get_type(k5_context
,
560 "smb_krb5_init_context gave incorrect client->name.name_type");
562 torture_assert_int_equal(tctx
,
563 krb5_principal_get_type(k5_context
,
566 "smb_krb5_init_context gave incorrect client->name.name_type");
569 torture_assert_int_equal(tctx
,
570 krb5_unparse_name(k5_context
,
571 my_creds
.client
, &got_principal_string
), 0,
572 "krb5_unparse_name failed");
574 assertion_message
= talloc_asprintf(tctx
,
575 "krb5_get_init_creds_password returned a different principal %s to what was expected %s",
576 got_principal_string
, expected_principal_string
);
577 krb5_xfree(got_principal_string
);
579 torture_assert(tctx
, krb5_principal_compare(k5_context
,
580 my_creds
.client
, expected_principal
),
584 torture_assert_int_equal(tctx
,
585 krb5_principal_get_type(k5_context
,
586 my_creds
.server
), KRB5_NT_SRV_INST
,
587 "smb_krb5_init_context gave incorrect server->name.name_type");
589 torture_assert_int_equal(tctx
,
590 krb5_principal_get_num_comp(k5_context
,
592 "smb_krb5_init_context gave incorrect number of components in my_creds.server->name");
594 torture_assert_str_equal(tctx
,
595 krb5_principal_get_comp_string(k5_context
,
598 "smb_krb5_init_context gave incorrect my_creds.server->name.name_string[0]");
600 if (test_data
->canonicalize
) {
601 torture_assert_str_equal(tctx
,
602 krb5_principal_get_comp_string(k5_context
,
604 test_data
->real_realm
,
606 "smb_krb5_init_context gave incorrect my_creds.server->name.name_string[1]");
608 torture_assert_str_equal(tctx
,
609 krb5_principal_get_comp_string(k5_context
,
613 "smb_krb5_init_context gave incorrect my_creds.server->name.name_string[1]");
615 torture_assert_str_equal(tctx
,
616 krb5_principal_get_realm(k5_context
,
618 test_data
->real_realm
,
619 "smb_krb5_init_context gave incorrect my_creds.server->realm");
621 /* Store the result of the 'kinit' above into a memory ccache */
622 cc_name
= talloc_asprintf(tctx
, "MEMORY:%s", test_data
->test_name
);
623 torture_assert_int_equal(tctx
, krb5_cc_resolve(k5_context
, cc_name
,
625 0, "krb5_cc_resolve failed");
627 torture_assert_int_equal(tctx
, krb5_cc_initialize(k5_context
,
628 ccache
, my_creds
.client
),
629 0, "krb5_cc_initialize failed");
631 torture_assert_int_equal(tctx
, krb5_cc_store_cred(k5_context
,
633 0, "krb5_cc_store_cred failed");
636 * Prepare a TGS-REQ and run the TEST_TGS_REQ_KRBTGT_CANON tests
638 * This tests krb5_get_creds behaviour, which allows us to set
639 * the KRB5_GC_CANONICALIZE option against the krbtgt/ principal
642 krbtgt_other_string
= talloc_asprintf(test_data
, "krbtgt/%s@%s", test_data
->real_domain
, test_data
->real_realm
);
643 torture_assert_int_equal(tctx
,
644 krb5_make_principal(k5_context
, &krbtgt_other
,
645 test_data
->real_realm
, "krbtgt",
646 test_data
->real_domain
, NULL
),
647 0, "krb5_make_principal failed");
649 test_context
->packet_count
= 0;
651 torture_assert_int_equal(tctx
,
652 krb5_get_creds_opt_alloc(k5_context
, &opt
),
653 0, "krb5_get_creds_opt_alloc");
655 krb5_get_creds_opt_add_options(k5_context
,
657 KRB5_GC_CANONICALIZE
);
659 krb5_get_creds_opt_add_options(k5_context
,
663 /* Confirm if we can get a ticket krbtgt/realm that we got back with the initial kinit */
664 k5ret
= krb5_get_creds(k5_context
, opt
, ccache
, krbtgt_other
, &server_creds
);
668 * In these situations, the code above does not store a
669 * principal in the credentials cache matching what
670 * krb5_get_creds() needs without talking to the KDC, so the
671 * test fails with looping detected because when we set
672 * canonicalize we confuse the client libs.
675 assertion_message
= talloc_asprintf(tctx
,
676 "krb5_get_creds for %s should have failed with looping detected: %s",
678 smb_get_krb5_error_message(k5_context
, k5ret
,
681 torture_assert_int_equal(tctx
, k5ret
, KRB5_GET_IN_TKT_LOOP
, assertion_message
);
682 torture_assert_int_equal(tctx
,
683 test_context
->packet_count
,
684 2, "Expected krb5_get_creds to send packets");
688 * Prepare a TGS-REQ and run the TEST_TGS_REQ_CANON tests
690 * This tests krb5_get_creds behaviour, which allows us to set
691 * the KRB5_GC_CANONICALIZE option
694 test_context
->packet_count
= 0;
696 torture_assert_int_equal(tctx
,
697 krb5_get_creds_opt_alloc(k5_context
, &opt
),
698 0, "krb5_get_creds_opt_alloc");
700 krb5_get_creds_opt_add_options(k5_context
,
702 KRB5_GC_CANONICALIZE
);
704 krb5_get_creds_opt_add_options(k5_context
,
708 if (test_data
->s4u2self
) {
709 torture_assert_int_equal(tctx
,
710 krb5_get_creds_opt_set_impersonate(k5_context
,
713 0, "krb5_get_creds_opt_set_impersonate failed");
716 /* Confirm if we can get a ticket to our own name */
717 k5ret
= krb5_get_creds(k5_context
, opt
, ccache
, principal
, &server_creds
);
720 * In these situations, the code above does not store a
721 * principal in the credentials cache matching what
722 * krb5_get_creds() needs, so the test fails.
726 assertion_message
= talloc_asprintf(tctx
,
727 "krb5_get_creds for %s failed: %s",
729 smb_get_krb5_error_message(k5_context
, k5ret
,
733 * Only machine accounts (strictly, accounts with a
734 * servicePrincipalName) can expect this test to succeed
736 if (torture_setting_bool(tctx
, "expect_machine_account", false)
737 && (test_data
->enterprise
738 || test_data
->spn_is_upn
739 || test_data
->upn
== false)) {
740 torture_assert_int_equal(tctx
, k5ret
, 0, assertion_message
);
741 torture_assert_int_equal(tctx
, krb5_cc_store_cred(k5_context
,
742 ccache
, server_creds
),
743 0, "krb5_cc_store_cred failed");
745 torture_assert_int_equal(tctx
,
746 krb5_free_creds(k5_context
,
748 0, "krb5_free_cred_contents failed");
750 torture_assert_int_equal(tctx
,
751 test_context
->packet_count
,
752 1, "Expected krb5_get_creds to send one packet");
755 torture_assert_int_equal(tctx
, k5ret
, KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN
,
757 /* Account for get_cred_kdc_capath() and get_cred_kdc_referral() fallback */
758 torture_assert_int_equal(tctx
,
759 test_context
->packet_count
,
760 2, "Expected krb5_get_creds to send 2 packets");
765 * Confirm getting a ticket to pass to the server, running
766 * either the TEST_TGS_REQ or TEST_SELF_TRUST_TGS_REQ stage.
768 * This triggers the client to attempt to get a
769 * cross-realm ticket between the alternate names of
770 * the server, and we need to confirm that behaviour.
774 test_context
->packet_count
= 0;
775 torture_assert_int_equal(tctx
, krb5_auth_con_init(k5_context
, &auth_context
),
776 0, "krb5_auth_con_init failed");
779 k5ret
= krb5_mk_req_exact(k5_context
,
785 assertion_message
= talloc_asprintf(tctx
,
786 "krb5_mk_req_exact for %s failed: %s",
788 smb_get_krb5_error_message(k5_context
, k5ret
, tctx
));
791 * Only machine accounts (strictly, accounts with a
792 * servicePrincipalName) can expect this test to succeed
794 if (torture_setting_bool(tctx
, "expect_machine_account", false)
795 && (test_data
->enterprise
||
796 (test_context
->test_data
->as_req_spn
797 || test_context
->test_data
->spn_is_upn
)
798 || test_data
->upn
== false)) {
799 DATA_BLOB client_to_server
;
800 torture_assert_int_equal(tctx
, k5ret
, 0, assertion_message
);
801 client_to_server
= data_blob_const(enc_ticket
.data
, enc_ticket
.length
);
803 /* This is very weird */
804 if (test_data
->canonicalize
== false
805 && test_context
->test_data
->as_req_spn
806 && test_context
->test_data
->spn_is_upn
807 && test_context
->test_data
->s4u2self
) {
810 test_accept_ticket(tctx
,
811 samba_cmdline_get_creds(),
814 "test_accept_ticket failed - failed to accept the ticket we just created");
815 } else if (test_data
->canonicalize
== true
816 && test_context
->test_data
->as_req_spn
817 && test_context
->test_data
->spn_is_upn
818 && test_context
->test_data
->s4u2self
) {
821 test_accept_ticket(tctx
,
822 samba_cmdline_get_creds(),
823 expected_principal_string
,
825 "test_accept_ticket failed - failed to accept the ticket we just created");
826 } else if (test_data
->canonicalize
== true
827 && test_data
->enterprise
== false
828 && test_context
->test_data
->upn
829 && test_context
->test_data
->spn_is_upn
830 && test_context
->test_data
->s4u2self
) {
833 test_accept_ticket(tctx
,
834 samba_cmdline_get_creds(),
835 expected_principal_string
,
837 "test_accept_ticket failed - failed to accept the ticket we just created");
838 } else if (test_data
->canonicalize
== false
839 && test_context
->test_data
->upn
840 && test_context
->test_data
->spn_is_upn
841 && test_context
->test_data
->s4u2self
) {
843 const char *accept_expected_principal_string
844 = talloc_asprintf(test_data
,
847 test_data
->real_realm
);
850 test_accept_ticket(tctx
,
851 samba_cmdline_get_creds(),
852 accept_expected_principal_string
,
854 "test_accept_ticket failed - failed to accept the ticket we just created");
858 test_accept_ticket(tctx
,
859 samba_cmdline_get_creds(),
860 expected_unparse_principal_string
,
862 "test_accept_ticket failed - failed to accept the ticket we just created");
864 krb5_data_free(&enc_ticket
);
866 torture_assert_int_equal(tctx
, k5ret
, KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN
,
871 * Confirm getting a ticket to pass to the server, running
872 * the TEST_TGS_REQ_HOST, TEST_TGS_REQ_HOST_SRV_INST, TEST_TGS_REQ_HOST_SRV_HST stage
874 * This triggers the client to attempt to get a
875 * cross-realm ticket between the alternate names of
876 * the server, and we need to confirm that behaviour.
880 if (*test_data
->krb5_service
&& *test_data
->krb5_hostname
) {
881 krb5_principal host_principal_srv_inst
;
883 * This tries to guess when the krb5 libs will ask for a
884 * cross-realm ticket, and when they will just ask the KDC
887 test_context
->packet_count
= 0;
888 torture_assert_int_equal(tctx
, krb5_auth_con_init(k5_context
, &auth_context
),
889 0, "krb5_auth_con_init failed");
892 k5ret
= krb5_mk_req(k5_context
,
895 test_data
->krb5_service
,
896 test_data
->krb5_hostname
,
901 assertion_message
= talloc_asprintf(tctx
,
902 "krb5_mk_req for %s/%s failed: %s",
903 test_data
->krb5_service
,
904 test_data
->krb5_hostname
,
905 smb_get_krb5_error_message(k5_context
, k5ret
, tctx
));
907 torture_assert_int_equal(tctx
, k5ret
, 0, assertion_message
);
909 if (test_data
->spn_is_upn
== false) {
911 * Only in these cases would the above
912 * code have needed to send packets to
916 test_context
->packet_count
> 0,
917 "Expected krb5_get_creds to send packets");
922 test_context
->packet_count
= 0;
924 torture_assert_int_equal(tctx
,
925 krb5_make_principal(k5_context
, &host_principal_srv_inst
,
926 test_data
->real_realm
,
927 strupper_talloc(tctx
, test_data
->krb5_service
),
928 test_data
->krb5_hostname
,
930 0, "krb5_make_principal failed");
932 krb5_principal_set_type(k5_context
, host_principal_srv_inst
, KRB5_NT_SRV_INST
);
934 torture_assert_int_equal(tctx
, krb5_auth_con_init(k5_context
, &auth_context
),
935 0, "krb5_auth_con_init failed");
938 k5ret
= krb5_mk_req_exact(k5_context
,
941 host_principal_srv_inst
,
944 krb5_free_principal(k5_context
, host_principal_srv_inst
);
946 assertion_message
= talloc_asprintf(tctx
,
947 "krb5_mk_req for %s/%s KRB5_NT_SRV_INST failed: %s",
948 test_data
->krb5_service
,
949 test_data
->krb5_hostname
,
950 smb_get_krb5_error_message(k5_context
, k5ret
, tctx
));
952 torture_assert_int_equal(tctx
, k5ret
, 0, assertion_message
);
954 * Only in these cases would the above code have needed to
955 * send packets to the network
958 test_context
->packet_count
> 0,
959 "Expected krb5_get_creds to send packets");
963 test_context
->packet_count
= 0;
965 torture_assert_int_equal(tctx
,
966 krb5_make_principal(k5_context
, &host_principal_srv_inst
,
967 test_data
->real_realm
,
968 test_data
->krb5_service
,
969 strupper_talloc(tctx
, test_data
->krb5_hostname
),
971 0, "krb5_make_principal failed");
973 krb5_principal_set_type(k5_context
, host_principal_srv_inst
, KRB5_NT_SRV_HST
);
975 torture_assert_int_equal(tctx
, krb5_auth_con_init(k5_context
, &auth_context
),
976 0, "krb5_auth_con_init failed");
979 k5ret
= krb5_mk_req_exact(k5_context
,
982 host_principal_srv_inst
,
985 krb5_free_principal(k5_context
, host_principal_srv_inst
);
987 assertion_message
= talloc_asprintf(tctx
,
988 "krb5_mk_req for %s/%s KRB5_NT_SRV_INST failed: %s",
989 test_data
->krb5_service
,
990 test_data
->krb5_hostname
,
991 smb_get_krb5_error_message(k5_context
, k5ret
, tctx
));
993 torture_assert_int_equal(tctx
, k5ret
, 0, assertion_message
);
995 * Only in these cases would the above code have needed to
996 * send packets to the network
999 test_context
->packet_count
> 0,
1000 "Expected krb5_get_creds to send packets");
1005 * Confirm getting a ticket for the same krbtgt/realm that we
1006 * got back with the initial ticket, running the
1007 * TEST_TGS_REQ_KRBTGT stage.
1011 test_context
->packet_count
= 0;
1014 k5ret
= krb5_mk_req_exact(k5_context
,
1021 assertion_message
= talloc_asprintf(tctx
,
1022 "krb5_mk_req_exact for %s failed: %s",
1024 smb_get_krb5_error_message(k5_context
, k5ret
, tctx
));
1025 torture_assert_int_equal(tctx
, k5ret
, 0, assertion_message
);
1027 krb5_free_principal(k5_context
, principal
);
1028 krb5_get_init_creds_opt_free(k5_context
, krb_options
);
1030 torture_assert_int_equal(tctx
, krb5_free_cred_contents(k5_context
, &my_creds
),
1031 0, "krb5_free_cred_contents failed");
1036 struct torture_suite
*torture_krb5_canon(TALLOC_CTX
*mem_ctx
)
1039 struct torture_suite
*suite
= torture_suite_create(mem_ctx
, "canon");
1040 suite
->description
= talloc_strdup(suite
, "Kerberos Canonicalisation tests");
1042 for (i
= 0; i
< TEST_ALL
; i
++) {
1043 char *name
= talloc_asprintf(suite
, "%s.%s.%s.%s.%s.%s",
1044 (i
& TEST_CANONICALIZE
) ? "canon" : "no-canon",
1045 (i
& TEST_ENTERPRISE
) ? "enterprise" : "no-enterprise",
1046 (i
& TEST_UPPER_USERNAME
) ? "uc-user" : "lc-user",
1047 (i
& TEST_WIN2K
) ? "win2k" : "no-win2k",
1048 (i
& TEST_UPN
) ? "upn" :
1049 ((i
& TEST_AS_REQ_SPN
) ? "spn" :
1050 ((i
& TEST_REMOVEDOLLAR
) ? "removedollar" : "samaccountname")),
1051 (i
& TEST_S4U2SELF
) ? "s4u2self" : "normal");
1052 struct torture_suite
*sub_suite
= torture_suite_create(mem_ctx
, name
);
1054 struct test_data
*test_data
= talloc_zero(suite
, struct test_data
);
1056 if (i
& TEST_AS_REQ_SPN
) {
1060 if ((i
& TEST_UPN
) || (i
& TEST_AS_REQ_SPN
)) {
1061 if (i
& TEST_REMOVEDOLLAR
) {
1066 test_data
->test_name
= name
;
1067 test_data
->real_realm
1068 = strupper_talloc(test_data
,
1069 cli_credentials_get_realm(
1070 samba_cmdline_get_creds()));
1071 test_data
->real_domain
= cli_credentials_get_domain(
1072 samba_cmdline_get_creds());
1073 test_data
->username
= cli_credentials_get_username(
1074 samba_cmdline_get_creds());
1075 test_data
->real_username
= cli_credentials_get_username(
1076 samba_cmdline_get_creds());
1077 test_data
->canonicalize
= (i
& TEST_CANONICALIZE
) != 0;
1078 test_data
->enterprise
= (i
& TEST_ENTERPRISE
) != 0;
1079 test_data
->upper_username
= (i
& TEST_UPPER_USERNAME
) != 0;
1080 test_data
->win2k
= (i
& TEST_WIN2K
) != 0;
1081 test_data
->upn
= (i
& TEST_UPN
) != 0;
1082 test_data
->s4u2self
= (i
& TEST_S4U2SELF
) != 0;
1083 test_data
->removedollar
= (i
& TEST_REMOVEDOLLAR
) != 0;
1084 test_data
->as_req_spn
= (i
& TEST_AS_REQ_SPN
) != 0;
1085 torture_suite_add_simple_tcase_const(sub_suite
, name
, torture_krb5_as_req_canon
,
1087 torture_suite_add_suite(suite
, sub_suite
);