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