torture-krb5: Add test in for normal TGS-REQ
[Samba.git] / source4 / torture / krb5 / kdc-canon.c
blobf6b781543fa528c6a286e11e1b2d8410d165459e
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"
33 #define TEST_CANONICALIZE 0x0000001
34 #define TEST_ENTERPRISE 0x0000002
35 #define TEST_UPPER_REALM 0x0000004
36 #define TEST_UPPER_USERNAME 0x0000008
37 #define TEST_NETBIOS_REALM 0x0000010
38 #define TEST_WIN2K 0x0000020
39 #define TEST_UPN 0x0000040
40 #define TEST_ALL 0x000007F
42 struct test_data {
43 const char *test_name;
44 const char *realm;
45 const char *real_realm;
46 const char *real_domain;
47 const char *username;
48 const char *real_username;
49 bool canonicalize;
50 bool enterprise;
51 bool upper_realm;
52 bool upper_username;
53 bool netbios_realm;
54 bool win2k;
55 bool upn;
56 bool other_upn_suffix;
57 const char *krb5_service;
58 const char *krb5_hostname;
59 };
61 enum test_stage {
62 TEST_AS_REQ = 0,
63 TEST_TGS_REQ_KRBTGT_CANON,
64 TEST_TGS_REQ_CANON,
65 TEST_SELF_TRUST_TGS_REQ,
66 TEST_TGS_REQ,
67 TEST_TGS_REQ_KRBTGT,
68 TEST_TGS_REQ_HOST,
69 TEST_AS_REQ_SELF,
70 TEST_DONE
73 struct torture_krb5_context {
74 struct smb_krb5_context *smb_krb5_context;
75 struct torture_context *tctx;
76 struct addrinfo *server;
77 struct test_data *test_data;
78 int packet_count;
79 enum test_stage test_stage;
80 AS_REQ as_req;
81 AS_REP as_rep;
82 TGS_REQ tgs_req;
83 TGS_REP tgs_rep;
88 * TEST_AS_REQ and TEST_AS_REQ_SELF - SEND
90 * Confirm that the outgoing packet meets certain expectations. This
91 * should be extended to further assert the correct and expected
92 * behaviour of the krb5 libs, so we know what we are sending to the
93 * server.
95 * Additionally, this CHANGES the request to remove the canonicalize
96 * flag automatically added by the krb5 libs when an enterprise
97 * principal is used, so we can test what the server does in this
98 * combination.
102 static bool torture_krb5_pre_send_as_req_test(struct torture_krb5_context *test_context,
103 const krb5_data *send_buf,
104 krb5_data *modified_send_buf)
106 AS_REQ mod_as_req;
107 krb5_error_code k5ret;
108 size_t used;
109 torture_assert_int_equal(test_context->tctx, decode_AS_REQ(send_buf->data, send_buf->length,
110 &test_context->as_req, &used),
111 0, "decode_AS_REQ for TEST_AS_REQ failed");
112 mod_as_req = test_context->as_req;
113 torture_assert_int_equal(test_context->tctx, used, send_buf->length, "length mismatch");
114 torture_assert_int_equal(test_context->tctx, test_context->as_req.pvno,
115 5, "Got wrong as_req->pvno");
116 if (test_context->test_data->canonicalize || test_context->test_data->enterprise) {
117 torture_assert(test_context->tctx,
118 test_context->as_req.req_body.kdc_options.canonicalize,
119 "krb5 libs did not set canonicalize!");
120 } else {
121 torture_assert_int_equal(test_context->tctx,
122 test_context->as_req.req_body.kdc_options.canonicalize,
123 false,
124 "krb5 libs unexpectedly set canonicalize!");
127 if (test_context->test_data->enterprise) {
128 torture_assert_int_equal(test_context->tctx,
129 test_context->as_req.req_body.cname->name_type,
130 KRB5_NT_ENTERPRISE_PRINCIPAL,
131 "krb5 libs did not pass principal as enterprise!");
132 } else {
133 torture_assert_int_equal(test_context->tctx,
134 test_context->as_req.req_body.cname->name_type,
135 KRB5_NT_PRINCIPAL,
136 "krb5 libs unexpectedly set principal as enterprise!");
139 /* Force off canonicalize that was forced on by the krb5 libs */
140 if (test_context->test_data->canonicalize == false && test_context->test_data->enterprise) {
141 mod_as_req.req_body.kdc_options.canonicalize = false;
144 if (test_context->test_stage == TEST_AS_REQ_SELF) {
146 * Force the server name to match the client name,
147 * including the name type. This isn't possible with
148 * the krb5 client libs alone
150 mod_as_req.req_body.sname = test_context->as_req.req_body.cname;
153 ASN1_MALLOC_ENCODE(AS_REQ, modified_send_buf->data, modified_send_buf->length,
154 &mod_as_req, &used, k5ret);
155 torture_assert_int_equal(test_context->tctx,
156 k5ret, 0,
157 "encode_AS_REQ failed");
159 if (test_context->test_stage != TEST_AS_REQ_SELF) {
160 torture_assert_int_equal(test_context->tctx, used, send_buf->length,
161 "re-encode length mismatch");
163 return true;
167 * TEST_AS_REQ - RECV
169 * Confirm that the reply packet from the KDC meets certain
170 * expectations as part of TEST_AS_REQ. This uses a packet count to
171 * work out what packet we are up to in the multiple exchanged
172 * triggerd by krb5_get_init_creds_password().
176 static bool torture_krb5_post_recv_as_req_test(struct torture_krb5_context *test_context,
177 const krb5_data *recv_buf)
179 KRB_ERROR error;
180 size_t used;
181 if (test_context->packet_count == 0) {
182 krb5_error_code k5ret;
184 * The client libs obtain the salt by attempting to
185 * authenticate without pre-authentication and getting
186 * the correct salt with the
187 * KRB5KDC_ERR_PREAUTH_REQUIRED error. If we are in
188 * the test (netbios_realm && upn) that deliberatly
189 * has an incorrect principal, we check we get the
190 * correct error.
192 k5ret = decode_KRB_ERROR(recv_buf->data, recv_buf->length,
193 &error, &used);
194 if (k5ret != 0) {
195 AS_REP as_rep;
196 k5ret = decode_AS_REP(recv_buf->data, recv_buf->length,
197 &as_rep, &used);
198 if (k5ret == 0) {
199 if (test_context->test_data->netbios_realm && test_context->test_data->upn) {
200 torture_assert(test_context->tctx, false,
201 "expected to get a KRB_ERROR packet with "
202 "KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN, got valid AS-REP");
203 } else {
204 torture_assert(test_context->tctx, false,
205 "expected to get a KRB_ERROR packet with "
206 "KRB5KDC_ERR_PREAUTH_REQUIRED, got valid AS-REP");
208 } else {
209 if (test_context->test_data->netbios_realm && test_context->test_data->upn) {
210 torture_assert(test_context->tctx, false,
211 "unable to decode as KRB-ERROR or AS-REP, "
212 "expected to get a KRB_ERROR packet with KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN");
213 } else {
214 torture_assert(test_context->tctx, false,
215 "unable to decode as KRB-ERROR or AS-REP, "
216 "expected to get a KRB_ERROR packet with KRB5KDC_ERR_PREAUTH_REQUIRED");
220 torture_assert_int_equal(test_context->tctx, used, recv_buf->length,
221 "length mismatch");
222 torture_assert_int_equal(test_context->tctx, error.pvno, 5,
223 "Got wrong error.pvno");
224 if (test_context->test_data->netbios_realm && test_context->test_data->upn) {
225 torture_assert_int_equal(test_context->tctx,
226 error.error_code,
227 KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN - KRB5KDC_ERR_NONE,
228 "Got wrong error.error_code");
229 } else {
230 torture_assert_int_equal(test_context->tctx,
231 error.error_code,
232 KRB5KDC_ERR_PREAUTH_REQUIRED - KRB5KDC_ERR_NONE,
233 "Got wrong error.error_code");
236 free_KRB_ERROR(&error);
237 } else if ((decode_KRB_ERROR(recv_buf->data, recv_buf->length, &error, &used) == 0)
238 && (test_context->packet_count == 1)) {
240 * The Windows 2012R2 KDC will always respond with
241 * KRB5KRB_ERR_RESPONSE_TOO_BIG over UDP as the ticket
242 * won't fit, because of the PAC. (It appears to do
243 * this always, even if it will). This triggers the
244 * client to try again over TCP.
246 torture_assert_int_equal(test_context->tctx,
247 used, recv_buf->length,
248 "length mismatch");
249 torture_assert_int_equal(test_context->tctx,
250 error.pvno, 5,
251 "Got wrong error.pvno");
252 torture_assert_int_equal(test_context->tctx,
253 error.error_code,
254 KRB5KRB_ERR_RESPONSE_TOO_BIG - KRB5KDC_ERR_NONE,
255 "Got wrong error.error_code");
256 free_KRB_ERROR(&error);
257 } else {
259 * Finally the successful packet.
261 torture_assert_int_equal(test_context->tctx,
262 decode_AS_REP(recv_buf->data, recv_buf->length,
263 &test_context->as_rep, &used), 0,
264 "decode_AS_REP failed");
265 torture_assert_int_equal(test_context->tctx, used, recv_buf->length,
266 "length mismatch");
267 torture_assert_int_equal(test_context->tctx,
268 test_context->as_rep.pvno, 5,
269 "Got wrong as_rep->pvno");
270 torture_assert_int_equal(test_context->tctx,
271 test_context->as_rep.ticket.tkt_vno, 5,
272 "Got wrong as_rep->ticket.tkt_vno");
273 torture_assert(test_context->tctx,
274 test_context->as_rep.ticket.enc_part.kvno,
275 "Did not get a KVNO in test_context->as_rep.ticket.enc_part.kvno");
278 * We can confirm that the correct proxy behaviour is
279 * in use on the KDC by checking the KVNO of the
280 * krbtgt account returned in the reply.
282 * A packet passed to the full RW DC will not have a
283 * KVNO in the upper bits, while a packet processed
284 * locally on the RODC will have these bits filled in
285 * the msDS-SecondaryKrbTgtNumber
287 if (torture_setting_bool(test_context->tctx, "expect_cached_at_rodc", false)) {
288 torture_assert_int_not_equal(test_context->tctx,
289 *test_context->as_rep.ticket.enc_part.kvno & 0xFFFF0000,
290 0, "Did not get a RODC number in the KVNO");
291 } else {
292 torture_assert_int_equal(test_context->tctx,
293 *test_context->as_rep.ticket.enc_part.kvno & 0xFFFF0000,
294 0, "Unexpecedly got a RODC number in the KVNO");
296 free_AS_REP(&test_context->as_rep);
298 torture_assert(test_context->tctx, test_context->packet_count < 3, "too many packets");
299 free_AS_REQ(&test_context->as_req);
300 return true;
304 * TEST_TGS_REQ_KRBTGT_CANON
307 * Confirm that the outgoing TGS-REQ packet from krb5_get_creds()
308 * for the krbtgt/realm principal meets certain expectations, like
309 * that the canonicalize bit is not set
313 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)
315 size_t used;
316 torture_assert_int_equal(test_context->tctx,
317 decode_TGS_REQ(send_buf->data, send_buf->length,
318 &test_context->tgs_req, &used),
319 0, "decode_TGS_REQ for TEST_TGS_REQ test failed");
320 torture_assert_int_equal(test_context->tctx,
321 used, send_buf->length,
322 "length mismatch");
323 torture_assert_int_equal(test_context->tctx,
324 test_context->tgs_req.pvno, 5,
325 "Got wrong as_req->pvno");
326 torture_assert_int_equal(test_context->tctx,
327 test_context->tgs_req.req_body.kdc_options.canonicalize,
328 true,
329 "krb5 libs unexpectedly did not set canonicalize!");
331 torture_assert_int_equal(test_context->tctx,
332 test_context->tgs_req.req_body.sname->name_type,
333 KRB5_NT_PRINCIPAL,
334 "Mismatch in name_type between request and expected request");
336 torture_assert_str_equal(test_context->tctx,
337 test_context->tgs_req.req_body.realm,
338 test_context->test_data->real_realm,
339 "Mismatch in realm between request and expected request");
341 *modified_send_buf = *send_buf;
342 return true;
346 * TEST_TGS_REQ_KRBTGT_CANON
348 * Confirm that the reply TGS-REP packet for krb5_get_creds()
349 * where the client is behaving as if this is a cross-realm trust due
350 * to case or netbios vs dns name differences meets certain
351 * expectations, while canonicalize is set
355 static bool torture_krb5_post_recv_tgs_req_krbtgt_canon_test(struct torture_krb5_context *test_context, const krb5_data *recv_buf)
357 size_t used;
358 torture_assert_int_equal(test_context->tctx,
359 decode_TGS_REP(recv_buf->data, recv_buf->length,
360 &test_context->tgs_rep, &used),
362 "decode_TGS_REP failed");
363 torture_assert_int_equal(test_context->tctx, used, recv_buf->length, "length mismatch");
364 torture_assert_int_equal(test_context->tctx,
365 test_context->tgs_rep.pvno, 5,
366 "Got wrong as_rep->pvno");
367 torture_assert_int_equal(test_context->tctx,
368 test_context->tgs_rep.ticket.tkt_vno, 5,
369 "Got wrong as_rep->ticket.tkt_vno");
370 torture_assert(test_context->tctx,
371 test_context->tgs_rep.ticket.enc_part.kvno,
372 "Did not get a KVNO in test_context->as_rep.ticket.enc_part.kvno");
373 torture_assert_str_equal(test_context->tctx,
374 test_context->tgs_req.req_body.realm,
375 test_context->tgs_rep.ticket.realm,
376 "Mismatch in realm between request and ticket response");
377 torture_assert_str_equal(test_context->tctx,
378 test_context->tgs_rep.ticket.realm,
379 test_context->test_data->real_realm,
380 "Mismatch in realm between ticket response and expected ticket response");
381 torture_assert_int_equal(test_context->tctx,
382 test_context->tgs_rep.ticket.sname.name_type,
383 KRB5_NT_SRV_INST,
384 "Mismatch in name_type between ticket response and expected value of KRB5_NT_SRV_INST");
386 torture_assert_int_equal(test_context->tctx,
387 test_context->tgs_rep.ticket.sname.name_string.len,
389 "Mismatch in name_type between ticket response and expected value, expected krbtgt/REALM@REALM");
391 torture_assert_str_equal(test_context->tctx,
392 test_context->tgs_rep.ticket.sname.name_string.val[0], "krbtgt",
393 "Mismatch in name between reponse and expected response, expected krbtgt");
394 torture_assert_str_equal(test_context->tctx,
395 test_context->tgs_rep.ticket.sname.name_string.val[1], test_context->test_data->real_realm,
396 "Mismatch in realm part of krbtgt/ in expected response, expected krbtgt/REALM@REALM");
399 * We can confirm that the correct proxy behaviour is
400 * in use on the KDC by checking the KVNO of the
401 * krbtgt account returned in the reply.
403 * A packet passed to the full RW DC will not have a
404 * KVNO in the upper bits, while a packet processed
405 * locally on the RODC will have these bits filled in
406 * the msDS-SecondaryKrbTgtNumber
408 if (torture_setting_bool(test_context->tctx, "expect_cached_at_rodc", false)) {
409 torture_assert_int_not_equal(test_context->tctx,
410 *test_context->tgs_rep.ticket.enc_part.kvno & 0xFFFF0000,
411 0, "Did not get a RODC number in the KVNO");
412 } else {
413 torture_assert_int_equal(test_context->tctx,
414 *test_context->tgs_rep.ticket.enc_part.kvno & 0xFFFF0000,
415 0, "Unexpecedly got a RODC number in the KVNO");
417 free_TGS_REP(&test_context->tgs_rep);
418 torture_assert(test_context->tctx,
419 test_context->packet_count < 2,
420 "too many packets");
421 free_TGS_REQ(&test_context->tgs_req);
422 return true;
426 * TEST_TGS_REQ_CANON
428 * Confirm that the outgoing TGS-REQ packet from krb5_get_creds
429 * certain expectations, like that the canonicalize bit is set (this
430 * test is to force that handling) and that if an enterprise name was
431 * requested, that it was sent.
435 static bool torture_krb5_pre_send_tgs_req_canon_test(struct torture_krb5_context *test_context,
436 const krb5_data *send_buf,
437 krb5_data *modified_send_buf)
439 size_t used;
440 torture_assert_int_equal(test_context->tctx,
441 decode_TGS_REQ(send_buf->data, send_buf->length,
442 &test_context->tgs_req, &used),
443 0, "decode_TGS_REQ for TEST_TGS_REQ_CANON test failed");
444 torture_assert_int_equal(test_context->tctx, used, send_buf->length, "length mismatch");
445 torture_assert_int_equal(test_context->tctx, test_context->tgs_req.pvno, 5, "Got wrong as_req->pvno");
446 torture_assert_int_equal(test_context->tctx,
447 test_context->tgs_req.req_body.kdc_options.canonicalize,
448 true, "krb5 libs unexpectedly did not set canonicalize!");
450 if (test_context->test_data->enterprise) {
451 torture_assert_int_equal(test_context->tctx,
452 test_context->tgs_req.req_body.sname->name_type, KRB5_NT_ENTERPRISE_PRINCIPAL,
453 "Mismatch in name type between request and expected request, expected KRB5_NT_ENTERPRISE_PRINCIPAL");
454 torture_assert_str_equal(test_context->tctx,
455 test_context->tgs_req.req_body.realm, test_context->test_data->real_realm,
456 "Mismatch in realm between request and expected request");
458 } else if (test_context->test_data->canonicalize) {
459 torture_assert_int_equal(test_context->tctx,
460 test_context->tgs_req.req_body.sname->name_type, KRB5_NT_PRINCIPAL,
461 "Mismatch in name type between request and expected request, expected KRB5_NT_PRINCIPAL");
462 torture_assert_str_equal(test_context->tctx,
463 test_context->tgs_req.req_body.realm, test_context->test_data->real_realm,
464 "Mismatch in realm between request and expected request");
466 } else {
467 torture_assert_int_equal(test_context->tctx,
468 test_context->tgs_req.req_body.sname->name_type, KRB5_NT_PRINCIPAL,
469 "Mismatch in name type between request and expected request, expected KRB5_NT_PRINCIPAL");
470 torture_assert_str_equal(test_context->tctx,
471 test_context->tgs_req.req_body.realm, test_context->test_data->realm,
472 "Mismatch in realm between request and expected request");
476 *modified_send_buf = *send_buf;
478 return true;
482 * TEST_TGS_REQ_CANON - RECV
484 * Confirm that the reply TGS-REP or error packet from the KDC meets
485 * certain expectations as part of TEST_TGS_REQ_CANON.
487 * This is triggered by krb5_get_creds()
491 static bool torture_krb5_post_recv_tgs_req_canon_test(struct torture_krb5_context *test_context, const krb5_data *recv_buf)
493 KRB_ERROR error;
494 size_t used;
497 * If this account did not have a servicePrincipalName, then
498 * we expect a errro packet, not a TGS-REQ
500 if (decode_KRB_ERROR(recv_buf->data, recv_buf->length, &error, &used) == 0) {
501 torture_assert_int_equal(test_context->tctx, used, recv_buf->length, "length mismatch");
502 torture_assert_int_equal(test_context->tctx,
503 error.pvno, 5,
504 "Got wrong error.pvno");
505 torture_assert_int_equal(test_context->tctx,
506 error.error_code,
507 KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN - KRB5KDC_ERR_NONE,
508 "Got wrong error.error_code");
509 } else {
510 torture_assert_int_equal(test_context->tctx,
511 decode_TGS_REP(recv_buf->data, recv_buf->length,
512 &test_context->tgs_rep,
513 &used),
515 "decode_TGS_REP failed");
516 torture_assert_int_equal(test_context->tctx,
517 used, recv_buf->length,
518 "length mismatch");
519 torture_assert_int_equal(test_context->tctx,
520 test_context->tgs_rep.pvno, 5,
521 "Got wrong as_rep->pvno");
522 torture_assert_int_equal(test_context->tctx,
523 test_context->tgs_rep.ticket.tkt_vno, 5,
524 "Got wrong as_rep->ticket.tkt_vno");
525 torture_assert(test_context->tctx,
526 test_context->tgs_rep.ticket.enc_part.kvno,
527 "Did not get a KVNO in test_context->as_rep.ticket.enc_part.kvno");
528 torture_assert_str_equal(test_context->tctx,
529 test_context->tgs_rep.ticket.realm,
530 test_context->test_data->real_realm,
531 "Mismatch in realm between ticket response and expected upper case REALM");
532 torture_assert_int_equal(test_context->tctx,
533 test_context->tgs_rep.ticket.sname.name_type,
534 test_context->tgs_req.req_body.sname->name_type,
535 "Mismatch in name_type between request and ticket response");
536 torture_assert_int_equal(test_context->tctx,
537 test_context->tgs_rep.ticket.sname.name_string.len,
538 test_context->tgs_req.req_body.sname->name_string.len,
539 "Mismatch in name_string.len between request and ticket response");
540 torture_assert(test_context->tctx,
541 test_context->tgs_rep.ticket.sname.name_string.len >= 1,
542 "name_string.len should be >=1 in ticket response");
543 torture_assert_str_equal(test_context->tctx,
544 test_context->tgs_rep.ticket.sname.name_string.val[0],
545 test_context->tgs_req.req_body.sname->name_string.val[0],
546 "Mismatch in name between request and expected request");
547 torture_assert_int_equal(test_context->tctx,
548 *test_context->tgs_rep.ticket.enc_part.kvno & 0xFFFF0000,
549 0, "Unexpecedly got a RODC number in the KVNO, should just be principal KVNO");
550 free_TGS_REP(&test_context->tgs_rep);
552 torture_assert(test_context->tctx, test_context->packet_count == 0, "too many packets");
553 free_TGS_REQ(&test_context->tgs_req);
555 return true;
559 * TEST_SELF_TRUST_TGS_REQ
561 * Confirm that the outgoing TGS-REQ packet from krb5_mk_req_exact()
562 * certain expectations, like that the canonicalize bit is set (this
563 * test is to force that handling).
565 * This test is for the case where the name we ask for, while a valid
566 * alternate name for our own realm is used. The client acts as if
567 * this is cross-realm trust.
571 static bool torture_krb5_pre_send_self_trust_tgs_req_test(struct torture_krb5_context *test_context,
572 const krb5_data *send_buf,
573 krb5_data *modified_send_buf)
575 size_t used;
576 torture_assert_int_equal(test_context->tctx,
577 decode_TGS_REQ(send_buf->data, send_buf->length,
578 &test_context->tgs_req, &used),
579 0, "decode_TGS_REQ for TEST_SELF_TRUST_TGS_REQ test failed");
580 torture_assert_int_equal(test_context->tctx, used, send_buf->length, "length mismatch");
581 torture_assert_int_equal(test_context->tctx, test_context->tgs_req.pvno, 5, "Got wrong as_req->pvno");
582 torture_assert_int_equal(test_context->tctx, test_context->tgs_req.req_body.kdc_options.canonicalize, false, "krb5 libs unexpectedly set canonicalize!");
584 if (test_context->test_data->canonicalize) {
585 torture_assert_str_equal(test_context->tctx,
586 test_context->tgs_req.req_body.realm,
587 test_context->test_data->real_realm,
588 "Mismatch in realm between request and expected request");
589 } else {
590 torture_assert_str_equal(test_context->tctx,
591 test_context->tgs_req.req_body.realm,
592 test_context->test_data->realm,
593 "Mismatch in realm between request and expected request");
595 torture_assert_int_equal(test_context->tctx,
596 test_context->tgs_req.req_body.sname->name_type, KRB5_NT_PRINCIPAL,
597 "Mismatch in name type between request and expected request, expected KRB5_NT_PRINCIPAL");
598 torture_assert_int_equal(test_context->tctx,
599 test_context->tgs_req.req_body.sname->name_string.len, 2,
600 "Mismatch in name between request and expected request, expected krbtgt/realm");
601 torture_assert_str_equal(test_context->tctx,
602 test_context->tgs_req.req_body.sname->name_string.val[0], "krbtgt",
603 "Mismatch in name between request and expected request, expected krbtgt");
604 torture_assert_str_equal(test_context->tctx,
605 test_context->tgs_req.req_body.sname->name_string.val[1], test_context->test_data->realm,
606 "Mismatch in realm part of cross-realm request principal between request and expected request");
607 *modified_send_buf = *send_buf;
609 return true;
613 * TEST_SELF_TRUST_TGS_REQ and TEST_TGS_REQ_KRBTGT - RECV
615 * Confirm that the reply TGS-REP packet for krb5_mk_req_exact(),
616 * where the client is behaving as if this is a cross-realm trust due
617 * to case or netbios vs dns name differences meets certain
618 * expectations.
622 static bool torture_krb5_post_recv_self_trust_tgs_req_test(struct torture_krb5_context *test_context, const krb5_data *recv_buf)
624 size_t used;
625 torture_assert_int_equal(test_context->tctx,
626 decode_TGS_REP(recv_buf->data, recv_buf->length,
627 &test_context->tgs_rep, &used),
629 "decode_TGS_REP failed");
630 torture_assert_int_equal(test_context->tctx, used, recv_buf->length, "length mismatch");
631 torture_assert_int_equal(test_context->tctx,
632 test_context->tgs_rep.pvno, 5,
633 "Got wrong as_rep->pvno");
634 torture_assert_int_equal(test_context->tctx,
635 test_context->tgs_rep.ticket.tkt_vno, 5,
636 "Got wrong as_rep->ticket.tkt_vno");
637 torture_assert(test_context->tctx,
638 test_context->tgs_rep.ticket.enc_part.kvno,
639 "Did not get a KVNO in test_context->as_rep.ticket.enc_part.kvno");
640 torture_assert_str_equal(test_context->tctx,
641 test_context->tgs_req.req_body.realm,
642 test_context->tgs_rep.ticket.realm,
643 "Mismatch in realm between request and ticket response");
644 torture_assert_int_equal(test_context->tctx,
645 test_context->tgs_rep.ticket.sname.name_type,
646 test_context->tgs_req.req_body.sname->name_type,
647 "Mismatch in name_type between request and ticket response");
649 torture_assert_int_equal(test_context->tctx,
650 test_context->tgs_rep.ticket.sname.name_string.len, 2,
651 "Mismatch in name between request and expected request, expected krbtgt/realm");
652 torture_assert_str_equal(test_context->tctx,
653 test_context->tgs_rep.ticket.sname.name_string.val[0], "krbtgt",
654 "Mismatch in name between request and expected request, expected krbtgt");
655 torture_assert_str_equal(test_context->tctx,
656 test_context->tgs_rep.ticket.sname.name_string.val[1], test_context->test_data->realm,
657 "Mismatch in realm part of cross-realm request principal between response and expected request");
659 * We can confirm that the correct proxy behaviour is
660 * in use on the KDC by checking the KVNO of the
661 * krbtgt account returned in the reply.
663 * A packet passed to the full RW DC will not have a
664 * KVNO in the upper bits, while a packet processed
665 * locally on the RODC will have these bits filled in
666 * the msDS-SecondaryKrbTgtNumber
668 if (torture_setting_bool(test_context->tctx, "expect_cached_at_rodc", false)) {
669 torture_assert_int_not_equal(test_context->tctx,
670 *test_context->tgs_rep.ticket.enc_part.kvno & 0xFFFF0000,
671 0, "Did not get a RODC number in the KVNO");
672 } else {
673 torture_assert_int_equal(test_context->tctx,
674 *test_context->tgs_rep.ticket.enc_part.kvno & 0xFFFF0000,
675 0, "Unexpecedly got a RODC number in the KVNO");
677 free_TGS_REP(&test_context->tgs_rep);
678 torture_assert_int_equal(test_context->tctx,
679 test_context->packet_count, 0,
680 "too many packets");
681 test_context->packet_count = 0;
682 test_context->test_stage = TEST_TGS_REQ;
683 free_TGS_REQ(&test_context->tgs_req);
684 return true;
688 * TEST_TGS_REQ
690 * Confirm that the outgoing TGS-REQ packet from krb5_mk_req_exact()
691 * certain expectations, like that the canonicalize bit is set (this
692 * test is to force that handling) and that if an enterprise name was
693 * requested, that it was sent.
697 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)
699 size_t used;
700 torture_assert_int_equal(test_context->tctx,
701 decode_TGS_REQ(send_buf->data, send_buf->length,
702 &test_context->tgs_req, &used),
703 0, "decode_TGS_REQ for TEST_TGS_REQ test failed");
704 torture_assert_int_equal(test_context->tctx, used, send_buf->length, "length mismatch");
705 torture_assert_int_equal(test_context->tctx, test_context->tgs_req.pvno, 5,
706 "Got wrong as_req->pvno");
707 torture_assert_int_equal(test_context->tctx,
708 test_context->tgs_req.req_body.kdc_options.canonicalize,
709 false,
710 "krb5 libs unexpectedly set canonicalize!");
712 if (test_context->test_data->enterprise) {
713 torture_assert_int_equal(test_context->tctx,
714 test_context->tgs_req.req_body.sname->name_type,
715 KRB5_NT_ENTERPRISE_PRINCIPAL,
716 "Mismatch in name type between request and expected request, expected KRB5_NT_ENTERPRISE_PRINCIPAL");
717 torture_assert_str_equal(test_context->tctx,
718 test_context->tgs_req.req_body.realm,
719 test_context->test_data->real_realm,
720 "Mismatch in realm between request and expected request");
722 } else {
723 torture_assert_int_equal(test_context->tctx,
724 test_context->tgs_req.req_body.sname->name_type,
725 KRB5_NT_PRINCIPAL,
726 "Mismatch in name type between request and expected request, expected KRB5_NT_PRINCIPAL");
727 torture_assert_str_equal(test_context->tctx,
728 test_context->tgs_req.req_body.realm,
729 test_context->test_data->realm,
730 "Mismatch in realm between request and expected request");
734 *modified_send_buf = *send_buf;
736 return true;
740 * TEST_TGS_REQ - RECV
742 * Confirm that the reply TGS-REP packet for krb5_mk_req_exact(), for
743 * the actual target service.
747 static bool torture_krb5_post_recv_tgs_req_test(struct torture_krb5_context *test_context, const krb5_data *recv_buf)
749 KRB_ERROR error;
750 size_t used;
752 * If this account did not have a servicePrincipalName, then
753 * we expect a errro packet, not a TGS-REQ
755 if (decode_KRB_ERROR(recv_buf->data, recv_buf->length, &error, &used) == 0) {
756 torture_assert_int_equal(test_context->tctx,
757 used, recv_buf->length,
758 "length mismatch");
759 torture_assert_int_equal(test_context->tctx,
760 error.pvno, 5,
761 "Got wrong error.pvno");
762 torture_assert_int_equal(test_context->tctx,
763 error.error_code,
764 KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN - KRB5KDC_ERR_NONE,
765 "Got wrong error.error_code");
766 } else {
767 torture_assert_int_equal(test_context->tctx,
768 decode_TGS_REP(recv_buf->data, recv_buf->length,
769 &test_context->tgs_rep, &used),
771 "decode_TGS_REP failed");
772 torture_assert_int_equal(test_context->tctx, used, recv_buf->length,
773 "length mismatch");
774 torture_assert_int_equal(test_context->tctx,
775 test_context->tgs_rep.pvno, 5,
776 "Got wrong as_rep->pvno");
777 torture_assert_int_equal(test_context->tctx,
778 test_context->tgs_rep.ticket.tkt_vno, 5,
779 "Got wrong as_rep->ticket.tkt_vno");
780 torture_assert(test_context->tctx,
781 test_context->tgs_rep.ticket.enc_part.kvno,
782 "Did not get a KVNO in test_context->as_rep.ticket.enc_part.kvno");
783 torture_assert_str_equal(test_context->tctx,
784 test_context->tgs_rep.ticket.realm,
785 test_context->test_data->real_realm,
786 "Mismatch in realm between ticket response and expected upper case REALM");
787 torture_assert_int_equal(test_context->tctx,
788 test_context->tgs_req.req_body.sname->name_type,
789 test_context->tgs_rep.ticket.sname.name_type, "Mismatch in name_type between request and ticket response");
790 torture_assert_int_equal(test_context->tctx,
791 *test_context->tgs_rep.ticket.enc_part.kvno & 0xFFFF0000,
792 0, "Unexpecedly got a RODC number in the KVNO, should just be principal KVNO");
793 free_TGS_REP(&test_context->tgs_rep);
795 torture_assert(test_context->tctx, test_context->packet_count < 3, "too many packets");
796 free_TGS_REQ(&test_context->tgs_req);
797 test_context->test_stage = TEST_DONE;
798 return true;
802 * TEST_TGS_REQ_KRBTGT
805 * Confirm that the outgoing TGS-REQ packet from krb5_mk_req_exact()
806 * for the krbtgt/realm principal meets certain expectations, like
807 * that the canonicalize bit is not set
811 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)
813 size_t used;
814 torture_assert_int_equal(test_context->tctx,
815 decode_TGS_REQ(send_buf->data, send_buf->length,
816 &test_context->tgs_req, &used),
817 0, "decode_TGS_REQ for TEST_TGS_REQ test failed");
818 torture_assert_int_equal(test_context->tctx,
819 used, send_buf->length,
820 "length mismatch");
821 torture_assert_int_equal(test_context->tctx,
822 test_context->tgs_req.pvno, 5,
823 "Got wrong as_req->pvno");
824 torture_assert_int_equal(test_context->tctx,
825 test_context->tgs_req.req_body.kdc_options.canonicalize,
826 false,
827 "krb5 libs unexpectedly set canonicalize!");
829 torture_assert_str_equal(test_context->tctx,
830 test_context->tgs_req.req_body.realm,
831 test_context->test_data->realm,
832 "Mismatch in realm between request and expected request");
834 *modified_send_buf = *send_buf;
835 test_context->test_stage = TEST_DONE;
836 return true;
840 * TEST_TGS_REQ_HOST
843 * Confirm that the outgoing TGS-REQ packet from krb5_mk_req_exact()
844 * for the krbtgt/realm principal meets certain expectations, like
845 * that the canonicalize bit is not set
849 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)
851 size_t used;
852 torture_assert_int_equal(test_context->tctx,
853 decode_TGS_REQ(send_buf->data, send_buf->length,
854 &test_context->tgs_req, &used),
855 0, "decode_TGS_REQ for TEST_TGS_REQ test failed");
856 torture_assert_int_equal(test_context->tctx,
857 used, send_buf->length,
858 "length mismatch");
859 torture_assert_int_equal(test_context->tctx,
860 test_context->tgs_req.pvno, 5,
861 "Got wrong as_req->pvno");
862 torture_assert_int_equal(test_context->tctx,
863 test_context->tgs_req.req_body.kdc_options.canonicalize,
864 true,
865 "krb5 libs unexpectedly did not set canonicalize!");
867 torture_assert_int_equal(test_context->tctx,
868 test_context->tgs_req.req_body.sname->name_type, KRB5_NT_PRINCIPAL,
869 "Mismatch in name type between request and expected request, expected KRB5_NT_PRINCIPAL");
870 torture_assert_int_equal(test_context->tctx,
871 test_context->tgs_req.req_body.sname->name_string.len, 2,
872 "Mismatch in name between request and expected request, expected krbtgt/realm");
873 torture_assert_str_equal(test_context->tctx,
874 test_context->tgs_req.req_body.sname->name_string.val[0],
875 test_context->test_data->krb5_service,
876 "Mismatch in name between request and expected request, expected krbtgt");
877 torture_assert_str_equal(test_context->tctx,
878 test_context->tgs_req.req_body.sname->name_string.val[1],
879 test_context->test_data->krb5_hostname,
880 "Mismatch in realm part of cross-realm request principal between request and expected request");
882 torture_assert_str_equal(test_context->tctx,
883 test_context->tgs_req.req_body.realm,
884 test_context->test_data->real_realm,
885 "Mismatch in realm between request and expected request");
887 *modified_send_buf = *send_buf;
888 return true;
892 * TEST_TGS_REQ_HOST - RECV
894 * Confirm that the reply TGS-REP packet for krb5_mk_req(), for
895 * the actual target service, as a SPN, not a any other name type.
899 static bool torture_krb5_post_recv_tgs_req_host_test(struct torture_krb5_context *test_context, const krb5_data *recv_buf)
901 size_t used;
902 torture_assert_int_equal(test_context->tctx,
903 decode_TGS_REP(recv_buf->data, recv_buf->length,
904 &test_context->tgs_rep, &used),
906 "decode_TGS_REP failed");
907 torture_assert_int_equal(test_context->tctx, used, recv_buf->length,
908 "length mismatch");
909 torture_assert_int_equal(test_context->tctx,
910 test_context->tgs_rep.pvno, 5,
911 "Got wrong as_rep->pvno");
912 torture_assert_int_equal(test_context->tctx,
913 test_context->tgs_rep.ticket.tkt_vno, 5,
914 "Got wrong as_rep->ticket.tkt_vno");
915 torture_assert(test_context->tctx,
916 test_context->tgs_rep.ticket.enc_part.kvno,
917 "Did not get a KVNO in test_context->as_rep.ticket.enc_part.kvno");
918 torture_assert_str_equal(test_context->tctx,
919 test_context->tgs_rep.ticket.realm,
920 test_context->test_data->real_realm,
921 "Mismatch in realm between ticket response and expected upper case REALM");
922 torture_assert_int_equal(test_context->tctx,
923 test_context->tgs_req.req_body.sname->name_type,
924 test_context->tgs_rep.ticket.sname.name_type, "Mismatch in name_type between request and ticket response");
925 torture_assert_int_equal(test_context->tctx,
926 test_context->tgs_rep.ticket.sname.name_string.len, 2,
927 "Mismatch in name between request and expected request, expected service/hostname");
928 torture_assert_str_equal(test_context->tctx,
929 test_context->tgs_rep.ticket.sname.name_string.val[0],
930 test_context->test_data->krb5_service,
931 "Mismatch in name between request and expected request, expected service/hostname");
932 torture_assert_str_equal(test_context->tctx,
933 test_context->tgs_rep.ticket.sname.name_string.val[1],
934 test_context->test_data->krb5_hostname,
935 "Mismatch in name between request and expected request, expected service/hostname");
937 torture_assert_int_equal(test_context->tctx,
938 *test_context->tgs_rep.ticket.enc_part.kvno & 0xFFFF0000,
939 0, "Unexpecedly got a RODC number in the KVNO, should just be principal KVNO");
940 free_TGS_REP(&test_context->tgs_rep);
942 torture_assert(test_context->tctx, test_context->packet_count < 2, "too many packets");
943 return true;
947 * TEST_AS_REQ_SELF - RECV
949 * Confirm that the reply packet from the KDC meets certain
950 * expectations as part of TEST_AS_REQ. This uses a packet count to
951 * work out what packet we are up to in the multiple exchanged
952 * triggerd by krb5_get_init_creds_password().
956 static bool torture_krb5_post_recv_as_req_self_test(struct torture_krb5_context *test_context,
957 const krb5_data *recv_buf)
959 KRB_ERROR error;
960 size_t used;
961 if (test_context->packet_count == 0) {
962 krb5_error_code k5ret;
964 * The client libs obtain the salt by attempting to
965 * authenticate without pre-authentication and getting
966 * the correct salt with the
967 * KRB5KDC_ERR_PREAUTH_REQUIRED error. If we are in
968 * the test (netbios_realm && upn) that deliberatly
969 * has an incorrect principal, we check we get the
970 * correct error.
972 k5ret = decode_KRB_ERROR(recv_buf->data, recv_buf->length,
973 &error, &used);
974 if (k5ret != 0) {
975 AS_REP as_rep;
976 k5ret = decode_AS_REP(recv_buf->data, recv_buf->length,
977 &as_rep, &used);
978 if (k5ret == 0) {
979 if (torture_setting_bool(test_context->tctx, "expect_machine_account", false) == false
980 || (test_context->test_data->upn == true)) {
981 torture_assert(test_context->tctx, false,
982 "expected to get a KRB_ERROR packet with "
983 "KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN or KRB5KDC_ERR_PREAUTH_REQUIRED, got valid AS-REP");
984 } else {
985 torture_assert(test_context->tctx, false,
986 "expected to get a KRB_ERROR packet with "
987 "KRB5KDC_ERR_PREAUTH_REQUIRED, got valid AS-REP");
989 } else {
990 if (torture_setting_bool(test_context->tctx, "expect_machine_account", false) == false
991 || (test_context->test_data->upn == true)) {
992 torture_assert(test_context->tctx, false,
993 "unable to decode as KRB-ERROR or AS-REP, "
994 "expected to get a KRB_ERROR packet with KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN or KRB5KDC_ERR_PREAUTH_REQUIRED");
995 } else {
996 torture_assert(test_context->tctx, false,
997 "unable to decode as KRB-ERROR or AS-REP, "
998 "expected to get a KRB_ERROR packet with KRB5KDC_ERR_PREAUTH_REQUIRED");
1002 torture_assert_int_equal(test_context->tctx, used, recv_buf->length,
1003 "length mismatch");
1004 torture_assert_int_equal(test_context->tctx, error.pvno, 5,
1005 "Got wrong error.pvno");
1006 if ((torture_setting_bool(test_context->tctx, "expect_machine_account", false) == false
1007 || (test_context->test_data->upn == true))
1008 && error.error_code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN - KRB5KDC_ERR_NONE) {
1010 * IGNORE
1012 * This case is because Samba's Heimdal KDC
1013 * checks server and client accounts before
1014 * checking for pre-authentication.
1016 } else {
1017 torture_assert_int_equal(test_context->tctx,
1018 error.error_code,
1019 KRB5KDC_ERR_PREAUTH_REQUIRED - KRB5KDC_ERR_NONE,
1020 "Got wrong error.error_code");
1023 free_KRB_ERROR(&error);
1024 } else if ((decode_KRB_ERROR(recv_buf->data, recv_buf->length, &error, &used) == 0)
1025 && (test_context->packet_count == 1)) {
1027 * The Windows 2012R2 KDC will always respond with
1028 * KRB5KRB_ERR_RESPONSE_TOO_BIG over UDP as the ticket
1029 * won't fit, because of the PAC. (It appears to do
1030 * this always, even if it will). This triggers the
1031 * client to try again over TCP.
1033 torture_assert_int_equal(test_context->tctx,
1034 used, recv_buf->length,
1035 "length mismatch");
1036 torture_assert_int_equal(test_context->tctx,
1037 error.pvno, 5,
1038 "Got wrong error.pvno");
1039 if ((torture_setting_bool(test_context->tctx, "expect_machine_account", false)
1040 && (test_context->test_data->upn == false))) {
1041 torture_assert_int_equal(test_context->tctx,
1042 error.error_code,
1043 KRB5KRB_ERR_RESPONSE_TOO_BIG - KRB5KDC_ERR_NONE,
1044 "Got wrong error.error_code");
1045 } else {
1046 torture_assert_int_equal(test_context->tctx,
1047 error.error_code,
1048 KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN - KRB5KDC_ERR_NONE,
1049 "Got wrong error.error_code");
1051 free_KRB_ERROR(&error);
1052 } else {
1054 * Finally the successful packet.
1056 torture_assert_int_equal(test_context->tctx,
1057 decode_AS_REP(recv_buf->data, recv_buf->length,
1058 &test_context->as_rep, &used), 0,
1059 "decode_AS_REP failed");
1060 torture_assert_int_equal(test_context->tctx, used, recv_buf->length,
1061 "length mismatch");
1062 torture_assert_int_equal(test_context->tctx,
1063 test_context->as_rep.pvno, 5,
1064 "Got wrong as_rep->pvno");
1065 torture_assert_int_equal(test_context->tctx,
1066 test_context->as_rep.ticket.tkt_vno, 5,
1067 "Got wrong as_rep->ticket.tkt_vno");
1068 torture_assert(test_context->tctx,
1069 test_context->as_rep.ticket.enc_part.kvno,
1070 "Did not get a KVNO in test_context->as_rep.ticket.enc_part.kvno");
1073 * We do not expect an RODC number here in the KVNO,
1074 * as this is a ticket to the user's own account.
1076 torture_assert_int_equal(test_context->tctx,
1077 *test_context->as_rep.ticket.enc_part.kvno & 0xFFFF0000,
1078 0, "Unexpecedly got a RODC number in the KVNO");
1079 free_AS_REP(&test_context->as_rep);
1081 torture_assert(test_context->tctx, test_context->packet_count < 3, "too many packets");
1082 free_AS_REQ(&test_context->as_req);
1083 return true;
1087 * This function is set in torture_krb5_init_context_canon as krb5
1088 * send_and_recv function. This allows us to override what server the
1089 * test is aimed at, and to inspect the packets just before they are
1090 * sent to the network, and before they are processed on the recv
1091 * side.
1093 * The torture_krb5_pre_send_test() and torture_krb5_post_recv_test()
1094 * functions are implement the actual tests.
1096 * When this asserts, the caller will get a spurious 'cannot contact
1097 * any KDC' message.
1100 static krb5_error_code smb_krb5_send_and_recv_func_canon_override(krb5_context context,
1101 void *data, /* struct torture_krb5_context */
1102 krb5_krbhst_info *hi,
1103 time_t timeout,
1104 const krb5_data *send_buf,
1105 krb5_data *recv_buf)
1107 krb5_error_code k5ret;
1108 bool ok = false;
1109 krb5_data modified_send_buf;
1111 struct torture_krb5_context *test_context
1112 = talloc_get_type_abort(data, struct torture_krb5_context);
1114 switch (test_context->test_stage) {
1115 case TEST_DONE:
1116 torture_warning(test_context->tctx, "Unexpected outgoing packet from krb5 libs");
1117 return EINVAL;
1118 case TEST_AS_REQ:
1119 ok = torture_krb5_pre_send_as_req_test(test_context, send_buf,
1120 &modified_send_buf);
1121 break;
1122 case TEST_TGS_REQ_KRBTGT_CANON:
1123 ok = torture_krb5_pre_send_tgs_req_krbtgt_canon_test(test_context, send_buf,
1124 &modified_send_buf);
1125 break;
1126 case TEST_TGS_REQ_CANON:
1127 ok = torture_krb5_pre_send_tgs_req_canon_test(test_context, send_buf,
1128 &modified_send_buf);
1129 break;
1130 case TEST_SELF_TRUST_TGS_REQ:
1131 ok = torture_krb5_pre_send_self_trust_tgs_req_test(test_context, send_buf,
1132 &modified_send_buf);
1133 break;
1134 case TEST_TGS_REQ:
1135 ok = torture_krb5_pre_send_tgs_req_test(test_context, send_buf,
1136 &modified_send_buf);
1137 break;
1138 case TEST_TGS_REQ_KRBTGT:
1139 ok = torture_krb5_pre_send_tgs_req_krbtgt_test(test_context, send_buf,
1140 &modified_send_buf);
1141 break;
1142 case TEST_TGS_REQ_HOST:
1143 ok = torture_krb5_pre_send_tgs_req_host_test(test_context, send_buf,
1144 &modified_send_buf);
1145 break;
1146 case TEST_AS_REQ_SELF:
1147 ok = torture_krb5_pre_send_as_req_test(test_context, send_buf,
1148 &modified_send_buf);
1149 break;
1151 if (ok == false) {
1152 return EINVAL;
1155 k5ret = smb_krb5_send_and_recv_func_forced(context, test_context->server,
1156 hi, timeout, &modified_send_buf,
1157 recv_buf);
1158 if (k5ret != 0) {
1159 return k5ret;
1162 switch (test_context->test_stage) {
1163 case TEST_DONE:
1164 torture_warning(test_context->tctx, "Unexpected outgoing packet from krb5 libs");
1165 return EINVAL;
1166 case TEST_AS_REQ:
1167 ok = torture_krb5_post_recv_as_req_test(test_context, recv_buf);
1168 break;
1169 case TEST_TGS_REQ_KRBTGT_CANON:
1170 ok = torture_krb5_post_recv_tgs_req_krbtgt_canon_test(test_context, recv_buf);
1171 break;
1172 case TEST_TGS_REQ_CANON:
1173 ok = torture_krb5_post_recv_tgs_req_canon_test(test_context, recv_buf);
1174 break;
1175 case TEST_SELF_TRUST_TGS_REQ:
1176 ok = torture_krb5_post_recv_self_trust_tgs_req_test(test_context, recv_buf);
1177 break;
1178 case TEST_TGS_REQ:
1179 ok = torture_krb5_post_recv_tgs_req_test(test_context, recv_buf);
1180 break;
1181 case TEST_TGS_REQ_KRBTGT:
1182 ok = torture_krb5_post_recv_self_trust_tgs_req_test(test_context, recv_buf);
1183 break;
1184 case TEST_TGS_REQ_HOST:
1185 ok = torture_krb5_post_recv_tgs_req_host_test(test_context, recv_buf);
1186 break;
1187 case TEST_AS_REQ_SELF:
1188 ok = torture_krb5_post_recv_as_req_self_test(test_context, recv_buf);
1189 break;
1191 if (ok == false) {
1192 return EINVAL;
1195 test_context->packet_count++;
1197 return k5ret;
1200 static int test_context_destructor(struct torture_krb5_context *test_context)
1202 freeaddrinfo(test_context->server);
1203 return 0;
1207 static bool torture_krb5_init_context_canon(struct torture_context *tctx,
1208 struct test_data *test_data,
1209 struct torture_krb5_context **torture_krb5_context)
1211 const char *host = torture_setting_string(tctx, "host", NULL);
1212 krb5_error_code k5ret;
1213 bool ok;
1215 struct torture_krb5_context *test_context = talloc_zero(tctx, struct torture_krb5_context);
1216 torture_assert(tctx, test_context != NULL, "Failed to allocate");
1218 test_context->test_data = test_data;
1219 test_context->tctx = tctx;
1221 k5ret = smb_krb5_init_context(test_context, tctx->lp_ctx, &test_context->smb_krb5_context);
1222 torture_assert_int_equal(tctx, k5ret, 0, "smb_krb5_init_context failed");
1224 ok = interpret_string_addr_internal(&test_context->server, host, AI_NUMERICHOST);
1225 torture_assert(tctx, ok, "Failed to parse target server");
1227 talloc_set_destructor(test_context, test_context_destructor);
1229 set_sockaddr_port(test_context->server->ai_addr, 88);
1231 k5ret = krb5_set_send_to_kdc_func(test_context->smb_krb5_context->krb5_context,
1232 smb_krb5_send_and_recv_func_canon_override,
1233 test_context);
1234 torture_assert_int_equal(tctx, k5ret, 0, "krb5_set_send_to_kdc_func failed");
1235 *torture_krb5_context = test_context;
1236 return true;
1240 static bool torture_krb5_as_req_canon(struct torture_context *tctx, const void *tcase_data)
1242 krb5_error_code k5ret;
1243 krb5_get_init_creds_opt *krb_options = NULL;
1244 struct test_data *test_data = talloc_get_type_abort(tcase_data, struct test_data);
1245 krb5_principal principal;
1246 krb5_principal krbtgt_other;
1247 krb5_principal expected_principal;
1248 char *principal_string;
1249 char *krbtgt_other_string;
1250 int principal_flags;
1251 char *expected_principal_string;
1252 int expected_principal_flags;
1253 char *got_principal_string;
1254 char *assertion_message;
1255 const char *password = cli_credentials_get_password(cmdline_credentials);
1256 krb5_context k5_context;
1257 struct torture_krb5_context *test_context;
1258 bool ok;
1259 krb5_creds my_creds;
1260 krb5_creds *server_creds;
1261 krb5_ccache ccache;
1262 krb5_auth_context auth_context;
1263 char *cc_name;
1264 krb5_data in_data, enc_ticket;
1265 krb5_get_creds_opt opt;
1267 const char *upn = torture_setting_string(tctx, "krb5-upn", "");
1268 test_data->krb5_service = torture_setting_string(tctx, "krb5-service", "host");
1269 test_data->krb5_hostname = torture_setting_string(tctx, "krb5-hostname", "");
1272 * If we have not passed a UPN on the command line,
1273 * then skip the UPN tests.
1275 if (test_data->upn && upn[0] == '\0') {
1276 torture_skip(tctx, "This test needs a UPN specified as --option=torture:krb5-upn=user@example.com to run");
1279 if (test_data->netbios_realm) {
1280 test_data->realm = test_data->real_domain;
1281 } else {
1282 test_data->realm = test_data->real_realm;
1285 if (test_data->upn) {
1286 char *p;
1287 test_data->username = talloc_strdup(test_data, upn);
1288 p = strchr(test_data->username, '@');
1289 if (p) {
1290 *p = '\0';
1291 p++;
1294 * Test the UPN behaviour carefully. We can
1295 * test in two different modes, depending on
1296 * what UPN has been set up for us.
1298 * If the UPN is in our realm, then we do all the tests with this name also.
1300 * If the UPN is not in our realm, then we
1301 * expect the tests that replace the realm to
1302 * fail (as it won't match)
1304 if (strcasecmp(p, test_data->real_realm) != 0) {
1305 test_data->other_upn_suffix = true;
1306 } else {
1307 test_data->other_upn_suffix = false;
1311 * This lets us test the combination of the UPN prefix
1312 * with a valid domain, without adding even more
1313 * combinations
1315 if (test_data->netbios_realm == false) {
1316 test_data->realm = p;
1320 ok = torture_krb5_init_context_canon(tctx, test_data, &test_context);
1321 torture_assert(tctx, ok, "torture_krb5_init_context failed");
1322 k5_context = test_context->smb_krb5_context->krb5_context;
1324 if (test_data->upper_realm) {
1325 test_data->realm = strupper_talloc(test_data, test_data->realm);
1326 } else {
1327 test_data->realm = strlower_talloc(test_data, test_data->realm);
1329 if (test_data->upper_username) {
1330 test_data->username = strupper_talloc(test_data, test_data->username);
1331 } else {
1332 test_data->username = talloc_strdup(test_data, test_data->username);
1335 principal_string = talloc_asprintf(test_data, "%s@%s", test_data->username, test_data->realm);
1338 * If we are set to canonicalize, we get back the fixed UPPER
1339 * case realm, and the real username (ie matching LDAP
1340 * samAccountName)
1342 * Otherwise, if we are set to enterprise, we
1343 * get back the whole principal as-sent
1345 * Finally, if we are not set to canonicalize, we get back the
1346 * fixed UPPER case realm, but the as-sent username
1348 if (test_data->canonicalize) {
1349 expected_principal_string = talloc_asprintf(test_data,
1350 "%s@%s",
1351 test_data->real_username,
1352 test_data->real_realm);
1353 } else if (test_data->enterprise) {
1354 expected_principal_string = principal_string;
1355 } else {
1356 expected_principal_string = talloc_asprintf(test_data,
1357 "%s@%s",
1358 test_data->username,
1359 test_data->real_realm);
1362 if (test_data->enterprise) {
1363 principal_flags = KRB5_PRINCIPAL_PARSE_ENTERPRISE;
1364 } else {
1365 if (test_data->upn && test_data->other_upn_suffix) {
1366 torture_skip(tctx, "UPN test for UPN with other UPN suffix only runs with enterprise principals");
1368 principal_flags = 0;
1371 if (test_data->canonicalize) {
1372 expected_principal_flags = 0;
1373 } else {
1374 expected_principal_flags = principal_flags;
1377 torture_assert_int_equal(tctx,
1378 krb5_parse_name_flags(k5_context,
1379 principal_string,
1380 principal_flags,
1381 &principal),
1382 0, "krb5_parse_name_flags failed");
1383 torture_assert_int_equal(tctx,
1384 krb5_parse_name_flags(k5_context,
1385 expected_principal_string,
1386 expected_principal_flags,
1387 &expected_principal),
1388 0, "krb5_parse_name_flags failed");
1391 * Prepare a AS-REQ and run the TEST_AS_REQ tests
1395 test_context->test_stage = TEST_AS_REQ;
1396 test_context->packet_count = 0;
1399 * Set the canonicalize flag if this test requires it
1401 torture_assert_int_equal(tctx,
1402 krb5_get_init_creds_opt_alloc(k5_context, &krb_options),
1403 0, "krb5_get_init_creds_opt_alloc failed");
1405 torture_assert_int_equal(tctx,
1406 krb5_get_init_creds_opt_set_canonicalize(k5_context,
1407 krb_options,
1408 test_data->canonicalize),
1409 0, "krb5_get_init_creds_opt_set_canonicalize failed");
1411 torture_assert_int_equal(tctx,
1412 krb5_get_init_creds_opt_set_win2k(k5_context,
1413 krb_options,
1414 test_data->win2k),
1415 0, "krb5_get_init_creds_opt_set_win2k failed");
1417 k5ret = krb5_get_init_creds_password(k5_context, &my_creds, principal,
1418 password, NULL, NULL, 0,
1419 NULL, krb_options);
1421 if (test_data->netbios_realm && test_data->upn) {
1422 torture_assert_int_equal(tctx, k5ret,
1423 KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN,
1424 "Got wrong error_code from krb5_get_init_creds_password");
1425 /* We can't proceed with more checks */
1426 return true;
1427 } else {
1428 assertion_message = talloc_asprintf(tctx,
1429 "krb5_get_init_creds_password for %s failed: %s",
1430 principal_string,
1431 smb_get_krb5_error_message(k5_context, k5ret, tctx));
1432 torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
1435 torture_assert(tctx,
1436 test_context->packet_count > 1,
1437 "Expected krb5_get_init_creds_password to send more packets");
1440 * Assert that the reply was with the correct type of
1441 * principal, depending on the flags we set
1443 if (test_data->canonicalize == false && test_data->enterprise) {
1444 torture_assert_int_equal(tctx,
1445 krb5_principal_get_type(k5_context,
1446 my_creds.client),
1447 KRB5_NT_ENTERPRISE_PRINCIPAL,
1448 "smb_krb5_init_context gave incorrect client->name.name_type");
1449 } else {
1450 torture_assert_int_equal(tctx,
1451 krb5_principal_get_type(k5_context,
1452 my_creds.client),
1453 KRB5_NT_PRINCIPAL,
1454 "smb_krb5_init_context gave incorrect client->name.name_type");
1457 torture_assert_int_equal(tctx,
1458 krb5_unparse_name(k5_context,
1459 my_creds.client, &got_principal_string), 0,
1460 "krb5_unparse_name failed");
1462 assertion_message = talloc_asprintf(tctx,
1463 "krb5_get_init_creds_password returned a different principal %s to what was expected %s",
1464 got_principal_string, expected_principal_string);
1465 krb5_free_unparsed_name(k5_context, got_principal_string);
1467 torture_assert(tctx, krb5_principal_compare(k5_context,
1468 my_creds.client, expected_principal),
1469 assertion_message);
1472 torture_assert_int_equal(tctx,
1473 krb5_principal_get_type(k5_context,
1474 my_creds.server), KRB5_NT_SRV_INST,
1475 "smb_krb5_init_context gave incorrect server->name.name_type");
1477 torture_assert_int_equal(tctx,
1478 krb5_principal_get_num_comp(k5_context,
1479 my_creds.server), 2,
1480 "smb_krb5_init_context gave incorrect number of components in my_creds.server->name");
1482 torture_assert_str_equal(tctx,
1483 krb5_principal_get_comp_string(k5_context,
1484 my_creds.server, 0),
1485 "krbtgt",
1486 "smb_krb5_init_context gave incorrect my_creds.server->name.name_string[0]");
1488 if (test_data->canonicalize || test_data->enterprise) {
1489 torture_assert_str_equal(tctx,
1490 krb5_principal_get_comp_string(k5_context,
1491 my_creds.server, 1),
1492 test_data->real_realm,
1494 "smb_krb5_init_context gave incorrect my_creds.server->name.name_string[1]");
1495 } else {
1496 torture_assert_str_equal(tctx,
1497 krb5_principal_get_comp_string(k5_context,
1498 my_creds.server, 1),
1499 test_data->realm,
1501 "smb_krb5_init_context gave incorrect my_creds.server->name.name_string[1]");
1503 torture_assert_str_equal(tctx,
1504 krb5_principal_get_realm(k5_context,
1505 my_creds.server),
1506 test_data->real_realm,
1507 "smb_krb5_init_context gave incorrect my_creds.server->realm");
1509 /* Store the result of the 'kinit' above into a memory ccache */
1510 cc_name = talloc_asprintf(tctx, "MEMORY:%s", test_data->test_name);
1511 torture_assert_int_equal(tctx, krb5_cc_resolve(k5_context, cc_name,
1512 &ccache),
1513 0, "krb5_cc_resolve failed");
1515 torture_assert_int_equal(tctx, krb5_cc_initialize(k5_context,
1516 ccache, my_creds.client),
1517 0, "krb5_cc_initialize failed");
1519 torture_assert_int_equal(tctx, krb5_cc_store_cred(k5_context,
1520 ccache, &my_creds),
1521 0, "krb5_cc_store_cred failed");
1524 * Prepare a TGS-REQ and run the TEST_TGS_REQ_KRBTGT_CANON tests
1526 * This tests krb5_get_creds behaviour, which allows us to set
1527 * the KRB5_GC_CANONICALIZE option against the krbtgt/ principal
1530 krbtgt_other_string = talloc_asprintf(test_data, "krbtgt/%s@%s", test_data->real_domain, test_data->real_realm);
1531 torture_assert_int_equal(tctx,
1532 krb5_make_principal(k5_context, &krbtgt_other,
1533 test_data->real_realm, "krbtgt",
1534 test_data->real_domain, NULL),
1535 0, "krb5_make_principal failed");
1537 test_context->test_stage = TEST_TGS_REQ_KRBTGT_CANON;
1538 test_context->packet_count = 0;
1540 torture_assert_int_equal(tctx,
1541 krb5_get_creds_opt_alloc(k5_context, &opt),
1542 0, "krb5_get_creds_opt_alloc");
1544 krb5_get_creds_opt_add_options(k5_context,
1545 opt,
1546 KRB5_GC_CANONICALIZE);
1548 krb5_get_creds_opt_add_options(k5_context,
1549 opt,
1550 KRB5_GC_NO_STORE);
1552 /* Confirm if we can get a ticket krbtgt/realm that we got back with the initial kinit */
1553 k5ret = krb5_get_creds(k5_context, opt, ccache, krbtgt_other, &server_creds);
1555 if (test_data->canonicalize == false && test_data->enterprise == false
1556 && test_data->netbios_realm && test_data->upper_realm) {
1558 * In these situations, the code above does store a
1559 * principal in the credentials cache matching what
1560 * krb5_get_creds() needs, so the test succeds, with no packets.
1563 assertion_message = talloc_asprintf(tctx,
1564 "krb5_get_creds for %s failed with: %s",
1565 krbtgt_other_string,
1566 smb_get_krb5_error_message(k5_context, k5ret,
1567 tctx));
1569 torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
1570 torture_assert_int_equal(tctx,
1571 test_context->packet_count,
1572 0, "Expected krb5_get_creds not to send packets");
1573 } else if (test_data->canonicalize == false && test_data->enterprise == false
1574 && (test_data->upper_realm == false || test_data->netbios_realm == true)) {
1575 torture_assert_int_equal(tctx, k5ret, KRB5_CC_NOTFOUND,
1576 "krb5_get_creds should have failed with KRB5_CC_NOTFOUND");
1577 } else {
1580 * In these situations, the code above does not store a
1581 * principal in the credentials cache matching what
1582 * krb5_get_creds() needs without talking to the KDC, so the
1583 * test fails with looping detected because when we set
1584 * canonicalize we confuse the client libs.
1587 assertion_message = talloc_asprintf(tctx,
1588 "krb5_get_creds for %s should have failed with looping detected: %s",
1589 krbtgt_other_string,
1590 smb_get_krb5_error_message(k5_context, k5ret,
1591 tctx));
1593 torture_assert_int_equal(tctx, k5ret, KRB5_GET_IN_TKT_LOOP, assertion_message);
1594 torture_assert_int_equal(tctx,
1595 test_context->packet_count,
1596 2, "Expected krb5_get_creds to send packets");
1600 * Prepare a TGS-REQ and run the TEST_TGS_REQ_CANON tests
1602 * This tests krb5_get_creds behaviour, which allows us to set
1603 * the KRB5_GC_CANONICALIZE option
1606 test_context->test_stage = TEST_TGS_REQ_CANON;
1607 test_context->packet_count = 0;
1609 torture_assert_int_equal(tctx,
1610 krb5_get_creds_opt_alloc(k5_context, &opt),
1611 0, "krb5_get_creds_opt_alloc");
1613 krb5_get_creds_opt_add_options(k5_context,
1614 opt,
1615 KRB5_GC_CANONICALIZE);
1617 krb5_get_creds_opt_add_options(k5_context,
1618 opt,
1619 KRB5_GC_NO_STORE);
1621 /* Confirm if we can get a ticket to our own name */
1622 k5ret = krb5_get_creds(k5_context, opt, ccache, principal, &server_creds);
1625 * In these situations, the code above does not store a
1626 * principal in the credentials cache matching what
1627 * krb5_get_creds() needs, so the test fails.
1630 if (test_data->canonicalize == false && test_data->enterprise == false
1631 && (test_data->upper_realm == false || test_data->netbios_realm == true)) {
1632 torture_assert_int_equal(tctx, k5ret, KRB5_CC_NOTFOUND,
1633 "krb5_get_creds should have failed with KRB5_CC_NOTFOUND");
1634 } else {
1635 assertion_message = talloc_asprintf(tctx,
1636 "krb5_get_creds for %s failed: %s",
1637 principal_string,
1638 smb_get_krb5_error_message(k5_context, k5ret,
1639 tctx));
1642 * Only machine accounts (strictly, accounts with a
1643 * servicePrincipalName) can expect this test to succeed
1645 if (torture_setting_bool(tctx, "expect_machine_account", false)
1646 && (test_data->enterprise || test_data->upn == false)) {
1647 torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
1648 torture_assert_int_equal(tctx, krb5_cc_store_cred(k5_context,
1649 ccache, server_creds),
1650 0, "krb5_cc_store_cred failed");
1652 torture_assert_int_equal(tctx,
1653 krb5_free_creds(k5_context,
1654 server_creds),
1655 0, "krb5_free_cred_contents failed");
1657 } else {
1658 torture_assert_int_equal(tctx, k5ret, KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN,
1659 assertion_message);
1662 torture_assert_int_equal(tctx,
1663 test_context->packet_count,
1664 1, "Expected krb5_get_creds to send packets");
1668 * Confirm gettting a ticket to pass to the server, running
1669 * either the TEST_TGS_REQ or TEST_SELF_TRUST_TGS_REQ stage.
1671 * This triggers the client to attempt to get a
1672 * cross-realm ticket between the alternate names of
1673 * the server, and we need to confirm that behaviour.
1678 * This tries to guess when the krb5 libs will ask for a
1679 * cross-realm ticket, and when they will just ask the KDC
1680 * directly.
1682 if (test_context->test_data->canonicalize == false
1683 || test_context->test_data->enterprise
1684 || (test_context->test_data->upper_realm
1685 && test_context->test_data->netbios_realm == false)) {
1686 test_context->test_stage = TEST_TGS_REQ;
1687 } else {
1688 test_context->test_stage = TEST_SELF_TRUST_TGS_REQ;
1691 test_context->packet_count = 0;
1692 torture_assert_int_equal(tctx, krb5_auth_con_init(k5_context, &auth_context),
1693 0, "krb5_auth_con_init failed");
1695 in_data.length = 0;
1696 k5ret = krb5_mk_req_exact(k5_context,
1697 &auth_context,
1699 principal,
1700 &in_data, ccache,
1701 &enc_ticket);
1702 assertion_message = talloc_asprintf(tctx,
1703 "krb5_mk_req_exact for %s failed: %s",
1704 principal_string,
1705 smb_get_krb5_error_message(k5_context, k5ret, tctx));
1708 * Only machine accounts (strictly, accounts with a
1709 * servicePrincipalName) can expect this test to succeed
1711 if (torture_setting_bool(tctx, "expect_machine_account", false) && (test_data->enterprise || test_data->upn == false)) {
1712 torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
1713 } else {
1714 torture_assert_int_equal(tctx, k5ret, KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN,
1715 assertion_message);
1719 * Only in these cases would the above code have needed to
1720 * send packets to the network
1722 if (test_data->canonicalize == false && test_data->enterprise == false
1723 && (test_data->upper_realm == false || test_data->netbios_realm == true)) {
1724 torture_assert(tctx,
1725 test_context->packet_count > 0,
1726 "Expected krb5_mk_req_exact to send packets");
1730 * Confirm gettting a ticket to pass to the server, running
1731 * the TEST_TGS_REQ_HOST stage
1733 * This triggers the client to attempt to get a
1734 * cross-realm ticket between the alternate names of
1735 * the server, and we need to confirm that behaviour.
1739 if (*test_data->krb5_service && *test_data->krb5_hostname) {
1741 * This tries to guess when the krb5 libs will ask for a
1742 * cross-realm ticket, and when they will just ask the KDC
1743 * directly.
1745 test_context->test_stage = TEST_TGS_REQ_HOST;
1747 test_context->packet_count = 0;
1748 torture_assert_int_equal(tctx, krb5_auth_con_init(k5_context, &auth_context),
1749 0, "krb5_auth_con_init failed");
1751 in_data.length = 0;
1752 k5ret = krb5_mk_req(k5_context,
1753 &auth_context,
1755 test_data->krb5_service,
1756 test_data->krb5_hostname,
1757 &in_data, ccache,
1758 &enc_ticket);
1760 if (test_data->canonicalize == false && test_data->enterprise == false
1761 && (test_data->upper_realm == false || test_data->netbios_realm == true)) {
1762 torture_assert_int_equal(tctx, k5ret, KRB5_CC_NOTFOUND,
1763 "krb5_get_creds should have failed with KRB5_CC_NOTFOUND");
1764 } else {
1765 assertion_message = talloc_asprintf(tctx,
1766 "krb5_mk_req for %s failed: %s",
1767 principal_string,
1768 smb_get_krb5_error_message(k5_context, k5ret, tctx));
1770 torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
1772 * Only in these cases would the above code have needed to
1773 * send packets to the network
1775 torture_assert(tctx,
1776 test_context->packet_count > 0,
1777 "Expected krb5_get_creds to send packets");
1782 * Confirm gettting a ticket for the same krbtgt/realm that we
1783 * got back with the initial ticket, running the
1784 * TEST_TGS_REQ_KRBTGT stage.
1788 test_context->test_stage = TEST_TGS_REQ_KRBTGT;
1789 test_context->packet_count = 0;
1791 in_data.length = 0;
1792 k5ret = krb5_mk_req_exact(k5_context,
1793 &auth_context,
1795 my_creds.server,
1796 &in_data, ccache,
1797 &enc_ticket);
1799 assertion_message = talloc_asprintf(tctx,
1800 "krb5_mk_req_exact for %s failed: %s",
1801 principal_string,
1802 smb_get_krb5_error_message(k5_context, k5ret, tctx));
1803 torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
1806 * Confirm gettting a ticket for our own principal that we
1807 * got back with the initial ticket, running the
1808 * TEST_AS_REQ_SELF stage.
1811 test_context->test_stage = TEST_AS_REQ_SELF;
1812 test_context->packet_count = 0;
1814 k5ret = krb5_get_init_creds_password(k5_context, &my_creds, principal,
1815 password, NULL, NULL, 0,
1816 principal_string, krb_options);
1818 if (torture_setting_bool(test_context->tctx, "expect_machine_account", false) && (test_data->upn == false)) {
1819 assertion_message = talloc_asprintf(tctx,
1820 "krb5_get_init_creds_password for %s failed: %s",
1821 principal_string,
1822 smb_get_krb5_error_message(k5_context, k5ret, tctx));
1823 torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
1824 torture_assert(tctx,
1825 test_context->packet_count >= 2,
1826 "Expected krb5_get_init_creds_password to send more packets");
1828 } else {
1829 assertion_message = talloc_asprintf(tctx,
1830 "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);
1831 torture_assert_int_equal(tctx, k5ret,
1832 KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN,
1833 assertion_message);
1834 torture_assert(tctx,
1835 test_context->packet_count >= 1,
1836 "Expected krb5_get_init_creds_password to send more packets");
1838 /* We can't proceed with more checks */
1839 return true;
1843 * Assert that the reply was with the correct type of
1844 * principal, depending on the flags we set
1846 if (test_data->canonicalize == false && test_data->enterprise) {
1847 torture_assert_int_equal(tctx,
1848 krb5_principal_get_type(k5_context,
1849 my_creds.client),
1850 KRB5_NT_ENTERPRISE_PRINCIPAL,
1851 "smb_krb5_init_context gave incorrect client->name.name_type");
1852 torture_assert_int_equal(tctx,
1853 krb5_principal_get_type(k5_context,
1854 my_creds.server),
1855 KRB5_NT_ENTERPRISE_PRINCIPAL,
1856 "smb_krb5_init_context gave incorrect server->name.name_type");
1857 } else {
1858 torture_assert_int_equal(tctx,
1859 krb5_principal_get_type(k5_context,
1860 my_creds.client),
1861 KRB5_NT_PRINCIPAL,
1862 "smb_krb5_init_context gave incorrect client->name.name_type");
1863 torture_assert_int_equal(tctx,
1864 krb5_principal_get_type(k5_context,
1865 my_creds.server),
1866 KRB5_NT_PRINCIPAL,
1867 "smb_krb5_init_context gave incorrect server->name.name_type");
1870 torture_assert_int_equal(tctx,
1871 krb5_unparse_name(k5_context,
1872 my_creds.client, &got_principal_string), 0,
1873 "krb5_unparse_name failed");
1875 assertion_message = talloc_asprintf(tctx,
1876 "krb5_get_init_creds_password returned a different principal %s to what was expected %s",
1877 got_principal_string, expected_principal_string);
1878 krb5_free_unparsed_name(k5_context, got_principal_string);
1880 torture_assert(tctx, krb5_principal_compare(k5_context,
1881 my_creds.client, expected_principal),
1882 assertion_message);
1884 torture_assert_int_equal(tctx,
1885 krb5_unparse_name(k5_context,
1886 my_creds.client, &got_principal_string), 0,
1887 "krb5_unparse_name failed");
1889 assertion_message = talloc_asprintf(tctx,
1890 "krb5_get_init_creds_password returned a different server principal %s to what was expected %s",
1891 got_principal_string, expected_principal_string);
1892 krb5_free_unparsed_name(k5_context, got_principal_string);
1894 torture_assert(tctx, krb5_principal_compare(k5_context,
1895 my_creds.client, expected_principal),
1896 assertion_message);
1898 krb5_free_principal(k5_context, principal);
1899 krb5_get_init_creds_opt_free(k5_context, krb_options);
1901 torture_assert_int_equal(tctx, krb5_free_cred_contents(k5_context, &my_creds),
1902 0, "krb5_free_cred_contents failed");
1904 return true;
1907 struct torture_suite *torture_krb5_canon(TALLOC_CTX *mem_ctx)
1909 unsigned int i;
1910 struct torture_suite *suite = torture_suite_create(mem_ctx, "canon");
1911 suite->description = talloc_strdup(suite, "Kerberos Canonicalisation tests");
1913 for (i = 0; i < TEST_ALL; i++) {
1914 char *name = talloc_asprintf(suite, "%s.%s.%s.%s.%s.%s.%s",
1915 (i & TEST_CANONICALIZE) ? "canon" : "no-canon",
1916 (i & TEST_ENTERPRISE) ? "enterprise" : "no-enterprise",
1917 (i & TEST_UPPER_REALM) ? "uc-realm" : "lc-realm",
1918 (i & TEST_UPPER_USERNAME) ? "uc-user" : "lc-user",
1919 (i & TEST_NETBIOS_REALM) ? "netbios-realm" : "krb5-realm",
1920 (i & TEST_WIN2K) ? "win2k" : "no-win2k",
1921 (i & TEST_UPN) ? "upn" : "no-upn");
1923 struct test_data *test_data = talloc_zero(suite, struct test_data);
1925 test_data->test_name = name;
1926 test_data->real_realm
1927 = strupper_talloc(test_data, cli_credentials_get_realm(cmdline_credentials));
1928 test_data->real_domain = cli_credentials_get_domain(cmdline_credentials);
1929 test_data->username = cli_credentials_get_username(cmdline_credentials);
1930 test_data->real_username = cli_credentials_get_username(cmdline_credentials);
1931 test_data->canonicalize = (i & TEST_CANONICALIZE) != 0;
1932 test_data->enterprise = (i & TEST_ENTERPRISE) != 0;
1933 test_data->upper_realm = (i & TEST_UPPER_REALM) != 0;
1934 test_data->upper_username = (i & TEST_UPPER_USERNAME) != 0;
1935 test_data->netbios_realm = (i & TEST_NETBIOS_REALM) != 0;
1936 test_data->win2k = (i & TEST_WIN2K) != 0;
1937 test_data->upn = (i & TEST_UPN) != 0;
1938 torture_suite_add_simple_tcase_const(suite, name, torture_krb5_as_req_canon,
1939 test_data);
1942 return suite;