torture-krb5: Add test for TGS-REQ with type KRB5_NT_PRINCIPAL, KRB5_NT_SRV_INST...
[kai/samba-autobuild/.git] / source4 / torture / krb5 / kdc-canon.c
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
33 #define TEST_CANONICALIZE     0x0000001
34 #define TEST_ENTERPRISE       0x0000002
35 #define TEST_UPPER_REALM      0x0000004
36 #define TEST_UPPER_USERNAME   0x0000008
37 #define TEST_NETBIOS_REALM    0x0000010
38 #define TEST_WIN2K            0x0000020
39 #define TEST_UPN              0x0000040
40 #define TEST_ALL              0x000007F
41
42 struct test_data {
43         const char *test_name;
44         const char *realm;
45         const char *real_realm;
46         const char *real_domain;
47         const char *username;
48         const char *real_username;
49         bool canonicalize;
50         bool enterprise;
51         bool upper_realm;
52         bool upper_username;
53         bool netbios_realm;
54         bool win2k;
55         bool upn;
56         bool other_upn_suffix;
57         const char *krb5_service;
58         const char *krb5_hostname;
59 };      
60
61 enum test_stage {
62         TEST_AS_REQ = 0,
63         TEST_TGS_REQ_KRBTGT_CANON,
64         TEST_TGS_REQ_CANON,
65         TEST_SELF_TRUST_TGS_REQ,
66         TEST_TGS_REQ,
67         TEST_TGS_REQ_KRBTGT,
68         TEST_TGS_REQ_HOST,
69         TEST_TGS_REQ_HOST_SRV_INST,
70         TEST_TGS_REQ_HOST_SRV_HST,
71         TEST_AS_REQ_SELF,
72         TEST_DONE
73 };
74
75 struct torture_krb5_context {
76         struct smb_krb5_context *smb_krb5_context;
77         struct torture_context *tctx;
78         struct addrinfo *server;
79         struct test_data *test_data;
80         int packet_count;
81         enum test_stage test_stage;
82         AS_REQ as_req;
83         AS_REP as_rep;
84         TGS_REQ tgs_req;
85         TGS_REP tgs_rep;
86 };
87
88
89 /*
90  * TEST_AS_REQ and TEST_AS_REQ_SELF - SEND
91  *
92  * Confirm that the outgoing packet meets certain expectations.  This
93  * should be extended to further assert the correct and expected
94  * behaviour of the krb5 libs, so we know what we are sending to the
95  * server.
96  *
97  * Additionally, this CHANGES the request to remove the canonicalize
98  * flag automatically added by the krb5 libs when an enterprise
99  * principal is used, so we can test what the server does in this
100  * combination.
101  *
102  */
103
104 static bool torture_krb5_pre_send_as_req_test(struct torture_krb5_context *test_context,
105                                               const krb5_data *send_buf,
106                                               krb5_data *modified_send_buf)
107 {
108         AS_REQ mod_as_req;
109         krb5_error_code k5ret;
110         size_t used;
111         torture_assert_int_equal(test_context->tctx, decode_AS_REQ(send_buf->data, send_buf->length,
112                                                &test_context->as_req, &used),
113                                  0, "decode_AS_REQ for TEST_AS_REQ failed");
114         mod_as_req = test_context->as_req;
115         torture_assert_int_equal(test_context->tctx, used, send_buf->length, "length mismatch");
116         torture_assert_int_equal(test_context->tctx, test_context->as_req.pvno,
117                                  5, "Got wrong as_req->pvno");
118         if (test_context->test_data->canonicalize || test_context->test_data->enterprise) {
119                 torture_assert(test_context->tctx,
120                                test_context->as_req.req_body.kdc_options.canonicalize,
121                                "krb5 libs did not set canonicalize!");
122         } else {
123                 torture_assert_int_equal(test_context->tctx,
124                                          test_context->as_req.req_body.kdc_options.canonicalize,
125                                          false,
126                                          "krb5 libs unexpectedly set canonicalize!");
127         }
128
129         if (test_context->test_data->enterprise) {
130                 torture_assert_int_equal(test_context->tctx,
131                                          test_context->as_req.req_body.cname->name_type,
132                                          KRB5_NT_ENTERPRISE_PRINCIPAL,
133                                          "krb5 libs did not pass principal as enterprise!");
134         } else {
135                 torture_assert_int_equal(test_context->tctx,
136                                          test_context->as_req.req_body.cname->name_type,
137                                          KRB5_NT_PRINCIPAL,
138                                          "krb5 libs unexpectedly set principal as enterprise!");
139         }
140
141         /* Force off canonicalize that was forced on by the krb5 libs */
142         if (test_context->test_data->canonicalize == false && test_context->test_data->enterprise) {
143                 mod_as_req.req_body.kdc_options.canonicalize = false;
144         }
145
146         if (test_context->test_stage == TEST_AS_REQ_SELF) {
147                 /*
148                  * Force the server name to match the client name,
149                  * including the name type.  This isn't possible with
150                  * the krb5 client libs alone
151                  */
152                 mod_as_req.req_body.sname = test_context->as_req.req_body.cname;
153         }
154
155         ASN1_MALLOC_ENCODE(AS_REQ, modified_send_buf->data, modified_send_buf->length,
156                            &mod_as_req, &used, k5ret);
157         torture_assert_int_equal(test_context->tctx,
158                                  k5ret, 0,
159                                  "encode_AS_REQ failed");
160
161         if (test_context->test_stage != TEST_AS_REQ_SELF) {
162                 torture_assert_int_equal(test_context->tctx, used, send_buf->length,
163                                          "re-encode length mismatch");
164         }
165         return true;
166 }
167
168 /*
169  * TEST_AS_REQ - RECV
170  *
171  * Confirm that the reply packet from the KDC meets certain
172  * expectations as part of TEST_AS_REQ.  This uses a packet count to
173  * work out what packet we are up to in the multiple exchanged
174  * triggerd by krb5_get_init_creds_password().
175  *
176  */
177
178 static bool torture_krb5_post_recv_as_req_test(struct torture_krb5_context *test_context,
179                                                const krb5_data *recv_buf)
180 {
181         KRB_ERROR error;
182         size_t used;
183         if (test_context->packet_count == 0) {
184                 krb5_error_code k5ret;
185                 /*
186                  * The client libs obtain the salt by attempting to
187                  * authenticate without pre-authentication and getting
188                  * the correct salt with the
189                  * KRB5KDC_ERR_PREAUTH_REQUIRED error.  If we are in
190                  * the test (netbios_realm && upn) that deliberatly
191                  * has an incorrect principal, we check we get the
192                  * correct error.
193                  */
194                 k5ret = decode_KRB_ERROR(recv_buf->data, recv_buf->length,
195                                          &error, &used);
196                 if (k5ret != 0) {
197                         AS_REP as_rep;
198                         k5ret = decode_AS_REP(recv_buf->data, recv_buf->length,
199                                       &as_rep, &used);
200                         if (k5ret == 0) {
201                                 if (test_context->test_data->netbios_realm && test_context->test_data->upn) {
202                                         torture_assert(test_context->tctx, false,
203                                                        "expected to get a KRB_ERROR packet with "
204                                                        "KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN, got valid AS-REP");
205                                 } else {
206                                         torture_assert(test_context->tctx, false,
207                                                        "expected to get a KRB_ERROR packet with "
208                                                        "KRB5KDC_ERR_PREAUTH_REQUIRED, got valid AS-REP");
209                                 }
210                         } else {
211                                 if (test_context->test_data->netbios_realm && test_context->test_data->upn) {
212                                         torture_assert(test_context->tctx, false,
213                                                        "unable to decode as KRB-ERROR or AS-REP, "
214                                                        "expected to get a KRB_ERROR packet with KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN");
215                                 } else {
216                                         torture_assert(test_context->tctx, false,
217                                                        "unable to decode as KRB-ERROR or AS-REP, "
218                                                        "expected to get a KRB_ERROR packet with KRB5KDC_ERR_PREAUTH_REQUIRED");
219                                 }
220                         }
221                 }
222                 torture_assert_int_equal(test_context->tctx, used, recv_buf->length,
223                                          "length mismatch");
224                 torture_assert_int_equal(test_context->tctx, error.pvno, 5,
225                                          "Got wrong error.pvno");
226                 if (test_context->test_data->netbios_realm && test_context->test_data->upn) {
227                         torture_assert_int_equal(test_context->tctx,
228                                                  error.error_code,
229                                                  KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN - KRB5KDC_ERR_NONE,
230                                                  "Got wrong error.error_code");
231                 } else {
232                         torture_assert_int_equal(test_context->tctx,
233                                                  error.error_code,
234                                                  KRB5KDC_ERR_PREAUTH_REQUIRED - KRB5KDC_ERR_NONE,
235                                                  "Got wrong error.error_code");
236                 }
237
238                 free_KRB_ERROR(&error);
239         } else if ((decode_KRB_ERROR(recv_buf->data, recv_buf->length, &error, &used) == 0)
240                    && (test_context->packet_count == 1)) {
241                 /*
242                  * The Windows 2012R2 KDC will always respond with
243                  * KRB5KRB_ERR_RESPONSE_TOO_BIG over UDP as the ticket
244                  * won't fit, because of the PAC.  (It appears to do
245                  * this always, even if it will).  This triggers the
246                  * client to try again over TCP.
247                  */
248                 torture_assert_int_equal(test_context->tctx,
249                                          used, recv_buf->length,
250                                          "length mismatch");
251                 torture_assert_int_equal(test_context->tctx,
252                                          error.pvno, 5,
253                                          "Got wrong error.pvno");
254                 torture_assert_int_equal(test_context->tctx,
255                                          error.error_code,
256                                          KRB5KRB_ERR_RESPONSE_TOO_BIG - KRB5KDC_ERR_NONE,
257                                          "Got wrong error.error_code");
258                 free_KRB_ERROR(&error);
259         } else {
260                 /*
261                  * Finally the successful packet.
262                  */
263                 torture_assert_int_equal(test_context->tctx,
264                                          decode_AS_REP(recv_buf->data, recv_buf->length,
265                                                        &test_context->as_rep, &used), 0,
266                                          "decode_AS_REP failed");
267                 torture_assert_int_equal(test_context->tctx, used, recv_buf->length,
268                                          "length mismatch");
269                 torture_assert_int_equal(test_context->tctx,
270                                          test_context->as_rep.pvno, 5,
271                                          "Got wrong as_rep->pvno");
272                 torture_assert_int_equal(test_context->tctx,
273                                          test_context->as_rep.ticket.tkt_vno, 5,
274                                          "Got wrong as_rep->ticket.tkt_vno");
275                 torture_assert(test_context->tctx,
276                                test_context->as_rep.ticket.enc_part.kvno,
277                                "Did not get a KVNO in test_context->as_rep.ticket.enc_part.kvno");
278
279                 /*
280                  * We can confirm that the correct proxy behaviour is
281                  * in use on the KDC by checking the KVNO of the
282                  * krbtgt account returned in the reply.
283                  *
284                  * A packet passed to the full RW DC will not have a
285                  * KVNO in the upper bits, while a packet processed
286                  * locally on the RODC will have these bits filled in
287                  * the msDS-SecondaryKrbTgtNumber
288                  */
289                 if (torture_setting_bool(test_context->tctx, "expect_cached_at_rodc", false)) {
290                         torture_assert_int_not_equal(test_context->tctx,
291                                                      *test_context->as_rep.ticket.enc_part.kvno & 0xFFFF0000,
292                                                      0, "Did not get a RODC number in the KVNO");
293                 } else {
294                         torture_assert_int_equal(test_context->tctx,
295                                                  *test_context->as_rep.ticket.enc_part.kvno & 0xFFFF0000,
296                                                  0, "Unexpecedly got a RODC number in the KVNO");
297                 }
298                 free_AS_REP(&test_context->as_rep);
299         }
300         torture_assert(test_context->tctx, test_context->packet_count < 3, "too many packets");
301         free_AS_REQ(&test_context->as_req);
302         return true;
303 }
304
305 /*
306  * TEST_TGS_REQ_KRBTGT_CANON
307  *
308  *
309  * Confirm that the outgoing TGS-REQ packet from krb5_get_creds()
310  * for the krbtgt/realm principal meets certain expectations, like
311  * that the canonicalize bit is not set
312  *
313  */
314
315 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)
316 {
317         size_t used;
318         torture_assert_int_equal(test_context->tctx,
319                                  decode_TGS_REQ(send_buf->data, send_buf->length,
320                                                 &test_context->tgs_req, &used),
321                                  0, "decode_TGS_REQ for TEST_TGS_REQ test failed");
322         torture_assert_int_equal(test_context->tctx,
323                                  used, send_buf->length,
324                                  "length mismatch");
325         torture_assert_int_equal(test_context->tctx,
326                                  test_context->tgs_req.pvno, 5,
327                                  "Got wrong as_req->pvno");
328         torture_assert_int_equal(test_context->tctx,
329                                  test_context->tgs_req.req_body.kdc_options.canonicalize,
330                                  true,
331                                  "krb5 libs unexpectedly did not set canonicalize!");
332
333         torture_assert_int_equal(test_context->tctx,
334                                  test_context->tgs_req.req_body.sname->name_type,
335                                  KRB5_NT_PRINCIPAL,
336                                  "Mismatch in name_type between request and expected request");
337
338         torture_assert_str_equal(test_context->tctx,
339                                  test_context->tgs_req.req_body.realm,
340                                  test_context->test_data->real_realm,
341                                  "Mismatch in realm between request and expected request");
342
343         *modified_send_buf = *send_buf;
344         return true;
345 }
346
347 /*
348  * TEST_TGS_REQ_KRBTGT_CANON
349  *
350  * Confirm that the reply TGS-REP packet for krb5_get_creds()
351  * where the client is behaving as if this is a cross-realm trust due
352  * to case or netbios vs dns name differences meets certain
353  * expectations, while canonicalize is set
354  *
355  */
356
357 static bool torture_krb5_post_recv_tgs_req_krbtgt_canon_test(struct torture_krb5_context *test_context, const krb5_data *recv_buf)
358 {
359         size_t used;
360         torture_assert_int_equal(test_context->tctx,
361                                  decode_TGS_REP(recv_buf->data, recv_buf->length,
362                                                 &test_context->tgs_rep, &used),
363                                  0,
364                                  "decode_TGS_REP failed");
365         torture_assert_int_equal(test_context->tctx, used, recv_buf->length, "length mismatch");
366         torture_assert_int_equal(test_context->tctx,
367                                  test_context->tgs_rep.pvno, 5,
368                                  "Got wrong as_rep->pvno");
369         torture_assert_int_equal(test_context->tctx,
370                                  test_context->tgs_rep.ticket.tkt_vno, 5,
371                                  "Got wrong as_rep->ticket.tkt_vno");
372         torture_assert(test_context->tctx,
373                        test_context->tgs_rep.ticket.enc_part.kvno,
374                        "Did not get a KVNO in test_context->as_rep.ticket.enc_part.kvno");
375         torture_assert_str_equal(test_context->tctx,
376                                  test_context->tgs_req.req_body.realm,
377                                  test_context->tgs_rep.ticket.realm,
378                                  "Mismatch in realm between request and ticket response");
379         torture_assert_str_equal(test_context->tctx,
380                                  test_context->tgs_rep.ticket.realm,
381                                  test_context->test_data->real_realm,
382                                  "Mismatch in realm between ticket response and expected ticket response");
383         torture_assert_int_equal(test_context->tctx,
384                                  test_context->tgs_rep.ticket.sname.name_type,
385                                  KRB5_NT_SRV_INST,
386                                  "Mismatch in name_type between ticket response and expected value of KRB5_NT_SRV_INST");
387
388         torture_assert_int_equal(test_context->tctx,
389                                  test_context->tgs_rep.ticket.sname.name_string.len,
390                                  2,
391                                  "Mismatch in name_type between ticket response and expected value, expected krbtgt/REALM@REALM");
392
393         torture_assert_str_equal(test_context->tctx,
394                                  test_context->tgs_rep.ticket.sname.name_string.val[0], "krbtgt",
395                                  "Mismatch in name between reponse and expected response, expected krbtgt");
396         torture_assert_str_equal(test_context->tctx,
397                                  test_context->tgs_rep.ticket.sname.name_string.val[1], test_context->test_data->real_realm,
398                                  "Mismatch in realm part of krbtgt/ in expected response, expected krbtgt/REALM@REALM");
399
400         /*
401          * We can confirm that the correct proxy behaviour is
402          * in use on the KDC by checking the KVNO of the
403          * krbtgt account returned in the reply.
404          *
405          * A packet passed to the full RW DC will not have a
406          * KVNO in the upper bits, while a packet processed
407          * locally on the RODC will have these bits filled in
408          * the msDS-SecondaryKrbTgtNumber
409          */
410         if (torture_setting_bool(test_context->tctx, "expect_cached_at_rodc", false)) {
411                 torture_assert_int_not_equal(test_context->tctx,
412                                              *test_context->tgs_rep.ticket.enc_part.kvno & 0xFFFF0000,
413                                              0, "Did not get a RODC number in the KVNO");
414         } else {
415                 torture_assert_int_equal(test_context->tctx,
416                                          *test_context->tgs_rep.ticket.enc_part.kvno & 0xFFFF0000,
417                                          0, "Unexpecedly got a RODC number in the KVNO");
418         }
419         free_TGS_REP(&test_context->tgs_rep);
420         torture_assert(test_context->tctx,
421                        test_context->packet_count < 2,
422                        "too many packets");
423         free_TGS_REQ(&test_context->tgs_req);
424         return true;
425 }
426
427 /*
428  * TEST_TGS_REQ_CANON
429  *
430  * Confirm that the outgoing TGS-REQ packet from krb5_get_creds
431  * certain expectations, like that the canonicalize bit is set (this
432  * test is to force that handling) and that if an enterprise name was
433  * requested, that it was sent.
434  *
435  */
436
437 static bool torture_krb5_pre_send_tgs_req_canon_test(struct torture_krb5_context *test_context,
438                                                      const krb5_data *send_buf,
439                                                      krb5_data *modified_send_buf)
440 {
441         size_t used;
442         torture_assert_int_equal(test_context->tctx,
443                                  decode_TGS_REQ(send_buf->data, send_buf->length,
444                                                 &test_context->tgs_req, &used),
445                                  0, "decode_TGS_REQ for TEST_TGS_REQ_CANON test failed");
446         torture_assert_int_equal(test_context->tctx, used, send_buf->length, "length mismatch");
447         torture_assert_int_equal(test_context->tctx, test_context->tgs_req.pvno, 5, "Got wrong as_req->pvno");
448         torture_assert_int_equal(test_context->tctx,
449                                  test_context->tgs_req.req_body.kdc_options.canonicalize,
450                                  true, "krb5 libs unexpectedly did not set canonicalize!");
451
452         if (test_context->test_data->enterprise) {
453                 torture_assert_int_equal(test_context->tctx,
454                                          test_context->tgs_req.req_body.sname->name_type, KRB5_NT_ENTERPRISE_PRINCIPAL,
455                                  "Mismatch in name type between request and expected request, expected  KRB5_NT_ENTERPRISE_PRINCIPAL");
456                 torture_assert_str_equal(test_context->tctx,
457                                          test_context->tgs_req.req_body.realm, test_context->test_data->real_realm,
458                                  "Mismatch in realm between request and expected request");
459
460         } else if (test_context->test_data->canonicalize) {
461                 torture_assert_int_equal(test_context->tctx,
462                                          test_context->tgs_req.req_body.sname->name_type, KRB5_NT_PRINCIPAL,
463                                          "Mismatch in name type between request and expected request, expected  KRB5_NT_PRINCIPAL");
464                 torture_assert_str_equal(test_context->tctx,
465                                          test_context->tgs_req.req_body.realm, test_context->test_data->real_realm,
466                                  "Mismatch in realm between request and expected request");
467
468         } else {
469                 torture_assert_int_equal(test_context->tctx,
470                                          test_context->tgs_req.req_body.sname->name_type, KRB5_NT_PRINCIPAL,
471                                          "Mismatch in name type between request and expected request, expected  KRB5_NT_PRINCIPAL");
472                 torture_assert_str_equal(test_context->tctx,
473                                          test_context->tgs_req.req_body.realm, test_context->test_data->realm,
474                                  "Mismatch in realm between request and expected request");
475
476         }
477
478         *modified_send_buf = *send_buf;
479
480         return true;
481 }
482
483 /*
484  * TEST_TGS_REQ_CANON - RECV
485  *
486  * Confirm that the reply TGS-REP or error packet from the KDC meets
487  * certain expectations as part of TEST_TGS_REQ_CANON.
488  *
489  * This is triggered by krb5_get_creds()
490  *
491  */
492
493 static bool torture_krb5_post_recv_tgs_req_canon_test(struct torture_krb5_context *test_context, const krb5_data *recv_buf)
494 {
495         KRB_ERROR error;
496         size_t used;
497
498         /*
499          * If this account did not have a servicePrincipalName, then
500          * we expect a errro packet, not a TGS-REQ
501          */
502         if (decode_KRB_ERROR(recv_buf->data, recv_buf->length, &error, &used) == 0) {
503                 torture_assert_int_equal(test_context->tctx, used, recv_buf->length, "length mismatch");
504                 torture_assert_int_equal(test_context->tctx,
505                                          error.pvno, 5,
506                                          "Got wrong error.pvno");
507                 torture_assert_int_equal(test_context->tctx,
508                                          error.error_code,
509                                          KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN - KRB5KDC_ERR_NONE,
510                                          "Got wrong error.error_code");
511         } else {
512                 torture_assert_int_equal(test_context->tctx,
513                                          decode_TGS_REP(recv_buf->data, recv_buf->length,
514                                                         &test_context->tgs_rep,
515                                                         &used),
516                                          0,
517                                          "decode_TGS_REP failed");
518                 torture_assert_int_equal(test_context->tctx,
519                                          used, recv_buf->length,
520                                          "length mismatch");
521                 torture_assert_int_equal(test_context->tctx,
522                                          test_context->tgs_rep.pvno, 5,
523                                          "Got wrong as_rep->pvno");
524                 torture_assert_int_equal(test_context->tctx,
525                                          test_context->tgs_rep.ticket.tkt_vno, 5,
526                                          "Got wrong as_rep->ticket.tkt_vno");
527                 torture_assert(test_context->tctx,
528                                test_context->tgs_rep.ticket.enc_part.kvno,
529                                "Did not get a KVNO in test_context->as_rep.ticket.enc_part.kvno");
530                 torture_assert_str_equal(test_context->tctx,
531                                          test_context->tgs_rep.ticket.realm,
532                                          test_context->test_data->real_realm,
533                                          "Mismatch in realm between ticket response and expected upper case REALM");
534                 torture_assert_int_equal(test_context->tctx,
535                                          test_context->tgs_rep.ticket.sname.name_type,
536                                          test_context->tgs_req.req_body.sname->name_type,
537                                          "Mismatch in name_type between request and ticket response");
538                 torture_assert_int_equal(test_context->tctx,
539                                          test_context->tgs_rep.ticket.sname.name_string.len,
540                                          test_context->tgs_req.req_body.sname->name_string.len,
541                                          "Mismatch in name_string.len between request and ticket response");
542                 torture_assert(test_context->tctx,
543                                test_context->tgs_rep.ticket.sname.name_string.len >= 1,
544                                "name_string.len should be >=1 in ticket response");
545                 torture_assert_str_equal(test_context->tctx,
546                                          test_context->tgs_rep.ticket.sname.name_string.val[0],
547                                          test_context->tgs_req.req_body.sname->name_string.val[0],
548                                          "Mismatch in name between request and expected request");
549                 torture_assert_int_equal(test_context->tctx,
550                                          *test_context->tgs_rep.ticket.enc_part.kvno & 0xFFFF0000,
551                                          0, "Unexpecedly got a RODC number in the KVNO, should just be principal KVNO");
552                 free_TGS_REP(&test_context->tgs_rep);
553         }
554         torture_assert(test_context->tctx, test_context->packet_count == 0, "too many packets");
555         free_TGS_REQ(&test_context->tgs_req);
556
557         return true;
558 }
559
560 /*
561  * TEST_SELF_TRUST_TGS_REQ
562  *
563  * Confirm that the outgoing TGS-REQ packet from krb5_mk_req_exact()
564  * certain expectations, like that the canonicalize bit is set (this
565  * test is to force that handling).
566  *
567  * This test is for the case where the name we ask for, while a valid
568  * alternate name for our own realm is used.  The client acts as if
569  * this is cross-realm trust.
570  *
571  */
572
573 static bool torture_krb5_pre_send_self_trust_tgs_req_test(struct torture_krb5_context *test_context,
574                                                           const krb5_data *send_buf,
575                                                           krb5_data *modified_send_buf)
576 {
577         size_t used;
578         torture_assert_int_equal(test_context->tctx,
579                                  decode_TGS_REQ(send_buf->data, send_buf->length,
580                                                 &test_context->tgs_req, &used),
581                                  0, "decode_TGS_REQ for TEST_SELF_TRUST_TGS_REQ test failed");
582         torture_assert_int_equal(test_context->tctx, used, send_buf->length, "length mismatch");
583         torture_assert_int_equal(test_context->tctx, test_context->tgs_req.pvno, 5, "Got wrong as_req->pvno");
584         torture_assert_int_equal(test_context->tctx, test_context->tgs_req.req_body.kdc_options.canonicalize, false, "krb5 libs unexpectedly set canonicalize!");
585
586         if (test_context->test_data->canonicalize) {
587                 torture_assert_str_equal(test_context->tctx,
588                                          test_context->tgs_req.req_body.realm,
589                                          test_context->test_data->real_realm,
590                                          "Mismatch in realm between request and expected request");
591         } else {
592                 torture_assert_str_equal(test_context->tctx,
593                                          test_context->tgs_req.req_body.realm,
594                                          test_context->test_data->realm,
595                                          "Mismatch in realm between request and expected request");
596         }
597         torture_assert_int_equal(test_context->tctx,
598                                  test_context->tgs_req.req_body.sname->name_type, KRB5_NT_PRINCIPAL,
599                                  "Mismatch in name type between request and expected request, expected  KRB5_NT_PRINCIPAL");
600         torture_assert_int_equal(test_context->tctx,
601                                  test_context->tgs_req.req_body.sname->name_string.len, 2,
602                                  "Mismatch in name between request and expected request, expected krbtgt/realm");
603         torture_assert_str_equal(test_context->tctx,
604                                  test_context->tgs_req.req_body.sname->name_string.val[0], "krbtgt",
605                                  "Mismatch in name between request and expected request, expected krbtgt");
606         torture_assert_str_equal(test_context->tctx,
607                                  test_context->tgs_req.req_body.sname->name_string.val[1], test_context->test_data->realm,
608                                  "Mismatch in realm part of cross-realm request principal between request and expected request");
609         *modified_send_buf = *send_buf;
610
611         return true;
612 }
613
614 /*
615  * TEST_SELF_TRUST_TGS_REQ and TEST_TGS_REQ_KRBTGT - RECV
616  *
617  * Confirm that the reply TGS-REP packet for krb5_mk_req_exact(),
618  * where the client is behaving as if this is a cross-realm trust due
619  * to case or netbios vs dns name differences meets certain
620  * expectations.
621  *
622  */
623
624 static bool torture_krb5_post_recv_self_trust_tgs_req_test(struct torture_krb5_context *test_context, const krb5_data *recv_buf)
625 {
626         size_t used;
627         torture_assert_int_equal(test_context->tctx,
628                                  decode_TGS_REP(recv_buf->data, recv_buf->length,
629                                                 &test_context->tgs_rep, &used),
630                                  0,
631                                  "decode_TGS_REP failed");
632         torture_assert_int_equal(test_context->tctx, used, recv_buf->length, "length mismatch");
633         torture_assert_int_equal(test_context->tctx,
634                                  test_context->tgs_rep.pvno, 5,
635                                  "Got wrong as_rep->pvno");
636         torture_assert_int_equal(test_context->tctx,
637                                  test_context->tgs_rep.ticket.tkt_vno, 5,
638                                  "Got wrong as_rep->ticket.tkt_vno");
639         torture_assert(test_context->tctx,
640                        test_context->tgs_rep.ticket.enc_part.kvno,
641                        "Did not get a KVNO in test_context->as_rep.ticket.enc_part.kvno");
642         torture_assert_str_equal(test_context->tctx,
643                                  test_context->tgs_req.req_body.realm,
644                                  test_context->tgs_rep.ticket.realm,
645                                  "Mismatch in realm between request and ticket response");
646         torture_assert_int_equal(test_context->tctx,
647                                  test_context->tgs_rep.ticket.sname.name_type,
648                                  test_context->tgs_req.req_body.sname->name_type,
649                                  "Mismatch in name_type between request and ticket response");
650
651         torture_assert_int_equal(test_context->tctx,
652                                  test_context->tgs_rep.ticket.sname.name_string.len, 2,
653                                  "Mismatch in name between request and expected request, expected krbtgt/realm");
654         torture_assert_str_equal(test_context->tctx,
655                                  test_context->tgs_rep.ticket.sname.name_string.val[0], "krbtgt",
656                                  "Mismatch in name between request and expected request, expected krbtgt");
657         torture_assert_str_equal(test_context->tctx,
658                                  test_context->tgs_rep.ticket.sname.name_string.val[1], test_context->test_data->realm,
659                                  "Mismatch in realm part of cross-realm request principal between response and expected request");
660         /*
661          * We can confirm that the correct proxy behaviour is
662          * in use on the KDC by checking the KVNO of the
663          * krbtgt account returned in the reply.
664          *
665          * A packet passed to the full RW DC will not have a
666          * KVNO in the upper bits, while a packet processed
667          * locally on the RODC will have these bits filled in
668          * the msDS-SecondaryKrbTgtNumber
669          */
670         if (torture_setting_bool(test_context->tctx, "expect_cached_at_rodc", false)) {
671                 torture_assert_int_not_equal(test_context->tctx,
672                                              *test_context->tgs_rep.ticket.enc_part.kvno & 0xFFFF0000,
673                                              0, "Did not get a RODC number in the KVNO");
674         } else {
675                 torture_assert_int_equal(test_context->tctx,
676                                          *test_context->tgs_rep.ticket.enc_part.kvno & 0xFFFF0000,
677                                          0, "Unexpecedly got a RODC number in the KVNO");
678         }
679         free_TGS_REP(&test_context->tgs_rep);
680         torture_assert_int_equal(test_context->tctx,
681                                  test_context->packet_count, 0,
682                                  "too many packets");
683         test_context->packet_count = 0;
684         test_context->test_stage = TEST_TGS_REQ;
685         free_TGS_REQ(&test_context->tgs_req);
686         return true;
687 }
688
689 /*
690  * TEST_TGS_REQ
691  *
692  * Confirm that the outgoing TGS-REQ packet from krb5_mk_req_exact()
693  * certain expectations, like that the canonicalize bit is set (this
694  * test is to force that handling) and that if an enterprise name was
695  * requested, that it was sent.
696  *
697  */
698
699 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)
700 {
701         size_t used;
702         torture_assert_int_equal(test_context->tctx,
703                                  decode_TGS_REQ(send_buf->data, send_buf->length,
704                                                 &test_context->tgs_req, &used),
705                                  0, "decode_TGS_REQ for TEST_TGS_REQ test failed");
706         torture_assert_int_equal(test_context->tctx, used, send_buf->length, "length mismatch");
707         torture_assert_int_equal(test_context->tctx, test_context->tgs_req.pvno, 5,
708                                  "Got wrong as_req->pvno");
709         torture_assert_int_equal(test_context->tctx,
710                                  test_context->tgs_req.req_body.kdc_options.canonicalize,
711                                  false,
712                                  "krb5 libs unexpectedly set canonicalize!");
713
714         if (test_context->test_data->enterprise) {
715                 torture_assert_int_equal(test_context->tctx,
716                                          test_context->tgs_req.req_body.sname->name_type,
717                                          KRB5_NT_ENTERPRISE_PRINCIPAL,
718                                          "Mismatch in name type between request and expected request, expected  KRB5_NT_ENTERPRISE_PRINCIPAL");
719                 torture_assert_str_equal(test_context->tctx,
720                                          test_context->tgs_req.req_body.realm,
721                                          test_context->test_data->real_realm,
722                                          "Mismatch in realm between request and expected request");
723
724         } else {
725                 torture_assert_int_equal(test_context->tctx,
726                                          test_context->tgs_req.req_body.sname->name_type,
727                                          KRB5_NT_PRINCIPAL,
728                                          "Mismatch in name type between request and expected request, expected  KRB5_NT_PRINCIPAL");
729                 torture_assert_str_equal(test_context->tctx,
730                                          test_context->tgs_req.req_body.realm,
731                                          test_context->test_data->realm,
732                                          "Mismatch in realm between request and expected request");
733
734         }
735
736         *modified_send_buf = *send_buf;
737
738         return true;
739 }
740
741 /*
742  * TEST_TGS_REQ - RECV
743  *
744  * Confirm that the reply TGS-REP packet for krb5_mk_req_exact(), for
745  * the actual target service.
746  *
747  */
748
749 static bool torture_krb5_post_recv_tgs_req_test(struct torture_krb5_context *test_context, const krb5_data *recv_buf)
750 {
751         KRB_ERROR error;
752         size_t used;
753         /*
754          * If this account did not have a servicePrincipalName, then
755          * we expect a errro packet, not a TGS-REQ
756          */
757         if (decode_KRB_ERROR(recv_buf->data, recv_buf->length, &error, &used) == 0) {
758                 torture_assert_int_equal(test_context->tctx,
759                                          used, recv_buf->length,
760                                          "length mismatch");
761                 torture_assert_int_equal(test_context->tctx,
762                                          error.pvno, 5,
763                                          "Got wrong error.pvno");
764                 torture_assert_int_equal(test_context->tctx,
765                                          error.error_code,
766                                          KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN - KRB5KDC_ERR_NONE,
767                                          "Got wrong error.error_code");
768         } else {
769                 torture_assert_int_equal(test_context->tctx,
770                                          decode_TGS_REP(recv_buf->data, recv_buf->length,
771                                                         &test_context->tgs_rep, &used),
772                                          0,
773                                          "decode_TGS_REP failed");
774                 torture_assert_int_equal(test_context->tctx, used, recv_buf->length,
775                                          "length mismatch");
776                 torture_assert_int_equal(test_context->tctx,
777                                          test_context->tgs_rep.pvno, 5,
778                                          "Got wrong as_rep->pvno");
779                 torture_assert_int_equal(test_context->tctx,
780                                          test_context->tgs_rep.ticket.tkt_vno, 5,
781                                          "Got wrong as_rep->ticket.tkt_vno");
782                 torture_assert(test_context->tctx,
783                                test_context->tgs_rep.ticket.enc_part.kvno,
784                                "Did not get a KVNO in test_context->as_rep.ticket.enc_part.kvno");
785                 torture_assert_str_equal(test_context->tctx,
786                                          test_context->tgs_rep.ticket.realm,
787                                          test_context->test_data->real_realm,
788                                          "Mismatch in realm between ticket response and expected upper case REALM");
789                 torture_assert_int_equal(test_context->tctx,
790                                          test_context->tgs_req.req_body.sname->name_type,
791                                          test_context->tgs_rep.ticket.sname.name_type, "Mismatch in name_type between request and ticket response");
792                 torture_assert_int_equal(test_context->tctx,
793                                          *test_context->tgs_rep.ticket.enc_part.kvno & 0xFFFF0000,
794                                          0, "Unexpecedly got a RODC number in the KVNO, should just be principal KVNO");
795                 free_TGS_REP(&test_context->tgs_rep);
796         }
797         torture_assert(test_context->tctx, test_context->packet_count < 3, "too many packets");
798         free_TGS_REQ(&test_context->tgs_req);
799         test_context->test_stage = TEST_DONE;
800         return true;
801 }
802
803 /*
804  * TEST_TGS_REQ_KRBTGT
805  *
806  *
807  * Confirm that the outgoing TGS-REQ packet from krb5_mk_req_exact()
808  * for the krbtgt/realm principal meets certain expectations, like
809  * that the canonicalize bit is not set
810  *
811  */
812
813 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)
814 {
815         size_t used;
816         torture_assert_int_equal(test_context->tctx,
817                                  decode_TGS_REQ(send_buf->data, send_buf->length,
818                                                 &test_context->tgs_req, &used),
819                                  0, "decode_TGS_REQ for TEST_TGS_REQ test failed");
820         torture_assert_int_equal(test_context->tctx,
821                                  used, send_buf->length,
822                                  "length mismatch");
823         torture_assert_int_equal(test_context->tctx,
824                                  test_context->tgs_req.pvno, 5,
825                                  "Got wrong as_req->pvno");
826         torture_assert_int_equal(test_context->tctx,
827                                  test_context->tgs_req.req_body.kdc_options.canonicalize,
828                                  false,
829                                  "krb5 libs unexpectedly set canonicalize!");
830
831         torture_assert_str_equal(test_context->tctx,
832                                  test_context->tgs_req.req_body.realm,
833                                  test_context->test_data->realm,
834                                  "Mismatch in realm between request and expected request");
835
836         *modified_send_buf = *send_buf;
837         test_context->test_stage = TEST_DONE;
838         return true;
839 }
840
841 /*
842  * TEST_TGS_REQ_HOST, TEST_TGS_REQ_HOST_SRV_INST and TEST_TGS_REQ_HOST_SRV_HST
843  *
844  *
845  * Confirm that the outgoing TGS-REQ packet from krb5_mk_req_exact()
846  * for the krbtgt/realm principal meets certain expectations, like
847  * that the canonicalize bit is not set
848  *
849  */
850
851 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)
852 {
853         size_t used;
854         torture_assert_int_equal(test_context->tctx,
855                                  decode_TGS_REQ(send_buf->data, send_buf->length,
856                                                 &test_context->tgs_req, &used),
857                                  0, "decode_TGS_REQ for TEST_TGS_REQ test failed");
858         torture_assert_int_equal(test_context->tctx,
859                                  used, send_buf->length,
860                                  "length mismatch");
861         torture_assert_int_equal(test_context->tctx,
862                                  test_context->tgs_req.pvno, 5,
863                                  "Got wrong as_req->pvno");
864         torture_assert_int_equal(test_context->tctx,
865                                  test_context->tgs_req.req_body.sname->name_string.len, 2,
866                                  "Mismatch in name between request and expected request, expected krbtgt/realm");
867                 torture_assert_int_equal(test_context->tctx,
868                                          test_context->tgs_req.req_body.kdc_options.canonicalize,
869                                          true,
870                                          "krb5 libs unexpectedly did not set canonicalize!");
871
872         if (test_context->test_stage == TEST_TGS_REQ_HOST_SRV_INST) {
873                 torture_assert_int_equal(test_context->tctx,
874                                          test_context->tgs_req.req_body.sname->name_type, KRB5_NT_SRV_INST,
875                                          "Mismatch in name type between request and expected request, expected KRB5_NT_SRV_INST");
876                 torture_assert_str_equal(test_context->tctx,
877                                          test_context->tgs_req.req_body.sname->name_string.val[0],
878                                          strupper_talloc(test_context, test_context->test_data->krb5_service),
879                                          "Mismatch in name between request and expected request, expected service");
880                 torture_assert_str_equal(test_context->tctx,
881                                          test_context->tgs_req.req_body.sname->name_string.val[1],
882                                          test_context->test_data->krb5_hostname,
883                                          "Mismatch in hostname part between request and expected request");
884
885         } else if (test_context->test_stage == TEST_TGS_REQ_HOST_SRV_HST) {
886
887                 torture_assert_int_equal(test_context->tctx,
888                                          test_context->tgs_req.req_body.sname->name_type, KRB5_NT_SRV_HST,
889                                          "Mismatch in name type between request and expected request, expected KRB5_NT_SRV_HST");
890                 torture_assert_str_equal(test_context->tctx,
891                                          test_context->tgs_req.req_body.sname->name_string.val[0],
892                                          test_context->test_data->krb5_service,
893                                          "Mismatch in name between request and expected request, expected service");
894                 torture_assert_str_equal(test_context->tctx,
895                                          test_context->tgs_req.req_body.sname->name_string.val[1],
896                                          strupper_talloc(test_context, test_context->test_data->krb5_hostname),
897                                          "Mismatch in hostname part between request and expected request");
898
899         } else {
900                 torture_assert_int_equal(test_context->tctx,
901                                          test_context->tgs_req.req_body.sname->name_type, KRB5_NT_PRINCIPAL,
902                                          "Mismatch in name type between request and expected request, expected  KRB5_NT_PRINCIPAL");
903                 torture_assert_str_equal(test_context->tctx,
904                                          test_context->tgs_req.req_body.sname->name_string.val[0],
905                                          test_context->test_data->krb5_service,
906                                          "Mismatch in name between request and expected request, expected service");
907                 torture_assert_str_equal(test_context->tctx,
908                                          test_context->tgs_req.req_body.sname->name_string.val[1],
909                                          test_context->test_data->krb5_hostname,
910                                          "Mismatch in hostname part between request and expected request");
911
912         }
913         torture_assert_str_equal(test_context->tctx,
914                                  test_context->tgs_req.req_body.realm,
915                                  test_context->test_data->real_realm,
916                                  "Mismatch in realm between request and expected request");
917
918         *modified_send_buf = *send_buf;
919         return true;
920 }
921
922 /*
923  * TEST_TGS_REQ_HOST, TEST_TGS_REQ_HOST_SRV_INST, TEST_TGS_REQ_HOST_SRV_HST - RECV
924  *
925  * Confirm that the reply TGS-REP packet for krb5_mk_req(), for
926  * the actual target service, as a SPN, not a any other name type.
927  *
928  */
929
930 static bool torture_krb5_post_recv_tgs_req_host_test(struct torture_krb5_context *test_context, const krb5_data *recv_buf)
931 {
932         size_t used;
933         torture_assert_int_equal(test_context->tctx,
934                                  decode_TGS_REP(recv_buf->data, recv_buf->length,
935                                                 &test_context->tgs_rep, &used),
936                                  0,
937                                  "decode_TGS_REP failed");
938         torture_assert_int_equal(test_context->tctx, used, recv_buf->length,
939                                  "length mismatch");
940         torture_assert_int_equal(test_context->tctx,
941                                  test_context->tgs_rep.pvno, 5,
942                                  "Got wrong as_rep->pvno");
943         torture_assert_int_equal(test_context->tctx,
944                                  test_context->tgs_rep.ticket.tkt_vno, 5,
945                                  "Got wrong as_rep->ticket.tkt_vno");
946         torture_assert(test_context->tctx,
947                        test_context->tgs_rep.ticket.enc_part.kvno,
948                        "Did not get a KVNO in test_context->as_rep.ticket.enc_part.kvno");
949         torture_assert_str_equal(test_context->tctx,
950                                  test_context->tgs_rep.ticket.realm,
951                                  test_context->test_data->real_realm,
952                                  "Mismatch in realm between ticket response and expected upper case REALM");
953         torture_assert_int_equal(test_context->tctx,
954                                  test_context->tgs_req.req_body.sname->name_type,
955                                  test_context->tgs_rep.ticket.sname.name_type, "Mismatch in name_type between request and ticket response");
956         torture_assert_int_equal(test_context->tctx,
957                                  test_context->tgs_rep.ticket.sname.name_string.len, 2,
958                                  "Mismatch in name between request and expected request, expected service/hostname");
959         torture_assert_str_equal(test_context->tctx,
960                                  test_context->tgs_rep.ticket.sname.name_string.val[0],
961                                  test_context->tgs_req.req_body.sname->name_string.val[0],
962                                  "Mismatch in name between request and expected request, expected service/hostname");
963         torture_assert_str_equal(test_context->tctx,
964                                  test_context->tgs_rep.ticket.sname.name_string.val[1],
965                                  test_context->tgs_req.req_body.sname->name_string.val[1],
966                                  "Mismatch in name between request and expected request, expected service/hostname");
967
968         torture_assert_int_equal(test_context->tctx,
969                                  *test_context->tgs_rep.ticket.enc_part.kvno & 0xFFFF0000,
970                                  0, "Unexpecedly got a RODC number in the KVNO, should just be principal KVNO");
971         free_TGS_REP(&test_context->tgs_rep);
972
973         torture_assert(test_context->tctx, test_context->packet_count < 2, "too many packets");
974         return true;
975 }
976
977 /*
978  * TEST_AS_REQ_SELF - RECV
979  *
980  * Confirm that the reply packet from the KDC meets certain
981  * expectations as part of TEST_AS_REQ.  This uses a packet count to
982  * work out what packet we are up to in the multiple exchanged
983  * triggerd by krb5_get_init_creds_password().
984  *
985  */
986
987 static bool torture_krb5_post_recv_as_req_self_test(struct torture_krb5_context *test_context,
988                                                     const krb5_data *recv_buf)
989 {
990         KRB_ERROR error;
991         size_t used;
992         if (test_context->packet_count == 0) {
993                 krb5_error_code k5ret;
994                 /*
995                  * The client libs obtain the salt by attempting to
996                  * authenticate without pre-authentication and getting
997                  * the correct salt with the
998                  * KRB5KDC_ERR_PREAUTH_REQUIRED error.  If we are in
999                  * the test (netbios_realm && upn) that deliberatly
1000                  * has an incorrect principal, we check we get the
1001                  * correct error.
1002                  */
1003                 k5ret = decode_KRB_ERROR(recv_buf->data, recv_buf->length,
1004                                          &error, &used);
1005                 if (k5ret != 0) {
1006                         AS_REP as_rep;
1007                         k5ret = decode_AS_REP(recv_buf->data, recv_buf->length,
1008                                       &as_rep, &used);
1009                         if (k5ret == 0) {
1010                                 if (torture_setting_bool(test_context->tctx, "expect_machine_account", false) == false
1011                                     || (test_context->test_data->upn == true)) {
1012                                         torture_assert(test_context->tctx, false,
1013                                                        "expected to get a KRB_ERROR packet with "
1014                                                        "KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN or KRB5KDC_ERR_PREAUTH_REQUIRED, got valid AS-REP");
1015                                 } else {
1016                                         torture_assert(test_context->tctx, false,
1017                                                        "expected to get a KRB_ERROR packet with "
1018                                                        "KRB5KDC_ERR_PREAUTH_REQUIRED, got valid AS-REP");
1019                                 }
1020                         } else {
1021                                 if (torture_setting_bool(test_context->tctx, "expect_machine_account", false) == false
1022                                     || (test_context->test_data->upn == true)) {
1023                                         torture_assert(test_context->tctx, false,
1024                                                        "unable to decode as KRB-ERROR or AS-REP, "
1025                                                        "expected to get a KRB_ERROR packet with KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN or KRB5KDC_ERR_PREAUTH_REQUIRED");
1026                                 } else {
1027                                         torture_assert(test_context->tctx, false,
1028                                                        "unable to decode as KRB-ERROR or AS-REP, "
1029                                                        "expected to get a KRB_ERROR packet with KRB5KDC_ERR_PREAUTH_REQUIRED");
1030                                 }
1031                         }
1032                 }
1033                 torture_assert_int_equal(test_context->tctx, used, recv_buf->length,
1034                                          "length mismatch");
1035                 torture_assert_int_equal(test_context->tctx, error.pvno, 5,
1036                                          "Got wrong error.pvno");
1037                 if ((torture_setting_bool(test_context->tctx, "expect_machine_account", false) == false
1038                      || (test_context->test_data->upn == true))
1039                     && error.error_code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN - KRB5KDC_ERR_NONE) {
1040                         /*
1041                          * IGNORE
1042                          *
1043                          * This case is because Samba's Heimdal KDC
1044                          * checks server and client accounts before
1045                          * checking for pre-authentication.
1046                          */
1047                 } else {
1048                         torture_assert_int_equal(test_context->tctx,
1049                                                  error.error_code,
1050                                                  KRB5KDC_ERR_PREAUTH_REQUIRED - KRB5KDC_ERR_NONE,
1051                                                  "Got wrong error.error_code");
1052                 }
1053
1054                 free_KRB_ERROR(&error);
1055         } else if ((decode_KRB_ERROR(recv_buf->data, recv_buf->length, &error, &used) == 0)
1056                    && (test_context->packet_count == 1)) {
1057                 /*
1058                  * The Windows 2012R2 KDC will always respond with
1059                  * KRB5KRB_ERR_RESPONSE_TOO_BIG over UDP as the ticket
1060                  * won't fit, because of the PAC.  (It appears to do
1061                  * this always, even if it will).  This triggers the
1062                  * client to try again over TCP.
1063                  */
1064                 torture_assert_int_equal(test_context->tctx,
1065                                          used, recv_buf->length,
1066                                          "length mismatch");
1067                 torture_assert_int_equal(test_context->tctx,
1068                                          error.pvno, 5,
1069                                          "Got wrong error.pvno");
1070                 if ((torture_setting_bool(test_context->tctx, "expect_machine_account", false)
1071                      && (test_context->test_data->upn == false))) {
1072                         torture_assert_int_equal(test_context->tctx,
1073                                                  error.error_code,
1074                                                  KRB5KRB_ERR_RESPONSE_TOO_BIG - KRB5KDC_ERR_NONE,
1075                                                  "Got wrong error.error_code");
1076                 } else {
1077                         torture_assert_int_equal(test_context->tctx,
1078                                                  error.error_code,
1079                                                  KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN - KRB5KDC_ERR_NONE,
1080                                                  "Got wrong error.error_code");
1081                 }
1082                 free_KRB_ERROR(&error);
1083         } else {
1084                 /*
1085                  * Finally the successful packet.
1086                  */
1087                 torture_assert_int_equal(test_context->tctx,
1088                                          decode_AS_REP(recv_buf->data, recv_buf->length,
1089                                                        &test_context->as_rep, &used), 0,
1090                                          "decode_AS_REP failed");
1091                 torture_assert_int_equal(test_context->tctx, used, recv_buf->length,
1092                                          "length mismatch");
1093                 torture_assert_int_equal(test_context->tctx,
1094                                          test_context->as_rep.pvno, 5,
1095                                          "Got wrong as_rep->pvno");
1096                 torture_assert_int_equal(test_context->tctx,
1097                                          test_context->as_rep.ticket.tkt_vno, 5,
1098                                          "Got wrong as_rep->ticket.tkt_vno");
1099                 torture_assert(test_context->tctx,
1100                                test_context->as_rep.ticket.enc_part.kvno,
1101                                "Did not get a KVNO in test_context->as_rep.ticket.enc_part.kvno");
1102
1103                 /*
1104                  * We do not expect an RODC number here in the KVNO,
1105                  * as this is a ticket to the user's own account.
1106                  */
1107                 torture_assert_int_equal(test_context->tctx,
1108                                          *test_context->as_rep.ticket.enc_part.kvno & 0xFFFF0000,
1109                                          0, "Unexpecedly got a RODC number in the KVNO");
1110                 free_AS_REP(&test_context->as_rep);
1111         }
1112         torture_assert(test_context->tctx, test_context->packet_count < 3, "too many packets");
1113         free_AS_REQ(&test_context->as_req);
1114         return true;
1115 }
1116
1117 /* 
1118  * This function is set in torture_krb5_init_context_canon as krb5
1119  * send_and_recv function.  This allows us to override what server the
1120  * test is aimed at, and to inspect the packets just before they are
1121  * sent to the network, and before they are processed on the recv
1122  * side.
1123  *
1124  * The torture_krb5_pre_send_test() and torture_krb5_post_recv_test()
1125  * functions are implement the actual tests.
1126  *
1127  * When this asserts, the caller will get a spurious 'cannot contact
1128  * any KDC' message.
1129  *
1130  */
1131 static krb5_error_code smb_krb5_send_and_recv_func_canon_override(krb5_context context,
1132                                                                    void *data, /* struct torture_krb5_context */
1133                                                                    krb5_krbhst_info *hi,
1134                                                                    time_t timeout,
1135                                                                    const krb5_data *send_buf,
1136                                                                    krb5_data *recv_buf)
1137 {
1138         krb5_error_code k5ret;
1139         bool ok = false;
1140         krb5_data modified_send_buf;
1141
1142         struct torture_krb5_context *test_context
1143                 = talloc_get_type_abort(data, struct torture_krb5_context);
1144
1145         switch (test_context->test_stage) {
1146         case TEST_DONE:
1147                 torture_warning(test_context->tctx, "Unexpected outgoing packet from krb5 libs");
1148                 return EINVAL;
1149         case TEST_AS_REQ:
1150                 ok = torture_krb5_pre_send_as_req_test(test_context, send_buf,
1151                                                               &modified_send_buf);
1152                 break;
1153         case TEST_TGS_REQ_KRBTGT_CANON:
1154                 ok = torture_krb5_pre_send_tgs_req_krbtgt_canon_test(test_context, send_buf,
1155                                                                      &modified_send_buf);
1156                 break;
1157         case TEST_TGS_REQ_CANON:
1158                 ok = torture_krb5_pre_send_tgs_req_canon_test(test_context, send_buf,
1159                                                               &modified_send_buf);
1160                 break;
1161         case TEST_SELF_TRUST_TGS_REQ:
1162                 ok = torture_krb5_pre_send_self_trust_tgs_req_test(test_context, send_buf,
1163                                                                    &modified_send_buf);
1164                 break;
1165         case TEST_TGS_REQ:
1166                 ok = torture_krb5_pre_send_tgs_req_test(test_context, send_buf,
1167                                                         &modified_send_buf);
1168                 break;
1169         case TEST_TGS_REQ_KRBTGT:
1170                 ok = torture_krb5_pre_send_tgs_req_krbtgt_test(test_context, send_buf,
1171                                                                &modified_send_buf);
1172                 break;
1173         case TEST_TGS_REQ_HOST:
1174         case TEST_TGS_REQ_HOST_SRV_INST:
1175         case TEST_TGS_REQ_HOST_SRV_HST:
1176                 ok = torture_krb5_pre_send_tgs_req_host_test(test_context, send_buf,
1177                                                              &modified_send_buf);
1178                 break;
1179         case TEST_AS_REQ_SELF:
1180                 ok = torture_krb5_pre_send_as_req_test(test_context, send_buf,
1181                                                        &modified_send_buf);
1182                 break;
1183         }
1184         if (ok == false) {
1185                 return EINVAL;
1186         }
1187
1188         k5ret = smb_krb5_send_and_recv_func_forced(context, test_context->server,
1189                                                    hi, timeout, &modified_send_buf, 
1190                                                    recv_buf);
1191         if (k5ret != 0) {
1192                 return k5ret;
1193         }
1194
1195         switch (test_context->test_stage) {
1196         case TEST_DONE:
1197                 torture_warning(test_context->tctx, "Unexpected outgoing packet from krb5 libs");
1198                 return EINVAL;
1199         case TEST_AS_REQ:
1200                 ok = torture_krb5_post_recv_as_req_test(test_context, recv_buf);
1201                 break;
1202         case TEST_TGS_REQ_KRBTGT_CANON:
1203                 ok = torture_krb5_post_recv_tgs_req_krbtgt_canon_test(test_context, recv_buf);
1204                 break;
1205         case TEST_TGS_REQ_CANON:
1206                 ok = torture_krb5_post_recv_tgs_req_canon_test(test_context, recv_buf);
1207                 break;
1208         case TEST_SELF_TRUST_TGS_REQ:
1209                 ok = torture_krb5_post_recv_self_trust_tgs_req_test(test_context, recv_buf);
1210                 break;
1211         case TEST_TGS_REQ:
1212                 ok = torture_krb5_post_recv_tgs_req_test(test_context, recv_buf);
1213                 break;
1214         case TEST_TGS_REQ_KRBTGT:
1215                 ok = torture_krb5_post_recv_self_trust_tgs_req_test(test_context, recv_buf);
1216                 break;
1217         case TEST_TGS_REQ_HOST:
1218         case TEST_TGS_REQ_HOST_SRV_INST:
1219         case TEST_TGS_REQ_HOST_SRV_HST:
1220                 ok = torture_krb5_post_recv_tgs_req_host_test(test_context, recv_buf);
1221                 break;
1222         case TEST_AS_REQ_SELF:
1223                 ok = torture_krb5_post_recv_as_req_self_test(test_context, recv_buf);
1224                 break;
1225         }
1226         if (ok == false) {
1227                 return EINVAL;
1228         }
1229
1230         test_context->packet_count++;
1231         
1232         return k5ret;
1233 }
1234
1235 static int test_context_destructor(struct torture_krb5_context *test_context)
1236 {
1237         freeaddrinfo(test_context->server);
1238         return 0;
1239 }
1240         
1241
1242 static bool torture_krb5_init_context_canon(struct torture_context *tctx,
1243                                              struct test_data *test_data,
1244                                              struct torture_krb5_context **torture_krb5_context)
1245 {
1246         const char *host = torture_setting_string(tctx, "host", NULL);
1247         krb5_error_code k5ret;
1248         bool ok;
1249
1250         struct torture_krb5_context *test_context = talloc_zero(tctx, struct torture_krb5_context);
1251         torture_assert(tctx, test_context != NULL, "Failed to allocate");
1252
1253         test_context->test_data = test_data;
1254         test_context->tctx = tctx;
1255         
1256         k5ret = smb_krb5_init_context(test_context, tctx->lp_ctx, &test_context->smb_krb5_context);
1257         torture_assert_int_equal(tctx, k5ret, 0, "smb_krb5_init_context failed");
1258
1259         ok = interpret_string_addr_internal(&test_context->server, host, AI_NUMERICHOST);
1260         torture_assert(tctx, ok, "Failed to parse target server");
1261
1262         talloc_set_destructor(test_context, test_context_destructor);
1263         
1264         set_sockaddr_port(test_context->server->ai_addr, 88);
1265
1266         k5ret = krb5_set_send_to_kdc_func(test_context->smb_krb5_context->krb5_context,
1267                                           smb_krb5_send_and_recv_func_canon_override,
1268                                           test_context);
1269         torture_assert_int_equal(tctx, k5ret, 0, "krb5_set_send_to_kdc_func failed");
1270         *torture_krb5_context = test_context;
1271         return true;
1272 }
1273
1274
1275 static bool torture_krb5_as_req_canon(struct torture_context *tctx, const void *tcase_data)
1276 {
1277         krb5_error_code k5ret;
1278         krb5_get_init_creds_opt *krb_options = NULL;
1279         struct test_data *test_data = talloc_get_type_abort(tcase_data, struct test_data);
1280         krb5_principal principal;
1281         krb5_principal krbtgt_other;
1282         krb5_principal expected_principal;
1283         char *principal_string;
1284         char *krbtgt_other_string;
1285         int principal_flags;
1286         char *expected_principal_string;
1287         int expected_principal_flags;
1288         char *got_principal_string;
1289         char *assertion_message;
1290         const char *password = cli_credentials_get_password(cmdline_credentials);
1291         krb5_context k5_context;
1292         struct torture_krb5_context *test_context;
1293         bool ok;
1294         krb5_creds my_creds;
1295         krb5_creds *server_creds;
1296         krb5_ccache ccache;
1297         krb5_auth_context auth_context;
1298         char *cc_name;
1299         krb5_data in_data, enc_ticket;
1300         krb5_get_creds_opt opt;
1301         
1302         const char *upn = torture_setting_string(tctx, "krb5-upn", "");
1303         test_data->krb5_service = torture_setting_string(tctx, "krb5-service", "host");
1304         test_data->krb5_hostname = torture_setting_string(tctx, "krb5-hostname", "");
1305
1306         /* 
1307          * If we have not passed a UPN on the command line,
1308          * then skip the UPN tests.
1309          */
1310         if (test_data->upn && upn[0] == '\0') {
1311                 torture_skip(tctx, "This test needs a UPN specified as --option=torture:krb5-upn=user@example.com to run");
1312         }
1313
1314         if (test_data->netbios_realm) {
1315                 test_data->realm = test_data->real_domain;
1316         } else {
1317                 test_data->realm = test_data->real_realm;
1318         }
1319
1320         if (test_data->upn) {
1321                 char *p;
1322                 test_data->username = talloc_strdup(test_data, upn);
1323                 p = strchr(test_data->username, '@');
1324                 if (p) {
1325                         *p = '\0';
1326                         p++;
1327                 }
1328                 /* 
1329                  * Test the UPN behaviour carefully.  We can
1330                  * test in two different modes, depending on
1331                  * what UPN has been set up for us.
1332                  *
1333                  * If the UPN is in our realm, then we do all the tests with this name also.  
1334                  *
1335                  * If the UPN is not in our realm, then we
1336                  * expect the tests that replace the realm to
1337                  * fail (as it won't match)
1338                  */
1339                 if (strcasecmp(p, test_data->real_realm) != 0) {
1340                         test_data->other_upn_suffix = true;
1341                 } else {
1342                         test_data->other_upn_suffix = false;
1343                 }
1344
1345                 /* 
1346                  * This lets us test the combination of the UPN prefix
1347                  * with a valid domain, without adding even more
1348                  * combinations 
1349                  */
1350                 if (test_data->netbios_realm == false) {
1351                         test_data->realm = p;
1352                 }
1353         }
1354
1355         ok = torture_krb5_init_context_canon(tctx, test_data, &test_context);
1356         torture_assert(tctx, ok, "torture_krb5_init_context failed");
1357         k5_context = test_context->smb_krb5_context->krb5_context;
1358         
1359         if (test_data->upper_realm) {
1360                 test_data->realm = strupper_talloc(test_data, test_data->realm);
1361         } else {
1362                 test_data->realm = strlower_talloc(test_data, test_data->realm);
1363         }
1364         if (test_data->upper_username) {
1365                 test_data->username = strupper_talloc(test_data, test_data->username);
1366         } else {
1367                 test_data->username = talloc_strdup(test_data, test_data->username);
1368         }
1369
1370         principal_string = talloc_asprintf(test_data, "%s@%s", test_data->username, test_data->realm);
1371         
1372         /* 
1373          * If we are set to canonicalize, we get back the fixed UPPER
1374          * case realm, and the real username (ie matching LDAP
1375          * samAccountName) 
1376          *
1377          * Otherwise, if we are set to enterprise, we
1378          * get back the whole principal as-sent 
1379          *
1380          * Finally, if we are not set to canonicalize, we get back the
1381          * fixed UPPER case realm, but the as-sent username
1382          */
1383         if (test_data->canonicalize) {
1384                 expected_principal_string = talloc_asprintf(test_data,
1385                                                             "%s@%s",
1386                                                             test_data->real_username,
1387                                                             test_data->real_realm);
1388         } else if (test_data->enterprise) {
1389                 expected_principal_string = principal_string;
1390         } else {
1391                 expected_principal_string = talloc_asprintf(test_data,
1392                                                             "%s@%s",
1393                                                             test_data->username,
1394                                                             test_data->real_realm);
1395         }
1396         
1397         if (test_data->enterprise) {
1398                 principal_flags = KRB5_PRINCIPAL_PARSE_ENTERPRISE;
1399         } else {
1400                 if (test_data->upn && test_data->other_upn_suffix) {
1401                         torture_skip(tctx, "UPN test for UPN with other UPN suffix only runs with enterprise principals");
1402                 }
1403                 principal_flags = 0;
1404         }
1405
1406         if (test_data->canonicalize) {
1407                 expected_principal_flags = 0;
1408         } else {
1409                 expected_principal_flags = principal_flags;
1410         }
1411
1412         torture_assert_int_equal(tctx,
1413                                  krb5_parse_name_flags(k5_context,
1414                                                        principal_string,
1415                                                        principal_flags,
1416                                                        &principal),
1417                                          0, "krb5_parse_name_flags failed");
1418         torture_assert_int_equal(tctx,
1419                                  krb5_parse_name_flags(k5_context,
1420                                                        expected_principal_string,
1421                                                        expected_principal_flags,
1422                                                        &expected_principal),
1423                                  0, "krb5_parse_name_flags failed");
1424
1425         /*
1426          * Prepare a AS-REQ and run the TEST_AS_REQ tests
1427          *
1428          */
1429
1430         test_context->test_stage = TEST_AS_REQ;
1431         test_context->packet_count = 0;
1432
1433         /* 
1434          * Set the canonicalize flag if this test requires it
1435          */
1436         torture_assert_int_equal(tctx,
1437                                  krb5_get_init_creds_opt_alloc(k5_context, &krb_options),
1438                                  0, "krb5_get_init_creds_opt_alloc failed");
1439                 
1440         torture_assert_int_equal(tctx,
1441                                  krb5_get_init_creds_opt_set_canonicalize(k5_context,
1442                                                                           krb_options,
1443                                                                           test_data->canonicalize),
1444                                  0, "krb5_get_init_creds_opt_set_canonicalize failed");
1445
1446         torture_assert_int_equal(tctx,
1447                                  krb5_get_init_creds_opt_set_win2k(k5_context,
1448                                                                    krb_options,
1449                                                                    test_data->win2k),
1450                                  0, "krb5_get_init_creds_opt_set_win2k failed");
1451
1452         k5ret = krb5_get_init_creds_password(k5_context, &my_creds, principal,
1453                                              password, NULL, NULL, 0,
1454                                              NULL, krb_options);
1455         
1456         if (test_data->netbios_realm && test_data->upn) {
1457                 torture_assert_int_equal(tctx, k5ret,
1458                                          KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN,
1459                                          "Got wrong error_code from krb5_get_init_creds_password");
1460                 /* We can't proceed with more checks */
1461                 return true;
1462         } else {
1463                 assertion_message = talloc_asprintf(tctx,
1464                                                     "krb5_get_init_creds_password for %s failed: %s",
1465                                                     principal_string,
1466                                                     smb_get_krb5_error_message(k5_context, k5ret, tctx));
1467                 torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
1468         }
1469         
1470         torture_assert(tctx,
1471                        test_context->packet_count > 1,
1472                        "Expected krb5_get_init_creds_password to send more packets");
1473
1474         /*
1475          * Assert that the reply was with the correct type of
1476          * principal, depending on the flags we set
1477          */
1478         if (test_data->canonicalize == false && test_data->enterprise) {
1479                 torture_assert_int_equal(tctx,
1480                                          krb5_principal_get_type(k5_context,
1481                                                                  my_creds.client),
1482                                          KRB5_NT_ENTERPRISE_PRINCIPAL,
1483                                          "smb_krb5_init_context gave incorrect client->name.name_type");
1484         } else {
1485                 torture_assert_int_equal(tctx,
1486                                          krb5_principal_get_type(k5_context,
1487                                                                  my_creds.client),
1488                                          KRB5_NT_PRINCIPAL,
1489                                          "smb_krb5_init_context gave incorrect client->name.name_type");
1490         }
1491
1492         torture_assert_int_equal(tctx,
1493                                  krb5_unparse_name(k5_context,
1494                                                    my_creds.client, &got_principal_string), 0,
1495                                  "krb5_unparse_name failed");
1496
1497         assertion_message = talloc_asprintf(tctx,
1498                                             "krb5_get_init_creds_password returned a different principal %s to what was expected %s",
1499                                             got_principal_string, expected_principal_string);
1500         krb5_free_unparsed_name(k5_context, got_principal_string);
1501
1502         torture_assert(tctx, krb5_principal_compare(k5_context,
1503                                                     my_creds.client, expected_principal),
1504                        assertion_message);
1505
1506
1507         torture_assert_int_equal(tctx,
1508                                  krb5_principal_get_type(k5_context,
1509                                                          my_creds.server), KRB5_NT_SRV_INST,
1510                                  "smb_krb5_init_context gave incorrect server->name.name_type");
1511
1512         torture_assert_int_equal(tctx,
1513                                  krb5_principal_get_num_comp(k5_context,
1514                                                              my_creds.server), 2,
1515                                  "smb_krb5_init_context gave incorrect number of components in my_creds.server->name");
1516
1517         torture_assert_str_equal(tctx,
1518                                  krb5_principal_get_comp_string(k5_context,
1519                                                                 my_creds.server, 0),
1520                                  "krbtgt",
1521                                  "smb_krb5_init_context gave incorrect my_creds.server->name.name_string[0]");
1522
1523         if (test_data->canonicalize || test_data->enterprise) {
1524                 torture_assert_str_equal(tctx,
1525                                          krb5_principal_get_comp_string(k5_context,
1526                                                                         my_creds.server, 1),
1527                                          test_data->real_realm,
1528
1529                                          "smb_krb5_init_context gave incorrect my_creds.server->name.name_string[1]");
1530         } else {
1531                 torture_assert_str_equal(tctx,
1532                                          krb5_principal_get_comp_string(k5_context,
1533                                                                         my_creds.server, 1),
1534                                          test_data->realm,
1535
1536                                          "smb_krb5_init_context gave incorrect my_creds.server->name.name_string[1]");
1537         }
1538         torture_assert_str_equal(tctx,
1539                                  krb5_principal_get_realm(k5_context,
1540                                                           my_creds.server),
1541                                  test_data->real_realm,
1542                                  "smb_krb5_init_context gave incorrect my_creds.server->realm");
1543
1544         /* Store the result of the 'kinit' above into a memory ccache */
1545         cc_name = talloc_asprintf(tctx, "MEMORY:%s", test_data->test_name);
1546         torture_assert_int_equal(tctx, krb5_cc_resolve(k5_context, cc_name,
1547                                                        &ccache),
1548                                  0, "krb5_cc_resolve failed");
1549
1550         torture_assert_int_equal(tctx, krb5_cc_initialize(k5_context,
1551                                                           ccache, my_creds.client),
1552                                  0, "krb5_cc_initialize failed");
1553
1554         torture_assert_int_equal(tctx, krb5_cc_store_cred(k5_context,
1555                                                           ccache, &my_creds),
1556                                  0, "krb5_cc_store_cred failed");
1557
1558         /*
1559          * Prepare a TGS-REQ and run the TEST_TGS_REQ_KRBTGT_CANON tests
1560          *
1561          * This tests krb5_get_creds behaviour, which allows us to set
1562          * the KRB5_GC_CANONICALIZE option against the krbtgt/ principal
1563          */
1564
1565         krbtgt_other_string = talloc_asprintf(test_data, "krbtgt/%s@%s", test_data->real_domain, test_data->real_realm);
1566         torture_assert_int_equal(tctx,
1567                                  krb5_make_principal(k5_context, &krbtgt_other,
1568                                                      test_data->real_realm, "krbtgt",
1569                                                      test_data->real_domain, NULL),
1570                                  0, "krb5_make_principal failed");
1571
1572         test_context->test_stage = TEST_TGS_REQ_KRBTGT_CANON;
1573         test_context->packet_count = 0;
1574
1575         torture_assert_int_equal(tctx,
1576                                  krb5_get_creds_opt_alloc(k5_context, &opt),
1577                                  0, "krb5_get_creds_opt_alloc");
1578
1579         krb5_get_creds_opt_add_options(k5_context,
1580                                        opt,
1581                                        KRB5_GC_CANONICALIZE);
1582
1583         krb5_get_creds_opt_add_options(k5_context,
1584                                        opt,
1585                                        KRB5_GC_NO_STORE);
1586
1587         /* Confirm if we can get a ticket krbtgt/realm that we got back with the initial kinit */
1588         k5ret = krb5_get_creds(k5_context, opt, ccache, krbtgt_other, &server_creds);
1589
1590         if (test_data->canonicalize == false && test_data->enterprise == false
1591             && test_data->netbios_realm && test_data->upper_realm) {
1592                 /*
1593                  * In these situations, the code above does store a
1594                  * principal in the credentials cache matching what
1595                  * krb5_get_creds() needs, so the test succeds, with no packets.
1596                  *
1597                  */
1598                 assertion_message = talloc_asprintf(tctx,
1599                                                     "krb5_get_creds for %s failed with: %s",
1600                                                     krbtgt_other_string,
1601                                                     smb_get_krb5_error_message(k5_context, k5ret,
1602                                                                                tctx));
1603
1604                 torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
1605                 torture_assert_int_equal(tctx,
1606                                          test_context->packet_count,
1607                                          0, "Expected krb5_get_creds not to send packets");
1608         } else if (test_data->canonicalize == false && test_data->enterprise == false
1609                    && (test_data->upper_realm == false || test_data->netbios_realm == true)) {
1610                 torture_assert_int_equal(tctx, k5ret, KRB5_CC_NOTFOUND,
1611                                          "krb5_get_creds should have failed with KRB5_CC_NOTFOUND");
1612         } else {
1613
1614                 /*
1615                  * In these situations, the code above does not store a
1616                  * principal in the credentials cache matching what
1617                  * krb5_get_creds() needs without talking to the KDC, so the
1618                  * test fails with looping detected because when we set
1619                  * canonicalize we confuse the client libs.
1620                  *
1621                  */
1622                 assertion_message = talloc_asprintf(tctx,
1623                                                     "krb5_get_creds for %s should have failed with looping detected: %s",
1624                                                     krbtgt_other_string,
1625                                                     smb_get_krb5_error_message(k5_context, k5ret,
1626                                                                                tctx));
1627
1628                 torture_assert_int_equal(tctx, k5ret, KRB5_GET_IN_TKT_LOOP, assertion_message);
1629                 torture_assert_int_equal(tctx,
1630                                          test_context->packet_count,
1631                                          2, "Expected krb5_get_creds to send packets");
1632         }
1633
1634         /*
1635          * Prepare a TGS-REQ and run the TEST_TGS_REQ_CANON tests
1636          *
1637          * This tests krb5_get_creds behaviour, which allows us to set
1638          * the KRB5_GC_CANONICALIZE option
1639          */
1640
1641         test_context->test_stage = TEST_TGS_REQ_CANON;
1642         test_context->packet_count = 0;
1643
1644         torture_assert_int_equal(tctx,
1645                                  krb5_get_creds_opt_alloc(k5_context, &opt),
1646                                  0, "krb5_get_creds_opt_alloc");
1647
1648         krb5_get_creds_opt_add_options(k5_context,
1649                                        opt,
1650                                        KRB5_GC_CANONICALIZE);
1651
1652         krb5_get_creds_opt_add_options(k5_context,
1653                                        opt,
1654                                        KRB5_GC_NO_STORE);
1655
1656         /* Confirm if we can get a ticket to our own name */
1657         k5ret = krb5_get_creds(k5_context, opt, ccache, principal, &server_creds);
1658
1659         /*
1660          * In these situations, the code above does not store a
1661          * principal in the credentials cache matching what
1662          * krb5_get_creds() needs, so the test fails.
1663          *
1664          */
1665         if (test_data->canonicalize == false && test_data->enterprise == false
1666             && (test_data->upper_realm == false || test_data->netbios_realm == true)) {
1667                 torture_assert_int_equal(tctx, k5ret, KRB5_CC_NOTFOUND,
1668                                          "krb5_get_creds should have failed with KRB5_CC_NOTFOUND");
1669         } else {
1670                 assertion_message = talloc_asprintf(tctx,
1671                                                     "krb5_get_creds for %s failed: %s",
1672                                                     principal_string,
1673                                                     smb_get_krb5_error_message(k5_context, k5ret,
1674                                                                                tctx));
1675
1676                 /*
1677                  * Only machine accounts (strictly, accounts with a
1678                  * servicePrincipalName) can expect this test to succeed
1679                  */
1680                 if (torture_setting_bool(tctx, "expect_machine_account", false)
1681                     && (test_data->enterprise || test_data->upn == false)) {
1682                         torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
1683                         torture_assert_int_equal(tctx, krb5_cc_store_cred(k5_context,
1684                                                                           ccache, server_creds),
1685                                                  0, "krb5_cc_store_cred failed");
1686
1687                         torture_assert_int_equal(tctx,
1688                                                  krb5_free_creds(k5_context,
1689                                                                  server_creds),
1690                                                  0, "krb5_free_cred_contents failed");
1691
1692                 } else {
1693                         torture_assert_int_equal(tctx, k5ret, KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN,
1694                                                  assertion_message);
1695                 }
1696
1697                 torture_assert_int_equal(tctx,
1698                                          test_context->packet_count,
1699                                          1, "Expected krb5_get_creds to send packets");
1700         }
1701
1702         /*
1703          * Confirm gettting a ticket to pass to the server, running
1704          * either the TEST_TGS_REQ or TEST_SELF_TRUST_TGS_REQ stage.
1705          *
1706          * This triggers the client to attempt to get a
1707          * cross-realm ticket between the alternate names of
1708          * the server, and we need to confirm that behaviour.
1709          *
1710          */
1711
1712         /*
1713          * This tries to guess when the krb5 libs will ask for a
1714          * cross-realm ticket, and when they will just ask the KDC
1715          * directly.
1716          */
1717         if (test_context->test_data->canonicalize == false
1718             || test_context->test_data->enterprise
1719             || (test_context->test_data->upper_realm
1720                 && test_context->test_data->netbios_realm == false)) {
1721                 test_context->test_stage = TEST_TGS_REQ;
1722         } else {
1723                 test_context->test_stage = TEST_SELF_TRUST_TGS_REQ;
1724         }
1725
1726         test_context->packet_count = 0;
1727         torture_assert_int_equal(tctx, krb5_auth_con_init(k5_context, &auth_context),
1728                                  0, "krb5_auth_con_init failed");
1729
1730         in_data.length = 0;
1731         k5ret = krb5_mk_req_exact(k5_context,
1732                                   &auth_context,
1733                                   0,
1734                                   principal,
1735                                   &in_data, ccache,
1736                                   &enc_ticket);
1737         assertion_message = talloc_asprintf(tctx,
1738                                             "krb5_mk_req_exact for %s failed: %s",
1739                                             principal_string,
1740                                             smb_get_krb5_error_message(k5_context, k5ret, tctx));
1741
1742         /*
1743          * Only machine accounts (strictly, accounts with a
1744          * servicePrincipalName) can expect this test to succeed
1745          */
1746         if (torture_setting_bool(tctx, "expect_machine_account", false) && (test_data->enterprise || test_data->upn == false)) {
1747                 torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
1748         } else {
1749                 torture_assert_int_equal(tctx, k5ret, KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN,
1750                                          assertion_message);
1751         }
1752
1753         /*
1754          * Only in these cases would the above code have needed to
1755          * send packets to the network
1756          */
1757         if (test_data->canonicalize == false && test_data->enterprise == false
1758             && (test_data->upper_realm == false || test_data->netbios_realm == true)) {
1759                 torture_assert(tctx,
1760                                test_context->packet_count > 0,
1761                                "Expected krb5_mk_req_exact to send packets");
1762         }
1763
1764         /*
1765          * Confirm gettting a ticket to pass to the server, running
1766          * the TEST_TGS_REQ_HOST, TEST_TGS_REQ_HOST_SRV_INST, TEST_TGS_REQ_HOST_SRV_HST stage
1767          *
1768          * This triggers the client to attempt to get a
1769          * cross-realm ticket between the alternate names of
1770          * the server, and we need to confirm that behaviour.
1771          *
1772          */
1773
1774         if (*test_data->krb5_service && *test_data->krb5_hostname) {
1775                 krb5_principal host_principal_srv_inst;
1776                 /*
1777                  * This tries to guess when the krb5 libs will ask for a
1778                  * cross-realm ticket, and when they will just ask the KDC
1779                  * directly.
1780                  */
1781                 test_context->test_stage = TEST_TGS_REQ_HOST;
1782                 test_context->packet_count = 0;
1783                 torture_assert_int_equal(tctx, krb5_auth_con_init(k5_context, &auth_context),
1784                                          0, "krb5_auth_con_init failed");
1785
1786                 in_data.length = 0;
1787                 k5ret = krb5_mk_req(k5_context,
1788                                     &auth_context,
1789                                     0,
1790                                     test_data->krb5_service,
1791                                     test_data->krb5_hostname,
1792                                     &in_data, ccache,
1793                                     &enc_ticket);
1794
1795                 if (test_data->canonicalize == false && test_data->enterprise == false
1796                     && (test_data->upper_realm == false || test_data->netbios_realm == true)) {
1797                         torture_assert_int_equal(tctx, k5ret, KRB5_CC_NOTFOUND,
1798                                                  "krb5_get_creds should have failed with KRB5_CC_NOTFOUND");
1799                 } else {
1800                         assertion_message = talloc_asprintf(tctx,
1801                                                             "krb5_mk_req for %s/%s failed: %s",
1802                                                             test_data->krb5_hostname,
1803                                                             test_data->krb5_service,
1804                                                             smb_get_krb5_error_message(k5_context, k5ret, tctx));
1805
1806                         torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
1807                         /*
1808                          * Only in these cases would the above code have needed to
1809                          * send packets to the network
1810                          */
1811                         torture_assert(tctx,
1812                                        test_context->packet_count > 0,
1813                                        "Expected krb5_get_creds to send packets");
1814                 }
1815
1816
1817                 test_context->test_stage = TEST_TGS_REQ_HOST_SRV_INST;
1818                 test_context->packet_count = 0;
1819
1820                 torture_assert_int_equal(tctx,
1821                                          krb5_make_principal(k5_context, &host_principal_srv_inst,
1822                                                              test_data->real_realm,
1823                                                              strupper_talloc(tctx, test_data->krb5_service),
1824                                                              test_data->krb5_hostname,
1825                                                              NULL),
1826                                          0, "krb5_make_principal failed");
1827
1828                 krb5_principal_set_type(k5_context, host_principal_srv_inst, KRB5_NT_SRV_INST);
1829
1830                 torture_assert_int_equal(tctx, krb5_auth_con_init(k5_context, &auth_context),
1831                                          0, "krb5_auth_con_init failed");
1832
1833                 in_data.length = 0;
1834                 k5ret = krb5_mk_req_exact(k5_context,
1835                                           &auth_context,
1836                                           0,
1837                                           host_principal_srv_inst,
1838                                           &in_data, ccache,
1839                                           &enc_ticket);
1840                 krb5_free_principal(k5_context, host_principal_srv_inst);
1841                 if (test_data->canonicalize == false && test_data->enterprise == false
1842                     && (test_data->upper_realm == false || test_data->netbios_realm == true)) {
1843                         torture_assert_int_equal(tctx, k5ret, KRB5_CC_NOTFOUND,
1844                                                  "krb5_get_creds should have failed with KRB5_CC_NOTFOUND");
1845                 } else {
1846                         assertion_message = talloc_asprintf(tctx,
1847                                                             "krb5_mk_req for %s/%s KRB5_NT_SRV_INST failed: %s",
1848                                                             test_data->krb5_service,
1849                                                             test_data->krb5_hostname,
1850                                                             smb_get_krb5_error_message(k5_context, k5ret, tctx));
1851
1852                         torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
1853                         /*
1854                          * Only in these cases would the above code have needed to
1855                          * send packets to the network
1856                          */
1857                         torture_assert(tctx,
1858                                        test_context->packet_count > 0,
1859                                        "Expected krb5_get_creds to send packets");
1860                 }
1861
1862
1863                 test_context->test_stage = TEST_TGS_REQ_HOST_SRV_HST;
1864                 test_context->packet_count = 0;
1865
1866                 torture_assert_int_equal(tctx,
1867                                          krb5_make_principal(k5_context, &host_principal_srv_inst,
1868                                                              test_data->real_realm,
1869                                                              test_data->krb5_service,
1870                                                              strupper_talloc(tctx, test_data->krb5_hostname),
1871                                                              NULL),
1872                                          0, "krb5_make_principal failed");
1873
1874                 krb5_principal_set_type(k5_context, host_principal_srv_inst, KRB5_NT_SRV_HST);
1875
1876                 torture_assert_int_equal(tctx, krb5_auth_con_init(k5_context, &auth_context),
1877                                          0, "krb5_auth_con_init failed");
1878
1879                 in_data.length = 0;
1880                 k5ret = krb5_mk_req_exact(k5_context,
1881                                           &auth_context,
1882                                           0,
1883                                           host_principal_srv_inst,
1884                                           &in_data, ccache,
1885                                           &enc_ticket);
1886                 krb5_free_principal(k5_context, host_principal_srv_inst);
1887                 if (test_data->canonicalize == false && test_data->enterprise == false
1888                     && (test_data->upper_realm == false || test_data->netbios_realm == true)) {
1889                         torture_assert_int_equal(tctx, k5ret, KRB5_CC_NOTFOUND,
1890                                                  "krb5_get_creds should have failed with KRB5_CC_NOTFOUND");
1891                 } else {
1892                         assertion_message = talloc_asprintf(tctx,
1893                                                             "krb5_mk_req for %s/%s KRB5_NT_SRV_INST failed: %s",
1894                                                             test_data->krb5_service,
1895                                                             test_data->krb5_hostname,
1896                                                             smb_get_krb5_error_message(k5_context, k5ret, tctx));
1897
1898                         torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
1899                         /*
1900                          * Only in these cases would the above code have needed to
1901                          * send packets to the network
1902                          */
1903                         torture_assert(tctx,
1904                                        test_context->packet_count > 0,
1905                                        "Expected krb5_get_creds to send packets");
1906                 }
1907         }
1908
1909         /*
1910          * Confirm gettting a ticket for the same krbtgt/realm that we
1911          * got back with the initial ticket, running the
1912          * TEST_TGS_REQ_KRBTGT stage.
1913          *
1914          */
1915
1916         test_context->test_stage = TEST_TGS_REQ_KRBTGT;
1917         test_context->packet_count = 0;
1918
1919         in_data.length = 0;
1920         k5ret = krb5_mk_req_exact(k5_context,
1921                                   &auth_context,
1922                                   0,
1923                                   my_creds.server,
1924                                   &in_data, ccache,
1925                                   &enc_ticket);
1926
1927         assertion_message = talloc_asprintf(tctx,
1928                                             "krb5_mk_req_exact for %s failed: %s",
1929                                             principal_string,
1930                                             smb_get_krb5_error_message(k5_context, k5ret, tctx));
1931         torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
1932
1933         /*
1934          * Confirm gettting a ticket for our own principal that we
1935          * got back with the initial ticket, running the
1936          * TEST_AS_REQ_SELF stage.
1937          *
1938          */
1939         test_context->test_stage = TEST_AS_REQ_SELF;
1940         test_context->packet_count = 0;
1941
1942         k5ret = krb5_get_init_creds_password(k5_context, &my_creds, principal,
1943                                              password, NULL, NULL, 0,
1944                                              principal_string, krb_options);
1945
1946         if (torture_setting_bool(test_context->tctx, "expect_machine_account", false) && (test_data->upn == false)) {
1947                 assertion_message = talloc_asprintf(tctx,
1948                                                     "krb5_get_init_creds_password for %s failed: %s",
1949                                                     principal_string,
1950                                                     smb_get_krb5_error_message(k5_context, k5ret, tctx));
1951                 torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
1952                 torture_assert(tctx,
1953                                test_context->packet_count >= 2,
1954                                "Expected krb5_get_init_creds_password to send more packets");
1955
1956         } else {
1957                 assertion_message = talloc_asprintf(tctx,
1958                                                     "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);
1959                 torture_assert_int_equal(tctx, k5ret,
1960                                          KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN,
1961                                          assertion_message);
1962                 torture_assert(tctx,
1963                                test_context->packet_count >= 1,
1964                                "Expected krb5_get_init_creds_password to send more packets");
1965
1966                 /* We can't proceed with more checks */
1967                 return true;
1968         }
1969
1970         /*
1971          * Assert that the reply was with the correct type of
1972          * principal, depending on the flags we set
1973          */
1974         if (test_data->canonicalize == false && test_data->enterprise) {
1975                 torture_assert_int_equal(tctx,
1976                                          krb5_principal_get_type(k5_context,
1977                                                                  my_creds.client),
1978                                          KRB5_NT_ENTERPRISE_PRINCIPAL,
1979                                          "smb_krb5_init_context gave incorrect client->name.name_type");
1980                 torture_assert_int_equal(tctx,
1981                                          krb5_principal_get_type(k5_context,
1982                                                                  my_creds.server),
1983                                          KRB5_NT_ENTERPRISE_PRINCIPAL,
1984                                          "smb_krb5_init_context gave incorrect server->name.name_type");
1985         } else {
1986                 torture_assert_int_equal(tctx,
1987                                          krb5_principal_get_type(k5_context,
1988                                                                  my_creds.client),
1989                                          KRB5_NT_PRINCIPAL,
1990                                          "smb_krb5_init_context gave incorrect client->name.name_type");
1991                 torture_assert_int_equal(tctx,
1992                                          krb5_principal_get_type(k5_context,
1993                                                                  my_creds.server),
1994                                          KRB5_NT_PRINCIPAL,
1995                                          "smb_krb5_init_context gave incorrect server->name.name_type");
1996         }
1997
1998         torture_assert_int_equal(tctx,
1999                                  krb5_unparse_name(k5_context,
2000                                                    my_creds.client, &got_principal_string), 0,
2001                                  "krb5_unparse_name failed");
2002
2003         assertion_message = talloc_asprintf(tctx,
2004                                             "krb5_get_init_creds_password returned a different principal %s to what was expected %s",
2005                                             got_principal_string, expected_principal_string);
2006         krb5_free_unparsed_name(k5_context, got_principal_string);
2007
2008         torture_assert(tctx, krb5_principal_compare(k5_context,
2009                                                     my_creds.client, expected_principal),
2010                        assertion_message);
2011
2012         torture_assert_int_equal(tctx,
2013                                  krb5_unparse_name(k5_context,
2014                                                    my_creds.client, &got_principal_string), 0,
2015                                  "krb5_unparse_name failed");
2016
2017         assertion_message = talloc_asprintf(tctx,
2018                                             "krb5_get_init_creds_password returned a different server principal %s to what was expected %s",
2019                                             got_principal_string, expected_principal_string);
2020         krb5_free_unparsed_name(k5_context, got_principal_string);
2021
2022         torture_assert(tctx, krb5_principal_compare(k5_context,
2023                                                     my_creds.client, expected_principal),
2024                        assertion_message);
2025
2026         krb5_free_principal(k5_context, principal);
2027         krb5_get_init_creds_opt_free(k5_context, krb_options);
2028
2029         torture_assert_int_equal(tctx, krb5_free_cred_contents(k5_context, &my_creds),
2030                                  0, "krb5_free_cred_contents failed");
2031
2032         return true;
2033 }
2034
2035 struct torture_suite *torture_krb5_canon(TALLOC_CTX *mem_ctx)
2036 {
2037         unsigned int i;
2038         struct torture_suite *suite = torture_suite_create(mem_ctx, "canon");
2039         suite->description = talloc_strdup(suite, "Kerberos Canonicalisation tests");
2040
2041         for (i = 0; i < TEST_ALL; i++) {
2042                 char *name = talloc_asprintf(suite, "%s.%s.%s.%s.%s.%s.%s",
2043                                              (i & TEST_CANONICALIZE) ? "canon" : "no-canon",
2044                                              (i & TEST_ENTERPRISE) ? "enterprise" : "no-enterprise",
2045                                              (i & TEST_UPPER_REALM) ? "uc-realm" : "lc-realm",
2046                                              (i & TEST_UPPER_USERNAME) ? "uc-user" : "lc-user",
2047                                              (i & TEST_NETBIOS_REALM) ? "netbios-realm" : "krb5-realm",
2048                                              (i & TEST_WIN2K) ? "win2k" : "no-win2k",
2049                                              (i & TEST_UPN) ? "upn" : "no-upn");
2050
2051                 struct test_data *test_data = talloc_zero(suite, struct test_data);
2052
2053                 test_data->test_name = name;
2054                 test_data->real_realm
2055                         = strupper_talloc(test_data, cli_credentials_get_realm(cmdline_credentials));
2056                 test_data->real_domain = cli_credentials_get_domain(cmdline_credentials);
2057                 test_data->username = cli_credentials_get_username(cmdline_credentials);
2058                 test_data->real_username = cli_credentials_get_username(cmdline_credentials);
2059                 test_data->canonicalize = (i & TEST_CANONICALIZE) != 0;
2060                 test_data->enterprise = (i & TEST_ENTERPRISE) != 0;
2061                 test_data->upper_realm = (i & TEST_UPPER_REALM) != 0;
2062                 test_data->upper_username = (i & TEST_UPPER_USERNAME) != 0;
2063                 test_data->netbios_realm = (i & TEST_NETBIOS_REALM) != 0;
2064                 test_data->win2k = (i & TEST_WIN2K) != 0;
2065                 test_data->upn = (i & TEST_UPN) != 0;
2066                 torture_suite_add_simple_tcase_const(suite, name, torture_krb5_as_req_canon,
2067                                                      test_data);
2068                                                      
2069         }
2070         return suite;
2071 }