waf: Fix parsing of cross-answers file in case answer includes a colon
[Samba.git] / source4 / torture / krb5 / kdc-canon.c
blob20f0cf1b6481b9e3321b8f7df62e7cc2ce39f597
1 /*
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/>.
23 #include "includes.h"
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/popt_common.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"
37 #define TEST_CANONICALIZE 0x0000001
38 #define TEST_ENTERPRISE 0x0000002
39 #define TEST_UPPER_REALM 0x0000004
40 #define TEST_UPPER_USERNAME 0x0000008
41 #define TEST_NETBIOS_REALM 0x0000010
42 #define TEST_WIN2K 0x0000020
43 #define TEST_UPN 0x0000040
44 #define TEST_S4U2SELF 0x0000080
45 #define TEST_ALL 0x00000FF
47 struct test_data {
48 const char *test_name;
49 const char *realm;
50 const char *real_realm;
51 const char *real_domain;
52 const char *username;
53 const char *real_username;
54 bool canonicalize;
55 bool enterprise;
56 bool upper_realm;
57 bool upper_username;
58 bool netbios_realm;
59 bool win2k;
60 bool upn;
61 bool other_upn_suffix;
62 bool s4u2self;
63 const char *krb5_service;
64 const char *krb5_hostname;
65 };
67 enum test_stage {
68 TEST_AS_REQ = 0,
69 TEST_TGS_REQ_KRBTGT_CANON = 1,
70 TEST_TGS_REQ_CANON = 2,
71 TEST_SELF_TRUST_TGS_REQ = 3,
72 TEST_TGS_REQ = 4,
73 TEST_TGS_REQ_KRBTGT = 5,
74 TEST_TGS_REQ_HOST = 6,
75 TEST_TGS_REQ_HOST_SRV_INST = 7,
76 TEST_TGS_REQ_HOST_SRV_HST = 8,
77 TEST_AS_REQ_SELF = 9,
78 TEST_DONE = 10
81 struct torture_krb5_context {
82 struct smb_krb5_context *smb_krb5_context;
83 struct torture_context *tctx;
84 struct addrinfo *server;
85 struct test_data *test_data;
86 int packet_count;
87 enum test_stage test_stage;
88 AS_REQ as_req;
89 AS_REP as_rep;
90 TGS_REQ tgs_req;
91 TGS_REP tgs_rep;
94 struct pac_data {
95 const char *principal_name;
99 * A helper function which avoids touching the local databases to
100 * generate the session info, as we just want to verify the principal
101 * name that we found in the ticket not the full local token
103 static NTSTATUS test_generate_session_info_pac(struct auth4_context *auth_ctx,
104 TALLOC_CTX *mem_ctx,
105 struct smb_krb5_context *smb_krb5_context,
106 DATA_BLOB *pac_blob,
107 const char *principal_name,
108 const struct tsocket_address *remote_address,
109 uint32_t session_info_flags,
110 struct auth_session_info **session_info)
112 NTSTATUS nt_status;
113 struct auth_user_info_dc *user_info_dc;
114 TALLOC_CTX *tmp_ctx;
115 struct pac_data *pac_data;
117 tmp_ctx = talloc_named(mem_ctx, 0, "gensec_gssapi_session_info context");
118 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
120 auth_ctx->private_data = pac_data = talloc_zero(auth_ctx, struct pac_data);
122 pac_data->principal_name = talloc_strdup(pac_data, principal_name);
123 if (!pac_data->principal_name) {
124 talloc_free(tmp_ctx);
125 return NT_STATUS_NO_MEMORY;
128 nt_status = kerberos_pac_blob_to_user_info_dc(tmp_ctx,
129 *pac_blob,
130 smb_krb5_context->krb5_context,
131 &user_info_dc, NULL, NULL);
132 if (!NT_STATUS_IS_OK(nt_status)) {
133 talloc_free(tmp_ctx);
134 return nt_status;
137 if (user_info_dc->info->authenticated) {
138 session_info_flags |= AUTH_SESSION_INFO_AUTHENTICATED;
141 session_info_flags |= AUTH_SESSION_INFO_SIMPLE_PRIVILEGES;
142 nt_status = auth_generate_session_info(mem_ctx,
143 NULL,
144 NULL,
145 user_info_dc, session_info_flags,
146 session_info);
147 if (!NT_STATUS_IS_OK(nt_status)) {
148 talloc_free(tmp_ctx);
149 return nt_status;
152 talloc_free(tmp_ctx);
153 return NT_STATUS_OK;
156 /* Check to see if we can pass the PAC across to the NETLOGON server for validation */
158 /* Also happens to be a really good one-step verfication of our Kerberos stack */
160 static bool test_accept_ticket(struct torture_context *tctx,
161 struct cli_credentials *credentials,
162 const char *principal,
163 DATA_BLOB client_to_server)
165 NTSTATUS status;
166 struct gensec_security *gensec_server_context;
167 DATA_BLOB server_to_client;
168 struct auth4_context *auth_context;
169 struct auth_session_info *session_info;
170 struct pac_data *pac_data;
171 TALLOC_CTX *tmp_ctx = talloc_new(tctx);
173 torture_assert(tctx, tmp_ctx != NULL, "talloc_new() failed");
175 auth_context = talloc_zero(tmp_ctx, struct auth4_context);
176 torture_assert(tctx, auth_context != NULL, "talloc_new() failed");
178 auth_context->generate_session_info_pac = test_generate_session_info_pac;
180 status = gensec_server_start(tctx,
181 lpcfg_gensec_settings(tctx, tctx->lp_ctx),
182 auth_context, &gensec_server_context);
183 torture_assert_ntstatus_ok(tctx, status, "gensec_server_start (server) failed");
185 status = gensec_set_credentials(gensec_server_context, credentials);
186 torture_assert_ntstatus_ok(tctx, status, "gensec_set_credentials (server) failed");
188 status = gensec_start_mech_by_name(gensec_server_context, "krb5");
189 torture_assert_ntstatus_ok(tctx, status, "gensec_start_mech_by_name (server) failed");
191 server_to_client = data_blob(NULL, 0);
193 /* Do a client-server update dance */
194 status = gensec_update(gensec_server_context, tmp_ctx, client_to_server, &server_to_client);
195 torture_assert_ntstatus_ok(tctx, status, "gensec_update (server) failed");
197 /* Extract the PAC using Samba's code */
199 status = gensec_session_info(gensec_server_context, gensec_server_context, &session_info);
200 torture_assert_ntstatus_ok(tctx, status, "gensec_session_info failed");
202 pac_data = talloc_get_type(auth_context->private_data, struct pac_data);
204 torture_assert(tctx, pac_data != NULL, "gensec_update failed to fill in pac_data in auth_context");
205 torture_assert(tctx, pac_data->principal_name != NULL, "principal_name not present");
206 torture_assert_str_equal(tctx, pac_data->principal_name, principal, "wrong principal name");
207 return true;
211 * TEST_AS_REQ and TEST_AS_REQ_SELF - SEND
213 * Confirm that the outgoing packet meets certain expectations. This
214 * should be extended to further assert the correct and expected
215 * behaviour of the krb5 libs, so we know what we are sending to the
216 * server.
218 * Additionally, this CHANGES the request to remove the canonicalize
219 * flag automatically added by the krb5 libs when an enterprise
220 * principal is used, so we can test what the server does in this
221 * combination.
225 static bool torture_krb5_pre_send_as_req_test(struct torture_krb5_context *test_context,
226 const krb5_data *send_buf,
227 krb5_data *modified_send_buf)
229 AS_REQ mod_as_req;
230 krb5_error_code k5ret;
231 size_t used;
232 torture_assert_int_equal(test_context->tctx, decode_AS_REQ(send_buf->data, send_buf->length,
233 &test_context->as_req, &used),
234 0, "decode_AS_REQ for TEST_AS_REQ failed");
235 mod_as_req = test_context->as_req;
236 torture_assert_int_equal(test_context->tctx, used, send_buf->length, "length mismatch");
237 torture_assert_int_equal(test_context->tctx, test_context->as_req.pvno,
238 5, "Got wrong as_req->pvno");
239 if (test_context->test_data->canonicalize || test_context->test_data->enterprise) {
240 torture_assert(test_context->tctx,
241 test_context->as_req.req_body.kdc_options.canonicalize,
242 "krb5 libs did not set canonicalize!");
243 } else {
244 torture_assert_int_equal(test_context->tctx,
245 test_context->as_req.req_body.kdc_options.canonicalize,
246 false,
247 "krb5 libs unexpectedly set canonicalize!");
250 if (test_context->test_data->enterprise) {
251 torture_assert_int_equal(test_context->tctx,
252 test_context->as_req.req_body.cname->name_type,
253 KRB5_NT_ENTERPRISE_PRINCIPAL,
254 "krb5 libs did not pass principal as enterprise!");
255 } else {
256 torture_assert_int_equal(test_context->tctx,
257 test_context->as_req.req_body.cname->name_type,
258 KRB5_NT_PRINCIPAL,
259 "krb5 libs unexpectedly set principal as enterprise!");
262 /* Force off canonicalize that was forced on by the krb5 libs */
263 if (test_context->test_data->canonicalize == false && test_context->test_data->enterprise) {
264 mod_as_req.req_body.kdc_options.canonicalize = false;
267 if (test_context->test_stage == TEST_AS_REQ_SELF) {
269 * Force the server name to match the client name,
270 * including the name type. This isn't possible with
271 * the krb5 client libs alone
273 mod_as_req.req_body.sname = test_context->as_req.req_body.cname;
276 ASN1_MALLOC_ENCODE(AS_REQ, modified_send_buf->data, modified_send_buf->length,
277 &mod_as_req, &used, k5ret);
278 torture_assert_int_equal(test_context->tctx,
279 k5ret, 0,
280 "encode_AS_REQ failed");
282 if (test_context->test_stage != TEST_AS_REQ_SELF) {
283 torture_assert_int_equal(test_context->tctx, used, send_buf->length,
284 "re-encode length mismatch");
286 return true;
290 * TEST_AS_REQ - RECV
292 * Confirm that the reply packet from the KDC meets certain
293 * expectations as part of TEST_AS_REQ. This uses a packet count to
294 * work out what packet we are up to in the multiple exchanged
295 * triggerd by krb5_get_init_creds_password().
299 static bool torture_krb5_post_recv_as_req_test(struct torture_krb5_context *test_context,
300 const krb5_data *recv_buf)
302 KRB_ERROR error;
303 size_t used;
304 if (test_context->packet_count == 0) {
305 krb5_error_code k5ret;
307 * The client libs obtain the salt by attempting to
308 * authenticate without pre-authentication and getting
309 * the correct salt with the
310 * KRB5KDC_ERR_PREAUTH_REQUIRED error. If we are in
311 * the test (netbios_realm && upn) that deliberatly
312 * has an incorrect principal, we check we get the
313 * correct error.
315 k5ret = decode_KRB_ERROR(recv_buf->data, recv_buf->length,
316 &error, &used);
317 if (k5ret != 0) {
318 AS_REP as_rep;
319 k5ret = decode_AS_REP(recv_buf->data, recv_buf->length,
320 &as_rep, &used);
321 if (k5ret == 0) {
322 if (test_context->test_data->netbios_realm && test_context->test_data->upn) {
323 torture_assert(test_context->tctx, false,
324 "expected to get a KRB_ERROR packet with "
325 "KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN, got valid AS-REP");
326 } else {
327 torture_assert(test_context->tctx, false,
328 "expected to get a KRB_ERROR packet with "
329 "KRB5KDC_ERR_PREAUTH_REQUIRED, got valid AS-REP");
331 } else {
332 if (test_context->test_data->netbios_realm && test_context->test_data->upn) {
333 torture_assert(test_context->tctx, false,
334 "unable to decode as KRB-ERROR or AS-REP, "
335 "expected to get a KRB_ERROR packet with KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN");
336 } else {
337 torture_assert(test_context->tctx, false,
338 "unable to decode as KRB-ERROR or AS-REP, "
339 "expected to get a KRB_ERROR packet with KRB5KDC_ERR_PREAUTH_REQUIRED");
343 torture_assert_int_equal(test_context->tctx, used, recv_buf->length,
344 "length mismatch");
345 torture_assert_int_equal(test_context->tctx, error.pvno, 5,
346 "Got wrong error.pvno");
347 if (test_context->test_data->netbios_realm && test_context->test_data->upn) {
348 torture_assert_int_equal(test_context->tctx,
349 error.error_code,
350 KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN - KRB5KDC_ERR_NONE,
351 "Got wrong error.error_code");
352 } else {
353 torture_assert_int_equal(test_context->tctx,
354 error.error_code,
355 KRB5KDC_ERR_PREAUTH_REQUIRED - KRB5KDC_ERR_NONE,
356 "Got wrong error.error_code");
359 free_KRB_ERROR(&error);
360 } else if ((decode_KRB_ERROR(recv_buf->data, recv_buf->length, &error, &used) == 0)
361 && (test_context->packet_count == 1)) {
363 * The Windows 2012R2 KDC will always respond with
364 * KRB5KRB_ERR_RESPONSE_TOO_BIG over UDP as the ticket
365 * won't fit, because of the PAC. (It appears to do
366 * this always, even if it will). This triggers the
367 * client to try again over TCP.
369 torture_assert_int_equal(test_context->tctx,
370 used, recv_buf->length,
371 "length mismatch");
372 torture_assert_int_equal(test_context->tctx,
373 error.pvno, 5,
374 "Got wrong error.pvno");
375 torture_assert_int_equal(test_context->tctx,
376 error.error_code,
377 KRB5KRB_ERR_RESPONSE_TOO_BIG - KRB5KDC_ERR_NONE,
378 "Got wrong error.error_code");
379 free_KRB_ERROR(&error);
380 } else {
382 * Finally the successful packet.
384 torture_assert_int_equal(test_context->tctx,
385 decode_AS_REP(recv_buf->data, recv_buf->length,
386 &test_context->as_rep, &used), 0,
387 "decode_AS_REP failed");
388 torture_assert_int_equal(test_context->tctx, used, recv_buf->length,
389 "length mismatch");
390 torture_assert_int_equal(test_context->tctx,
391 test_context->as_rep.pvno, 5,
392 "Got wrong as_rep->pvno");
393 torture_assert_int_equal(test_context->tctx,
394 test_context->as_rep.ticket.tkt_vno, 5,
395 "Got wrong as_rep->ticket.tkt_vno");
396 torture_assert(test_context->tctx,
397 test_context->as_rep.ticket.enc_part.kvno,
398 "Did not get a KVNO in test_context->as_rep.ticket.enc_part.kvno");
401 * We can confirm that the correct proxy behaviour is
402 * in use on the KDC by checking the KVNO of the
403 * krbtgt account returned in the reply.
405 * A packet passed to the full RW DC will not have a
406 * KVNO in the upper bits, while a packet processed
407 * locally on the RODC will have these bits filled in
408 * the msDS-SecondaryKrbTgtNumber
410 if (torture_setting_bool(test_context->tctx, "expect_cached_at_rodc", false)) {
411 torture_assert_int_not_equal(test_context->tctx,
412 *test_context->as_rep.ticket.enc_part.kvno & 0xFFFF0000,
413 0, "Did not get a RODC number in the KVNO");
414 } else {
415 torture_assert_int_equal(test_context->tctx,
416 *test_context->as_rep.ticket.enc_part.kvno & 0xFFFF0000,
417 0, "Unexpecedly got a RODC number in the KVNO");
419 free_AS_REP(&test_context->as_rep);
421 torture_assert(test_context->tctx, test_context->packet_count < 3, "too many packets");
422 free_AS_REQ(&test_context->as_req);
423 return true;
427 * TEST_TGS_REQ_KRBTGT_CANON
430 * Confirm that the outgoing TGS-REQ packet from krb5_get_creds()
431 * for the krbtgt/realm principal meets certain expectations, like
432 * that the canonicalize bit is not set
436 static bool torture_krb5_pre_send_tgs_req_krbtgt_canon_test(struct torture_krb5_context *test_context, const krb5_data *send_buf, krb5_data *modified_send_buf)
438 size_t used;
439 torture_assert_int_equal(test_context->tctx,
440 decode_TGS_REQ(send_buf->data, send_buf->length,
441 &test_context->tgs_req, &used),
442 0, "decode_TGS_REQ for TEST_TGS_REQ test failed");
443 torture_assert_int_equal(test_context->tctx,
444 used, send_buf->length,
445 "length mismatch");
446 torture_assert_int_equal(test_context->tctx,
447 test_context->tgs_req.pvno, 5,
448 "Got wrong as_req->pvno");
449 torture_assert_int_equal(test_context->tctx,
450 test_context->tgs_req.req_body.kdc_options.canonicalize,
451 true,
452 "krb5 libs unexpectedly did not set canonicalize!");
454 torture_assert_int_equal(test_context->tctx,
455 test_context->tgs_req.req_body.sname->name_type,
456 KRB5_NT_PRINCIPAL,
457 "Mismatch in name_type between request and expected request");
459 torture_assert_str_equal(test_context->tctx,
460 test_context->tgs_req.req_body.realm,
461 test_context->test_data->real_realm,
462 "Mismatch in realm between request and expected request");
464 *modified_send_buf = *send_buf;
465 return true;
469 * TEST_TGS_REQ_KRBTGT_CANON
471 * Confirm that the reply TGS-REP packet for krb5_get_creds()
472 * where the client is behaving as if this is a cross-realm trust due
473 * to case or netbios vs dns name differences meets certain
474 * expectations, while canonicalize is set
478 static bool torture_krb5_post_recv_tgs_req_krbtgt_canon_test(struct torture_krb5_context *test_context, const krb5_data *recv_buf)
480 size_t used;
481 torture_assert_int_equal(test_context->tctx,
482 decode_TGS_REP(recv_buf->data, recv_buf->length,
483 &test_context->tgs_rep, &used),
485 "decode_TGS_REP failed");
486 torture_assert_int_equal(test_context->tctx, used, recv_buf->length, "length mismatch");
487 torture_assert_int_equal(test_context->tctx,
488 test_context->tgs_rep.pvno, 5,
489 "Got wrong as_rep->pvno");
490 torture_assert_int_equal(test_context->tctx,
491 test_context->tgs_rep.ticket.tkt_vno, 5,
492 "Got wrong as_rep->ticket.tkt_vno");
493 torture_assert(test_context->tctx,
494 test_context->tgs_rep.ticket.enc_part.kvno,
495 "Did not get a KVNO in test_context->as_rep.ticket.enc_part.kvno");
496 torture_assert_str_equal(test_context->tctx,
497 test_context->tgs_req.req_body.realm,
498 test_context->tgs_rep.ticket.realm,
499 "Mismatch in realm between request and ticket response");
500 torture_assert_str_equal(test_context->tctx,
501 test_context->tgs_rep.ticket.realm,
502 test_context->test_data->real_realm,
503 "Mismatch in realm between ticket response and expected ticket response");
504 torture_assert_int_equal(test_context->tctx,
505 test_context->tgs_rep.ticket.sname.name_type,
506 KRB5_NT_SRV_INST,
507 "Mismatch in name_type between ticket response and expected value of KRB5_NT_SRV_INST");
509 torture_assert_int_equal(test_context->tctx,
510 test_context->tgs_rep.ticket.sname.name_string.len,
512 "Mismatch in name_type between ticket response and expected value, expected krbtgt/REALM@REALM");
514 torture_assert_str_equal(test_context->tctx,
515 test_context->tgs_rep.ticket.sname.name_string.val[0], "krbtgt",
516 "Mismatch in name between reponse and expected response, expected krbtgt");
517 torture_assert_str_equal(test_context->tctx,
518 test_context->tgs_rep.ticket.sname.name_string.val[1], test_context->test_data->real_realm,
519 "Mismatch in realm part of krbtgt/ in expected response, expected krbtgt/REALM@REALM");
522 * We can confirm that the correct proxy behaviour is
523 * in use on the KDC by checking the KVNO of the
524 * krbtgt account returned in the reply.
526 * A packet passed to the full RW DC will not have a
527 * KVNO in the upper bits, while a packet processed
528 * locally on the RODC will have these bits filled in
529 * the msDS-SecondaryKrbTgtNumber
531 if (torture_setting_bool(test_context->tctx, "expect_cached_at_rodc", false)) {
532 torture_assert_int_not_equal(test_context->tctx,
533 *test_context->tgs_rep.ticket.enc_part.kvno & 0xFFFF0000,
534 0, "Did not get a RODC number in the KVNO");
535 } else {
536 torture_assert_int_equal(test_context->tctx,
537 *test_context->tgs_rep.ticket.enc_part.kvno & 0xFFFF0000,
538 0, "Unexpecedly got a RODC number in the KVNO");
540 free_TGS_REP(&test_context->tgs_rep);
541 torture_assert(test_context->tctx,
542 test_context->packet_count < 2,
543 "too many packets");
544 free_TGS_REQ(&test_context->tgs_req);
545 return true;
549 * TEST_TGS_REQ_CANON
551 * Confirm that the outgoing TGS-REQ packet from krb5_get_creds
552 * certain expectations, like that the canonicalize bit is set (this
553 * test is to force that handling) and that if an enterprise name was
554 * requested, that it was sent.
558 static bool torture_krb5_pre_send_tgs_req_canon_test(struct torture_krb5_context *test_context,
559 const krb5_data *send_buf,
560 krb5_data *modified_send_buf)
562 size_t used;
563 torture_assert_int_equal(test_context->tctx,
564 decode_TGS_REQ(send_buf->data, send_buf->length,
565 &test_context->tgs_req, &used),
566 0, "decode_TGS_REQ for TEST_TGS_REQ_CANON test failed");
567 torture_assert_int_equal(test_context->tctx, used, send_buf->length, "length mismatch");
568 torture_assert_int_equal(test_context->tctx, test_context->tgs_req.pvno, 5, "Got wrong as_req->pvno");
569 torture_assert_int_equal(test_context->tctx,
570 test_context->tgs_req.req_body.kdc_options.canonicalize,
571 true, "krb5 libs unexpectedly did not set canonicalize!");
573 if (test_context->test_data->enterprise) {
574 torture_assert_int_equal(test_context->tctx,
575 test_context->tgs_req.req_body.sname->name_type, KRB5_NT_ENTERPRISE_PRINCIPAL,
576 "Mismatch in name type between request and expected request, expected KRB5_NT_ENTERPRISE_PRINCIPAL");
577 torture_assert_str_equal(test_context->tctx,
578 test_context->tgs_req.req_body.realm, test_context->test_data->real_realm,
579 "Mismatch in realm between request and expected request");
581 } else if (test_context->test_data->canonicalize) {
582 torture_assert_int_equal(test_context->tctx,
583 test_context->tgs_req.req_body.sname->name_type, KRB5_NT_PRINCIPAL,
584 "Mismatch in name type between request and expected request, expected KRB5_NT_PRINCIPAL");
585 torture_assert_str_equal(test_context->tctx,
586 test_context->tgs_req.req_body.realm, test_context->test_data->real_realm,
587 "Mismatch in realm between request and expected request");
589 } else {
590 torture_assert_int_equal(test_context->tctx,
591 test_context->tgs_req.req_body.sname->name_type, KRB5_NT_PRINCIPAL,
592 "Mismatch in name type between request and expected request, expected KRB5_NT_PRINCIPAL");
593 torture_assert_str_equal(test_context->tctx,
594 test_context->tgs_req.req_body.realm, test_context->test_data->realm,
595 "Mismatch in realm between request and expected request");
599 *modified_send_buf = *send_buf;
601 return true;
605 * TEST_TGS_REQ_CANON - RECV
607 * Confirm that the reply TGS-REP or error packet from the KDC meets
608 * certain expectations as part of TEST_TGS_REQ_CANON.
610 * This is triggered by krb5_get_creds()
614 static bool torture_krb5_post_recv_tgs_req_canon_test(struct torture_krb5_context *test_context, const krb5_data *recv_buf)
616 KRB_ERROR error;
617 size_t used;
620 * If this account did not have a servicePrincipalName, then
621 * we expect a errro packet, not a TGS-REQ
623 if (decode_KRB_ERROR(recv_buf->data, recv_buf->length, &error, &used) == 0) {
624 torture_assert_int_equal(test_context->tctx, used, recv_buf->length, "length mismatch");
625 torture_assert_int_equal(test_context->tctx,
626 error.pvno, 5,
627 "Got wrong error.pvno");
628 torture_assert_int_equal(test_context->tctx,
629 error.error_code,
630 KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN - KRB5KDC_ERR_NONE,
631 "Got wrong error.error_code");
632 } else {
633 torture_assert_int_equal(test_context->tctx,
634 decode_TGS_REP(recv_buf->data, recv_buf->length,
635 &test_context->tgs_rep,
636 &used),
638 "decode_TGS_REP failed");
639 torture_assert_int_equal(test_context->tctx,
640 used, recv_buf->length,
641 "length mismatch");
642 torture_assert_int_equal(test_context->tctx,
643 test_context->tgs_rep.pvno, 5,
644 "Got wrong as_rep->pvno");
645 torture_assert_int_equal(test_context->tctx,
646 test_context->tgs_rep.ticket.tkt_vno, 5,
647 "Got wrong as_rep->ticket.tkt_vno");
648 torture_assert(test_context->tctx,
649 test_context->tgs_rep.ticket.enc_part.kvno,
650 "Did not get a KVNO in test_context->as_rep.ticket.enc_part.kvno");
651 torture_assert_str_equal(test_context->tctx,
652 test_context->tgs_rep.ticket.realm,
653 test_context->test_data->real_realm,
654 "Mismatch in realm between ticket response and expected upper case REALM");
655 torture_assert_int_equal(test_context->tctx,
656 test_context->tgs_rep.ticket.sname.name_type,
657 test_context->tgs_req.req_body.sname->name_type,
658 "Mismatch in name_type between request and ticket response");
659 torture_assert_int_equal(test_context->tctx,
660 test_context->tgs_rep.ticket.sname.name_string.len,
661 test_context->tgs_req.req_body.sname->name_string.len,
662 "Mismatch in name_string.len between request and ticket response");
663 torture_assert(test_context->tctx,
664 test_context->tgs_rep.ticket.sname.name_string.len >= 1,
665 "name_string.len should be >=1 in ticket response");
666 torture_assert_str_equal(test_context->tctx,
667 test_context->tgs_rep.ticket.sname.name_string.val[0],
668 test_context->tgs_req.req_body.sname->name_string.val[0],
669 "Mismatch in name between request and expected request");
670 torture_assert_int_equal(test_context->tctx,
671 *test_context->tgs_rep.ticket.enc_part.kvno & 0xFFFF0000,
672 0, "Unexpecedly got a RODC number in the KVNO, should just be principal KVNO");
673 free_TGS_REP(&test_context->tgs_rep);
675 torture_assert(test_context->tctx, test_context->packet_count == 0, "too many packets");
676 free_TGS_REQ(&test_context->tgs_req);
678 return true;
682 * TEST_SELF_TRUST_TGS_REQ
684 * Confirm that the outgoing TGS-REQ packet from krb5_mk_req_exact()
685 * certain expectations, like that the canonicalize bit is set (this
686 * test is to force that handling).
688 * This test is for the case where the name we ask for, while a valid
689 * alternate name for our own realm is used. The client acts as if
690 * this is cross-realm trust.
694 static bool torture_krb5_pre_send_self_trust_tgs_req_test(struct torture_krb5_context *test_context,
695 const krb5_data *send_buf,
696 krb5_data *modified_send_buf)
698 size_t used;
699 torture_assert_int_equal(test_context->tctx,
700 decode_TGS_REQ(send_buf->data, send_buf->length,
701 &test_context->tgs_req, &used),
702 0, "decode_TGS_REQ for TEST_SELF_TRUST_TGS_REQ test failed");
703 torture_assert_int_equal(test_context->tctx, used, send_buf->length, "length mismatch");
704 torture_assert_int_equal(test_context->tctx, test_context->tgs_req.pvno, 5, "Got wrong as_req->pvno");
705 torture_assert_int_equal(test_context->tctx, test_context->tgs_req.req_body.kdc_options.canonicalize, false, "krb5 libs unexpectedly set canonicalize!");
707 if (test_context->test_data->canonicalize) {
708 torture_assert_str_equal(test_context->tctx,
709 test_context->tgs_req.req_body.realm,
710 test_context->test_data->real_realm,
711 "Mismatch in realm between request and expected request");
712 } else {
713 torture_assert_str_equal(test_context->tctx,
714 test_context->tgs_req.req_body.realm,
715 test_context->test_data->realm,
716 "Mismatch in realm between request and expected request");
718 torture_assert_int_equal(test_context->tctx,
719 test_context->tgs_req.req_body.sname->name_type, KRB5_NT_PRINCIPAL,
720 "Mismatch in name type between request and expected request, expected KRB5_NT_PRINCIPAL");
721 torture_assert_int_equal(test_context->tctx,
722 test_context->tgs_req.req_body.sname->name_string.len, 2,
723 "Mismatch in name between request and expected request, expected krbtgt/realm");
724 torture_assert_str_equal(test_context->tctx,
725 test_context->tgs_req.req_body.sname->name_string.val[0], "krbtgt",
726 "Mismatch in name between request and expected request, expected krbtgt");
727 torture_assert_str_equal(test_context->tctx,
728 test_context->tgs_req.req_body.sname->name_string.val[1], test_context->test_data->realm,
729 "Mismatch in realm part of cross-realm request principal between request and expected request");
730 *modified_send_buf = *send_buf;
732 return true;
736 * TEST_SELF_TRUST_TGS_REQ and TEST_TGS_REQ_KRBTGT - RECV
738 * Confirm that the reply TGS-REP packet for krb5_mk_req_exact(),
739 * where the client is behaving as if this is a cross-realm trust due
740 * to case or netbios vs dns name differences meets certain
741 * expectations.
745 static bool torture_krb5_post_recv_self_trust_tgs_req_test(struct torture_krb5_context *test_context, const krb5_data *recv_buf)
747 size_t used;
748 torture_assert_int_equal(test_context->tctx,
749 decode_TGS_REP(recv_buf->data, recv_buf->length,
750 &test_context->tgs_rep, &used),
752 "decode_TGS_REP failed");
753 torture_assert_int_equal(test_context->tctx, used, recv_buf->length, "length mismatch");
754 torture_assert_int_equal(test_context->tctx,
755 test_context->tgs_rep.pvno, 5,
756 "Got wrong as_rep->pvno");
757 torture_assert_int_equal(test_context->tctx,
758 test_context->tgs_rep.ticket.tkt_vno, 5,
759 "Got wrong as_rep->ticket.tkt_vno");
760 torture_assert(test_context->tctx,
761 test_context->tgs_rep.ticket.enc_part.kvno,
762 "Did not get a KVNO in test_context->as_rep.ticket.enc_part.kvno");
763 torture_assert_str_equal(test_context->tctx,
764 test_context->tgs_req.req_body.realm,
765 test_context->tgs_rep.ticket.realm,
766 "Mismatch in realm between request and ticket response");
767 torture_assert_int_equal(test_context->tctx,
768 test_context->tgs_rep.ticket.sname.name_type,
769 test_context->tgs_req.req_body.sname->name_type,
770 "Mismatch in name_type between request and ticket response");
772 torture_assert_int_equal(test_context->tctx,
773 test_context->tgs_rep.ticket.sname.name_string.len, 2,
774 "Mismatch in name between request and expected request, expected krbtgt/realm");
775 torture_assert_str_equal(test_context->tctx,
776 test_context->tgs_rep.ticket.sname.name_string.val[0], "krbtgt",
777 "Mismatch in name between request and expected request, expected krbtgt");
778 torture_assert_str_equal(test_context->tctx,
779 test_context->tgs_rep.ticket.sname.name_string.val[1], test_context->test_data->realm,
780 "Mismatch in realm part of cross-realm request principal between response and expected request");
782 * We can confirm that the correct proxy behaviour is
783 * in use on the KDC by checking the KVNO of the
784 * krbtgt account returned in the reply.
786 * A packet passed to the full RW DC will not have a
787 * KVNO in the upper bits, while a packet processed
788 * locally on the RODC will have these bits filled in
789 * the msDS-SecondaryKrbTgtNumber
791 if (torture_setting_bool(test_context->tctx, "expect_cached_at_rodc", false)) {
792 torture_assert_int_not_equal(test_context->tctx,
793 *test_context->tgs_rep.ticket.enc_part.kvno & 0xFFFF0000,
794 0, "Did not get a RODC number in the KVNO");
795 } else {
796 torture_assert_int_equal(test_context->tctx,
797 *test_context->tgs_rep.ticket.enc_part.kvno & 0xFFFF0000,
798 0, "Unexpecedly got a RODC number in the KVNO");
800 free_TGS_REP(&test_context->tgs_rep);
801 torture_assert_int_equal(test_context->tctx,
802 test_context->packet_count, 0,
803 "too many packets");
804 test_context->packet_count = 0;
805 test_context->test_stage = TEST_TGS_REQ;
806 free_TGS_REQ(&test_context->tgs_req);
807 return true;
811 * TEST_TGS_REQ
813 * Confirm that the outgoing TGS-REQ packet from krb5_mk_req_exact()
814 * certain expectations, like that the canonicalize bit is set (this
815 * test is to force that handling) and that if an enterprise name was
816 * requested, that it was sent.
820 static bool torture_krb5_pre_send_tgs_req_test(struct torture_krb5_context *test_context, const krb5_data *send_buf, krb5_data *modified_send_buf)
822 size_t used;
823 torture_assert_int_equal(test_context->tctx,
824 decode_TGS_REQ(send_buf->data, send_buf->length,
825 &test_context->tgs_req, &used),
826 0, "decode_TGS_REQ for TEST_TGS_REQ test failed");
827 torture_assert_int_equal(test_context->tctx, used, send_buf->length, "length mismatch");
828 torture_assert_int_equal(test_context->tctx, test_context->tgs_req.pvno, 5,
829 "Got wrong as_req->pvno");
830 torture_assert_int_equal(test_context->tctx,
831 test_context->tgs_req.req_body.kdc_options.canonicalize,
832 false,
833 "krb5 libs unexpectedly set canonicalize!");
835 if (test_context->test_data->enterprise) {
836 torture_assert_int_equal(test_context->tctx,
837 test_context->tgs_req.req_body.sname->name_type,
838 KRB5_NT_ENTERPRISE_PRINCIPAL,
839 "Mismatch in name type between request and expected request, expected KRB5_NT_ENTERPRISE_PRINCIPAL");
840 torture_assert_str_equal(test_context->tctx,
841 test_context->tgs_req.req_body.realm,
842 test_context->test_data->real_realm,
843 "Mismatch in realm between request and expected request");
845 } else {
846 torture_assert_int_equal(test_context->tctx,
847 test_context->tgs_req.req_body.sname->name_type,
848 KRB5_NT_PRINCIPAL,
849 "Mismatch in name type between request and expected request, expected KRB5_NT_PRINCIPAL");
850 torture_assert_str_equal(test_context->tctx,
851 test_context->tgs_req.req_body.realm,
852 test_context->test_data->realm,
853 "Mismatch in realm between request and expected request");
857 *modified_send_buf = *send_buf;
859 return true;
863 * TEST_TGS_REQ - RECV
865 * Confirm that the reply TGS-REP packet for krb5_mk_req_exact(), for
866 * the actual target service.
870 static bool torture_krb5_post_recv_tgs_req_test(struct torture_krb5_context *test_context, const krb5_data *recv_buf)
872 KRB_ERROR error;
873 size_t used;
875 * If this account did not have a servicePrincipalName, then
876 * we expect a errro packet, not a TGS-REQ
878 if (decode_KRB_ERROR(recv_buf->data, recv_buf->length, &error, &used) == 0) {
879 torture_assert_int_equal(test_context->tctx,
880 used, recv_buf->length,
881 "length mismatch");
882 torture_assert_int_equal(test_context->tctx,
883 error.pvno, 5,
884 "Got wrong error.pvno");
885 torture_assert_int_equal(test_context->tctx,
886 error.error_code,
887 KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN - KRB5KDC_ERR_NONE,
888 "Got wrong error.error_code");
889 } else {
890 torture_assert_int_equal(test_context->tctx,
891 decode_TGS_REP(recv_buf->data, recv_buf->length,
892 &test_context->tgs_rep, &used),
894 "decode_TGS_REP failed");
895 torture_assert_int_equal(test_context->tctx, used, recv_buf->length,
896 "length mismatch");
897 torture_assert_int_equal(test_context->tctx,
898 test_context->tgs_rep.pvno, 5,
899 "Got wrong as_rep->pvno");
900 torture_assert_int_equal(test_context->tctx,
901 test_context->tgs_rep.ticket.tkt_vno, 5,
902 "Got wrong as_rep->ticket.tkt_vno");
903 torture_assert(test_context->tctx,
904 test_context->tgs_rep.ticket.enc_part.kvno,
905 "Did not get a KVNO in test_context->as_rep.ticket.enc_part.kvno");
906 torture_assert_str_equal(test_context->tctx,
907 test_context->tgs_rep.ticket.realm,
908 test_context->test_data->real_realm,
909 "Mismatch in realm between ticket response and expected upper case REALM");
910 torture_assert_int_equal(test_context->tctx,
911 test_context->tgs_req.req_body.sname->name_type,
912 test_context->tgs_rep.ticket.sname.name_type, "Mismatch in name_type between request and ticket response");
913 torture_assert_int_equal(test_context->tctx,
914 *test_context->tgs_rep.ticket.enc_part.kvno & 0xFFFF0000,
915 0, "Unexpecedly got a RODC number in the KVNO, should just be principal KVNO");
916 free_TGS_REP(&test_context->tgs_rep);
918 torture_assert(test_context->tctx, test_context->packet_count < 3, "too many packets");
919 free_TGS_REQ(&test_context->tgs_req);
920 test_context->test_stage = TEST_DONE;
921 return true;
925 * TEST_TGS_REQ_KRBTGT
928 * Confirm that the outgoing TGS-REQ packet from krb5_mk_req_exact()
929 * for the krbtgt/realm principal meets certain expectations, like
930 * that the canonicalize bit is not set
934 static bool torture_krb5_pre_send_tgs_req_krbtgt_test(struct torture_krb5_context *test_context, const krb5_data *send_buf, krb5_data *modified_send_buf)
936 size_t used;
937 torture_assert_int_equal(test_context->tctx,
938 decode_TGS_REQ(send_buf->data, send_buf->length,
939 &test_context->tgs_req, &used),
940 0, "decode_TGS_REQ for TEST_TGS_REQ test failed");
941 torture_assert_int_equal(test_context->tctx,
942 used, send_buf->length,
943 "length mismatch");
944 torture_assert_int_equal(test_context->tctx,
945 test_context->tgs_req.pvno, 5,
946 "Got wrong as_req->pvno");
947 torture_assert_int_equal(test_context->tctx,
948 test_context->tgs_req.req_body.kdc_options.canonicalize,
949 false,
950 "krb5 libs unexpectedly set canonicalize!");
952 torture_assert_str_equal(test_context->tctx,
953 test_context->tgs_req.req_body.realm,
954 test_context->test_data->realm,
955 "Mismatch in realm between request and expected request");
957 *modified_send_buf = *send_buf;
958 test_context->test_stage = TEST_DONE;
959 return true;
963 * TEST_TGS_REQ_HOST, TEST_TGS_REQ_HOST_SRV_INST and TEST_TGS_REQ_HOST_SRV_HST
966 * Confirm that the outgoing TGS-REQ packet from krb5_mk_req_exact()
967 * for the krbtgt/realm principal meets certain expectations, like
968 * that the canonicalize bit is not set
972 static bool torture_krb5_pre_send_tgs_req_host_test(struct torture_krb5_context *test_context, const krb5_data *send_buf, krb5_data *modified_send_buf)
974 size_t used;
975 torture_assert_int_equal(test_context->tctx,
976 decode_TGS_REQ(send_buf->data, send_buf->length,
977 &test_context->tgs_req, &used),
978 0, "decode_TGS_REQ for TEST_TGS_REQ test failed");
979 torture_assert_int_equal(test_context->tctx,
980 used, send_buf->length,
981 "length mismatch");
982 torture_assert_int_equal(test_context->tctx,
983 test_context->tgs_req.pvno, 5,
984 "Got wrong as_req->pvno");
985 torture_assert_int_equal(test_context->tctx,
986 test_context->tgs_req.req_body.sname->name_string.len, 2,
987 "Mismatch in name between request and expected request, expected krbtgt/realm");
988 torture_assert_int_equal(test_context->tctx,
989 test_context->tgs_req.req_body.kdc_options.canonicalize,
990 true,
991 "krb5 libs unexpectedly did not set canonicalize!");
993 if (test_context->test_stage == TEST_TGS_REQ_HOST_SRV_INST) {
994 torture_assert_int_equal(test_context->tctx,
995 test_context->tgs_req.req_body.sname->name_type, KRB5_NT_SRV_INST,
996 "Mismatch in name type between request and expected request, expected KRB5_NT_SRV_INST");
997 torture_assert_str_equal(test_context->tctx,
998 test_context->tgs_req.req_body.sname->name_string.val[0],
999 strupper_talloc(test_context, test_context->test_data->krb5_service),
1000 "Mismatch in name between request and expected request, expected service");
1001 torture_assert_str_equal(test_context->tctx,
1002 test_context->tgs_req.req_body.sname->name_string.val[1],
1003 test_context->test_data->krb5_hostname,
1004 "Mismatch in hostname part between request and expected request");
1006 } else if (test_context->test_stage == TEST_TGS_REQ_HOST_SRV_HST) {
1008 torture_assert_int_equal(test_context->tctx,
1009 test_context->tgs_req.req_body.sname->name_type, KRB5_NT_SRV_HST,
1010 "Mismatch in name type between request and expected request, expected KRB5_NT_SRV_HST");
1011 torture_assert_str_equal(test_context->tctx,
1012 test_context->tgs_req.req_body.sname->name_string.val[0],
1013 test_context->test_data->krb5_service,
1014 "Mismatch in name between request and expected request, expected service");
1015 torture_assert_str_equal(test_context->tctx,
1016 test_context->tgs_req.req_body.sname->name_string.val[1],
1017 strupper_talloc(test_context, test_context->test_data->krb5_hostname),
1018 "Mismatch in hostname part between request and expected request");
1020 } else {
1021 torture_assert_int_equal(test_context->tctx,
1022 test_context->tgs_req.req_body.sname->name_type, KRB5_NT_PRINCIPAL,
1023 "Mismatch in name type between request and expected request, expected KRB5_NT_PRINCIPAL");
1024 torture_assert_str_equal(test_context->tctx,
1025 test_context->tgs_req.req_body.sname->name_string.val[0],
1026 test_context->test_data->krb5_service,
1027 "Mismatch in name between request and expected request, expected service");
1028 torture_assert_str_equal(test_context->tctx,
1029 test_context->tgs_req.req_body.sname->name_string.val[1],
1030 test_context->test_data->krb5_hostname,
1031 "Mismatch in hostname part between request and expected request");
1034 torture_assert_str_equal(test_context->tctx,
1035 test_context->tgs_req.req_body.realm,
1036 test_context->test_data->real_realm,
1037 "Mismatch in realm between request and expected request");
1039 *modified_send_buf = *send_buf;
1040 return true;
1044 * TEST_TGS_REQ_HOST, TEST_TGS_REQ_HOST_SRV_INST, TEST_TGS_REQ_HOST_SRV_HST - RECV
1046 * Confirm that the reply TGS-REP packet for krb5_mk_req(), for
1047 * the actual target service, as a SPN, not a any other name type.
1051 static bool torture_krb5_post_recv_tgs_req_host_test(struct torture_krb5_context *test_context, const krb5_data *recv_buf)
1053 size_t used;
1054 torture_assert_int_equal(test_context->tctx,
1055 decode_TGS_REP(recv_buf->data, recv_buf->length,
1056 &test_context->tgs_rep, &used),
1058 "decode_TGS_REP failed");
1059 torture_assert_int_equal(test_context->tctx, used, recv_buf->length,
1060 "length mismatch");
1061 torture_assert_int_equal(test_context->tctx,
1062 test_context->tgs_rep.pvno, 5,
1063 "Got wrong as_rep->pvno");
1064 torture_assert_int_equal(test_context->tctx,
1065 test_context->tgs_rep.ticket.tkt_vno, 5,
1066 "Got wrong as_rep->ticket.tkt_vno");
1067 torture_assert(test_context->tctx,
1068 test_context->tgs_rep.ticket.enc_part.kvno,
1069 "Did not get a KVNO in test_context->as_rep.ticket.enc_part.kvno");
1070 torture_assert_str_equal(test_context->tctx,
1071 test_context->tgs_rep.ticket.realm,
1072 test_context->test_data->real_realm,
1073 "Mismatch in realm between ticket response and expected upper case REALM");
1074 torture_assert_int_equal(test_context->tctx,
1075 test_context->tgs_req.req_body.sname->name_type,
1076 test_context->tgs_rep.ticket.sname.name_type, "Mismatch in name_type between request and ticket response");
1077 torture_assert_int_equal(test_context->tctx,
1078 test_context->tgs_rep.ticket.sname.name_string.len, 2,
1079 "Mismatch in name between request and expected request, expected service/hostname");
1080 torture_assert_str_equal(test_context->tctx,
1081 test_context->tgs_rep.ticket.sname.name_string.val[0],
1082 test_context->tgs_req.req_body.sname->name_string.val[0],
1083 "Mismatch in name between request and expected request, expected service/hostname");
1084 torture_assert_str_equal(test_context->tctx,
1085 test_context->tgs_rep.ticket.sname.name_string.val[1],
1086 test_context->tgs_req.req_body.sname->name_string.val[1],
1087 "Mismatch in name between request and expected request, expected service/hostname");
1089 torture_assert_int_equal(test_context->tctx,
1090 *test_context->tgs_rep.ticket.enc_part.kvno & 0xFFFF0000,
1091 0, "Unexpecedly got a RODC number in the KVNO, should just be principal KVNO");
1092 free_TGS_REP(&test_context->tgs_rep);
1094 torture_assert(test_context->tctx, test_context->packet_count < 2, "too many packets");
1095 return true;
1099 * TEST_AS_REQ_SELF - RECV
1101 * Confirm that the reply packet from the KDC meets certain
1102 * expectations as part of TEST_AS_REQ. This uses a packet count to
1103 * work out what packet we are up to in the multiple exchanged
1104 * triggerd by krb5_get_init_creds_password().
1108 static bool torture_krb5_post_recv_as_req_self_test(struct torture_krb5_context *test_context,
1109 const krb5_data *recv_buf)
1111 KRB_ERROR error;
1112 size_t used;
1113 if (test_context->packet_count == 0) {
1114 krb5_error_code k5ret;
1116 * The client libs obtain the salt by attempting to
1117 * authenticate without pre-authentication and getting
1118 * the correct salt with the
1119 * KRB5KDC_ERR_PREAUTH_REQUIRED error. If we are in
1120 * the test (netbios_realm && upn) that deliberatly
1121 * has an incorrect principal, we check we get the
1122 * correct error.
1124 k5ret = decode_KRB_ERROR(recv_buf->data, recv_buf->length,
1125 &error, &used);
1126 if (k5ret != 0) {
1127 AS_REP as_rep;
1128 k5ret = decode_AS_REP(recv_buf->data, recv_buf->length,
1129 &as_rep, &used);
1130 if (k5ret == 0) {
1131 if (torture_setting_bool(test_context->tctx, "expect_machine_account", false) == false
1132 || (test_context->test_data->upn == true)) {
1133 torture_assert(test_context->tctx, false,
1134 "expected to get a KRB_ERROR packet with "
1135 "KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN or KRB5KDC_ERR_PREAUTH_REQUIRED, got valid AS-REP");
1136 } else {
1137 torture_assert(test_context->tctx, false,
1138 "expected to get a KRB_ERROR packet with "
1139 "KRB5KDC_ERR_PREAUTH_REQUIRED, got valid AS-REP");
1141 } else {
1142 if (torture_setting_bool(test_context->tctx, "expect_machine_account", false) == false
1143 || (test_context->test_data->upn == true)) {
1144 torture_assert(test_context->tctx, false,
1145 "unable to decode as KRB-ERROR or AS-REP, "
1146 "expected to get a KRB_ERROR packet with KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN or KRB5KDC_ERR_PREAUTH_REQUIRED");
1147 } else {
1148 torture_assert(test_context->tctx, false,
1149 "unable to decode as KRB-ERROR or AS-REP, "
1150 "expected to get a KRB_ERROR packet with KRB5KDC_ERR_PREAUTH_REQUIRED");
1154 torture_assert_int_equal(test_context->tctx, used, recv_buf->length,
1155 "length mismatch");
1156 torture_assert_int_equal(test_context->tctx, error.pvno, 5,
1157 "Got wrong error.pvno");
1158 if ((torture_setting_bool(test_context->tctx, "expect_machine_account", false) == false
1159 || (test_context->test_data->upn == true))
1160 && error.error_code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN - KRB5KDC_ERR_NONE) {
1162 * IGNORE
1164 * This case is because Samba's Heimdal KDC
1165 * checks server and client accounts before
1166 * checking for pre-authentication.
1168 } else {
1169 torture_assert_int_equal(test_context->tctx,
1170 error.error_code,
1171 KRB5KDC_ERR_PREAUTH_REQUIRED - KRB5KDC_ERR_NONE,
1172 "Got wrong error.error_code");
1175 free_KRB_ERROR(&error);
1176 } else if ((decode_KRB_ERROR(recv_buf->data, recv_buf->length, &error, &used) == 0)
1177 && (test_context->packet_count == 1)) {
1179 * The Windows 2012R2 KDC will always respond with
1180 * KRB5KRB_ERR_RESPONSE_TOO_BIG over UDP as the ticket
1181 * won't fit, because of the PAC. (It appears to do
1182 * this always, even if it will). This triggers the
1183 * client to try again over TCP.
1185 torture_assert_int_equal(test_context->tctx,
1186 used, recv_buf->length,
1187 "length mismatch");
1188 torture_assert_int_equal(test_context->tctx,
1189 error.pvno, 5,
1190 "Got wrong error.pvno");
1191 if ((torture_setting_bool(test_context->tctx, "expect_machine_account", false)
1192 && (test_context->test_data->upn == false))) {
1193 torture_assert_int_equal(test_context->tctx,
1194 error.error_code,
1195 KRB5KRB_ERR_RESPONSE_TOO_BIG - KRB5KDC_ERR_NONE,
1196 "Got wrong error.error_code");
1197 } else {
1198 torture_assert_int_equal(test_context->tctx,
1199 error.error_code,
1200 KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN - KRB5KDC_ERR_NONE,
1201 "Got wrong error.error_code");
1203 free_KRB_ERROR(&error);
1204 } else {
1206 * Finally the successful packet.
1208 torture_assert_int_equal(test_context->tctx,
1209 decode_AS_REP(recv_buf->data, recv_buf->length,
1210 &test_context->as_rep, &used), 0,
1211 "decode_AS_REP failed");
1212 torture_assert_int_equal(test_context->tctx, used, recv_buf->length,
1213 "length mismatch");
1214 torture_assert_int_equal(test_context->tctx,
1215 test_context->as_rep.pvno, 5,
1216 "Got wrong as_rep->pvno");
1217 torture_assert_int_equal(test_context->tctx,
1218 test_context->as_rep.ticket.tkt_vno, 5,
1219 "Got wrong as_rep->ticket.tkt_vno");
1220 torture_assert(test_context->tctx,
1221 test_context->as_rep.ticket.enc_part.kvno,
1222 "Did not get a KVNO in test_context->as_rep.ticket.enc_part.kvno");
1225 * We do not expect an RODC number here in the KVNO,
1226 * as this is a ticket to the user's own account.
1228 torture_assert_int_equal(test_context->tctx,
1229 *test_context->as_rep.ticket.enc_part.kvno & 0xFFFF0000,
1230 0, "Unexpecedly got a RODC number in the KVNO");
1231 free_AS_REP(&test_context->as_rep);
1233 torture_assert(test_context->tctx, test_context->packet_count < 3, "too many packets");
1234 free_AS_REQ(&test_context->as_req);
1235 return true;
1239 * This function is set in torture_krb5_init_context_canon as krb5
1240 * send_and_recv function. This allows us to override what server the
1241 * test is aimed at, and to inspect the packets just before they are
1242 * sent to the network, and before they are processed on the recv
1243 * side.
1245 * The torture_krb5_pre_send_test() and torture_krb5_post_recv_test()
1246 * functions are implement the actual tests.
1248 * When this asserts, the caller will get a spurious 'cannot contact
1249 * any KDC' message.
1252 static krb5_error_code smb_krb5_send_and_recv_func_canon_override(krb5_context context,
1253 void *data, /* struct torture_krb5_context */
1254 krb5_krbhst_info *hi,
1255 time_t timeout,
1256 const krb5_data *send_buf,
1257 krb5_data *recv_buf)
1259 krb5_error_code k5ret;
1260 bool ok = false;
1261 krb5_data modified_send_buf;
1263 struct torture_krb5_context *test_context
1264 = talloc_get_type_abort(data, struct torture_krb5_context);
1266 switch (test_context->test_stage) {
1267 case TEST_DONE:
1268 torture_warning(test_context->tctx, "Unexpected outgoing packet from krb5 libs");
1269 return EINVAL;
1270 case TEST_AS_REQ:
1271 ok = torture_krb5_pre_send_as_req_test(test_context, send_buf,
1272 &modified_send_buf);
1273 break;
1274 case TEST_TGS_REQ_KRBTGT_CANON:
1275 ok = torture_krb5_pre_send_tgs_req_krbtgt_canon_test(test_context, send_buf,
1276 &modified_send_buf);
1277 break;
1278 case TEST_TGS_REQ_CANON:
1279 ok = torture_krb5_pre_send_tgs_req_canon_test(test_context, send_buf,
1280 &modified_send_buf);
1281 break;
1282 case TEST_SELF_TRUST_TGS_REQ:
1283 ok = torture_krb5_pre_send_self_trust_tgs_req_test(test_context, send_buf,
1284 &modified_send_buf);
1285 break;
1286 case TEST_TGS_REQ:
1287 ok = torture_krb5_pre_send_tgs_req_test(test_context, send_buf,
1288 &modified_send_buf);
1289 break;
1290 case TEST_TGS_REQ_KRBTGT:
1291 ok = torture_krb5_pre_send_tgs_req_krbtgt_test(test_context, send_buf,
1292 &modified_send_buf);
1293 break;
1294 case TEST_TGS_REQ_HOST:
1295 case TEST_TGS_REQ_HOST_SRV_INST:
1296 case TEST_TGS_REQ_HOST_SRV_HST:
1297 ok = torture_krb5_pre_send_tgs_req_host_test(test_context, send_buf,
1298 &modified_send_buf);
1299 break;
1300 case TEST_AS_REQ_SELF:
1301 ok = torture_krb5_pre_send_as_req_test(test_context, send_buf,
1302 &modified_send_buf);
1303 break;
1305 if (ok == false) {
1306 return EINVAL;
1309 k5ret = smb_krb5_send_and_recv_func_forced(context, test_context->server,
1310 hi, timeout, &modified_send_buf,
1311 recv_buf);
1312 if (k5ret != 0) {
1313 return k5ret;
1316 switch (test_context->test_stage) {
1317 case TEST_DONE:
1318 torture_warning(test_context->tctx, "Unexpected outgoing packet from krb5 libs");
1319 return EINVAL;
1320 case TEST_AS_REQ:
1321 ok = torture_krb5_post_recv_as_req_test(test_context, recv_buf);
1322 break;
1323 case TEST_TGS_REQ_KRBTGT_CANON:
1324 ok = torture_krb5_post_recv_tgs_req_krbtgt_canon_test(test_context, recv_buf);
1325 break;
1326 case TEST_TGS_REQ_CANON:
1327 ok = torture_krb5_post_recv_tgs_req_canon_test(test_context, recv_buf);
1328 break;
1329 case TEST_SELF_TRUST_TGS_REQ:
1330 ok = torture_krb5_post_recv_self_trust_tgs_req_test(test_context, recv_buf);
1331 break;
1332 case TEST_TGS_REQ:
1333 ok = torture_krb5_post_recv_tgs_req_test(test_context, recv_buf);
1334 break;
1335 case TEST_TGS_REQ_KRBTGT:
1336 ok = torture_krb5_post_recv_self_trust_tgs_req_test(test_context, recv_buf);
1337 break;
1338 case TEST_TGS_REQ_HOST:
1339 case TEST_TGS_REQ_HOST_SRV_INST:
1340 case TEST_TGS_REQ_HOST_SRV_HST:
1341 ok = torture_krb5_post_recv_tgs_req_host_test(test_context, recv_buf);
1342 break;
1343 case TEST_AS_REQ_SELF:
1344 ok = torture_krb5_post_recv_as_req_self_test(test_context, recv_buf);
1345 break;
1347 if (ok == false) {
1348 KRB_ERROR error;
1349 size_t used;
1350 torture_warning(test_context->tctx, "Packet of length %llu failed post-recv checks in test stage %d", (unsigned long long)recv_buf->length, test_context->test_stage);
1351 if (decode_KRB_ERROR(recv_buf->data, recv_buf->length, &error, &used) == 0) {
1352 torture_warning(test_context->tctx,
1353 "STAGE: %d Unexpectedly got a KRB-ERROR packet "
1354 "with error code %d (%s)",
1355 test_context->test_stage,
1356 error.error_code,
1357 error_message(error.error_code + KRB5KDC_ERR_NONE));
1358 free_KRB_ERROR(&error);
1360 return EINVAL;
1363 test_context->packet_count++;
1365 return k5ret;
1368 static int test_context_destructor(struct torture_krb5_context *test_context)
1370 freeaddrinfo(test_context->server);
1371 return 0;
1375 static bool torture_krb5_init_context_canon(struct torture_context *tctx,
1376 struct test_data *test_data,
1377 struct torture_krb5_context **torture_krb5_context)
1379 const char *host = torture_setting_string(tctx, "host", NULL);
1380 krb5_error_code k5ret;
1381 bool ok;
1383 struct torture_krb5_context *test_context = talloc_zero(tctx, struct torture_krb5_context);
1384 torture_assert(tctx, test_context != NULL, "Failed to allocate");
1386 test_context->test_data = test_data;
1387 test_context->tctx = tctx;
1389 k5ret = smb_krb5_init_context(test_context, tctx->lp_ctx, &test_context->smb_krb5_context);
1390 torture_assert_int_equal(tctx, k5ret, 0, "smb_krb5_init_context failed");
1392 ok = interpret_string_addr_internal(&test_context->server, host, AI_NUMERICHOST);
1393 torture_assert(tctx, ok, "Failed to parse target server");
1395 talloc_set_destructor(test_context, test_context_destructor);
1397 set_sockaddr_port(test_context->server->ai_addr, 88);
1399 k5ret = krb5_set_send_to_kdc_func(test_context->smb_krb5_context->krb5_context,
1400 smb_krb5_send_and_recv_func_canon_override,
1401 test_context);
1402 torture_assert_int_equal(tctx, k5ret, 0, "krb5_set_send_to_kdc_func failed");
1403 *torture_krb5_context = test_context;
1404 return true;
1408 static bool torture_krb5_as_req_canon(struct torture_context *tctx, const void *tcase_data)
1410 krb5_error_code k5ret;
1411 krb5_get_init_creds_opt *krb_options = NULL;
1412 struct test_data *test_data = talloc_get_type_abort(tcase_data, struct test_data);
1413 krb5_principal principal;
1414 krb5_principal krbtgt_other;
1415 krb5_principal expected_principal;
1416 char *principal_string;
1417 char *krbtgt_other_string;
1418 int principal_flags;
1419 char *expected_principal_string;
1420 char *expected_unparse_principal_string;
1421 int expected_principal_flags;
1422 char *got_principal_string;
1423 char *assertion_message;
1424 const char *password = cli_credentials_get_password(cmdline_credentials);
1425 krb5_context k5_context;
1426 struct torture_krb5_context *test_context;
1427 bool ok;
1428 krb5_creds my_creds;
1429 krb5_creds *server_creds;
1430 krb5_ccache ccache;
1431 krb5_auth_context auth_context;
1432 char *cc_name;
1433 krb5_data in_data, enc_ticket;
1434 krb5_get_creds_opt opt;
1436 const char *upn = torture_setting_string(tctx, "krb5-upn", "");
1437 test_data->krb5_service = torture_setting_string(tctx, "krb5-service", "host");
1438 test_data->krb5_hostname = torture_setting_string(tctx, "krb5-hostname", "");
1441 * If we have not passed a UPN on the command line,
1442 * then skip the UPN tests.
1444 if (test_data->upn && upn[0] == '\0') {
1445 torture_skip(tctx, "This test needs a UPN specified as --option=torture:krb5-upn=user@example.com to run");
1448 if (test_data->netbios_realm) {
1449 test_data->realm = test_data->real_domain;
1450 } else {
1451 test_data->realm = test_data->real_realm;
1454 if (test_data->upn) {
1455 char *p;
1456 test_data->username = talloc_strdup(test_data, upn);
1457 p = strchr(test_data->username, '@');
1458 if (p) {
1459 *p = '\0';
1460 p++;
1463 * Test the UPN behaviour carefully. We can
1464 * test in two different modes, depending on
1465 * what UPN has been set up for us.
1467 * If the UPN is in our realm, then we do all the tests with this name also.
1469 * If the UPN is not in our realm, then we
1470 * expect the tests that replace the realm to
1471 * fail (as it won't match)
1473 if (strcasecmp(p, test_data->real_realm) != 0) {
1474 test_data->other_upn_suffix = true;
1475 } else {
1476 test_data->other_upn_suffix = false;
1480 * This lets us test the combination of the UPN prefix
1481 * with a valid domain, without adding even more
1482 * combinations
1484 if (test_data->netbios_realm == false) {
1485 test_data->realm = p;
1489 ok = torture_krb5_init_context_canon(tctx, test_data, &test_context);
1490 torture_assert(tctx, ok, "torture_krb5_init_context failed");
1491 k5_context = test_context->smb_krb5_context->krb5_context;
1493 if (test_data->upper_realm) {
1494 test_data->realm = strupper_talloc(test_data, test_data->realm);
1495 } else {
1496 test_data->realm = strlower_talloc(test_data, test_data->realm);
1498 if (test_data->upper_username) {
1499 test_data->username = strupper_talloc(test_data, test_data->username);
1500 } else {
1501 test_data->username = talloc_strdup(test_data, test_data->username);
1504 principal_string = talloc_asprintf(test_data, "%s@%s", test_data->username, test_data->realm);
1507 * If we are set to canonicalize, we get back the fixed UPPER
1508 * case realm, and the real username (ie matching LDAP
1509 * samAccountName)
1511 * Otherwise, if we are set to enterprise, we
1512 * get back the whole principal as-sent
1514 * Finally, if we are not set to canonicalize, we get back the
1515 * fixed UPPER case realm, but the as-sent username
1517 if (test_data->canonicalize) {
1518 expected_principal_string = talloc_asprintf(test_data,
1519 "%s@%s",
1520 test_data->real_username,
1521 test_data->real_realm);
1522 } else if (test_data->enterprise) {
1523 expected_principal_string = principal_string;
1524 } else {
1525 expected_principal_string = talloc_asprintf(test_data,
1526 "%s@%s",
1527 test_data->username,
1528 test_data->real_realm);
1531 if (test_data->enterprise) {
1532 principal_flags = KRB5_PRINCIPAL_PARSE_ENTERPRISE;
1533 } else {
1534 if (test_data->upn && test_data->other_upn_suffix) {
1535 torture_skip(tctx, "UPN test for UPN with other UPN suffix only runs with enterprise principals");
1537 principal_flags = 0;
1540 if (test_data->canonicalize) {
1541 expected_principal_flags = 0;
1542 } else {
1543 expected_principal_flags = principal_flags;
1546 torture_assert_int_equal(tctx,
1547 krb5_parse_name_flags(k5_context,
1548 principal_string,
1549 principal_flags,
1550 &principal),
1551 0, "krb5_parse_name_flags failed");
1552 torture_assert_int_equal(tctx,
1553 krb5_parse_name_flags(k5_context,
1554 expected_principal_string,
1555 expected_principal_flags,
1556 &expected_principal),
1557 0, "krb5_parse_name_flags failed");
1559 torture_assert_int_equal(tctx,
1560 krb5_unparse_name(k5_context,
1561 expected_principal,
1562 &expected_unparse_principal_string),
1563 0, "krb5_unparse_name failed");
1565 * Prepare a AS-REQ and run the TEST_AS_REQ tests
1569 test_context->test_stage = TEST_AS_REQ;
1570 test_context->packet_count = 0;
1573 * Set the canonicalize flag if this test requires it
1575 torture_assert_int_equal(tctx,
1576 krb5_get_init_creds_opt_alloc(k5_context, &krb_options),
1577 0, "krb5_get_init_creds_opt_alloc failed");
1579 torture_assert_int_equal(tctx,
1580 krb5_get_init_creds_opt_set_canonicalize(k5_context,
1581 krb_options,
1582 test_data->canonicalize),
1583 0, "krb5_get_init_creds_opt_set_canonicalize failed");
1585 torture_assert_int_equal(tctx,
1586 krb5_get_init_creds_opt_set_win2k(k5_context,
1587 krb_options,
1588 test_data->win2k),
1589 0, "krb5_get_init_creds_opt_set_win2k failed");
1591 k5ret = krb5_get_init_creds_password(k5_context, &my_creds, principal,
1592 password, NULL, NULL, 0,
1593 NULL, krb_options);
1595 if (test_data->netbios_realm && test_data->upn) {
1596 torture_assert_int_equal(tctx, k5ret,
1597 KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN,
1598 "Got wrong error_code from krb5_get_init_creds_password");
1599 /* We can't proceed with more checks */
1600 return true;
1601 } else {
1602 assertion_message = talloc_asprintf(tctx,
1603 "krb5_get_init_creds_password for %s failed: %s",
1604 principal_string,
1605 smb_get_krb5_error_message(k5_context, k5ret, tctx));
1606 torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
1609 torture_assert(tctx,
1610 test_context->packet_count > 1,
1611 "Expected krb5_get_init_creds_password to send more packets");
1614 * Assert that the reply was with the correct type of
1615 * principal, depending on the flags we set
1617 if (test_data->canonicalize == false && test_data->enterprise) {
1618 torture_assert_int_equal(tctx,
1619 krb5_principal_get_type(k5_context,
1620 my_creds.client),
1621 KRB5_NT_ENTERPRISE_PRINCIPAL,
1622 "smb_krb5_init_context gave incorrect client->name.name_type");
1623 } else {
1624 torture_assert_int_equal(tctx,
1625 krb5_principal_get_type(k5_context,
1626 my_creds.client),
1627 KRB5_NT_PRINCIPAL,
1628 "smb_krb5_init_context gave incorrect client->name.name_type");
1631 torture_assert_int_equal(tctx,
1632 krb5_unparse_name(k5_context,
1633 my_creds.client, &got_principal_string), 0,
1634 "krb5_unparse_name failed");
1636 assertion_message = talloc_asprintf(tctx,
1637 "krb5_get_init_creds_password returned a different principal %s to what was expected %s",
1638 got_principal_string, expected_principal_string);
1639 krb5_free_unparsed_name(k5_context, got_principal_string);
1641 torture_assert(tctx, krb5_principal_compare(k5_context,
1642 my_creds.client, expected_principal),
1643 assertion_message);
1646 torture_assert_int_equal(tctx,
1647 krb5_principal_get_type(k5_context,
1648 my_creds.server), KRB5_NT_SRV_INST,
1649 "smb_krb5_init_context gave incorrect server->name.name_type");
1651 torture_assert_int_equal(tctx,
1652 krb5_principal_get_num_comp(k5_context,
1653 my_creds.server), 2,
1654 "smb_krb5_init_context gave incorrect number of components in my_creds.server->name");
1656 torture_assert_str_equal(tctx,
1657 krb5_principal_get_comp_string(k5_context,
1658 my_creds.server, 0),
1659 "krbtgt",
1660 "smb_krb5_init_context gave incorrect my_creds.server->name.name_string[0]");
1662 if (test_data->canonicalize || test_data->enterprise) {
1663 torture_assert_str_equal(tctx,
1664 krb5_principal_get_comp_string(k5_context,
1665 my_creds.server, 1),
1666 test_data->real_realm,
1668 "smb_krb5_init_context gave incorrect my_creds.server->name.name_string[1]");
1669 } else {
1670 torture_assert_str_equal(tctx,
1671 krb5_principal_get_comp_string(k5_context,
1672 my_creds.server, 1),
1673 test_data->realm,
1675 "smb_krb5_init_context gave incorrect my_creds.server->name.name_string[1]");
1677 torture_assert_str_equal(tctx,
1678 krb5_principal_get_realm(k5_context,
1679 my_creds.server),
1680 test_data->real_realm,
1681 "smb_krb5_init_context gave incorrect my_creds.server->realm");
1683 /* Store the result of the 'kinit' above into a memory ccache */
1684 cc_name = talloc_asprintf(tctx, "MEMORY:%s", test_data->test_name);
1685 torture_assert_int_equal(tctx, krb5_cc_resolve(k5_context, cc_name,
1686 &ccache),
1687 0, "krb5_cc_resolve failed");
1689 torture_assert_int_equal(tctx, krb5_cc_initialize(k5_context,
1690 ccache, my_creds.client),
1691 0, "krb5_cc_initialize failed");
1693 torture_assert_int_equal(tctx, krb5_cc_store_cred(k5_context,
1694 ccache, &my_creds),
1695 0, "krb5_cc_store_cred failed");
1698 * Prepare a TGS-REQ and run the TEST_TGS_REQ_KRBTGT_CANON tests
1700 * This tests krb5_get_creds behaviour, which allows us to set
1701 * the KRB5_GC_CANONICALIZE option against the krbtgt/ principal
1704 krbtgt_other_string = talloc_asprintf(test_data, "krbtgt/%s@%s", test_data->real_domain, test_data->real_realm);
1705 torture_assert_int_equal(tctx,
1706 krb5_make_principal(k5_context, &krbtgt_other,
1707 test_data->real_realm, "krbtgt",
1708 test_data->real_domain, NULL),
1709 0, "krb5_make_principal failed");
1711 test_context->test_stage = TEST_TGS_REQ_KRBTGT_CANON;
1712 test_context->packet_count = 0;
1714 torture_assert_int_equal(tctx,
1715 krb5_get_creds_opt_alloc(k5_context, &opt),
1716 0, "krb5_get_creds_opt_alloc");
1718 krb5_get_creds_opt_add_options(k5_context,
1719 opt,
1720 KRB5_GC_CANONICALIZE);
1722 krb5_get_creds_opt_add_options(k5_context,
1723 opt,
1724 KRB5_GC_NO_STORE);
1726 /* Confirm if we can get a ticket krbtgt/realm that we got back with the initial kinit */
1727 k5ret = krb5_get_creds(k5_context, opt, ccache, krbtgt_other, &server_creds);
1729 if (test_data->canonicalize == false && test_data->enterprise == false
1730 && test_data->netbios_realm && test_data->upper_realm) {
1732 * In these situations, the code above does store a
1733 * principal in the credentials cache matching what
1734 * krb5_get_creds() needs, so the test succeds, with no packets.
1737 assertion_message = talloc_asprintf(tctx,
1738 "krb5_get_creds for %s failed with: %s",
1739 krbtgt_other_string,
1740 smb_get_krb5_error_message(k5_context, k5ret,
1741 tctx));
1743 torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
1744 torture_assert_int_equal(tctx,
1745 test_context->packet_count,
1746 0, "Expected krb5_get_creds not to send packets");
1747 } else if (test_data->canonicalize == false && test_data->enterprise == false
1748 && (test_data->upper_realm == false || test_data->netbios_realm == true)) {
1749 torture_assert_int_equal(tctx, k5ret, KRB5_CC_NOTFOUND,
1750 "krb5_get_creds should have failed with KRB5_CC_NOTFOUND");
1751 } else {
1754 * In these situations, the code above does not store a
1755 * principal in the credentials cache matching what
1756 * krb5_get_creds() needs without talking to the KDC, so the
1757 * test fails with looping detected because when we set
1758 * canonicalize we confuse the client libs.
1761 assertion_message = talloc_asprintf(tctx,
1762 "krb5_get_creds for %s should have failed with looping detected: %s",
1763 krbtgt_other_string,
1764 smb_get_krb5_error_message(k5_context, k5ret,
1765 tctx));
1767 torture_assert_int_equal(tctx, k5ret, KRB5_GET_IN_TKT_LOOP, assertion_message);
1768 torture_assert_int_equal(tctx,
1769 test_context->packet_count,
1770 2, "Expected krb5_get_creds to send packets");
1774 * Prepare a TGS-REQ and run the TEST_TGS_REQ_CANON tests
1776 * This tests krb5_get_creds behaviour, which allows us to set
1777 * the KRB5_GC_CANONICALIZE option
1780 test_context->test_stage = TEST_TGS_REQ_CANON;
1781 test_context->packet_count = 0;
1783 torture_assert_int_equal(tctx,
1784 krb5_get_creds_opt_alloc(k5_context, &opt),
1785 0, "krb5_get_creds_opt_alloc");
1787 krb5_get_creds_opt_add_options(k5_context,
1788 opt,
1789 KRB5_GC_CANONICALIZE);
1791 krb5_get_creds_opt_add_options(k5_context,
1792 opt,
1793 KRB5_GC_NO_STORE);
1795 if (test_data->s4u2self) {
1796 torture_assert_int_equal(tctx,
1797 krb5_get_creds_opt_set_impersonate(k5_context,
1798 opt,
1799 principal),
1800 0, "krb5_get_creds_opt_set_impersonate failed");
1803 /* Confirm if we can get a ticket to our own name */
1804 k5ret = krb5_get_creds(k5_context, opt, ccache, principal, &server_creds);
1807 * In these situations, the code above does not store a
1808 * principal in the credentials cache matching what
1809 * krb5_get_creds() needs, so the test fails.
1812 if (test_data->canonicalize == false && test_data->enterprise == false
1813 && (test_data->upper_realm == false || test_data->netbios_realm == true)) {
1814 torture_assert_int_equal(tctx, k5ret, KRB5_CC_NOTFOUND,
1815 "krb5_get_creds should have failed with KRB5_CC_NOTFOUND");
1816 } else {
1817 assertion_message = talloc_asprintf(tctx,
1818 "krb5_get_creds for %s failed: %s",
1819 principal_string,
1820 smb_get_krb5_error_message(k5_context, k5ret,
1821 tctx));
1824 * Only machine accounts (strictly, accounts with a
1825 * servicePrincipalName) can expect this test to succeed
1827 if (torture_setting_bool(tctx, "expect_machine_account", false)
1828 && (test_data->enterprise || test_data->upn == false)) {
1829 torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
1830 torture_assert_int_equal(tctx, krb5_cc_store_cred(k5_context,
1831 ccache, server_creds),
1832 0, "krb5_cc_store_cred failed");
1834 torture_assert_int_equal(tctx,
1835 krb5_free_creds(k5_context,
1836 server_creds),
1837 0, "krb5_free_cred_contents failed");
1839 } else {
1840 torture_assert_int_equal(tctx, k5ret, KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN,
1841 assertion_message);
1844 torture_assert_int_equal(tctx,
1845 test_context->packet_count,
1846 1, "Expected krb5_get_creds to send packets");
1850 * Confirm gettting a ticket to pass to the server, running
1851 * either the TEST_TGS_REQ or TEST_SELF_TRUST_TGS_REQ stage.
1853 * This triggers the client to attempt to get a
1854 * cross-realm ticket between the alternate names of
1855 * the server, and we need to confirm that behaviour.
1860 * This tries to guess when the krb5 libs will ask for a
1861 * cross-realm ticket, and when they will just ask the KDC
1862 * directly.
1864 if (test_context->test_data->canonicalize == false
1865 || test_context->test_data->enterprise
1866 || (test_context->test_data->upper_realm
1867 && test_context->test_data->netbios_realm == false)) {
1868 test_context->test_stage = TEST_TGS_REQ;
1869 } else {
1870 test_context->test_stage = TEST_SELF_TRUST_TGS_REQ;
1873 test_context->packet_count = 0;
1874 torture_assert_int_equal(tctx, krb5_auth_con_init(k5_context, &auth_context),
1875 0, "krb5_auth_con_init failed");
1877 in_data.length = 0;
1878 k5ret = krb5_mk_req_exact(k5_context,
1879 &auth_context,
1880 AP_OPTS_USE_SUBKEY,
1881 principal,
1882 &in_data, ccache,
1883 &enc_ticket);
1884 assertion_message = talloc_asprintf(tctx,
1885 "krb5_mk_req_exact for %s failed: %s",
1886 principal_string,
1887 smb_get_krb5_error_message(k5_context, k5ret, tctx));
1890 * Only machine accounts (strictly, accounts with a
1891 * servicePrincipalName) can expect this test to succeed
1893 if (torture_setting_bool(tctx, "expect_machine_account", false) && (test_data->enterprise || test_data->upn == false)) {
1894 DATA_BLOB client_to_server;
1895 torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
1896 client_to_server = data_blob_const(enc_ticket.data, enc_ticket.length);
1897 torture_assert(tctx,
1898 test_accept_ticket(tctx, cmdline_credentials,
1899 expected_unparse_principal_string,
1900 client_to_server),
1901 "test_accept_ticket failed - failed to accept the ticket we just created");
1902 krb5_data_free(&enc_ticket);
1903 } else {
1904 torture_assert_int_equal(tctx, k5ret, KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN,
1905 assertion_message);
1909 * Only in these cases would the above code have needed to
1910 * send packets to the network
1912 if (test_data->canonicalize == false && test_data->enterprise == false
1913 && (test_data->upper_realm == false || test_data->netbios_realm == true)) {
1914 torture_assert(tctx,
1915 test_context->packet_count > 0,
1916 "Expected krb5_mk_req_exact to send packets");
1920 * Confirm gettting a ticket to pass to the server, running
1921 * the TEST_TGS_REQ_HOST, TEST_TGS_REQ_HOST_SRV_INST, TEST_TGS_REQ_HOST_SRV_HST stage
1923 * This triggers the client to attempt to get a
1924 * cross-realm ticket between the alternate names of
1925 * the server, and we need to confirm that behaviour.
1929 if (*test_data->krb5_service && *test_data->krb5_hostname) {
1930 krb5_principal host_principal_srv_inst;
1932 * This tries to guess when the krb5 libs will ask for a
1933 * cross-realm ticket, and when they will just ask the KDC
1934 * directly.
1936 test_context->test_stage = TEST_TGS_REQ_HOST;
1937 test_context->packet_count = 0;
1938 torture_assert_int_equal(tctx, krb5_auth_con_init(k5_context, &auth_context),
1939 0, "krb5_auth_con_init failed");
1941 in_data.length = 0;
1942 k5ret = krb5_mk_req(k5_context,
1943 &auth_context,
1945 test_data->krb5_service,
1946 test_data->krb5_hostname,
1947 &in_data, ccache,
1948 &enc_ticket);
1950 if (test_data->canonicalize == false && test_data->enterprise == false
1951 && (test_data->upper_realm == false || test_data->netbios_realm == true)) {
1952 torture_assert_int_equal(tctx, k5ret, KRB5_CC_NOTFOUND,
1953 "krb5_get_creds should have failed with KRB5_CC_NOTFOUND");
1954 } else {
1955 assertion_message = talloc_asprintf(tctx,
1956 "krb5_mk_req for %s/%s failed: %s",
1957 test_data->krb5_hostname,
1958 test_data->krb5_service,
1959 smb_get_krb5_error_message(k5_context, k5ret, tctx));
1961 torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
1963 * Only in these cases would the above code have needed to
1964 * send packets to the network
1966 torture_assert(tctx,
1967 test_context->packet_count > 0,
1968 "Expected krb5_get_creds to send packets");
1972 test_context->test_stage = TEST_TGS_REQ_HOST_SRV_INST;
1973 test_context->packet_count = 0;
1975 torture_assert_int_equal(tctx,
1976 krb5_make_principal(k5_context, &host_principal_srv_inst,
1977 test_data->real_realm,
1978 strupper_talloc(tctx, test_data->krb5_service),
1979 test_data->krb5_hostname,
1980 NULL),
1981 0, "krb5_make_principal failed");
1983 krb5_principal_set_type(k5_context, host_principal_srv_inst, KRB5_NT_SRV_INST);
1985 torture_assert_int_equal(tctx, krb5_auth_con_init(k5_context, &auth_context),
1986 0, "krb5_auth_con_init failed");
1988 in_data.length = 0;
1989 k5ret = krb5_mk_req_exact(k5_context,
1990 &auth_context,
1992 host_principal_srv_inst,
1993 &in_data, ccache,
1994 &enc_ticket);
1995 krb5_free_principal(k5_context, host_principal_srv_inst);
1996 if (test_data->canonicalize == false && test_data->enterprise == false
1997 && (test_data->upper_realm == false || test_data->netbios_realm == true)) {
1998 torture_assert_int_equal(tctx, k5ret, KRB5_CC_NOTFOUND,
1999 "krb5_get_creds should have failed with KRB5_CC_NOTFOUND");
2000 } else {
2001 assertion_message = talloc_asprintf(tctx,
2002 "krb5_mk_req for %s/%s KRB5_NT_SRV_INST failed: %s",
2003 test_data->krb5_service,
2004 test_data->krb5_hostname,
2005 smb_get_krb5_error_message(k5_context, k5ret, tctx));
2007 torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
2009 * Only in these cases would the above code have needed to
2010 * send packets to the network
2012 torture_assert(tctx,
2013 test_context->packet_count > 0,
2014 "Expected krb5_get_creds to send packets");
2018 test_context->test_stage = TEST_TGS_REQ_HOST_SRV_HST;
2019 test_context->packet_count = 0;
2021 torture_assert_int_equal(tctx,
2022 krb5_make_principal(k5_context, &host_principal_srv_inst,
2023 test_data->real_realm,
2024 test_data->krb5_service,
2025 strupper_talloc(tctx, test_data->krb5_hostname),
2026 NULL),
2027 0, "krb5_make_principal failed");
2029 krb5_principal_set_type(k5_context, host_principal_srv_inst, KRB5_NT_SRV_HST);
2031 torture_assert_int_equal(tctx, krb5_auth_con_init(k5_context, &auth_context),
2032 0, "krb5_auth_con_init failed");
2034 in_data.length = 0;
2035 k5ret = krb5_mk_req_exact(k5_context,
2036 &auth_context,
2038 host_principal_srv_inst,
2039 &in_data, ccache,
2040 &enc_ticket);
2041 krb5_free_principal(k5_context, host_principal_srv_inst);
2042 if (test_data->canonicalize == false && test_data->enterprise == false
2043 && (test_data->upper_realm == false || test_data->netbios_realm == true)) {
2044 torture_assert_int_equal(tctx, k5ret, KRB5_CC_NOTFOUND,
2045 "krb5_get_creds should have failed with KRB5_CC_NOTFOUND");
2046 } else {
2047 assertion_message = talloc_asprintf(tctx,
2048 "krb5_mk_req for %s/%s KRB5_NT_SRV_INST failed: %s",
2049 test_data->krb5_service,
2050 test_data->krb5_hostname,
2051 smb_get_krb5_error_message(k5_context, k5ret, tctx));
2053 torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
2055 * Only in these cases would the above code have needed to
2056 * send packets to the network
2058 torture_assert(tctx,
2059 test_context->packet_count > 0,
2060 "Expected krb5_get_creds to send packets");
2065 * Confirm gettting a ticket for the same krbtgt/realm that we
2066 * got back with the initial ticket, running the
2067 * TEST_TGS_REQ_KRBTGT stage.
2071 test_context->test_stage = TEST_TGS_REQ_KRBTGT;
2072 test_context->packet_count = 0;
2074 in_data.length = 0;
2075 k5ret = krb5_mk_req_exact(k5_context,
2076 &auth_context,
2078 my_creds.server,
2079 &in_data, ccache,
2080 &enc_ticket);
2082 assertion_message = talloc_asprintf(tctx,
2083 "krb5_mk_req_exact for %s failed: %s",
2084 principal_string,
2085 smb_get_krb5_error_message(k5_context, k5ret, tctx));
2086 torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
2089 * Confirm gettting a ticket for our own principal that we
2090 * got back with the initial ticket, running the
2091 * TEST_AS_REQ_SELF stage.
2094 test_context->test_stage = TEST_AS_REQ_SELF;
2095 test_context->packet_count = 0;
2097 k5ret = krb5_get_init_creds_password(k5_context, &my_creds, principal,
2098 password, NULL, NULL, 0,
2099 principal_string, krb_options);
2101 if (torture_setting_bool(test_context->tctx, "expect_machine_account", false) && (test_data->upn == false)) {
2102 assertion_message = talloc_asprintf(tctx,
2103 "krb5_get_init_creds_password for %s failed: %s",
2104 principal_string,
2105 smb_get_krb5_error_message(k5_context, k5ret, tctx));
2106 torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
2107 torture_assert(tctx,
2108 test_context->packet_count >= 2,
2109 "Expected krb5_get_init_creds_password to send more packets");
2111 } else {
2112 assertion_message = talloc_asprintf(tctx,
2113 "Got wrong error_code from krb5_get_init_creds_password, expected KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN trying to get a ticket to %s for %s", principal_string, principal_string);
2114 torture_assert_int_equal(tctx, k5ret,
2115 KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN,
2116 assertion_message);
2117 torture_assert(tctx,
2118 test_context->packet_count >= 1,
2119 "Expected krb5_get_init_creds_password to send more packets");
2121 /* We can't proceed with more checks */
2122 return true;
2126 * Assert that the reply was with the correct type of
2127 * principal, depending on the flags we set
2129 if (test_data->canonicalize == false && test_data->enterprise) {
2130 torture_assert_int_equal(tctx,
2131 krb5_principal_get_type(k5_context,
2132 my_creds.client),
2133 KRB5_NT_ENTERPRISE_PRINCIPAL,
2134 "smb_krb5_init_context gave incorrect client->name.name_type");
2135 torture_assert_int_equal(tctx,
2136 krb5_principal_get_type(k5_context,
2137 my_creds.server),
2138 KRB5_NT_ENTERPRISE_PRINCIPAL,
2139 "smb_krb5_init_context gave incorrect server->name.name_type");
2140 } else {
2141 torture_assert_int_equal(tctx,
2142 krb5_principal_get_type(k5_context,
2143 my_creds.client),
2144 KRB5_NT_PRINCIPAL,
2145 "smb_krb5_init_context gave incorrect client->name.name_type");
2146 torture_assert_int_equal(tctx,
2147 krb5_principal_get_type(k5_context,
2148 my_creds.server),
2149 KRB5_NT_PRINCIPAL,
2150 "smb_krb5_init_context gave incorrect server->name.name_type");
2153 torture_assert_int_equal(tctx,
2154 krb5_unparse_name(k5_context,
2155 my_creds.client, &got_principal_string), 0,
2156 "krb5_unparse_name failed");
2158 assertion_message = talloc_asprintf(tctx,
2159 "krb5_get_init_creds_password returned a different principal %s to what was expected %s",
2160 got_principal_string, expected_principal_string);
2161 krb5_free_unparsed_name(k5_context, got_principal_string);
2163 torture_assert(tctx, krb5_principal_compare(k5_context,
2164 my_creds.client, expected_principal),
2165 assertion_message);
2167 torture_assert_int_equal(tctx,
2168 krb5_unparse_name(k5_context,
2169 my_creds.client, &got_principal_string), 0,
2170 "krb5_unparse_name failed");
2172 assertion_message = talloc_asprintf(tctx,
2173 "krb5_get_init_creds_password returned a different server principal %s to what was expected %s",
2174 got_principal_string, expected_principal_string);
2175 krb5_free_unparsed_name(k5_context, got_principal_string);
2177 torture_assert(tctx, krb5_principal_compare(k5_context,
2178 my_creds.client, expected_principal),
2179 assertion_message);
2181 krb5_free_principal(k5_context, principal);
2182 krb5_get_init_creds_opt_free(k5_context, krb_options);
2184 torture_assert_int_equal(tctx, krb5_free_cred_contents(k5_context, &my_creds),
2185 0, "krb5_free_cred_contents failed");
2187 return true;
2190 struct torture_suite *torture_krb5_canon(TALLOC_CTX *mem_ctx)
2192 unsigned int i;
2193 struct torture_suite *suite = torture_suite_create(mem_ctx, "canon");
2194 suite->description = talloc_strdup(suite, "Kerberos Canonicalisation tests");
2196 for (i = 0; i < TEST_ALL; i++) {
2197 char *name = talloc_asprintf(suite, "%s.%s.%s.%s.%s.%s.%s.%s",
2198 (i & TEST_CANONICALIZE) ? "canon" : "no-canon",
2199 (i & TEST_ENTERPRISE) ? "enterprise" : "no-enterprise",
2200 (i & TEST_UPPER_REALM) ? "uc-realm" : "lc-realm",
2201 (i & TEST_UPPER_USERNAME) ? "uc-user" : "lc-user",
2202 (i & TEST_NETBIOS_REALM) ? "netbios-realm" : "krb5-realm",
2203 (i & TEST_WIN2K) ? "win2k" : "no-win2k",
2204 (i & TEST_UPN) ? "upn" : "no-upn",
2205 (i & TEST_S4U2SELF) ? "s4u2self" : "normal");
2207 struct test_data *test_data = talloc_zero(suite, struct test_data);
2209 test_data->test_name = name;
2210 test_data->real_realm
2211 = strupper_talloc(test_data, cli_credentials_get_realm(cmdline_credentials));
2212 test_data->real_domain = cli_credentials_get_domain(cmdline_credentials);
2213 test_data->username = cli_credentials_get_username(cmdline_credentials);
2214 test_data->real_username = cli_credentials_get_username(cmdline_credentials);
2215 test_data->canonicalize = (i & TEST_CANONICALIZE) != 0;
2216 test_data->enterprise = (i & TEST_ENTERPRISE) != 0;
2217 test_data->upper_realm = (i & TEST_UPPER_REALM) != 0;
2218 test_data->upper_username = (i & TEST_UPPER_USERNAME) != 0;
2219 test_data->netbios_realm = (i & TEST_NETBIOS_REALM) != 0;
2220 test_data->win2k = (i & TEST_WIN2K) != 0;
2221 test_data->upn = (i & TEST_UPN) != 0;
2222 test_data->s4u2self = (i & TEST_S4U2SELF) != 0;
2223 torture_suite_add_simple_tcase_const(suite, name, torture_krb5_as_req_canon,
2224 test_data);
2227 return suite;