1 /*
2    Unix SMB/CIFS implementation.
3 
4    Validate the krb5 pac generation routines
5 
6    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2015
7 
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.
12 
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.
17 
18 
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/>.
21 */
22 
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"
36 #include "zlib.h"
37 
38 #define TEST_CANONICALIZE     0x0000001
39 #define TEST_ENTERPRISE       0x0000002
40 #define TEST_UPPER_REALM      0x0000004
41 #define TEST_UPPER_USERNAME   0x0000008
42 #define TEST_NETBIOS_REALM    0x0000010
43 #define TEST_WIN2K            0x0000020
44 #define TEST_UPN              0x0000040
45 #define TEST_S4U2SELF         0x0000080
46 #define TEST_REMOVEDOLLAR     0x0000100
47 #define TEST_AS_REQ_SPN       0x0000200
48 #define TEST_MITM_S4U2SELF    0x0000400
49 #define TEST_ALL              0x00007FF
50 
51 struct test_data {
52 	const char *test_name;
53 	const char *realm;
54 	const char *real_realm;
55 	const char *real_domain;
56 	const char *username;
57 	const char *real_username;
58 	bool canonicalize;
59 	bool enterprise;
60 	bool upper_realm;
61 	bool upper_username;
62 	bool netbios_realm;
63 	bool win2k;
64 	bool upn;
65 	bool other_upn_suffix;
66 	bool s4u2self;
67 	bool mitm_s4u2self;
68 	bool removedollar;
69 	bool as_req_spn;
70 	bool spn_is_upn;
71 	const char *krb5_service;
72 	const char *krb5_hostname;
73 };
74 
75 enum test_stage {
76 	TEST_AS_REQ = 0,
77 	TEST_TGS_REQ_KRBTGT_CANON = 1,
78 	TEST_TGS_REQ_CANON = 2,
79 	TEST_SELF_TRUST_TGS_REQ = 3,
80 	TEST_TGS_REQ = 4,
81 	TEST_TGS_REQ_KRBTGT = 5,
82 	TEST_TGS_REQ_HOST = 6,
83 	TEST_TGS_REQ_HOST_SRV_INST = 7,
84 	TEST_TGS_REQ_HOST_SRV_HST = 8,
85 	TEST_AS_REQ_SELF = 9,
86 	TEST_DONE = 10
87 };
88 
89 struct torture_krb5_context {
90 	struct smb_krb5_context *smb_krb5_context;
91 	struct torture_context *tctx;
92 	struct addrinfo *server;
93 	struct test_data *test_data;
94 	int packet_count;
95 	enum test_stage test_stage;
96 	AS_REQ as_req;
97 	AS_REP as_rep;
98 	TGS_REQ tgs_req;
99 	TGS_REP tgs_rep;
100 };
101 
102 struct pac_data {
103 	const char *principal_name;
104 };
105 
106 /*
107  * A helper function which avoids touching the local databases to
108  * generate the session info, as we just want to verify the principal
109  * name that we found in the ticket not the full local token
110  */
test_generate_session_info_pac(struct auth4_context * auth_ctx,TALLOC_CTX * mem_ctx,struct smb_krb5_context * smb_krb5_context,DATA_BLOB * pac_blob,const char * principal_name,const struct tsocket_address * remote_address,uint32_t session_info_flags,struct auth_session_info ** session_info)111 static NTSTATUS test_generate_session_info_pac(struct auth4_context *auth_ctx,
112 					       TALLOC_CTX *mem_ctx,
113 					       struct smb_krb5_context *smb_krb5_context,
114 					       DATA_BLOB *pac_blob,
115 					       const char *principal_name,
116 					       const struct tsocket_address *remote_address,
117 					       uint32_t session_info_flags,
118 					       struct auth_session_info **session_info)
119 {
120 	NTSTATUS nt_status;
121 	struct auth_user_info_dc *user_info_dc;
122 	TALLOC_CTX *tmp_ctx;
123 	struct pac_data *pac_data;
124 
125 	tmp_ctx = talloc_named(mem_ctx, 0, "gensec_gssapi_session_info context");
126 	NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
127 
128 	auth_ctx->private_data = pac_data = talloc_zero(auth_ctx, struct pac_data);
129 
130 	pac_data->principal_name = talloc_strdup(pac_data, principal_name);
131 	if (!pac_data->principal_name) {
132 		talloc_free(tmp_ctx);
133 		return NT_STATUS_NO_MEMORY;
134 	}
135 
136 	nt_status = kerberos_pac_blob_to_user_info_dc(tmp_ctx,
137 						      *pac_blob,
138 						      smb_krb5_context->krb5_context,
139 						      &user_info_dc, NULL, NULL);
140 	if (!NT_STATUS_IS_OK(nt_status)) {
141 		talloc_free(tmp_ctx);
142 		return nt_status;
143 	}
144 
145 	if (user_info_dc->info->authenticated) {
146 		session_info_flags |= AUTH_SESSION_INFO_AUTHENTICATED;
147 	}
148 
149 	session_info_flags |= AUTH_SESSION_INFO_SIMPLE_PRIVILEGES;
150 	nt_status = auth_generate_session_info(mem_ctx,
151 					       NULL,
152 					       NULL,
153 					       user_info_dc, session_info_flags,
154 					       session_info);
155 	if (!NT_STATUS_IS_OK(nt_status)) {
156 		talloc_free(tmp_ctx);
157 		return nt_status;
158 	}
159 
160 	talloc_free(tmp_ctx);
161 	return NT_STATUS_OK;
162 }
163 
164 /* Check to see if we can pass the PAC across to the NETLOGON server for validation */
165 
166 /* Also happens to be a really good one-step verfication of our Kerberos stack */
167 
test_accept_ticket(struct torture_context * tctx,struct cli_credentials * credentials,const char * principal,DATA_BLOB client_to_server)168 static bool test_accept_ticket(struct torture_context *tctx,
169 			       struct cli_credentials *credentials,
170 			       const char *principal,
171 			       DATA_BLOB client_to_server)
172 {
173 	NTSTATUS status;
174 	struct gensec_security *gensec_server_context;
175 	DATA_BLOB server_to_client;
176 	struct auth4_context *auth_context;
177 	struct auth_session_info *session_info;
178 	struct pac_data *pac_data;
179 	TALLOC_CTX *tmp_ctx = talloc_new(tctx);
180 
181 	torture_assert(tctx, tmp_ctx != NULL, "talloc_new() failed");
182 
183 	auth_context = talloc_zero(tmp_ctx, struct auth4_context);
184 	torture_assert(tctx, auth_context != NULL, "talloc_new() failed");
185 
186 	auth_context->generate_session_info_pac = test_generate_session_info_pac;
187 
188 	status = gensec_server_start(tctx,
189 				     lpcfg_gensec_settings(tctx, tctx->lp_ctx),
190 				     auth_context, &gensec_server_context);
191 	torture_assert_ntstatus_ok(tctx, status, "gensec_server_start (server) failed");
192 
193 	status = gensec_set_credentials(gensec_server_context, credentials);
194 	torture_assert_ntstatus_ok(tctx, status, "gensec_set_credentials (server) failed");
195 
196 	status = gensec_start_mech_by_name(gensec_server_context, "krb5");
197 	torture_assert_ntstatus_ok(tctx, status, "gensec_start_mech_by_name (server) failed");
198 
199 	server_to_client = data_blob(NULL, 0);
200 
201 	/* Do a client-server update dance */
202 	status = gensec_update(gensec_server_context, tmp_ctx, client_to_server, &server_to_client);
203 	torture_assert_ntstatus_ok(tctx, status, "gensec_update (server) failed");
204 
205 	/* Extract the PAC using Samba's code */
206 
207 	status = gensec_session_info(gensec_server_context, gensec_server_context, &session_info);
208 	torture_assert_ntstatus_ok(tctx, status, "gensec_session_info failed");
209 
210 	pac_data = talloc_get_type(auth_context->private_data, struct pac_data);
211 
212 	torture_assert(tctx, pac_data != NULL, "gensec_update failed to fill in pac_data in auth_context");
213 	torture_assert(tctx, pac_data->principal_name != NULL, "principal_name not present");
214 	torture_assert_str_equal(tctx, pac_data->principal_name, principal, "wrong principal name");
215 	return true;
216 }
217 
218 static void
zCRC32_checksum(const void * data,size_t len,Checksum * C)219 zCRC32_checksum(const void *data,
220 		size_t len,
221 		Checksum *C)
222 {
223 	uint32_t *crc = C->checksum.data;
224 	*crc = ~(crc32(0xffffffff, data, len));
225 	C->checksum.length = 4;
226 	C->cksumtype = 1;
227 }
228 
229 krb5_error_code
230 _krb5_s4u2self_to_checksumdata(krb5_context context,
231 			       const PA_S4U2Self *self,
232 			       krb5_data *data);
233 
234 /* Helper function to modify the principal in PA_FOR_USER padata */
change_for_user_principal(struct torture_krb5_context * test_context,krb5_data * modified_send_buf)235 static bool change_for_user_principal(struct torture_krb5_context *test_context,
236 				      krb5_data *modified_send_buf)
237 {
238 	PA_DATA *for_user;
239 	int i = 0;
240 	size_t used;
241 	krb5_error_code ret;
242 	PA_S4U2Self self, mod_self;
243 	krb5_data cksum_data;
244 	krb5_principal admin;
245 	heim_octet_string orig_padata_value;
246 	krb5_context k5_ctx = test_context->smb_krb5_context->krb5_context;
247 
248 	for_user = krb5_find_padata(test_context->tgs_req.padata->val,
249 				    test_context->tgs_req.padata->len, KRB5_PADATA_FOR_USER, &i);
250 	torture_assert(test_context->tctx, for_user != NULL, "No PA_FOR_USER in s4u2self request");
251 	orig_padata_value = for_user->padata_value;
252 
253 	torture_assert_int_equal(test_context->tctx,
254 				 krb5_make_principal(k5_ctx, &admin, test_context->test_data->realm,
255 						     "Administrator", NULL),
256 				 0, "krb5_make_principal() failed");
257 	torture_assert_int_equal(test_context->tctx,
258 				 decode_PA_S4U2Self(for_user->padata_value.data,
259 						    for_user->padata_value.length, &self, NULL),
260 				 0, "decode_PA_S4U2Self() failed");
261 	mod_self = self;
262 	mod_self.name = admin->name;
263 
264 	torture_assert_int_equal(test_context->tctx,
265 				 _krb5_s4u2self_to_checksumdata(k5_ctx, &mod_self, &cksum_data),
266 				 0, "_krb5_s4u2self_to_checksumdata() failed");
267 	zCRC32_checksum(cksum_data.data, cksum_data.length, &mod_self.cksum);
268 
269 	ASN1_MALLOC_ENCODE(PA_S4U2Self, for_user->padata_value.data, for_user->padata_value.length,
270 			   &mod_self, &used, ret);
271 	torture_assert(test_context->tctx, ret == 0, "Failed to encode PA_S4U2Self ASN1 struct");
272 	ASN1_MALLOC_ENCODE(TGS_REQ, modified_send_buf->data, modified_send_buf->length,
273 			   &test_context->tgs_req, &used, ret);
274 	torture_assert(test_context->tctx, ret == 0, "Failed to encode TGS_REQ ASN1 struct");
275 
276 	free(for_user->padata_value.data);
277 	for_user->padata_value = orig_padata_value;
278 
279 	free_PA_S4U2Self(&self);
280 	krb5_data_free(&cksum_data);
281 
282 	return true;
283 }
284 
285 /*
286  * TEST_AS_REQ and TEST_AS_REQ_SELF - SEND
287  *
288  * Confirm that the outgoing packet meets certain expectations.  This
289  * should be extended to further assert the correct and expected
290  * behaviour of the krb5 libs, so we know what we are sending to the
291  * server.
292  *
293  * Additionally, this CHANGES the request to remove the canonicalize
294  * flag automatically added by the krb5 libs when an enterprise
295  * principal is used, so we can test what the server does in this
296  * combination.
297  *
298  */
299 
torture_krb5_pre_send_as_req_test(struct torture_krb5_context * test_context,const krb5_data * send_buf,krb5_data * modified_send_buf)300 static bool torture_krb5_pre_send_as_req_test(struct torture_krb5_context *test_context,
301 					      const krb5_data *send_buf,
302 					      krb5_data *modified_send_buf)
303 {
304 	AS_REQ mod_as_req;
305 	krb5_error_code k5ret;
306 	size_t used;
307 	torture_assert_int_equal(test_context->tctx, decode_AS_REQ(send_buf->data, send_buf->length,
308 					       &test_context->as_req, &used),
309 				 0, "decode_AS_REQ for TEST_AS_REQ failed");
310 	mod_as_req = test_context->as_req;
311 	torture_assert_int_equal(test_context->tctx, used, send_buf->length, "length mismatch");
312 	torture_assert_int_equal(test_context->tctx, test_context->as_req.pvno,
313 				 5, "Got wrong as_req->pvno");
314 	if (test_context->test_data->canonicalize
315 	    || test_context->test_data->enterprise) {
316 		torture_assert(test_context->tctx,
317 			       test_context->as_req.req_body.kdc_options.canonicalize,
318 			       "krb5 libs did not set canonicalize!");
319 	} else {
320 		torture_assert_int_equal(test_context->tctx,
321 					 test_context->as_req.req_body.kdc_options.canonicalize,
322 					 false,
323 					 "krb5 libs unexpectedly set canonicalize!");
324 	}
325 
326 	if (test_context->test_data->as_req_spn) {
327 		if (test_context->test_data->upn) {
328 			torture_assert_int_equal(test_context->tctx,
329 						 test_context->as_req.req_body.cname->name_type,
330 						 KRB5_NT_PRINCIPAL,
331 						 "krb5 libs unexpectedly "
332 						 "did not set principal "
333 						 "as NT_SRV_HST!");
334 		} else {
335 			torture_assert_int_equal(test_context->tctx,
336 						 test_context->as_req.req_body.cname->name_type,
337 						 KRB5_NT_SRV_HST,
338 						 "krb5 libs unexpectedly "
339 						 "did not set principal "
340 						 "as NT_SRV_HST!");
341 		}
342 	} else if (test_context->test_data->enterprise) {
343 		torture_assert_int_equal(test_context->tctx,
344 					 test_context->as_req.req_body.cname->name_type,
345 					 KRB5_NT_ENTERPRISE_PRINCIPAL,
346 					 "krb5 libs did not pass principal as enterprise!");
347 	} else {
348 		torture_assert_int_equal(test_context->tctx,
349 					 test_context->as_req.req_body.cname->name_type,
350 					 KRB5_NT_PRINCIPAL,
351 					 "krb5 libs unexpectedly set principal as enterprise!");
352 	}
353 
354 	/* Force off canonicalize that was forced on by the krb5 libs */
355 	if (test_context->test_data->canonicalize == false && test_context->test_data->enterprise) {
356 		mod_as_req.req_body.kdc_options.canonicalize = false;
357 	}
358 
359 	if (test_context->test_stage == TEST_AS_REQ_SELF) {
360 		/*
361 		 * Force the server name to match the client name,
362 		 * including the name type.  This isn't possible with
363 		 * the krb5 client libs alone
364 		 */
365 		mod_as_req.req_body.sname = test_context->as_req.req_body.cname;
366 	}
367 
368 	ASN1_MALLOC_ENCODE(AS_REQ, modified_send_buf->data, modified_send_buf->length,
369 			   &mod_as_req, &used, k5ret);
370 	torture_assert_int_equal(test_context->tctx,
371 				 k5ret, 0,
372 				 "encode_AS_REQ failed");
373 
374 	if (test_context->test_stage != TEST_AS_REQ_SELF) {
375 		torture_assert_int_equal(test_context->tctx, used, send_buf->length,
376 					 "re-encode length mismatch");
377 	}
378 	return true;
379 }
380 
381 /*
382  * TEST_AS_REQ - RECV
383  *
384  * Confirm that the reply packet from the KDC meets certain
385  * expectations as part of TEST_AS_REQ.  This uses a packet count to
386  * work out what packet we are up to in the multiple exchanged
387  * triggerd by krb5_get_init_creds_password().
388  *
389  */
390 
torture_krb5_post_recv_as_req_test(struct torture_krb5_context * test_context,const krb5_data * recv_buf)391 static bool torture_krb5_post_recv_as_req_test(struct torture_krb5_context *test_context,
392 					       const krb5_data *recv_buf)
393 {
394 	KRB_ERROR error;
395 	size_t used;
396 	if (test_context->packet_count == 0) {
397 		krb5_error_code k5ret;
398 		/*
399 		 * The client libs obtain the salt by attempting to
400 		 * authenticate without pre-authentication and getting
401 		 * the correct salt with the
402 		 * KRB5KDC_ERR_PREAUTH_REQUIRED error.  If we are in
403 		 * the test (netbios_realm && upn) that deliberatly
404 		 * has an incorrect principal, we check we get the
405 		 * correct error.
406 		 */
407 		k5ret = decode_KRB_ERROR(recv_buf->data, recv_buf->length,
408 					 &error, &used);
409 		if (k5ret != 0) {
410 			AS_REP as_rep;
411 			k5ret = decode_AS_REP(recv_buf->data, recv_buf->length,
412 				      &as_rep, &used);
413 			if (k5ret == 0) {
414 				if (test_context->test_data->netbios_realm && test_context->test_data->upn) {
415 					torture_assert(test_context->tctx, false,
416 						       "expected to get a KRB_ERROR packet with "
417 						       "KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN, got valid AS-REP");
418 				} else {
419 					torture_assert(test_context->tctx, false,
420 						       "expected to get a KRB_ERROR packet with "
421 						       "KRB5KDC_ERR_PREAUTH_REQUIRED, got valid AS-REP");
422 				}
423 			} else {
424 				if (test_context->test_data->netbios_realm && test_context->test_data->upn) {
425 					torture_assert(test_context->tctx, false,
426 						       "unable to decode as KRB-ERROR or AS-REP, "
427 						       "expected to get a KRB_ERROR packet with KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN");
428 				} else {
429 					torture_assert(test_context->tctx, false,
430 						       "unable to decode as KRB-ERROR or AS-REP, "
431 						       "expected to get a KRB_ERROR packet with KRB5KDC_ERR_PREAUTH_REQUIRED");
432 				}
433 			}
434 		}
435 		torture_assert_int_equal(test_context->tctx, used, recv_buf->length,
436 					 "length mismatch");
437 		torture_assert_int_equal(test_context->tctx, error.pvno, 5,
438 					 "Got wrong error.pvno");
439 		if (test_context->test_data->netbios_realm && test_context->test_data->upn) {
440 			torture_assert_int_equal(test_context->tctx,
441 						 error.error_code,
442 						 KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN - KRB5KDC_ERR_NONE,
443 						 "Got wrong error.error_code");
444 		} else if (test_context->test_data->as_req_spn && !test_context->test_data->spn_is_upn) {
445 			torture_assert_int_equal(test_context->tctx,
446 						 error.error_code,
447 						 KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN - KRB5KDC_ERR_NONE,
448 						 "Got wrong error.error_code");
449 		} else {
450 			torture_assert_int_equal(test_context->tctx,
451 						 error.error_code,
452 						 KRB5KDC_ERR_PREAUTH_REQUIRED - KRB5KDC_ERR_NONE,
453 						 "Got wrong error.error_code");
454 		}
455 
456 		free_KRB_ERROR(&error);
457 	} else if ((decode_KRB_ERROR(recv_buf->data, recv_buf->length, &error, &used) == 0)
458 		   && (test_context->packet_count == 1)) {
459 		/*
460 		 * The Windows 2012R2 KDC will always respond with
461 		 * KRB5KRB_ERR_RESPONSE_TOO_BIG over UDP as the ticket
462 		 * won't fit, because of the PAC.  (It appears to do
463 		 * this always, even if it will).  This triggers the
464 		 * client to try again over TCP.
465 		 */
466 		torture_assert_int_equal(test_context->tctx,
467 					 used, recv_buf->length,
468 					 "length mismatch");
469 		torture_assert_int_equal(test_context->tctx,
470 					 error.pvno, 5,
471 					 "Got wrong error.pvno");
472 		torture_assert_int_equal(test_context->tctx,
473 					 error.error_code,
474 					 KRB5KRB_ERR_RESPONSE_TOO_BIG - KRB5KDC_ERR_NONE,
475 					 "Got wrong error.error_code");
476 		free_KRB_ERROR(&error);
477 	} else {
478 		/*
479 		 * Finally the successful packet.
480 		 */
481 		torture_assert_int_equal(test_context->tctx,
482 					 decode_AS_REP(recv_buf->data, recv_buf->length,
483 						       &test_context->as_rep, &used), 0,
484 					 "decode_AS_REP failed");
485 		torture_assert_int_equal(test_context->tctx, used, recv_buf->length,
486 					 "length mismatch");
487 		torture_assert_int_equal(test_context->tctx,
488 					 test_context->as_rep.pvno, 5,
489 					 "Got wrong as_rep->pvno");
490 		torture_assert_int_equal(test_context->tctx,
491 					 test_context->as_rep.ticket.tkt_vno, 5,
492 					 "Got wrong as_rep->ticket.tkt_vno");
493 		torture_assert(test_context->tctx,
494 			       test_context->as_rep.ticket.enc_part.kvno,
495 			       "Did not get a KVNO in test_context->as_rep.ticket.enc_part.kvno");
496 
497 		/*
498 		 * We can confirm that the correct proxy behaviour is
499 		 * in use on the KDC by checking the KVNO of the
500 		 * krbtgt account returned in the reply.
501 		 *
502 		 * A packet passed to the full RW DC will not have a
503 		 * KVNO in the upper bits, while a packet processed
504 		 * locally on the RODC will have these bits filled in
505 		 * the msDS-SecondaryKrbTgtNumber
506 		 */
507 		if (torture_setting_bool(test_context->tctx, "expect_cached_at_rodc", false)) {
508 			torture_assert_int_not_equal(test_context->tctx,
509 						     *test_context->as_rep.ticket.enc_part.kvno & 0xFFFF0000,
510 						     0, "Did not get a RODC number in the KVNO");
511 		} else {
512 			torture_assert_int_equal(test_context->tctx,
513 						 *test_context->as_rep.ticket.enc_part.kvno & 0xFFFF0000,
514 						 0, "Unexpecedly got a RODC number in the KVNO");
515 		}
516 		free_AS_REP(&test_context->as_rep);
517 	}
518 	torture_assert(test_context->tctx, test_context->packet_count < 3, "too many packets");
519 	free_AS_REQ(&test_context->as_req);
520 	return true;
521 }
522 
523 /*
524  * TEST_TGS_REQ_KRBTGT_CANON
525  *
526  *
527  * Confirm that the outgoing TGS-REQ packet from krb5_get_creds()
528  * for the krbtgt/realm principal meets certain expectations, like
529  * that the canonicalize bit is not set
530  *
531  */
532 
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)533 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)
534 {
535 	size_t used;
536 	torture_assert_int_equal(test_context->tctx,
537 				 decode_TGS_REQ(send_buf->data, send_buf->length,
538 						&test_context->tgs_req, &used),
539 				 0, "decode_TGS_REQ for TEST_TGS_REQ test failed");
540 	torture_assert_int_equal(test_context->tctx,
541 				 used, send_buf->length,
542 				 "length mismatch");
543 	torture_assert_int_equal(test_context->tctx,
544 				 test_context->tgs_req.pvno, 5,
545 				 "Got wrong as_req->pvno");
546 	torture_assert_int_equal(test_context->tctx,
547 				 test_context->tgs_req.req_body.kdc_options.canonicalize,
548 				 true,
549 				 "krb5 libs unexpectedly did not set canonicalize!");
550 
551 	torture_assert_int_equal(test_context->tctx,
552 				 test_context->tgs_req.req_body.sname->name_type,
553 				 KRB5_NT_PRINCIPAL,
554 				 "Mismatch in name_type between request and expected request");
555 
556 	torture_assert_str_equal(test_context->tctx,
557 				 test_context->tgs_req.req_body.realm,
558 				 test_context->test_data->real_realm,
559 				 "Mismatch in realm between request and expected request");
560 
561 	*modified_send_buf = *send_buf;
562 	return true;
563 }
564 
565 /*
566  * TEST_TGS_REQ_KRBTGT_CANON
567  *
568  * Confirm that the reply TGS-REP packet for krb5_get_creds()
569  * where the client is behaving as if this is a cross-realm trust due
570  * to case or netbios vs dns name differences meets certain
571  * expectations, while canonicalize is set
572  *
573  */
574 
torture_krb5_post_recv_tgs_req_krbtgt_canon_test(struct torture_krb5_context * test_context,const krb5_data * recv_buf)575 static bool torture_krb5_post_recv_tgs_req_krbtgt_canon_test(struct torture_krb5_context *test_context, const krb5_data *recv_buf)
576 {
577 	size_t used;
578 	torture_assert_int_equal(test_context->tctx,
579 				 decode_TGS_REP(recv_buf->data, recv_buf->length,
580 						&test_context->tgs_rep, &used),
581 				 0,
582 				 "decode_TGS_REP failed");
583 	torture_assert_int_equal(test_context->tctx, used, recv_buf->length, "length mismatch");
584 	torture_assert_int_equal(test_context->tctx,
585 				 test_context->tgs_rep.pvno, 5,
586 				 "Got wrong as_rep->pvno");
587 	torture_assert_int_equal(test_context->tctx,
588 				 test_context->tgs_rep.ticket.tkt_vno, 5,
589 				 "Got wrong as_rep->ticket.tkt_vno");
590 	torture_assert(test_context->tctx,
591 		       test_context->tgs_rep.ticket.enc_part.kvno,
592 		       "Did not get a KVNO in test_context->as_rep.ticket.enc_part.kvno");
593 	torture_assert_str_equal(test_context->tctx,
594 				 test_context->tgs_req.req_body.realm,
595 				 test_context->tgs_rep.ticket.realm,
596 				 "Mismatch in realm between request and ticket response");
597 	torture_assert_str_equal(test_context->tctx,
598 				 test_context->tgs_rep.ticket.realm,
599 				 test_context->test_data->real_realm,
600 				 "Mismatch in realm between ticket response and expected ticket response");
601 	torture_assert_int_equal(test_context->tctx,
602 				 test_context->tgs_rep.ticket.sname.name_type,
603 				 KRB5_NT_SRV_INST,
604 				 "Mismatch in name_type between ticket response and expected value of KRB5_NT_SRV_INST");
605 
606 	torture_assert_int_equal(test_context->tctx,
607 				 test_context->tgs_rep.ticket.sname.name_string.len,
608 				 2,
609 				 "Mismatch in name_type between ticket response and expected value, expected krbtgt/REALM@REALM");
610 
611 	torture_assert_str_equal(test_context->tctx,
612 				 test_context->tgs_rep.ticket.sname.name_string.val[0], "krbtgt",
613 				 "Mismatch in name between response and expected response, expected krbtgt");
614 	torture_assert_str_equal(test_context->tctx,
615 				 test_context->tgs_rep.ticket.sname.name_string.val[1], test_context->test_data->real_realm,
616 				 "Mismatch in realm part of krbtgt/ in expected response, expected krbtgt/REALM@REALM");
617 
618 	/*
619 	 * We can confirm that the correct proxy behaviour is
620 	 * in use on the KDC by checking the KVNO of the
621 	 * krbtgt account returned in the reply.
622 	 *
623 	 * A packet passed to the full RW DC will not have a
624 	 * KVNO in the upper bits, while a packet processed
625 	 * locally on the RODC will have these bits filled in
626 	 * the msDS-SecondaryKrbTgtNumber
627 	 */
628 	if (torture_setting_bool(test_context->tctx, "expect_cached_at_rodc", false)) {
629 		torture_assert_int_not_equal(test_context->tctx,
630 					     *test_context->tgs_rep.ticket.enc_part.kvno & 0xFFFF0000,
631 					     0, "Did not get a RODC number in the KVNO");
632 	} else {
633 		torture_assert_int_equal(test_context->tctx,
634 					 *test_context->tgs_rep.ticket.enc_part.kvno & 0xFFFF0000,
635 					 0, "Unexpecedly got a RODC number in the KVNO");
636 	}
637 	free_TGS_REP(&test_context->tgs_rep);
638 	torture_assert(test_context->tctx,
639 		       test_context->packet_count < 2,
640 		       "too many packets");
641 	free_TGS_REQ(&test_context->tgs_req);
642 	return true;
643 }
644 
645 /*
646  * TEST_TGS_REQ_CANON
647  *
648  * Confirm that the outgoing TGS-REQ packet from krb5_get_creds
649  * certain expectations, like that the canonicalize bit is set (this
650  * test is to force that handling) and that if an enterprise name was
651  * requested, that it was sent.
652  *
653  */
654 
torture_krb5_pre_send_tgs_req_canon_test(struct torture_krb5_context * test_context,const krb5_data * send_buf,krb5_data * modified_send_buf)655 static bool torture_krb5_pre_send_tgs_req_canon_test(struct torture_krb5_context *test_context,
656 						     const krb5_data *send_buf,
657 						     krb5_data *modified_send_buf)
658 {
659 	size_t used;
660 	torture_assert_int_equal(test_context->tctx,
661 				 decode_TGS_REQ(send_buf->data, send_buf->length,
662 						&test_context->tgs_req, &used),
663 				 0, "decode_TGS_REQ for TEST_TGS_REQ_CANON test failed");
664 	torture_assert_int_equal(test_context->tctx, used, send_buf->length, "length mismatch");
665 	torture_assert_int_equal(test_context->tctx, test_context->tgs_req.pvno, 5, "Got wrong as_req->pvno");
666 	torture_assert_int_equal(test_context->tctx,
667 				 test_context->tgs_req.req_body.kdc_options.canonicalize,
668 				 true, "krb5 libs unexpectedly did not set canonicalize!");
669 
670 	if (test_context->test_data->enterprise) {
671 		torture_assert_int_equal(test_context->tctx,
672 					 test_context->tgs_req.req_body.sname->name_type, KRB5_NT_ENTERPRISE_PRINCIPAL,
673 				 "Mismatch in name type between request and expected request, expected  KRB5_NT_ENTERPRISE_PRINCIPAL");
674 		torture_assert_str_equal(test_context->tctx,
675 					 test_context->tgs_req.req_body.realm, test_context->test_data->real_realm,
676 				 "Mismatch in realm between request and expected request");
677 
678 	} else if (test_context->test_data->as_req_spn) {
679 		torture_assert_int_equal(test_context->tctx,
680 					 test_context->tgs_req.req_body.sname->name_type, KRB5_NT_SRV_HST,
681 					 "Mismatch in name type between request and expected request, expected  KRB5_NT_SRV_HST");
682 		torture_assert_str_equal(test_context->tctx,
683 					 test_context->tgs_req.req_body.realm, test_context->test_data->real_realm,
684 				 "Mismatch in realm between request and expected request");
685 
686 	} else if (test_context->test_data->canonicalize) {
687 		torture_assert_int_equal(test_context->tctx,
688 					 test_context->tgs_req.req_body.sname->name_type, KRB5_NT_PRINCIPAL,
689 					 "Mismatch in name type between request and expected request, expected  KRB5_NT_PRINCIPAL");
690 		torture_assert_str_equal(test_context->tctx,
691 					 test_context->tgs_req.req_body.realm, test_context->test_data->real_realm,
692 				 "Mismatch in realm between request and expected request");
693 
694 	} else {
695 		torture_assert_int_equal(test_context->tctx,
696 					 test_context->tgs_req.req_body.sname->name_type, KRB5_NT_PRINCIPAL,
697 					 "Mismatch in name type between request and expected request, expected  KRB5_NT_PRINCIPAL");
698 		torture_assert_str_equal(test_context->tctx,
699 					 test_context->tgs_req.req_body.realm, test_context->test_data->realm,
700 				 "Mismatch in realm between request and expected request");
701 
702 	}
703 
704 	if (test_context->test_data->mitm_s4u2self) {
705 		torture_assert(test_context->tctx, change_for_user_principal(test_context, modified_send_buf),
706 			       "Failed to modify PA_FOR_USER principal name");
707 	} else {
708 		*modified_send_buf = *send_buf;
709 	}
710 
711 	return true;
712 }
713 
714 /*
715  * TEST_TGS_REQ_CANON - RECV
716  *
717  * Confirm that the reply TGS-REP or error packet from the KDC meets
718  * certain expectations as part of TEST_TGS_REQ_CANON.
719  *
720  * This is triggered by krb5_get_creds()
721  *
722  */
723 
torture_krb5_post_recv_tgs_req_canon_test(struct torture_krb5_context * test_context,const krb5_data * recv_buf)724 static bool torture_krb5_post_recv_tgs_req_canon_test(struct torture_krb5_context *test_context, const krb5_data *recv_buf)
725 {
726 	KRB_ERROR error;
727 	size_t used;
728 	krb5_error_code expected_error;
729 
730 	/*
731 	 * If this account did not have a servicePrincipalName, then
732 	 * we expect a errro packet, not a TGS-REQ
733 	 */
734 	if (decode_KRB_ERROR(recv_buf->data, recv_buf->length, &error, &used) == 0) {
735 		torture_assert_int_equal(test_context->tctx, used, recv_buf->length, "length mismatch");
736 		torture_assert_int_equal(test_context->tctx,
737 					 error.pvno, 5,
738 					 "Got wrong error.pvno");
739 		expected_error = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN - KRB5KDC_ERR_NONE;
740 		if (!test_context->test_data->mitm_s4u2self) {
741 			torture_assert_int_equal(test_context->tctx,
742 						 error.error_code,
743 						 expected_error,
744 						 "Got wrong error.error_code");
745 		}
746 	} else {
747 		torture_assert_int_equal(test_context->tctx,
748 					 decode_TGS_REP(recv_buf->data, recv_buf->length,
749 							&test_context->tgs_rep,
750 							&used),
751 					 0,
752 					 "decode_TGS_REP failed");
753 		torture_assert_int_equal(test_context->tctx,
754 					 used, recv_buf->length,
755 					 "length mismatch");
756 		torture_assert_int_equal(test_context->tctx,
757 					 test_context->tgs_rep.pvno, 5,
758 					 "Got wrong as_rep->pvno");
759 		torture_assert_int_equal(test_context->tctx,
760 					 test_context->tgs_rep.ticket.tkt_vno, 5,
761 					 "Got wrong as_rep->ticket.tkt_vno");
762 		torture_assert(test_context->tctx,
763 			       test_context->tgs_rep.ticket.enc_part.kvno,
764 			       "Did not get a KVNO in test_context->as_rep.ticket.enc_part.kvno");
765 		torture_assert_str_equal(test_context->tctx,
766 					 test_context->tgs_rep.ticket.realm,
767 					 test_context->test_data->real_realm,
768 					 "Mismatch in realm between ticket response and expected upper case REALM");
769 		torture_assert_int_equal(test_context->tctx,
770 					 test_context->tgs_rep.ticket.sname.name_type,
771 					 test_context->tgs_req.req_body.sname->name_type,
772 					 "Mismatch in name_type between request and ticket response");
773 		torture_assert_int_equal(test_context->tctx,
774 					 test_context->tgs_rep.ticket.sname.name_string.len,
775 					 test_context->tgs_req.req_body.sname->name_string.len,
776 					 "Mismatch in name_string.len between request and ticket response");
777 		torture_assert(test_context->tctx,
778 			       test_context->tgs_rep.ticket.sname.name_string.len >= 1,
779 			       "name_string.len should be >=1 in ticket response");
780 		torture_assert_str_equal(test_context->tctx,
781 					 test_context->tgs_rep.ticket.sname.name_string.val[0],
782 					 test_context->tgs_req.req_body.sname->name_string.val[0],
783 					 "Mismatch in name between request and expected request");
784 		torture_assert_int_equal(test_context->tctx,
785 					 *test_context->tgs_rep.ticket.enc_part.kvno & 0xFFFF0000,
786 					 0, "Unexpecedly got a RODC number in the KVNO, should just be principal KVNO");
787 		torture_assert(test_context->tctx, test_context->test_data->mitm_s4u2self == false,
788 			       "KDC accepted PA_S4U2Self with unkeyed checksum!");
789 		free_TGS_REP(&test_context->tgs_rep);
790 	}
791 	torture_assert(test_context->tctx, test_context->packet_count == 0, "too many packets");
792 	free_TGS_REQ(&test_context->tgs_req);
793 
794 	return true;
795 }
796 
797 /*
798  * TEST_SELF_TRUST_TGS_REQ
799  *
800  * Confirm that the outgoing TGS-REQ packet from krb5_mk_req_exact()
801  * certain expectations, like that the canonicalize bit is set (this
802  * test is to force that handling).
803  *
804  * This test is for the case where the name we ask for, while a valid
805  * alternate name for our own realm is used.  The client acts as if
806  * this is cross-realm trust.
807  *
808  */
809 
torture_krb5_pre_send_self_trust_tgs_req_test(struct torture_krb5_context * test_context,const krb5_data * send_buf,krb5_data * modified_send_buf)810 static bool torture_krb5_pre_send_self_trust_tgs_req_test(struct torture_krb5_context *test_context,
811 							  const krb5_data *send_buf,
812 							  krb5_data *modified_send_buf)
813 {
814 	size_t used;
815 	torture_assert_int_equal(test_context->tctx,
816 				 decode_TGS_REQ(send_buf->data, send_buf->length,
817 						&test_context->tgs_req, &used),
818 				 0, "decode_TGS_REQ for TEST_SELF_TRUST_TGS_REQ test failed");
819 	torture_assert_int_equal(test_context->tctx, used, send_buf->length, "length mismatch");
820 	torture_assert_int_equal(test_context->tctx, test_context->tgs_req.pvno, 5, "Got wrong as_req->pvno");
821 
822 	if (test_context->test_data->enterprise
823 	    || (test_context->test_data->spn_is_upn && test_context->test_data->upn)) {
824 		torture_assert_int_equal(test_context->tctx,
825 					 test_context->tgs_req.req_body.kdc_options.canonicalize,
826 					 true,
827 					 "krb5 libs unexpectedly"
828 					 " did not set canonicalize!");
829 	} else {
830 		torture_assert_int_equal(test_context->tctx,
831 					 test_context->tgs_req.req_body.kdc_options.canonicalize,
832 					 false,
833 					 "krb5 libs unexpectedly"
834 					 " set canonicalize!");
835 	}
836 
837 
838 	if (test_context->test_data->canonicalize) {
839 		torture_assert_str_equal(test_context->tctx,
840 					 test_context->tgs_req.req_body.realm,
841 					 test_context->test_data->real_realm,
842 					 "Mismatch in realm between request and expected request");
843 	} else {
844 		torture_assert_str_equal(test_context->tctx,
845 					 test_context->tgs_req.req_body.realm,
846 					 test_context->test_data->realm,
847 					 "Mismatch in realm between request and expected request");
848 	}
849 	torture_assert_int_equal(test_context->tctx,
850 				 test_context->tgs_req.req_body.sname->name_type, KRB5_NT_PRINCIPAL,
851 				 "Mismatch in name type between request and expected request, expected  KRB5_NT_PRINCIPAL");
852 	torture_assert_int_equal(test_context->tctx,
853 				 test_context->tgs_req.req_body.sname->name_string.len, 2,
854 				 "Mismatch in name between request and expected request, expected krbtgt/realm");
855 	torture_assert_str_equal(test_context->tctx,
856 				 test_context->tgs_req.req_body.sname->name_string.val[0], "krbtgt",
857 				 "Mismatch in name between request and expected request, expected krbtgt");
858 	torture_assert_str_equal(test_context->tctx,
859 				 test_context->tgs_req.req_body.sname->name_string.val[1], test_context->test_data->realm,
860 				 "Mismatch in realm part of cross-realm request principal between request and expected request");
861 	*modified_send_buf = *send_buf;
862 
863 	return true;
864 }
865 
866 /*
867  * TEST_SELF_TRUST_TGS_REQ and TEST_TGS_REQ_KRBTGT - RECV
868  *
869  * Confirm that the reply TGS-REP packet for krb5_mk_req_exact(),
870  * where the client is behaving as if this is a cross-realm trust due
871  * to case or netbios vs dns name differences meets certain
872  * expectations.
873  *
874  */
875 
torture_krb5_post_recv_self_trust_tgs_req_test(struct torture_krb5_context * test_context,const krb5_data * recv_buf)876 static bool torture_krb5_post_recv_self_trust_tgs_req_test(struct torture_krb5_context *test_context, const krb5_data *recv_buf)
877 {
878 	size_t used;
879 	torture_assert_int_equal(test_context->tctx,
880 				 decode_TGS_REP(recv_buf->data, recv_buf->length,
881 						&test_context->tgs_rep, &used),
882 				 0,
883 				 "decode_TGS_REP failed");
884 	torture_assert_int_equal(test_context->tctx, used, recv_buf->length, "length mismatch");
885 	torture_assert_int_equal(test_context->tctx,
886 				 test_context->tgs_rep.pvno, 5,
887 				 "Got wrong as_rep->pvno");
888 	torture_assert_int_equal(test_context->tctx,
889 				 test_context->tgs_rep.ticket.tkt_vno, 5,
890 				 "Got wrong as_rep->ticket.tkt_vno");
891 	torture_assert(test_context->tctx,
892 		       test_context->tgs_rep.ticket.enc_part.kvno,
893 		       "Did not get a KVNO in test_context->as_rep.ticket.enc_part.kvno");
894 	torture_assert_str_equal(test_context->tctx,
895 				 test_context->tgs_req.req_body.realm,
896 				 test_context->tgs_rep.ticket.realm,
897 				 "Mismatch in realm between request and ticket response");
898 	torture_assert_int_equal(test_context->tctx,
899 				 test_context->tgs_rep.ticket.sname.name_type,
900 				 test_context->tgs_req.req_body.sname->name_type,
901 				 "Mismatch in name_type between request and ticket response");
902 
903 	torture_assert_int_equal(test_context->tctx,
904 				 test_context->tgs_rep.ticket.sname.name_string.len, 2,
905 				 "Mismatch in name between request and expected request, expected krbtgt/realm");
906 	torture_assert_str_equal(test_context->tctx,
907 				 test_context->tgs_rep.ticket.sname.name_string.val[0], "krbtgt",
908 				 "Mismatch in name between request and expected request, expected krbtgt");
909 	torture_assert_str_equal(test_context->tctx,
910 				 test_context->tgs_rep.ticket.sname.name_string.val[1], test_context->test_data->realm,
911 				 "Mismatch in realm part of cross-realm request principal between response and expected request");
912 	/*
913 	 * We can confirm that the correct proxy behaviour is
914 	 * in use on the KDC by checking the KVNO of the
915 	 * krbtgt account returned in the reply.
916 	 *
917 	 * A packet passed to the full RW DC will not have a
918 	 * KVNO in the upper bits, while a packet processed
919 	 * locally on the RODC will have these bits filled in
920 	 * the msDS-SecondaryKrbTgtNumber
921 	 */
922 	if (torture_setting_bool(test_context->tctx, "expect_cached_at_rodc", false)) {
923 		torture_assert_int_not_equal(test_context->tctx,
924 					     *test_context->tgs_rep.ticket.enc_part.kvno & 0xFFFF0000,
925 					     0, "Did not get a RODC number in the KVNO");
926 	} else {
927 		torture_assert_int_equal(test_context->tctx,
928 					 *test_context->tgs_rep.ticket.enc_part.kvno & 0xFFFF0000,
929 					 0, "Unexpecedly got a RODC number in the KVNO");
930 	}
931 	free_TGS_REP(&test_context->tgs_rep);
932 	torture_assert_int_equal(test_context->tctx,
933 				 test_context->packet_count, 0,
934 				 "too many packets");
935 	test_context->packet_count = 0;
936 	test_context->test_stage = TEST_TGS_REQ;
937 	free_TGS_REQ(&test_context->tgs_req);
938 	return true;
939 }
940 
941 /*
942  * TEST_TGS_REQ
943  *
944  * Confirm that the outgoing TGS-REQ packet from krb5_mk_req_exact()
945  * certain expectations, like that the canonicalize bit is set (this
946  * test is to force that handling) and that if an enterprise name was
947  * requested, that it was sent.
948  *
949  */
950 
torture_krb5_pre_send_tgs_req_test(struct torture_krb5_context * test_context,const krb5_data * send_buf,krb5_data * modified_send_buf)951 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)
952 {
953 	size_t used;
954 	torture_assert_int_equal(test_context->tctx,
955 				 decode_TGS_REQ(send_buf->data, send_buf->length,
956 						&test_context->tgs_req, &used),
957 				 0, "decode_TGS_REQ for TEST_TGS_REQ test failed");
958 	torture_assert_int_equal(test_context->tctx, used, send_buf->length, "length mismatch");
959 	torture_assert_int_equal(test_context->tctx, test_context->tgs_req.pvno, 5,
960 				 "Got wrong as_req->pvno");
961 
962 	if (test_context->test_data->enterprise
963 	    && test_context->test_data->s4u2self == false
964 	    && test_context->test_data->spn_is_upn) {
965 		torture_assert_int_equal(test_context->tctx,
966 					 test_context->tgs_req.req_body.kdc_options.canonicalize,
967 					 true,
968 					 "krb5 libs unexpectedly"
969 					 " did not set canonicalize!");
970 	} else {
971 		torture_assert_int_equal(test_context->tctx,
972 					 test_context->tgs_req.req_body.kdc_options.canonicalize,
973 					 false,
974 					 "krb5 libs unexpectedly"
975 					 " set canonicalize!");
976 	}
977 
978 	if (test_context->test_data->enterprise) {
979 		torture_assert_int_equal(test_context->tctx,
980 					 test_context->tgs_req.req_body.sname->name_type,
981 					 KRB5_NT_ENTERPRISE_PRINCIPAL,
982 					 "Mismatch in name type between request and expected request, expected  KRB5_NT_ENTERPRISE_PRINCIPAL");
983 		torture_assert_str_equal(test_context->tctx,
984 					 test_context->tgs_req.req_body.realm,
985 					 test_context->test_data->real_realm,
986 					 "Mismatch in realm between request and expected request");
987 
988 	} else if (test_context->test_data->spn_is_upn && test_context->test_data->upn && test_context->test_data->canonicalize) {
989 		torture_assert_int_equal(test_context->tctx,
990 					 test_context->tgs_req.req_body.sname->name_type,
991 					 KRB5_NT_PRINCIPAL,
992 					 "Mismatch in name type between request and expected request, expected  KRB5_NT_PRINCIPAL");
993 		torture_assert_str_equal(test_context->tctx,
994 					 test_context->tgs_req.req_body.realm,
995 					 test_context->test_data->real_realm,
996 					 "Mismatch in realm between request and expected request");
997 
998 	} else if (test_context->test_data->spn_is_upn
999 		   && test_context->test_data->as_req_spn
1000 		   && test_context->test_data->canonicalize == false) {
1001 		torture_assert_int_equal(test_context->tctx,
1002 					 test_context->tgs_req.req_body.sname->name_type,
1003 					 KRB5_NT_SRV_HST,
1004 					 "Mismatch in name type between request and expected request, expected  KRB5_NT_SRV_HST");
1005 		torture_assert_str_equal(test_context->tctx,
1006 					 test_context->tgs_req.req_body.realm,
1007 					 test_context->test_data->realm,
1008 					 "Mismatch in realm between request and expected request");
1009 
1010 	} else {
1011 		torture_assert_int_equal(test_context->tctx,
1012 					 test_context->tgs_req.req_body.sname->name_type,
1013 					 KRB5_NT_PRINCIPAL,
1014 					 "Mismatch in name type between request and expected request, expected  KRB5_NT_PRINCIPAL");
1015 		torture_assert_str_equal(test_context->tctx,
1016 					 test_context->tgs_req.req_body.realm,
1017 					 test_context->test_data->realm,
1018 					 "Mismatch in realm between request and expected request");
1019 
1020 	}
1021 
1022 	*modified_send_buf = *send_buf;
1023 
1024 	return true;
1025 }
1026 
1027 /*
1028  * TEST_TGS_REQ - RECV
1029  *
1030  * Confirm that the reply TGS-REP packet for krb5_mk_req_exact(), for
1031  * the actual target service.
1032  *
1033  */
1034 
torture_krb5_post_recv_tgs_req_test(struct torture_krb5_context * test_context,const krb5_data * recv_buf)1035 static bool torture_krb5_post_recv_tgs_req_test(struct torture_krb5_context *test_context, const krb5_data *recv_buf)
1036 {
1037 	KRB_ERROR error;
1038 	size_t used;
1039 	/*
1040 	 * If this account did not have a servicePrincipalName, then
1041 	 * we expect a errro packet, not a TGS-REQ
1042 	 */
1043 	if (decode_KRB_ERROR(recv_buf->data, recv_buf->length, &error, &used) == 0) {
1044 		torture_assert_int_equal(test_context->tctx,
1045 					 used, recv_buf->length,
1046 					 "length mismatch");
1047 		torture_assert_int_equal(test_context->tctx,
1048 					 error.pvno, 5,
1049 					 "Got wrong error.pvno");
1050 		torture_assert_int_equal(test_context->tctx,
1051 					 error.error_code,
1052 					 KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN - KRB5KDC_ERR_NONE,
1053 					 "Got wrong error.error_code");
1054 	} else {
1055 		torture_assert_int_equal(test_context->tctx,
1056 					 decode_TGS_REP(recv_buf->data, recv_buf->length,
1057 							&test_context->tgs_rep, &used),
1058 					 0,
1059 					 "decode_TGS_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->tgs_rep.pvno, 5,
1064 					 "Got wrong as_rep->pvno");
1065 		torture_assert_int_equal(test_context->tctx,
1066 					 test_context->tgs_rep.ticket.tkt_vno, 5,
1067 					 "Got wrong as_rep->ticket.tkt_vno");
1068 		torture_assert(test_context->tctx,
1069 			       test_context->tgs_rep.ticket.enc_part.kvno,
1070 			       "Did not get a KVNO in test_context->as_rep.ticket.enc_part.kvno");
1071 		torture_assert_str_equal(test_context->tctx,
1072 					 test_context->tgs_rep.ticket.realm,
1073 					 test_context->test_data->real_realm,
1074 					 "Mismatch in realm between ticket response and expected upper case REALM");
1075 		torture_assert_int_equal(test_context->tctx,
1076 					 test_context->tgs_req.req_body.sname->name_type,
1077 					 test_context->tgs_rep.ticket.sname.name_type, "Mismatch in name_type between request and ticket response");
1078 		torture_assert_int_equal(test_context->tctx,
1079 					 *test_context->tgs_rep.ticket.enc_part.kvno & 0xFFFF0000,
1080 					 0, "Unexpecedly got a RODC number in the KVNO, should just be principal KVNO");
1081 		free_TGS_REP(&test_context->tgs_rep);
1082 	}
1083 	torture_assert(test_context->tctx, test_context->packet_count < 3, "too many packets");
1084 	free_TGS_REQ(&test_context->tgs_req);
1085 	test_context->test_stage = TEST_DONE;
1086 	return true;
1087 }
1088 
1089 /*
1090  * TEST_TGS_REQ_KRBTGT
1091  *
1092  *
1093  * Confirm that the outgoing TGS-REQ packet from krb5_mk_req_exact()
1094  * for the krbtgt/realm principal meets certain expectations, like
1095  * that the canonicalize bit is not set
1096  *
1097  */
1098 
torture_krb5_pre_send_tgs_req_krbtgt_test(struct torture_krb5_context * test_context,const krb5_data * send_buf,krb5_data * modified_send_buf)1099 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)
1100 {
1101 	size_t used;
1102 	torture_assert_int_equal(test_context->tctx,
1103 				 decode_TGS_REQ(send_buf->data, send_buf->length,
1104 						&test_context->tgs_req, &used),
1105 				 0, "decode_TGS_REQ for TEST_TGS_REQ test failed");
1106 	torture_assert_int_equal(test_context->tctx,
1107 				 used, send_buf->length,
1108 				 "length mismatch");
1109 	torture_assert_int_equal(test_context->tctx,
1110 				 test_context->tgs_req.pvno, 5,
1111 				 "Got wrong as_req->pvno");
1112 	torture_assert_int_equal(test_context->tctx,
1113 				 test_context->tgs_req.req_body.kdc_options.canonicalize,
1114 				 false,
1115 				 "krb5 libs unexpectedly set canonicalize!");
1116 
1117 	torture_assert_str_equal(test_context->tctx,
1118 				 test_context->tgs_req.req_body.realm,
1119 				 test_context->test_data->realm,
1120 				 "Mismatch in realm between request and expected request");
1121 
1122 	*modified_send_buf = *send_buf;
1123 	test_context->test_stage = TEST_DONE;
1124 	return true;
1125 }
1126 
1127 /*
1128  * TEST_TGS_REQ_HOST, TEST_TGS_REQ_HOST_SRV_INST and TEST_TGS_REQ_HOST_SRV_HST
1129  *
1130  *
1131  * Confirm that the outgoing TGS-REQ packet from krb5_mk_req_exact()
1132  * for the krbtgt/realm principal meets certain expectations, like
1133  * that the canonicalize bit is not set
1134  *
1135  */
1136 
torture_krb5_pre_send_tgs_req_host_test(struct torture_krb5_context * test_context,const krb5_data * send_buf,krb5_data * modified_send_buf)1137 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)
1138 {
1139 	size_t used;
1140 	torture_assert_int_equal(test_context->tctx,
1141 				 decode_TGS_REQ(send_buf->data, send_buf->length,
1142 						&test_context->tgs_req, &used),
1143 				 0, "decode_TGS_REQ for TEST_TGS_REQ test failed");
1144 	torture_assert_int_equal(test_context->tctx,
1145 				 used, send_buf->length,
1146 				 "length mismatch");
1147 	torture_assert_int_equal(test_context->tctx,
1148 				 test_context->tgs_req.pvno, 5,
1149 				 "Got wrong as_req->pvno");
1150 	torture_assert_int_equal(test_context->tctx,
1151 				 test_context->tgs_req.req_body.sname->name_string.len, 2,
1152 				 "Mismatch in name between request and expected request, expected krbtgt/realm");
1153 		torture_assert_int_equal(test_context->tctx,
1154 					 test_context->tgs_req.req_body.kdc_options.canonicalize,
1155 					 true,
1156 					 "krb5 libs unexpectedly did not set canonicalize!");
1157 
1158 	if (test_context->test_stage == TEST_TGS_REQ_HOST_SRV_INST) {
1159 		torture_assert_int_equal(test_context->tctx,
1160 					 test_context->tgs_req.req_body.sname->name_type, KRB5_NT_SRV_INST,
1161 					 "Mismatch in name type between request and expected request, expected KRB5_NT_SRV_INST");
1162 		torture_assert_str_equal(test_context->tctx,
1163 					 test_context->tgs_req.req_body.sname->name_string.val[0],
1164 					 strupper_talloc(test_context, test_context->test_data->krb5_service),
1165 					 "Mismatch in name between request and expected request, expected service");
1166 		torture_assert_str_equal(test_context->tctx,
1167 					 test_context->tgs_req.req_body.sname->name_string.val[1],
1168 					 test_context->test_data->krb5_hostname,
1169 					 "Mismatch in hostname part between request and expected request");
1170 
1171 	} else if (test_context->test_stage == TEST_TGS_REQ_HOST_SRV_HST) {
1172 
1173 		torture_assert_int_equal(test_context->tctx,
1174 					 test_context->tgs_req.req_body.sname->name_type, KRB5_NT_SRV_HST,
1175 					 "Mismatch in name type between request and expected request, expected KRB5_NT_SRV_HST");
1176 		torture_assert_str_equal(test_context->tctx,
1177 					 test_context->tgs_req.req_body.sname->name_string.val[0],
1178 					 test_context->test_data->krb5_service,
1179 					 "Mismatch in name between request and expected request, expected service");
1180 		torture_assert_str_equal(test_context->tctx,
1181 					 test_context->tgs_req.req_body.sname->name_string.val[1],
1182 					 strupper_talloc(test_context, test_context->test_data->krb5_hostname),
1183 					 "Mismatch in hostname part between request and expected request");
1184 
1185 	} else {
1186 		torture_assert_int_equal(test_context->tctx,
1187 					 test_context->tgs_req.req_body.sname->name_type, KRB5_NT_PRINCIPAL,
1188 					 "Mismatch in name type between request and expected request, expected  KRB5_NT_PRINCIPAL");
1189 		torture_assert_str_equal(test_context->tctx,
1190 					 test_context->tgs_req.req_body.sname->name_string.val[0],
1191 					 test_context->test_data->krb5_service,
1192 					 "Mismatch in name between request and expected request, expected service");
1193 		torture_assert_str_equal(test_context->tctx,
1194 					 test_context->tgs_req.req_body.sname->name_string.val[1],
1195 					 test_context->test_data->krb5_hostname,
1196 					 "Mismatch in hostname part between request and expected request");
1197 
1198 	}
1199 	torture_assert_str_equal(test_context->tctx,
1200 				 test_context->tgs_req.req_body.realm,
1201 				 test_context->test_data->real_realm,
1202 				 "Mismatch in realm between request and expected request");
1203 
1204 	*modified_send_buf = *send_buf;
1205 	return true;
1206 }
1207 
1208 /*
1209  * TEST_TGS_REQ_HOST, TEST_TGS_REQ_HOST_SRV_INST, TEST_TGS_REQ_HOST_SRV_HST - RECV
1210  *
1211  * Confirm that the reply TGS-REP packet for krb5_mk_req(), for
1212  * the actual target service, as a SPN, not a any other name type.
1213  *
1214  */
1215 
torture_krb5_post_recv_tgs_req_host_test(struct torture_krb5_context * test_context,const krb5_data * recv_buf)1216 static bool torture_krb5_post_recv_tgs_req_host_test(struct torture_krb5_context *test_context, const krb5_data *recv_buf)
1217 {
1218 	size_t used;
1219 	torture_assert_int_equal(test_context->tctx,
1220 				 decode_TGS_REP(recv_buf->data, recv_buf->length,
1221 						&test_context->tgs_rep, &used),
1222 				 0,
1223 				 "decode_TGS_REP failed");
1224 	torture_assert_int_equal(test_context->tctx, used, recv_buf->length,
1225 				 "length mismatch");
1226 	torture_assert_int_equal(test_context->tctx,
1227 				 test_context->tgs_rep.pvno, 5,
1228 				 "Got wrong as_rep->pvno");
1229 	torture_assert_int_equal(test_context->tctx,
1230 				 test_context->tgs_rep.ticket.tkt_vno, 5,
1231 				 "Got wrong as_rep->ticket.tkt_vno");
1232 	torture_assert(test_context->tctx,
1233 		       test_context->tgs_rep.ticket.enc_part.kvno,
1234 		       "Did not get a KVNO in test_context->as_rep.ticket.enc_part.kvno");
1235 	torture_assert_str_equal(test_context->tctx,
1236 				 test_context->tgs_rep.ticket.realm,
1237 				 test_context->test_data->real_realm,
1238 				 "Mismatch in realm between ticket response and expected upper case REALM");
1239 	torture_assert_int_equal(test_context->tctx,
1240 				 test_context->tgs_req.req_body.sname->name_type,
1241 				 test_context->tgs_rep.ticket.sname.name_type, "Mismatch in name_type between request and ticket response");
1242 	torture_assert_int_equal(test_context->tctx,
1243 				 test_context->tgs_rep.ticket.sname.name_string.len, 2,
1244 				 "Mismatch in name between request and expected request, expected service/hostname");
1245 	torture_assert_str_equal(test_context->tctx,
1246 				 test_context->tgs_rep.ticket.sname.name_string.val[0],
1247 				 test_context->tgs_req.req_body.sname->name_string.val[0],
1248 				 "Mismatch in name between request and expected request, expected service/hostname");
1249 	torture_assert_str_equal(test_context->tctx,
1250 				 test_context->tgs_rep.ticket.sname.name_string.val[1],
1251 				 test_context->tgs_req.req_body.sname->name_string.val[1],
1252 				 "Mismatch in name between request and expected request, expected service/hostname");
1253 
1254 	torture_assert_int_equal(test_context->tctx,
1255 				 *test_context->tgs_rep.ticket.enc_part.kvno & 0xFFFF0000,
1256 				 0, "Unexpecedly got a RODC number in the KVNO, should just be principal KVNO");
1257 	free_TGS_REP(&test_context->tgs_rep);
1258 
1259 	torture_assert(test_context->tctx, test_context->packet_count < 2, "too many packets");
1260 	return true;
1261 }
1262 
1263 /*
1264  * TEST_AS_REQ_SELF - RECV
1265  *
1266  * Confirm that the reply packet from the KDC meets certain
1267  * expectations as part of TEST_AS_REQ.  This uses a packet count to
1268  * work out what packet we are up to in the multiple exchanged
1269  * triggerd by krb5_get_init_creds_password().
1270  *
1271  */
1272 
torture_krb5_post_recv_as_req_self_test(struct torture_krb5_context * test_context,const krb5_data * recv_buf)1273 static bool torture_krb5_post_recv_as_req_self_test(struct torture_krb5_context *test_context,
1274 						    const krb5_data *recv_buf)
1275 {
1276 	KRB_ERROR error;
1277 	size_t used;
1278 	if (test_context->packet_count == 0) {
1279 		krb5_error_code k5ret;
1280 		/*
1281 		 * The client libs obtain the salt by attempting to
1282 		 * authenticate without pre-authentication and getting
1283 		 * the correct salt with the
1284 		 * KRB5KDC_ERR_PREAUTH_REQUIRED error.  If we are in
1285 		 * the test (netbios_realm && upn) that deliberatly
1286 		 * has an incorrect principal, we check we get the
1287 		 * correct error.
1288 		 */
1289 		k5ret = decode_KRB_ERROR(recv_buf->data, recv_buf->length,
1290 					 &error, &used);
1291 		if (k5ret != 0) {
1292 			AS_REP as_rep;
1293 			k5ret = decode_AS_REP(recv_buf->data, recv_buf->length,
1294 				      &as_rep, &used);
1295 			if (k5ret == 0) {
1296 				if (torture_setting_bool(test_context->tctx, "expect_machine_account", false) == false
1297 				    || (test_context->test_data->upn == true)) {
1298 					torture_assert(test_context->tctx, false,
1299 						       "expected to get a KRB_ERROR packet with "
1300 						       "KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN or KRB5KDC_ERR_PREAUTH_REQUIRED, got valid AS-REP");
1301 				} else {
1302 					torture_assert(test_context->tctx, false,
1303 						       "expected to get a KRB_ERROR packet with "
1304 						       "KRB5KDC_ERR_PREAUTH_REQUIRED, got valid AS-REP");
1305 				}
1306 			} else {
1307 				if (torture_setting_bool(test_context->tctx, "expect_machine_account", false) == false
1308 				    || (test_context->test_data->upn == true)) {
1309 					torture_assert(test_context->tctx, false,
1310 						       "unable to decode as KRB-ERROR or AS-REP, "
1311 						       "expected to get a KRB_ERROR packet with KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN or KRB5KDC_ERR_PREAUTH_REQUIRED");
1312 				} else {
1313 					torture_assert(test_context->tctx, false,
1314 						       "unable to decode as KRB-ERROR or AS-REP, "
1315 						       "expected to get a KRB_ERROR packet with KRB5KDC_ERR_PREAUTH_REQUIRED");
1316 				}
1317 			}
1318 		}
1319 		torture_assert_int_equal(test_context->tctx, used, recv_buf->length,
1320 					 "length mismatch");
1321 		torture_assert_int_equal(test_context->tctx, error.pvno, 5,
1322 					 "Got wrong error.pvno");
1323 		if ((torture_setting_bool(test_context->tctx, "expect_machine_account", false) == false
1324 		     || (test_context->test_data->upn == true))
1325 		    && error.error_code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN - KRB5KDC_ERR_NONE) {
1326 			/*
1327 			 * IGNORE
1328 			 *
1329 			 * This case is because Samba's Heimdal KDC
1330 			 * checks server and client accounts before
1331 			 * checking for pre-authentication.
1332 			 */
1333 		} else {
1334 			torture_assert_int_equal(test_context->tctx,
1335 						 error.error_code,
1336 						 KRB5KDC_ERR_PREAUTH_REQUIRED - KRB5KDC_ERR_NONE,
1337 						 "Got wrong error.error_code");
1338 		}
1339 
1340 		free_KRB_ERROR(&error);
1341 	} else if ((decode_KRB_ERROR(recv_buf->data, recv_buf->length, &error, &used) == 0)
1342 		   && (test_context->packet_count == 1)) {
1343 		/*
1344 		 * The Windows 2012R2 KDC will always respond with
1345 		 * KRB5KRB_ERR_RESPONSE_TOO_BIG over UDP as the ticket
1346 		 * won't fit, because of the PAC.  (It appears to do
1347 		 * this always, even if it will).  This triggers the
1348 		 * client to try again over TCP.
1349 		 */
1350 		torture_assert_int_equal(test_context->tctx,
1351 					 used, recv_buf->length,
1352 					 "length mismatch");
1353 		torture_assert_int_equal(test_context->tctx,
1354 					 error.pvno, 5,
1355 					 "Got wrong error.pvno");
1356 		if ((torture_setting_bool(test_context->tctx, "expect_machine_account", false)
1357 		     && ((test_context->test_data->upn == false)
1358 			 || (test_context->test_data->as_req_spn &&
1359 			     test_context->test_data->spn_is_upn)
1360 			 || (test_context->test_data->enterprise == false &&
1361 			     test_context->test_data->upn &&
1362 			    test_context->test_data->spn_is_upn)))) {
1363 			torture_assert_int_equal(test_context->tctx,
1364 						 error.error_code,
1365 						 KRB5KRB_ERR_RESPONSE_TOO_BIG - KRB5KDC_ERR_NONE,
1366 						 "Got wrong error.error_code");
1367 		} else {
1368 			torture_assert_int_equal(test_context->tctx,
1369 						 error.error_code,
1370 						 KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN - KRB5KDC_ERR_NONE,
1371 						 "Got wrong error.error_code");
1372 		}
1373 		free_KRB_ERROR(&error);
1374 	} else {
1375 		/*
1376 		 * Finally the successful packet.
1377 		 */
1378 		torture_assert_int_equal(test_context->tctx,
1379 					 decode_AS_REP(recv_buf->data, recv_buf->length,
1380 						       &test_context->as_rep, &used), 0,
1381 					 "decode_AS_REP failed");
1382 		torture_assert_int_equal(test_context->tctx, used, recv_buf->length,
1383 					 "length mismatch");
1384 		torture_assert_int_equal(test_context->tctx,
1385 					 test_context->as_rep.pvno, 5,
1386 					 "Got wrong as_rep->pvno");
1387 		torture_assert_int_equal(test_context->tctx,
1388 					 test_context->as_rep.ticket.tkt_vno, 5,
1389 					 "Got wrong as_rep->ticket.tkt_vno");
1390 		torture_assert(test_context->tctx,
1391 			       test_context->as_rep.ticket.enc_part.kvno,
1392 			       "Did not get a KVNO in test_context->as_rep.ticket.enc_part.kvno");
1393 
1394 		/*
1395 		 * We do not expect an RODC number here in the KVNO,
1396 		 * as this is a ticket to the user's own account.
1397 		 */
1398 		torture_assert_int_equal(test_context->tctx,
1399 					 *test_context->as_rep.ticket.enc_part.kvno & 0xFFFF0000,
1400 					 0, "Unexpecedly got a RODC number in the KVNO");
1401 		free_AS_REP(&test_context->as_rep);
1402 	}
1403 	torture_assert(test_context->tctx, test_context->packet_count < 3, "too many packets");
1404 	free_AS_REQ(&test_context->as_req);
1405 	return true;
1406 }
1407 
1408 /*
1409  * This function is set in torture_krb5_init_context_canon as krb5
1410  * send_and_recv function.  This allows us to override what server the
1411  * test is aimed at, and to inspect the packets just before they are
1412  * sent to the network, and before they are processed on the recv
1413  * side.
1414  *
1415  * The torture_krb5_pre_send_test() and torture_krb5_post_recv_test()
1416  * functions are implement the actual tests.
1417  *
1418  * When this asserts, the caller will get a spurious 'cannot contact
1419  * any KDC' message.
1420  *
1421  */
smb_krb5_send_and_recv_func_canon_override(krb5_context context,void * data,krb5_krbhst_info * hi,time_t timeout,const krb5_data * send_buf,krb5_data * recv_buf)1422 static krb5_error_code smb_krb5_send_and_recv_func_canon_override(krb5_context context,
1423 								   void *data, /* struct torture_krb5_context */
1424 								   krb5_krbhst_info *hi,
1425 								   time_t timeout,
1426 								   const krb5_data *send_buf,
1427 								   krb5_data *recv_buf)
1428 {
1429 	krb5_error_code k5ret;
1430 	bool ok = false;
1431 	krb5_data modified_send_buf;
1432 
1433 	struct torture_krb5_context *test_context
1434 		= talloc_get_type_abort(data, struct torture_krb5_context);
1435 
1436 	switch (test_context->test_stage) {
1437 	case TEST_DONE:
1438 		torture_warning(test_context->tctx, "Unexpected outgoing packet from krb5 libs");
1439 		return EINVAL;
1440 	case TEST_AS_REQ:
1441 		ok = torture_krb5_pre_send_as_req_test(test_context, send_buf,
1442 							      &modified_send_buf);
1443 		break;
1444 	case TEST_TGS_REQ_KRBTGT_CANON:
1445 		ok = torture_krb5_pre_send_tgs_req_krbtgt_canon_test(test_context, send_buf,
1446 								     &modified_send_buf);
1447 		break;
1448 	case TEST_TGS_REQ_CANON:
1449 		ok = torture_krb5_pre_send_tgs_req_canon_test(test_context, send_buf,
1450 							      &modified_send_buf);
1451 		break;
1452 	case TEST_SELF_TRUST_TGS_REQ:
1453 		ok = torture_krb5_pre_send_self_trust_tgs_req_test(test_context, send_buf,
1454 								   &modified_send_buf);
1455 		break;
1456 	case TEST_TGS_REQ:
1457 		ok = torture_krb5_pre_send_tgs_req_test(test_context, send_buf,
1458 							&modified_send_buf);
1459 		break;
1460 	case TEST_TGS_REQ_KRBTGT:
1461 		ok = torture_krb5_pre_send_tgs_req_krbtgt_test(test_context, send_buf,
1462 							       &modified_send_buf);
1463 		break;
1464 	case TEST_TGS_REQ_HOST:
1465 	case TEST_TGS_REQ_HOST_SRV_INST:
1466 	case TEST_TGS_REQ_HOST_SRV_HST:
1467 		ok = torture_krb5_pre_send_tgs_req_host_test(test_context, send_buf,
1468 							     &modified_send_buf);
1469 		break;
1470 	case TEST_AS_REQ_SELF:
1471 		ok = torture_krb5_pre_send_as_req_test(test_context, send_buf,
1472 						       &modified_send_buf);
1473 		break;
1474 	}
1475 	if (ok == false) {
1476 		return EINVAL;
1477 	}
1478 
1479 	k5ret = smb_krb5_send_and_recv_func_forced(context, test_context->server,
1480 						   hi, timeout, &modified_send_buf,
1481 						   recv_buf);
1482 	if (k5ret != 0) {
1483 		return k5ret;
1484 	}
1485 
1486 	switch (test_context->test_stage) {
1487 	case TEST_DONE:
1488 		torture_warning(test_context->tctx, "Unexpected outgoing packet from krb5 libs");
1489 		return EINVAL;
1490 	case TEST_AS_REQ:
1491 		ok = torture_krb5_post_recv_as_req_test(test_context, recv_buf);
1492 		break;
1493 	case TEST_TGS_REQ_KRBTGT_CANON:
1494 		ok = torture_krb5_post_recv_tgs_req_krbtgt_canon_test(test_context, recv_buf);
1495 		break;
1496 	case TEST_TGS_REQ_CANON:
1497 		ok = torture_krb5_post_recv_tgs_req_canon_test(test_context, recv_buf);
1498 		break;
1499 	case TEST_SELF_TRUST_TGS_REQ:
1500 		ok = torture_krb5_post_recv_self_trust_tgs_req_test(test_context, recv_buf);
1501 		break;
1502 	case TEST_TGS_REQ:
1503 		ok = torture_krb5_post_recv_tgs_req_test(test_context, recv_buf);
1504 		break;
1505 	case TEST_TGS_REQ_KRBTGT:
1506 		ok = torture_krb5_post_recv_self_trust_tgs_req_test(test_context, recv_buf);
1507 		break;
1508 	case TEST_TGS_REQ_HOST:
1509 	case TEST_TGS_REQ_HOST_SRV_INST:
1510 	case TEST_TGS_REQ_HOST_SRV_HST:
1511 		ok = torture_krb5_post_recv_tgs_req_host_test(test_context, recv_buf);
1512 		break;
1513 	case TEST_AS_REQ_SELF:
1514 		ok = torture_krb5_post_recv_as_req_self_test(test_context, recv_buf);
1515 		break;
1516 	}
1517 	if (ok == false) {
1518 		KRB_ERROR error;
1519 		size_t used;
1520 		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);
1521 		if (decode_KRB_ERROR(recv_buf->data, recv_buf->length, &error, &used) == 0) {
1522 			torture_warning(test_context->tctx,
1523 					"STAGE: %d Unexpectedly got a KRB-ERROR packet "
1524 					"with error code %d (%s)",
1525 					test_context->test_stage,
1526 					error.error_code,
1527 					error_message(error.error_code + KRB5KDC_ERR_NONE));
1528 			free_KRB_ERROR(&error);
1529 		}
1530 		return EINVAL;
1531 	}
1532 
1533 	test_context->packet_count++;
1534 
1535 	return k5ret;
1536 }
1537 
test_context_destructor(struct torture_krb5_context * test_context)1538 static int test_context_destructor(struct torture_krb5_context *test_context)
1539 {
1540 	freeaddrinfo(test_context->server);
1541 	return 0;
1542 }
1543 
1544 
torture_krb5_init_context_canon(struct torture_context * tctx,struct test_data * test_data,struct torture_krb5_context ** torture_krb5_context)1545 static bool torture_krb5_init_context_canon(struct torture_context *tctx,
1546 					     struct test_data *test_data,
1547 					     struct torture_krb5_context **torture_krb5_context)
1548 {
1549 	const char *host = torture_setting_string(tctx, "host", NULL);
1550 	krb5_error_code k5ret;
1551 	bool ok;
1552 
1553 	struct torture_krb5_context *test_context = talloc_zero(tctx, struct torture_krb5_context);
1554 	torture_assert(tctx, test_context != NULL, "Failed to allocate");
1555 
1556 	test_context->test_data = test_data;
1557 	test_context->tctx = tctx;
1558 
1559 	k5ret = smb_krb5_init_context(test_context, tctx->lp_ctx, &test_context->smb_krb5_context);
1560 	torture_assert_int_equal(tctx, k5ret, 0, "smb_krb5_init_context failed");
1561 
1562 	ok = interpret_string_addr_internal(&test_context->server, host, AI_NUMERICHOST);
1563 	torture_assert(tctx, ok, "Failed to parse target server");
1564 
1565 	talloc_set_destructor(test_context, test_context_destructor);
1566 
1567 	set_sockaddr_port(test_context->server->ai_addr, 88);
1568 
1569 	k5ret = krb5_set_send_to_kdc_func(test_context->smb_krb5_context->krb5_context,
1570 					  smb_krb5_send_and_recv_func_canon_override,
1571 					  test_context);
1572 	torture_assert_int_equal(tctx, k5ret, 0, "krb5_set_send_to_kdc_func failed");
1573 	*torture_krb5_context = test_context;
1574 	return true;
1575 }
1576 
1577 
torture_krb5_as_req_canon(struct torture_context * tctx,const void * tcase_data)1578 static bool torture_krb5_as_req_canon(struct torture_context *tctx, const void *tcase_data)
1579 {
1580 	krb5_error_code k5ret;
1581 	krb5_get_init_creds_opt *krb_options = NULL;
1582 	struct test_data *test_data = talloc_get_type_abort(tcase_data, struct test_data);
1583 	krb5_principal principal;
1584 	krb5_principal krbtgt_other;
1585 	krb5_principal expected_principal;
1586 	const char *principal_string = NULL;
1587 	char *krbtgt_other_string;
1588 	int principal_flags;
1589 	const char *expected_principal_string = NULL;
1590 	char *expected_unparse_principal_string;
1591 	int expected_principal_flags;
1592 	char *got_principal_string;
1593 	char *assertion_message;
1594 	const char *password = cli_credentials_get_password(
1595 			popt_get_cmdline_credentials());
1596 	krb5_context k5_context;
1597 	struct torture_krb5_context *test_context;
1598 	bool ok;
1599 	krb5_creds my_creds;
1600 	krb5_creds *server_creds;
1601 	krb5_ccache ccache;
1602 	krb5_auth_context auth_context;
1603 	char *cc_name;
1604 	krb5_data in_data, enc_ticket;
1605 	krb5_get_creds_opt opt;
1606 
1607 	const char *spn = NULL;
1608 	const char *spn_real_realm = NULL;
1609 	const char *upn = torture_setting_string(tctx, "krb5-upn", "");
1610 	test_data->krb5_service = torture_setting_string(tctx, "krb5-service", "host");
1611 	test_data->krb5_hostname = torture_setting_string(tctx, "krb5-hostname", "");
1612 
1613 	/*
1614 	 * If we have not passed a UPN on the command line,
1615 	 * then skip the UPN tests.
1616 	 */
1617 	if (test_data->upn && upn[0] == '\0') {
1618 		torture_skip(tctx, "This test needs a UPN specified as --option=torture:krb5-upn=user@example.com to run");
1619 	}
1620 
1621 	/*
1622 	 * If we have not passed a SPN on the command line,
1623 	 * then skip the SPN tests.
1624 	 */
1625 	if (test_data->as_req_spn && test_data->krb5_hostname[0] == '\0') {
1626 		torture_skip(tctx, "This test needs a hostname specified as --option=torture:krb5-hostname=hostname.example.com and optionally --option=torture:krb5-service=service (defaults to host) to run");
1627 	}
1628 
1629 	if (test_data->removedollar &&
1630 	    !torture_setting_bool(tctx, "run_removedollar_test", false))
1631 	{
1632 		torture_skip(tctx, "--option=torture:run_removedollar_test=true not specified");
1633 	}
1634 
1635 	if (test_data->netbios_realm) {
1636 		test_data->realm = test_data->real_domain;
1637 	} else {
1638 		test_data->realm = test_data->real_realm;
1639 	}
1640 
1641 	if (test_data->upn) {
1642 		char *p;
1643 		test_data->username = talloc_strdup(test_data, upn);
1644 		p = strchr(test_data->username, '@');
1645 		if (p) {
1646 			*p = '\0';
1647 			p++;
1648 		}
1649 		/*
1650 		 * Test the UPN behaviour carefully.  We can
1651 		 * test in two different modes, depending on
1652 		 * what UPN has been set up for us.
1653 		 *
1654 		 * If the UPN is in our realm, then we do all the tests with this name also.
1655 		 *
1656 		 * If the UPN is not in our realm, then we
1657 		 * expect the tests that replace the realm to
1658 		 * fail (as it won't match)
1659 		 */
1660 		if (strcasecmp(p, test_data->real_realm) != 0) {
1661 			test_data->other_upn_suffix = true;
1662 		} else {
1663 			test_data->other_upn_suffix = false;
1664 		}
1665 
1666 		/*
1667 		 * This lets us test the combination of the UPN prefix
1668 		 * with a valid domain, without adding even more
1669 		 * combinations
1670 		 */
1671 		if (test_data->netbios_realm == false) {
1672 			test_data->realm = p;
1673 		}
1674 	}
1675 
1676 	ok = torture_krb5_init_context_canon(tctx, test_data, &test_context);
1677 	torture_assert(tctx, ok, "torture_krb5_init_context failed");
1678 	k5_context = test_context->smb_krb5_context->krb5_context;
1679 
1680 	if (test_data->upper_realm) {
1681 		test_data->realm = strupper_talloc(test_data, test_data->realm);
1682 	} else {
1683 		test_data->realm = strlower_talloc(test_data, test_data->realm);
1684 	}
1685 	if (test_data->upper_username) {
1686 		test_data->username = strupper_talloc(test_data, test_data->username);
1687 	} else {
1688 		test_data->username = talloc_strdup(test_data, test_data->username);
1689 	}
1690 
1691 	if (test_data->removedollar) {
1692 		char *p;
1693 
1694 		p = strchr_m(test_data->username, '$');
1695 		torture_assert(tctx, p != NULL, talloc_asprintf(tctx,
1696 			       "username[%s] contains no '$'\n",
1697 			       test_data->username));
1698 		*p = '\0';
1699 	}
1700 
1701 	spn = talloc_asprintf(test_data, "%s/%s@%s",
1702 			      test_data->krb5_service,
1703 			      test_data->krb5_hostname,
1704 			      test_data->realm);
1705 
1706 	spn_real_realm = talloc_asprintf(test_data, "%s/%s@%s",
1707 					 test_data->krb5_service,
1708 					 test_data->krb5_hostname,
1709 					 test_data->real_realm);
1710 
1711 	if (test_data->as_req_spn) {
1712 		if (test_data->enterprise) {
1713 			torture_skip(tctx,
1714 				     "This test combination "
1715 				     "is skipped intentionally");
1716 		}
1717 		principal_string = spn;
1718 	} else {
1719 		principal_string = talloc_asprintf(test_data,
1720 						   "%s@%s",
1721 						   test_data->username,
1722 						   test_data->realm);
1723 
1724 	}
1725 
1726 	test_data->spn_is_upn
1727 		= (strcasecmp(upn, spn) == 0);
1728 
1729 	/*
1730 	 * If we are set to canonicalize, we get back the fixed UPPER
1731 	 * case realm, and the real username (ie matching LDAP
1732 	 * samAccountName)
1733 	 *
1734 	 * Otherwise, if we are set to enterprise, we
1735 	 * get back the whole principal as-sent
1736 	 *
1737 	 * Finally, if we are not set to canonicalize, we get back the
1738 	 * fixed UPPER case realm, but the as-sent username
1739 	 */
1740 	if (test_data->as_req_spn && !test_data->spn_is_upn) {
1741 		expected_principal_string = spn;
1742 	} else if (test_data->canonicalize) {
1743 		expected_principal_string = talloc_asprintf(test_data,
1744 							    "%s@%s",
1745 							    test_data->real_username,
1746 							    test_data->real_realm);
1747 	} else if (test_data->enterprise) {
1748 		expected_principal_string = principal_string;
1749 	} else if (test_data->as_req_spn && test_data->spn_is_upn) {
1750 		expected_principal_string = spn_real_realm;
1751 	} else {
1752 		expected_principal_string = talloc_asprintf(test_data,
1753 							    "%s@%s",
1754 							    test_data->username,
1755 							    test_data->real_realm);
1756 	}
1757 
1758 	if (test_data->enterprise) {
1759 		principal_flags = KRB5_PRINCIPAL_PARSE_ENTERPRISE;
1760 	} else {
1761 		if (test_data->upn && test_data->other_upn_suffix) {
1762 			torture_skip(tctx, "UPN test for UPN with other UPN suffix only runs with enterprise principals");
1763 		}
1764 		principal_flags = 0;
1765 	}
1766 
1767 	if (test_data->canonicalize) {
1768 		expected_principal_flags = 0;
1769 	} else {
1770 		expected_principal_flags = principal_flags;
1771 	}
1772 
1773 	torture_assert_int_equal(tctx,
1774 				 krb5_parse_name_flags(k5_context,
1775 						       principal_string,
1776 						       principal_flags,
1777 						       &principal),
1778 					 0, "krb5_parse_name_flags failed");
1779 	torture_assert_int_equal(tctx,
1780 				 krb5_parse_name_flags(k5_context,
1781 						       expected_principal_string,
1782 						       expected_principal_flags,
1783 						       &expected_principal),
1784 				 0, "krb5_parse_name_flags failed");
1785 
1786 	if (test_data->as_req_spn) {
1787 		if (test_data->upn) {
1788 			krb5_principal_set_type(k5_context,
1789 						principal,
1790 						KRB5_NT_PRINCIPAL);
1791 			krb5_principal_set_type(k5_context,
1792 						expected_principal,
1793 						KRB5_NT_PRINCIPAL);
1794 		} else {
1795 			krb5_principal_set_type(k5_context,
1796 						principal,
1797 						KRB5_NT_SRV_HST);
1798 			krb5_principal_set_type(k5_context,
1799 						expected_principal,
1800 						KRB5_NT_SRV_HST);
1801 		}
1802 	}
1803 
1804 	torture_assert_int_equal(tctx,
1805 				 krb5_unparse_name(k5_context,
1806 						   expected_principal,
1807 						   &expected_unparse_principal_string),
1808 				 0, "krb5_unparse_name failed");
1809 	/*
1810 	 * Prepare a AS-REQ and run the TEST_AS_REQ tests
1811 	 *
1812 	 */
1813 
1814 	test_context->test_stage = TEST_AS_REQ;
1815 	test_context->packet_count = 0;
1816 
1817 	/*
1818 	 * Set the canonicalize flag if this test requires it
1819 	 */
1820 	torture_assert_int_equal(tctx,
1821 				 krb5_get_init_creds_opt_alloc(k5_context, &krb_options),
1822 				 0, "krb5_get_init_creds_opt_alloc failed");
1823 
1824 	torture_assert_int_equal(tctx,
1825 				 krb5_get_init_creds_opt_set_canonicalize(k5_context,
1826 									  krb_options,
1827 									  test_data->canonicalize),
1828 				 0, "krb5_get_init_creds_opt_set_canonicalize failed");
1829 
1830 	torture_assert_int_equal(tctx,
1831 				 krb5_get_init_creds_opt_set_win2k(k5_context,
1832 								   krb_options,
1833 								   test_data->win2k),
1834 				 0, "krb5_get_init_creds_opt_set_win2k failed");
1835 
1836 	k5ret = krb5_get_init_creds_password(k5_context, &my_creds, principal,
1837 					     password, NULL, NULL, 0,
1838 					     NULL, krb_options);
1839 
1840 	if (test_data->netbios_realm && test_data->upn) {
1841 		torture_assert_int_equal(tctx, k5ret,
1842 					 KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN,
1843 					 "Got wrong error_code from krb5_get_init_creds_password");
1844 		/* We can't proceed with more checks */
1845 		return true;
1846 	} else if (test_context->test_data->as_req_spn
1847 		   && !test_context->test_data->spn_is_upn) {
1848 		torture_assert_int_equal(tctx, k5ret,
1849 					 KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN,
1850 					 "Got wrong error_code from "
1851 					 "krb5_get_init_creds_password");
1852 		/* We can't proceed with more checks */
1853 		return true;
1854 	} else {
1855 		assertion_message = talloc_asprintf(tctx,
1856 						    "krb5_get_init_creds_password for %s failed: %s",
1857 						    principal_string,
1858 						    smb_get_krb5_error_message(k5_context, k5ret, tctx));
1859 		torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
1860 	}
1861 
1862 	torture_assert(tctx,
1863 		       test_context->packet_count > 1,
1864 		       "Expected krb5_get_init_creds_password to send more packets");
1865 
1866 	/*
1867 	 * Assert that the reply was with the correct type of
1868 	 * principal, depending on the flags we set
1869 	 */
1870 	if (test_data->canonicalize == false && test_data->enterprise) {
1871 		torture_assert_int_equal(tctx,
1872 					 krb5_principal_get_type(k5_context,
1873 								 my_creds.client),
1874 					 KRB5_NT_ENTERPRISE_PRINCIPAL,
1875 					 "smb_krb5_init_context gave incorrect client->name.name_type");
1876 	} else if (test_data->canonicalize == false && test_data->as_req_spn) {
1877 		torture_assert_int_equal(tctx,
1878 					 krb5_principal_get_type(k5_context,
1879 								 my_creds.client),
1880 					 KRB5_NT_SRV_HST,
1881 					 "smb_krb5_init_context gave incorrect client->name.name_type");
1882 	} else {
1883 		torture_assert_int_equal(tctx,
1884 					 krb5_principal_get_type(k5_context,
1885 								 my_creds.client),
1886 					 KRB5_NT_PRINCIPAL,
1887 					 "smb_krb5_init_context gave incorrect client->name.name_type");
1888 	}
1889 
1890 	torture_assert_int_equal(tctx,
1891 				 krb5_unparse_name(k5_context,
1892 						   my_creds.client, &got_principal_string), 0,
1893 				 "krb5_unparse_name failed");
1894 
1895 	assertion_message = talloc_asprintf(tctx,
1896 					    "krb5_get_init_creds_password returned a different principal %s to what was expected %s",
1897 					    got_principal_string, expected_principal_string);
1898 	krb5_free_unparsed_name(k5_context, got_principal_string);
1899 
1900 	torture_assert(tctx, krb5_principal_compare(k5_context,
1901 						    my_creds.client, expected_principal),
1902 		       assertion_message);
1903 
1904 
1905 	torture_assert_int_equal(tctx,
1906 				 krb5_principal_get_type(k5_context,
1907 							 my_creds.server), KRB5_NT_SRV_INST,
1908 				 "smb_krb5_init_context gave incorrect server->name.name_type");
1909 
1910 	torture_assert_int_equal(tctx,
1911 				 krb5_principal_get_num_comp(k5_context,
1912 							     my_creds.server), 2,
1913 				 "smb_krb5_init_context gave incorrect number of components in my_creds.server->name");
1914 
1915 	torture_assert_str_equal(tctx,
1916 				 krb5_principal_get_comp_string(k5_context,
1917 								my_creds.server, 0),
1918 				 "krbtgt",
1919 				 "smb_krb5_init_context gave incorrect my_creds.server->name.name_string[0]");
1920 
1921 	if (test_data->canonicalize || test_data->enterprise) {
1922 		torture_assert_str_equal(tctx,
1923 					 krb5_principal_get_comp_string(k5_context,
1924 									my_creds.server, 1),
1925 					 test_data->real_realm,
1926 
1927 					 "smb_krb5_init_context gave incorrect my_creds.server->name.name_string[1]");
1928 	} else {
1929 		torture_assert_str_equal(tctx,
1930 					 krb5_principal_get_comp_string(k5_context,
1931 									my_creds.server, 1),
1932 					 test_data->realm,
1933 
1934 					 "smb_krb5_init_context gave incorrect my_creds.server->name.name_string[1]");
1935 	}
1936 	torture_assert_str_equal(tctx,
1937 				 krb5_principal_get_realm(k5_context,
1938 							  my_creds.server),
1939 				 test_data->real_realm,
1940 				 "smb_krb5_init_context gave incorrect my_creds.server->realm");
1941 
1942 	/* Store the result of the 'kinit' above into a memory ccache */
1943 	cc_name = talloc_asprintf(tctx, "MEMORY:%s", test_data->test_name);
1944 	torture_assert_int_equal(tctx, krb5_cc_resolve(k5_context, cc_name,
1945 						       &ccache),
1946 				 0, "krb5_cc_resolve failed");
1947 
1948 	torture_assert_int_equal(tctx, krb5_cc_initialize(k5_context,
1949 							  ccache, my_creds.client),
1950 				 0, "krb5_cc_initialize failed");
1951 
1952 	torture_assert_int_equal(tctx, krb5_cc_store_cred(k5_context,
1953 							  ccache, &my_creds),
1954 				 0, "krb5_cc_store_cred failed");
1955 
1956 	/*
1957 	 * Prepare a TGS-REQ and run the TEST_TGS_REQ_KRBTGT_CANON tests
1958 	 *
1959 	 * This tests krb5_get_creds behaviour, which allows us to set
1960 	 * the KRB5_GC_CANONICALIZE option against the krbtgt/ principal
1961 	 */
1962 
1963 	krbtgt_other_string = talloc_asprintf(test_data, "krbtgt/%s@%s", test_data->real_domain, test_data->real_realm);
1964 	torture_assert_int_equal(tctx,
1965 				 krb5_make_principal(k5_context, &krbtgt_other,
1966 						     test_data->real_realm, "krbtgt",
1967 						     test_data->real_domain, NULL),
1968 				 0, "krb5_make_principal failed");
1969 
1970 	test_context->test_stage = TEST_TGS_REQ_KRBTGT_CANON;
1971 	test_context->packet_count = 0;
1972 
1973 	torture_assert_int_equal(tctx,
1974 				 krb5_get_creds_opt_alloc(k5_context, &opt),
1975 				 0, "krb5_get_creds_opt_alloc");
1976 
1977 	krb5_get_creds_opt_add_options(k5_context,
1978 				       opt,
1979 				       KRB5_GC_CANONICALIZE);
1980 
1981 	krb5_get_creds_opt_add_options(k5_context,
1982 				       opt,
1983 				       KRB5_GC_NO_STORE);
1984 
1985 	/* Confirm if we can get a ticket krbtgt/realm that we got back with the initial kinit */
1986 	k5ret = krb5_get_creds(k5_context, opt, ccache, krbtgt_other, &server_creds);
1987 
1988 	if (test_data->canonicalize == false && test_data->enterprise == false
1989 	    && test_data->netbios_realm && test_data->upper_realm) {
1990 		/*
1991 		 * In these situations, the code above does store a
1992 		 * principal in the credentials cache matching what
1993 		 * krb5_get_creds() needs, so the test succeds, with no packets.
1994 		 *
1995 		 */
1996 		assertion_message = talloc_asprintf(tctx,
1997 						    "krb5_get_creds for %s failed with: %s",
1998 						    krbtgt_other_string,
1999 						    smb_get_krb5_error_message(k5_context, k5ret,
2000 									       tctx));
2001 
2002 		torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
2003 		torture_assert_int_equal(tctx,
2004 					 test_context->packet_count,
2005 					 0, "Expected krb5_get_creds not to send packets");
2006 	} else if (test_data->canonicalize == false && test_data->enterprise == false
2007 		   && (test_data->upper_realm == false || test_data->netbios_realm == true)) {
2008 		torture_assert_int_equal(tctx, k5ret, KRB5_CC_NOTFOUND,
2009 					 "krb5_get_creds should have failed with KRB5_CC_NOTFOUND");
2010 	} else {
2011 
2012 		/*
2013 		 * In these situations, the code above does not store a
2014 		 * principal in the credentials cache matching what
2015 		 * krb5_get_creds() needs without talking to the KDC, so the
2016 		 * test fails with looping detected because when we set
2017 		 * canonicalize we confuse the client libs.
2018 		 *
2019 		 */
2020 		assertion_message = talloc_asprintf(tctx,
2021 						    "krb5_get_creds for %s should have failed with looping detected: %s",
2022 						    krbtgt_other_string,
2023 						    smb_get_krb5_error_message(k5_context, k5ret,
2024 									       tctx));
2025 
2026 		torture_assert_int_equal(tctx, k5ret, KRB5_GET_IN_TKT_LOOP, assertion_message);
2027 		torture_assert_int_equal(tctx,
2028 					 test_context->packet_count,
2029 					 2, "Expected krb5_get_creds to send packets");
2030 	}
2031 
2032 	/*
2033 	 * Prepare a TGS-REQ and run the TEST_TGS_REQ_CANON tests
2034 	 *
2035 	 * This tests krb5_get_creds behaviour, which allows us to set
2036 	 * the KRB5_GC_CANONICALIZE option
2037 	 */
2038 
2039 	test_context->test_stage = TEST_TGS_REQ_CANON;
2040 	test_context->packet_count = 0;
2041 
2042 	torture_assert_int_equal(tctx,
2043 				 krb5_get_creds_opt_alloc(k5_context, &opt),
2044 				 0, "krb5_get_creds_opt_alloc");
2045 
2046 	krb5_get_creds_opt_add_options(k5_context,
2047 				       opt,
2048 				       KRB5_GC_CANONICALIZE);
2049 
2050 	krb5_get_creds_opt_add_options(k5_context,
2051 				       opt,
2052 				       KRB5_GC_NO_STORE);
2053 
2054 	if (test_data->s4u2self) {
2055 		torture_assert_int_equal(tctx,
2056 					 krb5_get_creds_opt_set_impersonate(k5_context,
2057 									    opt,
2058 									    principal),
2059 					 0, "krb5_get_creds_opt_set_impersonate failed");
2060 	}
2061 
2062 	/* Confirm if we can get a ticket to our own name */
2063 	k5ret = krb5_get_creds(k5_context, opt, ccache, principal, &server_creds);
2064 
2065 	/*
2066 	 * In these situations, the code above does not store a
2067 	 * principal in the credentials cache matching what
2068 	 * krb5_get_creds() needs, so the test fails.
2069 	 *
2070 	 */
2071 	if (test_data->canonicalize == false && test_data->enterprise == false
2072 	    && (test_data->upper_realm == false || test_data->netbios_realm == true)) {
2073 		torture_assert_int_equal(tctx, k5ret, KRB5_CC_NOTFOUND,
2074 					 "krb5_get_creds should have failed with KRB5_CC_NOTFOUND");
2075 	} else {
2076 		assertion_message = talloc_asprintf(tctx,
2077 						    "krb5_get_creds for %s failed: %s",
2078 						    principal_string,
2079 						    smb_get_krb5_error_message(k5_context, k5ret,
2080 									       tctx));
2081 
2082 		/*
2083 		 * Only machine accounts (strictly, accounts with a
2084 		 * servicePrincipalName) can expect this test to succeed
2085 		 */
2086 		if (torture_setting_bool(tctx, "expect_machine_account", false)
2087 		    && (test_data->enterprise
2088 			|| test_data->spn_is_upn
2089 			|| test_data->upn == false)) {
2090 
2091 			if (test_data->mitm_s4u2self) {
2092 				torture_assert_int_not_equal(tctx, k5ret, 0, assertion_message);
2093 				/* Done testing mitm-s4u2self */
2094 				return true;
2095 			}
2096 
2097 			torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
2098 
2099 			/* Check that the impersonate principal is not being canonicalized by the KDC. */
2100 			if (test_data->s4u2self) {
2101 				torture_assert(tctx, krb5_principal_compare(k5_context, server_creds->client,
2102 									    principal),
2103 					       "TGS-REP cname does not match requested client principal");
2104 			}
2105 
2106 			torture_assert_int_equal(tctx, krb5_cc_store_cred(k5_context,
2107 									  ccache, server_creds),
2108 						 0, "krb5_cc_store_cred failed");
2109 
2110 			torture_assert_int_equal(tctx,
2111 						 krb5_free_creds(k5_context,
2112 								 server_creds),
2113 						 0, "krb5_free_cred_contents failed");
2114 
2115 		} else {
2116 			torture_assert_int_equal(tctx, k5ret, KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN,
2117 						 assertion_message);
2118 		}
2119 
2120 		torture_assert_int_equal(tctx,
2121 					 test_context->packet_count,
2122 					 1, "Expected krb5_get_creds to send packets");
2123 	}
2124 
2125 	/*
2126 	 * Confirm gettting a ticket to pass to the server, running
2127 	 * either the TEST_TGS_REQ or TEST_SELF_TRUST_TGS_REQ stage.
2128 	 *
2129 	 * This triggers the client to attempt to get a
2130 	 * cross-realm ticket between the alternate names of
2131 	 * the server, and we need to confirm that behaviour.
2132 	 *
2133 	 */
2134 
2135 	/*
2136 	 * This tries to guess when the krb5 libs will ask for a
2137 	 * cross-realm ticket, and when they will just ask the KDC
2138 	 * directly.
2139 	 */
2140 	if (test_context->test_data->canonicalize == false
2141 	    || test_context->test_data->enterprise
2142 	    || (test_context->test_data->spn_is_upn && test_context->test_data->upn)
2143 	    || (test_context->test_data->upper_realm
2144 		&& test_context->test_data->netbios_realm == false)) {
2145 		test_context->test_stage = TEST_TGS_REQ;
2146 	} else {
2147 		test_context->test_stage = TEST_SELF_TRUST_TGS_REQ;
2148 	}
2149 
2150 	test_context->packet_count = 0;
2151 	torture_assert_int_equal(tctx, krb5_auth_con_init(k5_context, &auth_context),
2152 				 0, "krb5_auth_con_init failed");
2153 
2154 	in_data.length = 0;
2155 	k5ret = krb5_mk_req_exact(k5_context,
2156 				  &auth_context,
2157 				  AP_OPTS_USE_SUBKEY,
2158 				  principal,
2159 				  &in_data, ccache,
2160 				  &enc_ticket);
2161 	assertion_message = talloc_asprintf(tctx,
2162 					    "krb5_mk_req_exact for %s failed: %s",
2163 					    principal_string,
2164 					    smb_get_krb5_error_message(k5_context, k5ret, tctx));
2165 
2166 	/*
2167 	 * Only machine accounts (strictly, accounts with a
2168 	 * servicePrincipalName) can expect this test to succeed
2169 	 */
2170 	if (torture_setting_bool(tctx, "expect_machine_account", false)
2171 	    && (test_data->enterprise ||
2172 		(test_context->test_data->as_req_spn
2173 		 || test_context->test_data->spn_is_upn)
2174 		|| test_data->upn == false)) {
2175 		DATA_BLOB client_to_server;
2176 		torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
2177 		client_to_server = data_blob_const(enc_ticket.data, enc_ticket.length);
2178 
2179 		/* This is very weird */
2180 		if (test_data->canonicalize == false
2181 		    && test_context->test_data->as_req_spn
2182 		    && test_context->test_data->spn_is_upn
2183 		    && test_context->test_data->s4u2self) {
2184 
2185 			torture_assert(tctx,
2186 				       test_accept_ticket(tctx,
2187 							  popt_get_cmdline_credentials(),
2188 							  spn_real_realm,
2189 							  client_to_server),
2190 				       "test_accept_ticket failed - failed to accept the ticket we just created");
2191 		} else if (test_data->canonicalize == true
2192 		    && test_context->test_data->as_req_spn
2193 		    && test_context->test_data->spn_is_upn
2194 		    && test_context->test_data->s4u2self) {
2195 
2196 			torture_assert(tctx,
2197 				       test_accept_ticket(tctx,
2198 							  popt_get_cmdline_credentials(),
2199 							  spn,
2200 							  client_to_server),
2201 				       "test_accept_ticket failed - failed to accept the ticket we just created");
2202 		} else if (test_data->canonicalize == true
2203 			   && test_data->enterprise == false
2204 			   && test_context->test_data->upn
2205 			   && test_context->test_data->spn_is_upn
2206 			   && test_context->test_data->s4u2self) {
2207 
2208 			torture_assert(tctx,
2209 				       test_accept_ticket(tctx,
2210 							  popt_get_cmdline_credentials(),
2211 							  principal_string,
2212 							  client_to_server),
2213 				       "test_accept_ticket failed - failed to accept the ticket we just created");
2214 		} else if (test_data->canonicalize == false
2215 			   && test_data->enterprise == false
2216 			   && test_context->test_data->upn
2217 			   && test_context->test_data->spn_is_upn
2218 			   && test_context->test_data->s4u2self) {
2219 
2220 			const char *accept_expected_principal_string
2221 				= talloc_asprintf(test_data,
2222 						  "%s@%s",
2223 						  test_data->username,
2224 						  test_data->real_realm);
2225 
2226 			torture_assert(tctx,
2227 				       test_accept_ticket(tctx,
2228 							  popt_get_cmdline_credentials(),
2229 							  accept_expected_principal_string,
2230 							  client_to_server),
2231 				       "test_accept_ticket failed - failed to accept the ticket we just created");
2232 		} else {
2233 
2234 			torture_assert(tctx,
2235 				       test_accept_ticket(tctx,
2236 							  popt_get_cmdline_credentials(),
2237 							  expected_unparse_principal_string,
2238 							  client_to_server),
2239 				       "test_accept_ticket failed - failed to accept the ticket we just created");
2240 		}
2241 		krb5_data_free(&enc_ticket);
2242 	} else {
2243 		torture_assert_int_equal(tctx, k5ret, KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN,
2244 					 assertion_message);
2245 	}
2246 
2247 	/*
2248 	 * Only in these cases would the above code have needed to
2249 	 * send packets to the network
2250 	 */
2251 	if (test_data->canonicalize == false && test_data->enterprise == false
2252 	    && (test_data->upper_realm == false || test_data->netbios_realm == true)) {
2253 		torture_assert(tctx,
2254 			       test_context->packet_count > 0,
2255 			       "Expected krb5_mk_req_exact to send packets");
2256 	}
2257 
2258 	/*
2259 	 * Confirm gettting a ticket to pass to the server, running
2260 	 * the TEST_TGS_REQ_HOST, TEST_TGS_REQ_HOST_SRV_INST, TEST_TGS_REQ_HOST_SRV_HST stage
2261 	 *
2262 	 * This triggers the client to attempt to get a
2263 	 * cross-realm ticket between the alternate names of
2264 	 * the server, and we need to confirm that behaviour.
2265 	 *
2266 	 */
2267 
2268 	if (*test_data->krb5_service && *test_data->krb5_hostname) {
2269 		bool implied_canonicalize;
2270 		krb5_principal host_principal_srv_inst;
2271 		/*
2272 		 * This tries to guess when the krb5 libs will ask for a
2273 		 * cross-realm ticket, and when they will just ask the KDC
2274 		 * directly.
2275 		 */
2276 		test_context->test_stage = TEST_TGS_REQ_HOST;
2277 		test_context->packet_count = 0;
2278 		torture_assert_int_equal(tctx, krb5_auth_con_init(k5_context, &auth_context),
2279 					 0, "krb5_auth_con_init failed");
2280 
2281 		in_data.length = 0;
2282 		k5ret = krb5_mk_req(k5_context,
2283 				    &auth_context,
2284 				    0,
2285 				    test_data->krb5_service,
2286 				    test_data->krb5_hostname,
2287 				    &in_data, ccache,
2288 				    &enc_ticket);
2289 
2290 		implied_canonicalize = test_data->canonicalize;
2291 		if (test_data->spn_is_upn && (test_data->upn || test_data->as_req_spn)) {
2292 			implied_canonicalize = true;
2293 		}
2294 		if (test_data->enterprise) {
2295 			implied_canonicalize = true;
2296 		}
2297 
2298 		if (implied_canonicalize == false
2299 		    && (test_data->upper_realm == false || test_data->netbios_realm == true)) {
2300 			torture_assert_int_equal(tctx, k5ret, KRB5_CC_NOTFOUND,
2301 						 "krb5_get_creds should have failed with KRB5_CC_NOTFOUND");
2302 		} else if (test_data->spn_is_upn
2303 			   && test_data->canonicalize == false
2304 			   && test_data->enterprise == false
2305 			   && test_data->upper_realm == false
2306 			   && test_data->upper_username == true
2307 			   && test_data->upn) {
2308 			torture_assert_int_equal(tctx, k5ret, KRB5_CC_NOTFOUND,
2309 						 "krb5_get_creds should have failed with KRB5_CC_NOTFOUND");
2310 		} else {
2311 			assertion_message = talloc_asprintf(tctx,
2312 							    "krb5_mk_req for %s/%s failed: %s",
2313 							    test_data->krb5_service,
2314 							    test_data->krb5_hostname,
2315 							    smb_get_krb5_error_message(k5_context, k5ret, tctx));
2316 
2317 			torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
2318 
2319 			if (test_data->spn_is_upn == false) {
2320 				/*
2321 				 * Only in these cases would the above
2322 				 * code have needed to send packets to
2323 				 * the network
2324 				 */
2325 				torture_assert(tctx,
2326 					       test_context->packet_count > 0,
2327 					       "Expected krb5_get_creds to send packets");
2328 			}
2329 		}
2330 
2331 
2332 		test_context->test_stage = TEST_TGS_REQ_HOST_SRV_INST;
2333 		test_context->packet_count = 0;
2334 
2335 		torture_assert_int_equal(tctx,
2336 					 krb5_make_principal(k5_context, &host_principal_srv_inst,
2337 							     test_data->real_realm,
2338 							     strupper_talloc(tctx, test_data->krb5_service),
2339 							     test_data->krb5_hostname,
2340 							     NULL),
2341 					 0, "krb5_make_principal failed");
2342 
2343 		krb5_principal_set_type(k5_context, host_principal_srv_inst, KRB5_NT_SRV_INST);
2344 
2345 		torture_assert_int_equal(tctx, krb5_auth_con_init(k5_context, &auth_context),
2346 					 0, "krb5_auth_con_init failed");
2347 
2348 		in_data.length = 0;
2349 		k5ret = krb5_mk_req_exact(k5_context,
2350 					  &auth_context,
2351 					  0,
2352 					  host_principal_srv_inst,
2353 					  &in_data, ccache,
2354 					  &enc_ticket);
2355 		krb5_free_principal(k5_context, host_principal_srv_inst);
2356 		if (test_data->canonicalize == false && test_data->enterprise == false
2357 		    && (test_data->upper_realm == false || test_data->netbios_realm == true)) {
2358 			torture_assert_int_equal(tctx, k5ret, KRB5_CC_NOTFOUND,
2359 						 "krb5_get_creds should have failed with KRB5_CC_NOTFOUND");
2360 		} else {
2361 			assertion_message = talloc_asprintf(tctx,
2362 							    "krb5_mk_req for %s/%s KRB5_NT_SRV_INST failed: %s",
2363 							    test_data->krb5_service,
2364 							    test_data->krb5_hostname,
2365 							    smb_get_krb5_error_message(k5_context, k5ret, tctx));
2366 
2367 			torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
2368 			/*
2369 			 * Only in these cases would the above code have needed to
2370 			 * send packets to the network
2371 			 */
2372 			torture_assert(tctx,
2373 				       test_context->packet_count > 0,
2374 				       "Expected krb5_get_creds to send packets");
2375 		}
2376 
2377 
2378 		test_context->test_stage = TEST_TGS_REQ_HOST_SRV_HST;
2379 		test_context->packet_count = 0;
2380 
2381 		torture_assert_int_equal(tctx,
2382 					 krb5_make_principal(k5_context, &host_principal_srv_inst,
2383 							     test_data->real_realm,
2384 							     test_data->krb5_service,
2385 							     strupper_talloc(tctx, test_data->krb5_hostname),
2386 							     NULL),
2387 					 0, "krb5_make_principal failed");
2388 
2389 		krb5_principal_set_type(k5_context, host_principal_srv_inst, KRB5_NT_SRV_HST);
2390 
2391 		torture_assert_int_equal(tctx, krb5_auth_con_init(k5_context, &auth_context),
2392 					 0, "krb5_auth_con_init failed");
2393 
2394 		in_data.length = 0;
2395 		k5ret = krb5_mk_req_exact(k5_context,
2396 					  &auth_context,
2397 					  0,
2398 					  host_principal_srv_inst,
2399 					  &in_data, ccache,
2400 					  &enc_ticket);
2401 		krb5_free_principal(k5_context, host_principal_srv_inst);
2402 		if (test_data->canonicalize == false && test_data->enterprise == false
2403 		    && (test_data->upper_realm == false || test_data->netbios_realm == true)) {
2404 			torture_assert_int_equal(tctx, k5ret, KRB5_CC_NOTFOUND,
2405 						 "krb5_get_creds should have failed with KRB5_CC_NOTFOUND");
2406 		} else {
2407 			assertion_message = talloc_asprintf(tctx,
2408 							    "krb5_mk_req for %s/%s KRB5_NT_SRV_INST failed: %s",
2409 							    test_data->krb5_service,
2410 							    test_data->krb5_hostname,
2411 							    smb_get_krb5_error_message(k5_context, k5ret, tctx));
2412 
2413 			torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
2414 			/*
2415 			 * Only in these cases would the above code have needed to
2416 			 * send packets to the network
2417 			 */
2418 			torture_assert(tctx,
2419 				       test_context->packet_count > 0,
2420 				       "Expected krb5_get_creds to send packets");
2421 		}
2422 	}
2423 
2424 	/*
2425 	 * Confirm gettting a ticket for the same krbtgt/realm that we
2426 	 * got back with the initial ticket, running the
2427 	 * TEST_TGS_REQ_KRBTGT stage.
2428 	 *
2429 	 */
2430 
2431 	test_context->test_stage = TEST_TGS_REQ_KRBTGT;
2432 	test_context->packet_count = 0;
2433 
2434 	in_data.length = 0;
2435 	k5ret = krb5_mk_req_exact(k5_context,
2436 				  &auth_context,
2437 				  0,
2438 				  my_creds.server,
2439 				  &in_data, ccache,
2440 				  &enc_ticket);
2441 
2442 	assertion_message = talloc_asprintf(tctx,
2443 					    "krb5_mk_req_exact for %s failed: %s",
2444 					    principal_string,
2445 					    smb_get_krb5_error_message(k5_context, k5ret, tctx));
2446 	torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
2447 
2448 	/*
2449 	 * Confirm gettting a ticket for our own principal that we
2450 	 * got back with the initial ticket, running the
2451 	 * TEST_AS_REQ_SELF stage.
2452 	 *
2453 	 */
2454 	test_context->test_stage = TEST_AS_REQ_SELF;
2455 	test_context->packet_count = 0;
2456 
2457 	k5ret = krb5_get_init_creds_password(k5_context, &my_creds, principal,
2458 					     password, NULL, NULL, 0,
2459 					     principal_string, krb_options);
2460 
2461 	if (torture_setting_bool(test_context->tctx, "expect_machine_account", false)
2462 	    && (test_data->upn == false || (test_data->enterprise == false && test_data->upn == true && test_data->spn_is_upn))) {
2463 		assertion_message = talloc_asprintf(tctx,
2464 						    "krb5_get_init_creds_password for %s failed: %s",
2465 						    principal_string,
2466 						    smb_get_krb5_error_message(k5_context, k5ret, tctx));
2467 		torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
2468 		torture_assert(tctx,
2469 			       test_context->packet_count >= 2,
2470 			       "Expected krb5_get_init_creds_password to send more packets");
2471 
2472 	} else {
2473 		assertion_message = talloc_asprintf(tctx,
2474 						    "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);
2475 		torture_assert_int_equal(tctx, k5ret,
2476 					 KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN,
2477 					 assertion_message);
2478 		torture_assert(tctx,
2479 			       test_context->packet_count >= 1,
2480 			       "Expected krb5_get_init_creds_password to send more packets");
2481 
2482 		/* We can't proceed with more checks */
2483 		return true;
2484 	}
2485 
2486 	/*
2487 	 * Assert that the reply was with the correct type of
2488 	 * principal, depending on the flags we set
2489 	 */
2490 	if (test_data->as_req_spn && test_data->spn_is_upn && test_data->canonicalize == false) {
2491 		torture_assert_int_equal(tctx,
2492 					 krb5_principal_get_type(k5_context,
2493 								 my_creds.client),
2494 					 KRB5_NT_SRV_HST,
2495 					 "smb_krb5_init_context gave incorrect client->name.name_type");
2496 		torture_assert_int_equal(tctx,
2497 					 krb5_principal_get_type(k5_context,
2498 								 my_creds.server),
2499 					 KRB5_NT_SRV_HST,
2500 					 "smb_krb5_init_context gave incorrect server->name.name_type");
2501 	} else if (test_data->canonicalize == false && test_data->enterprise) {
2502 		torture_assert_int_equal(tctx,
2503 					 krb5_principal_get_type(k5_context,
2504 								 my_creds.client),
2505 					 KRB5_NT_ENTERPRISE_PRINCIPAL,
2506 					 "smb_krb5_init_context gave incorrect client->name.name_type");
2507 		torture_assert_int_equal(tctx,
2508 					 krb5_principal_get_type(k5_context,
2509 								 my_creds.server),
2510 					 KRB5_NT_ENTERPRISE_PRINCIPAL,
2511 					 "smb_krb5_init_context gave incorrect server->name.name_type");
2512 	} else {
2513 		torture_assert_int_equal(tctx,
2514 					 krb5_principal_get_type(k5_context,
2515 								 my_creds.client),
2516 					 KRB5_NT_PRINCIPAL,
2517 					 "smb_krb5_init_context gave incorrect client->name.name_type");
2518 		torture_assert_int_equal(tctx,
2519 					 krb5_principal_get_type(k5_context,
2520 								 my_creds.server),
2521 					 KRB5_NT_PRINCIPAL,
2522 					 "smb_krb5_init_context gave incorrect server->name.name_type");
2523 	}
2524 
2525 	torture_assert_int_equal(tctx,
2526 				 krb5_unparse_name(k5_context,
2527 						   my_creds.client, &got_principal_string), 0,
2528 				 "krb5_unparse_name failed");
2529 
2530 	assertion_message = talloc_asprintf(tctx,
2531 					    "krb5_get_init_creds_password returned a different principal %s to what was expected %s",
2532 					    got_principal_string, expected_principal_string);
2533 	krb5_free_unparsed_name(k5_context, got_principal_string);
2534 
2535 	torture_assert(tctx, krb5_principal_compare(k5_context,
2536 						    my_creds.client, expected_principal),
2537 		       assertion_message);
2538 
2539 	torture_assert_int_equal(tctx,
2540 				 krb5_unparse_name(k5_context,
2541 						   my_creds.client, &got_principal_string), 0,
2542 				 "krb5_unparse_name failed");
2543 
2544 	assertion_message = talloc_asprintf(tctx,
2545 					    "krb5_get_init_creds_password returned a different server principal %s to what was expected %s",
2546 					    got_principal_string, expected_principal_string);
2547 	krb5_free_unparsed_name(k5_context, got_principal_string);
2548 
2549 	torture_assert(tctx, krb5_principal_compare(k5_context,
2550 						    my_creds.server, expected_principal),
2551 		       assertion_message);
2552 
2553 	krb5_free_principal(k5_context, principal);
2554 	krb5_get_init_creds_opt_free(k5_context, krb_options);
2555 
2556 	torture_assert_int_equal(tctx, krb5_free_cred_contents(k5_context, &my_creds),
2557 				 0, "krb5_free_cred_contents failed");
2558 
2559 	return true;
2560 }
2561 
torture_krb5_canon(TALLOC_CTX * mem_ctx)2562 struct torture_suite *torture_krb5_canon(TALLOC_CTX *mem_ctx)
2563 {
2564 	unsigned int i;
2565 	struct torture_suite *suite = torture_suite_create(mem_ctx, "canon");
2566 	suite->description = talloc_strdup(suite, "Kerberos Canonicalisation tests");
2567 
2568 	for (i = 0; i < TEST_ALL; i++) {
2569 		char *name = talloc_asprintf(suite, "%s.%s.%s.%s.%s.%s.%s.%s",
2570 					     (i & TEST_CANONICALIZE) ? "canon" : "no-canon",
2571 					     (i & TEST_ENTERPRISE) ? "enterprise" : "no-enterprise",
2572 					     (i & TEST_UPPER_REALM) ? "uc-realm" : "lc-realm",
2573 					     (i & TEST_UPPER_USERNAME) ? "uc-user" : "lc-user",
2574 					     (i & TEST_NETBIOS_REALM) ? "netbios-realm" : "krb5-realm",
2575 					     (i & TEST_WIN2K) ? "win2k" : "no-win2k",
2576 					     (i & TEST_UPN) ? "upn" :
2577 					     ((i & TEST_AS_REQ_SPN) ? "spn" :
2578 					      ((i & TEST_REMOVEDOLLAR) ? "removedollar" : "samaccountname")),
2579 					     (i & TEST_S4U2SELF) ? (i & TEST_MITM_S4U2SELF) ? "mitm-s4u2self" : "s4u2self" : "normal");
2580 		struct torture_suite *sub_suite = torture_suite_create(mem_ctx, name);
2581 
2582 		struct test_data *test_data = talloc_zero(suite, struct test_data);
2583 		if (i & TEST_UPN) {
2584 			if (i & TEST_AS_REQ_SPN) {
2585 				continue;
2586 			}
2587 		}
2588 		if ((i & TEST_UPN) || (i & TEST_AS_REQ_SPN)) {
2589 			if (i & TEST_REMOVEDOLLAR) {
2590 				continue;
2591 			}
2592 		}
2593 		if (i & TEST_MITM_S4U2SELF) {
2594 			if (!(i & TEST_S4U2SELF)) {
2595 				continue;
2596 			}
2597 		}
2598 
2599 		test_data->test_name = name;
2600 		test_data->real_realm
2601 			= strupper_talloc(test_data,
2602 				cli_credentials_get_realm(
2603 					popt_get_cmdline_credentials()));
2604 		test_data->real_domain = cli_credentials_get_domain(
2605 						popt_get_cmdline_credentials());
2606 		test_data->username = cli_credentials_get_username(
2607 						popt_get_cmdline_credentials());
2608 		test_data->real_username = cli_credentials_get_username(
2609 						popt_get_cmdline_credentials());
2610 		test_data->canonicalize = (i & TEST_CANONICALIZE) != 0;
2611 		test_data->enterprise = (i & TEST_ENTERPRISE) != 0;
2612 		test_data->upper_realm = (i & TEST_UPPER_REALM) != 0;
2613 		test_data->upper_username = (i & TEST_UPPER_USERNAME) != 0;
2614 		test_data->netbios_realm = (i & TEST_NETBIOS_REALM) != 0;
2615 		test_data->win2k = (i & TEST_WIN2K) != 0;
2616 		test_data->upn = (i & TEST_UPN) != 0;
2617 		test_data->s4u2self = (i & TEST_S4U2SELF) != 0;
2618 		test_data->mitm_s4u2self = (i & TEST_MITM_S4U2SELF) != 0;
2619 		test_data->removedollar = (i & TEST_REMOVEDOLLAR) != 0;
2620 		test_data->as_req_spn = (i & TEST_AS_REQ_SPN) != 0;
2621 		torture_suite_add_simple_tcase_const(sub_suite, name, torture_krb5_as_req_canon,
2622 						     test_data);
2623 		torture_suite_add_suite(suite, sub_suite);
2624 
2625 	}
2626 	return suite;
2627 }
2628