076120bfeeea839a4c7b613acddb384729a70e8f
[bbaumbach/samba-autobuild/.git] / source4 / torture / auth / pac.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
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 "auth/auth.h"
26 #include "auth/kerberos/kerberos.h"
27 #include "librpc/gen_ndr/ndr_krb5pac.h"
28 #include "samba3/samba3.h"
29 #include "libcli/security/security.h"
30 #include "torture/torture.h"
31 #include "auth/auth_sam_reply.h"
32 #include "param/param.h"
33
34 static bool torture_pac_self_check(struct torture_context *tctx)
35 {
36         NTSTATUS nt_status;
37         DATA_BLOB tmp_blob;
38         struct PAC_DATA *pac_data;
39         struct PAC_LOGON_INFO *logon_info;
40         union netr_Validation validation;
41
42         /* Generate a nice, arbitary keyblock */
43         uint8_t server_bytes[16];
44         uint8_t krbtgt_bytes[16];
45         krb5_keyblock server_keyblock;
46         krb5_keyblock krbtgt_keyblock;
47         
48         krb5_error_code ret;
49
50         struct smb_krb5_context *smb_krb5_context;
51
52         struct auth_serversupplied_info *server_info;
53         struct auth_serversupplied_info *server_info_out;
54
55         krb5_principal client_principal;
56         time_t logon_time = time(NULL);
57
58         TALLOC_CTX *mem_ctx = tctx;
59
60         torture_assert(tctx, 0 == smb_krb5_init_context(mem_ctx, 
61                                                         NULL,
62                                                         tctx->lp_ctx,
63                                                         &smb_krb5_context), 
64                        "smb_krb5_init_context");
65
66         generate_random_buffer(server_bytes, 16);
67         generate_random_buffer(krbtgt_bytes, 16);
68
69         ret = krb5_keyblock_init(smb_krb5_context->krb5_context,
70                                  ENCTYPE_ARCFOUR_HMAC,
71                                  server_bytes, sizeof(server_bytes),
72                                  &server_keyblock);
73         torture_assert(tctx, !ret, talloc_asprintf(tctx, 
74                                                    "(self test) Server Keyblock encoding failed: %s", 
75                                                    smb_get_krb5_error_message(smb_krb5_context->krb5_context, 
76                                                                               ret, mem_ctx)));
77
78         ret = krb5_keyblock_init(smb_krb5_context->krb5_context,
79                                  ENCTYPE_ARCFOUR_HMAC,
80                                  krbtgt_bytes, sizeof(krbtgt_bytes),
81                                  &krbtgt_keyblock);
82         if (ret) {
83                 char *err = smb_get_krb5_error_message(smb_krb5_context->krb5_context, 
84                                                        ret, mem_ctx);
85         
86                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
87                                             &server_keyblock);
88
89                 torture_fail(tctx, talloc_asprintf(tctx, 
90                                                    "(self test) KRBTGT Keyblock encoding failed: %s", err));
91         }
92
93         /* We need an input, and this one requires no underlying database */
94         nt_status = auth_anonymous_server_info(mem_ctx, lp_netbios_name(tctx->lp_ctx), &server_info);
95
96         if (!NT_STATUS_IS_OK(nt_status)) {
97                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
98                                             &server_keyblock);
99                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
100                                             &krbtgt_keyblock);
101                 torture_fail(tctx, "auth_anonymous_server_info");
102         }
103
104         ret = krb5_parse_name_flags(smb_krb5_context->krb5_context, 
105                                     server_info->account_name, 
106                                     KRB5_PRINCIPAL_PARSE_NO_REALM, 
107                                     &client_principal);
108         if (ret) {
109                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
110                                             &server_keyblock);
111                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
112                                             &krbtgt_keyblock);
113                 torture_fail(tctx, "krb5_parse_name_flags(norealm)");
114         }
115
116         /* OK, go ahead and make a PAC */
117         ret = kerberos_create_pac(mem_ctx, 
118                                   lp_iconv_convenience(tctx->lp_ctx),
119                                   server_info, 
120                                   smb_krb5_context->krb5_context,  
121                                   &krbtgt_keyblock,
122                                   &server_keyblock,
123                                   client_principal,
124                                   logon_time,
125                                   &tmp_blob);
126         
127         if (ret) {
128                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
129                                             &krbtgt_keyblock);
130                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
131                                             &server_keyblock);
132                 krb5_free_principal(smb_krb5_context->krb5_context, 
133                                     client_principal);
134
135                 torture_fail(tctx, talloc_asprintf(tctx,
136                                                    "(self test) PAC encoding failed: %s", 
137                                                    smb_get_krb5_error_message(smb_krb5_context->krb5_context, 
138                                                                               ret, mem_ctx)));
139         }
140
141         dump_data(10,tmp_blob.data,tmp_blob.length);
142
143         /* Now check that we can read it back (using full decode and validate) */
144         nt_status = kerberos_decode_pac(mem_ctx, 
145                                         lp_iconv_convenience(tctx->lp_ctx),
146                                         &pac_data,
147                                         tmp_blob,
148                                         smb_krb5_context->krb5_context,
149                                         &krbtgt_keyblock,
150                                         &server_keyblock,
151                                         client_principal, 
152                                         logon_time, NULL);
153
154         if (!NT_STATUS_IS_OK(nt_status)) {
155                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
156                                             &krbtgt_keyblock);
157                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
158                                             &server_keyblock);
159                 krb5_free_principal(smb_krb5_context->krb5_context, 
160                                     client_principal);
161
162                 torture_fail(tctx, talloc_asprintf(tctx,
163                                                    "(self test) PAC decoding failed: %s", 
164                                                    nt_errstr(nt_status)));
165         }
166
167         /* Now check we can read it back (using Heimdal's pac parsing) */
168         nt_status = kerberos_pac_blob_to_server_info(mem_ctx, 
169                                                      lp_iconv_convenience(tctx->lp_ctx),
170                                                      tmp_blob, 
171                                                      smb_krb5_context->krb5_context,
172                                                      &server_info_out);
173
174         if (!dom_sid_equal(server_info->account_sid, 
175                            server_info_out->account_sid)) {
176                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
177                                             &krbtgt_keyblock);
178                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
179                                             &server_keyblock);
180                 krb5_free_principal(smb_krb5_context->krb5_context, 
181                                     client_principal);
182
183                 torture_fail(tctx,  
184                              talloc_asprintf(tctx, 
185                                              "(self test) PAC Decode resulted in *different* domain SID: %s != %s",
186                                              dom_sid_string(mem_ctx, server_info->account_sid), 
187                                              dom_sid_string(mem_ctx, server_info_out->account_sid)));
188         }
189         talloc_free(server_info_out);
190
191         /* Now check that we can read it back (yet again) */
192         nt_status = kerberos_pac_logon_info(mem_ctx, 
193                                             lp_iconv_convenience(tctx->lp_ctx),
194                                             &logon_info,
195                                             tmp_blob,
196                                             smb_krb5_context->krb5_context,
197                                             &krbtgt_keyblock,
198                                             &server_keyblock,
199                                             client_principal, 
200                                             logon_time, 
201                                             NULL);
202         
203         if (!NT_STATUS_IS_OK(nt_status)) {
204                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
205                                             &krbtgt_keyblock);
206                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
207                                             &server_keyblock);
208                 krb5_free_principal(smb_krb5_context->krb5_context, 
209                                     client_principal);
210                 
211                 torture_fail(tctx,  
212                              talloc_asprintf(tctx, 
213                                              "(self test) PAC decoding (for logon info) failed: %s", 
214                                              nt_errstr(nt_status)));
215         }
216         
217         krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
218                                     &krbtgt_keyblock);
219         krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
220                                     &server_keyblock);
221         krb5_free_principal(smb_krb5_context->krb5_context, 
222                             client_principal);
223
224         /* And make a server info from the samba-parsed PAC */
225         validation.sam3 = &logon_info->info3;
226         nt_status = make_server_info_netlogon_validation(mem_ctx,
227                                                          "",
228                                                          3, &validation,
229                                                          &server_info_out); 
230         if (!NT_STATUS_IS_OK(nt_status)) {
231                 torture_fail(tctx, 
232                              talloc_asprintf(tctx, 
233                                              "(self test) PAC decoding (make server info) failed: %s", 
234                                              nt_errstr(nt_status)));
235         }
236         
237         if (!dom_sid_equal(server_info->account_sid, 
238                            server_info_out->account_sid)) {
239                 torture_fail(tctx,  
240                              talloc_asprintf(tctx, 
241                                              "(self test) PAC Decode resulted in *different* domain SID: %s != %s",
242                                              dom_sid_string(mem_ctx, server_info->account_sid), 
243                                              dom_sid_string(mem_ctx, server_info_out->account_sid)));
244         }
245         return true;
246 }
247
248
249 /* This is the PAC generated on my test network, by my test Win2k3 server.
250    -- abartlet 2005-07-04
251 */
252
253 static const uint8_t saved_pac[] = {
254         0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xd8, 0x01, 0x00, 0x00, 
255         0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
256         0x20, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
257         0x40, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
258         0x58, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc,
259         0xc8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x30, 0xdf, 0xa6, 0xcb, 
260         0x4f, 0x7d, 0xc5, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 
261         0xff, 0xff, 0xff, 0x7f, 0xc0, 0x3c, 0x4e, 0x59, 0x62, 0x73, 0xc5, 0x01, 0xc0, 0x3c, 0x4e, 0x59,
262         0x62, 0x73, 0xc5, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x16, 0x00, 0x16, 0x00,
263         0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
264         0x0c, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 
265         0x14, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x02, 0x00, 0x65, 0x00, 0x00, 0x00, 
266         0xed, 0x03, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x02, 0x00,
267         0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
268         0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x16, 0x00, 0x20, 0x00, 0x02, 0x00, 0x16, 0x00, 0x18, 0x00,
269         0x24, 0x00, 0x02, 0x00, 0x28, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
270         0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
271         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
272         0x01, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
273         0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
274         0x57, 0x00, 0x32, 0x00, 0x30, 0x00, 0x30, 0x00, 0x33, 0x00, 0x46, 0x00, 0x49, 0x00, 0x4e, 0x00,
275         0x41, 0x00, 0x4c, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
276         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
277         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
278         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
279         0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
280         0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x57, 0x00, 0x32, 0x00,
281         0x30, 0x00, 0x30, 0x00, 0x33, 0x00, 0x46, 0x00, 0x49, 0x00, 0x4e, 0x00, 0x41, 0x00, 0x4c, 0x00,
282         0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x57, 0x00, 0x49, 0x00,
283         0x4e, 0x00, 0x32, 0x00, 0x4b, 0x00, 0x33, 0x00, 0x54, 0x00, 0x48, 0x00, 0x49, 0x00, 0x4e, 0x00,
284         0x4b, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
285         0x15, 0x00, 0x00, 0x00, 0x11, 0x2f, 0xaf, 0xb5, 0x90, 0x04, 0x1b, 0xec, 0x50, 0x3b, 0xec, 0xdc,
286         0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x02, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
287         0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
288         0x80, 0x66, 0x28, 0xea, 0x37, 0x80, 0xc5, 0x01, 0x16, 0x00, 0x77, 0x00, 0x32, 0x00, 0x30, 0x00,
289         0x30, 0x00, 0x33, 0x00, 0x66, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x24, 0x00,
290         0x76, 0xff, 0xff, 0xff, 0x37, 0xd5, 0xb0, 0xf7, 0x24, 0xf0, 0xd6, 0xd4, 0xec, 0x09, 0x86, 0x5a,
291         0xa0, 0xe8, 0xc3, 0xa9, 0x00, 0x00, 0x00, 0x00, 0x76, 0xff, 0xff, 0xff, 0xb4, 0xd8, 0xb8, 0xfe,
292         0x83, 0xb3, 0x13, 0x3f, 0xfc, 0x5c, 0x41, 0xad, 0xe2, 0x64, 0x83, 0xe0, 0x00, 0x00, 0x00, 0x00
293 };
294
295 /* Check with a known 'well formed' PAC, from my test server */
296 static bool torture_pac_saved_check(struct torture_context *tctx)
297 {
298         NTSTATUS nt_status;
299         enum ndr_err_code ndr_err;
300         DATA_BLOB tmp_blob, validate_blob;
301         struct PAC_DATA *pac_data, pac_data2;
302         struct PAC_LOGON_INFO *logon_info;
303         union netr_Validation validation;
304         const char *pac_file, *pac_kdc_key, *pac_member_key;
305         struct auth_serversupplied_info *server_info_out;
306
307         krb5_keyblock server_keyblock;
308         krb5_keyblock krbtgt_keyblock, *krbtgt_keyblock_p;
309         struct samr_Password *krbtgt_bytes, *krbsrv_bytes;
310         
311         krb5_error_code ret;
312         struct smb_krb5_context *smb_krb5_context;
313
314         const char *principal_string;
315         char *broken_principal_string;
316         krb5_principal client_principal;
317         const char *authtime_string;
318         time_t authtime;
319         TALLOC_CTX *mem_ctx = tctx;
320
321         torture_assert(tctx, 0 == smb_krb5_init_context(mem_ctx, NULL,
322                                                         tctx->lp_ctx,
323                                                         &smb_krb5_context),
324                        "smb_krb5_init_context");
325
326         pac_kdc_key = torture_setting_string(tctx, "pac_kdc_key", 
327                                              "B286757148AF7FD252C53603A150B7E7");
328
329         pac_member_key = torture_setting_string(tctx, "pac_member_key", 
330                                                 "D217FAEAE5E6B5F95CCC94077AB8A5FC");
331
332         torture_comment(tctx, "Using pac_kdc_key '%s'\n", pac_kdc_key);
333         torture_comment(tctx, "Using pac_member_key '%s'\n", pac_member_key);
334
335         /* The krbtgt key in use when the above PAC was generated.
336          * This is an arcfour-hmac-md5 key, extracted with our 'net
337          * samdump' tool. */
338         if (*pac_kdc_key == 0) {
339                 krbtgt_bytes = NULL;
340         } else {
341                 krbtgt_bytes = smbpasswd_gethexpwd(mem_ctx, pac_kdc_key);
342                 if (!krbtgt_bytes) {
343                         torture_fail(tctx, "(saved test) Could not interpret krbtgt key");
344                 }
345         }
346
347         krbsrv_bytes = smbpasswd_gethexpwd(mem_ctx, pac_member_key);
348         if (!krbsrv_bytes) {
349                 torture_fail(tctx, "(saved test) Could not interpret krbsrv key");
350         }
351
352         ret = krb5_keyblock_init(smb_krb5_context->krb5_context,
353                                  ENCTYPE_ARCFOUR_HMAC,
354                                  krbsrv_bytes->hash, sizeof(krbsrv_bytes->hash),
355                                  &server_keyblock);
356         torture_assert(tctx, !ret,
357                        talloc_asprintf(tctx,
358                                        "(saved test) Server Keyblock encoding failed: %s", 
359                                        smb_get_krb5_error_message(smb_krb5_context->krb5_context, 
360                                                                   ret, mem_ctx)));
361
362         if (krbtgt_bytes) {
363                 ret = krb5_keyblock_init(smb_krb5_context->krb5_context,
364                                          ENCTYPE_ARCFOUR_HMAC,
365                                          krbtgt_bytes->hash, sizeof(krbtgt_bytes->hash),
366                                          &krbtgt_keyblock);
367                 if (ret) {
368                         krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
369                                                     &server_keyblock);
370                         torture_fail(tctx, 
371                                      talloc_asprintf(tctx, 
372                                                      "(saved test) Server Keyblock encoding failed: %s", 
373                                                      smb_get_krb5_error_message(smb_krb5_context->krb5_context, 
374                                                                                 ret, mem_ctx)));
375                 }
376                 krbtgt_keyblock_p = &krbtgt_keyblock;
377         } else {
378                 krbtgt_keyblock_p = NULL;
379         }
380
381         pac_file = torture_setting_string(tctx, "pac_file", NULL);
382         if (pac_file) {
383                 tmp_blob.data = (uint8_t *)file_load(pac_file, &tmp_blob.length, 0, mem_ctx);
384                 torture_comment(tctx, "(saved test) Loaded pac of size %ld from %s\n", (long)tmp_blob.length, pac_file);
385         } else {
386                 tmp_blob = data_blob_talloc(mem_ctx, saved_pac, sizeof(saved_pac));
387         }
388         
389         dump_data(10,tmp_blob.data,tmp_blob.length);
390
391         principal_string = torture_setting_string(tctx, "pac_client_principal", 
392                                                   "w2003final$@WIN2K3.THINKER.LOCAL");
393
394         authtime_string = torture_setting_string(tctx, "pac_authtime", "1120440609");
395         authtime = strtoull(authtime_string, NULL, 0);
396
397         ret = krb5_parse_name(smb_krb5_context->krb5_context, principal_string, 
398                               &client_principal);
399         if (ret) {
400                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
401                                             krbtgt_keyblock_p);
402                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
403                                             &server_keyblock);
404                 torture_fail(tctx,  
405                              talloc_asprintf(tctx, 
406                                              "(saved test) parsing of client principal [%s] failed: %s", 
407                                              principal_string, 
408                                              smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx)));
409         }
410
411         /* Decode and verify the signaure on the PAC */
412         nt_status = kerberos_decode_pac(mem_ctx, 
413                                         lp_iconv_convenience(tctx->lp_ctx),
414                                         &pac_data,
415                                         tmp_blob,
416                                         smb_krb5_context->krb5_context,
417                                         krbtgt_keyblock_p,
418                                         &server_keyblock, 
419                                         client_principal, authtime, NULL);
420         if (!NT_STATUS_IS_OK(nt_status)) {
421                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
422                                             krbtgt_keyblock_p);
423                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
424                                             &server_keyblock);
425                 krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
426                 
427                 torture_fail(tctx, talloc_asprintf(tctx, 
428                                                    "(saved test) PAC decoding failed: %s", 
429                                                    nt_errstr(nt_status)));
430         }
431
432         /* Now check we can read it back (using Heimdal's pac parsing) */
433         nt_status = kerberos_pac_blob_to_server_info(mem_ctx, 
434                                                      lp_iconv_convenience(tctx->lp_ctx),
435                                                      tmp_blob, 
436                                                      smb_krb5_context->krb5_context,
437                                                      &server_info_out);
438
439         if (!NT_STATUS_IS_OK(nt_status)) {
440                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
441                                             krbtgt_keyblock_p);
442                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
443                                             &server_keyblock);
444                 krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
445                 
446                 torture_fail(tctx, talloc_asprintf(tctx, 
447                                                    "(saved test) Heimdal PAC decoding failed: %s", 
448                                                    nt_errstr(nt_status)));
449         }
450
451         if (!pac_file &&
452             !dom_sid_equal(dom_sid_parse_talloc(mem_ctx, 
453                                                 "S-1-5-21-3048156945-3961193616-3706469200-1005"), 
454                            server_info_out->account_sid)) {
455                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
456                                             krbtgt_keyblock_p);
457                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
458                                             &server_keyblock);
459                 krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
460
461                 torture_fail(tctx,  
462                              talloc_asprintf(tctx, 
463                                              "(saved test) Heimdal PAC Decode resulted in *different* domain SID: %s != %s",
464                                              "S-1-5-21-3048156945-3961193616-3706469200-1005", 
465                                              dom_sid_string(mem_ctx, server_info_out->account_sid)));
466         }
467
468         talloc_free(server_info_out);
469
470         /* Parse the PAC again, for the logon info this time (using Samba4's parsing) */
471         nt_status = kerberos_pac_logon_info(mem_ctx, 
472                                             lp_iconv_convenience(tctx->lp_ctx),
473                                             &logon_info,
474                                             tmp_blob,
475                                             smb_krb5_context->krb5_context,
476                                             krbtgt_keyblock_p,
477                                             &server_keyblock,
478                                             client_principal, authtime, NULL);
479
480         if (!NT_STATUS_IS_OK(nt_status)) {
481                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
482                                             krbtgt_keyblock_p);
483                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
484                                             &server_keyblock);
485                 krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
486         
487                 torture_fail(tctx,  
488                              talloc_asprintf(tctx, 
489                                              "(saved test) PAC decoding (for logon info) failed: %s", 
490                                              nt_errstr(nt_status)));
491         }
492
493         validation.sam3 = &logon_info->info3;
494         nt_status = make_server_info_netlogon_validation(mem_ctx,
495                                                          "",
496                                                          3, &validation,
497                                                          &server_info_out); 
498         if (!NT_STATUS_IS_OK(nt_status)) {
499                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
500                                             krbtgt_keyblock_p);
501                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
502                                             &server_keyblock);
503                 krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
504
505                 torture_fail(tctx,  
506                              talloc_asprintf(tctx, 
507                                              "(saved test) PAC decoding (make server info) failed: %s", 
508                                              nt_errstr(nt_status)));
509         }
510
511         if (!pac_file &&
512             !dom_sid_equal(dom_sid_parse_talloc(mem_ctx, 
513                                                 "S-1-5-21-3048156945-3961193616-3706469200-1005"), 
514                            server_info_out->account_sid)) {
515                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
516                                             krbtgt_keyblock_p);
517                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
518                                             &server_keyblock);
519                 krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
520
521                 torture_fail(tctx,  
522                              talloc_asprintf(tctx, 
523                                              "(saved test) PAC Decode resulted in *different* domain SID: %s != %s",
524                                              "S-1-5-21-3048156945-3961193616-3706469200-1005", 
525                                              dom_sid_string(mem_ctx, server_info_out->account_sid)));
526         }
527
528         if (krbtgt_bytes == NULL) {
529                 torture_comment(tctx, "skipping PAC encoding tests as non kdc key\n");
530                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
531                                             &server_keyblock);
532                 krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
533                 return true;
534         }
535
536         ret = kerberos_encode_pac(mem_ctx, 
537                                   lp_iconv_convenience(tctx->lp_ctx),
538                                   pac_data,
539                                   smb_krb5_context->krb5_context,
540                                   krbtgt_keyblock_p,
541                                   &server_keyblock,
542                                   &validate_blob);
543
544         if (ret != 0) {
545                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
546                                             krbtgt_keyblock_p);
547                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
548                                             &server_keyblock);
549                 krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
550
551                 torture_fail(tctx, "(saved test) PAC push failed");
552         }
553
554         dump_data(10, validate_blob.data, validate_blob.length);
555
556         /* compare both the length and the data bytes after a
557          * pull/push cycle.  This ensures we use the exact same
558          * pointer, padding etc algorithms as win2k3.
559          */
560         if (tmp_blob.length != validate_blob.length) {
561                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
562                                             krbtgt_keyblock_p);
563                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
564                                             &server_keyblock);
565                 krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
566
567                 torture_fail(tctx, 
568                              talloc_asprintf(tctx, 
569                                              "(saved test) PAC push failed: original buffer length[%u] != created buffer length[%u]",
570                                              (unsigned)tmp_blob.length, (unsigned)validate_blob.length));
571         }
572
573         if (memcmp(tmp_blob.data, validate_blob.data, tmp_blob.length) != 0) {
574                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
575                                             krbtgt_keyblock_p);
576                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
577                                             &server_keyblock);
578                 krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
579
580                 DEBUG(0, ("tmp_data:\n"));
581                 dump_data(0, tmp_blob.data, tmp_blob.length);
582                 DEBUG(0, ("validate_blob:\n"));
583                 dump_data(0, validate_blob.data, validate_blob.length);
584
585                 torture_fail(tctx, talloc_asprintf(tctx, "(saved test) PAC push failed: length[%u] matches, but data does not", (unsigned)tmp_blob.length));
586         }
587
588         ret = kerberos_create_pac(mem_ctx, 
589                                   lp_iconv_convenience(tctx->lp_ctx),
590                                   server_info_out,
591                                   smb_krb5_context->krb5_context,
592                                   krbtgt_keyblock_p,
593                                   &server_keyblock,
594                                   client_principal, authtime,
595                                   &validate_blob);
596
597         if (ret != 0) {
598                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
599                                             krbtgt_keyblock_p);
600                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
601                                             &server_keyblock);
602                 krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
603
604                 torture_fail(tctx, "(saved test) regnerated PAC create failed");
605         }
606
607         dump_data(10,validate_blob.data,validate_blob.length);
608
609         /* compare both the length and the data bytes after a
610          * pull/push cycle.  This ensures we use the exact same
611          * pointer, padding etc algorithms as win2k3.
612          */
613         if (tmp_blob.length != validate_blob.length) {
614                 ndr_err = ndr_pull_struct_blob(&validate_blob, mem_ctx, 
615                                                lp_iconv_convenience(tctx->lp_ctx), &pac_data2,
616                                                (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA);
617                 nt_status = ndr_map_error2ntstatus(ndr_err);
618                 torture_assert_ntstatus_ok(tctx, nt_status, "can't parse the PAC");
619                 
620                 NDR_PRINT_DEBUG(PAC_DATA, pac_data);
621
622                 NDR_PRINT_DEBUG(PAC_DATA, &pac_data2);
623
624                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
625                                             krbtgt_keyblock_p);
626                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
627                                             &server_keyblock);
628                 krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
629
630                 torture_fail(tctx, talloc_asprintf(tctx, 
631                                                    "(saved test) PAC regenerate failed: original buffer length[%u] != created buffer length[%u]",
632                                                    (unsigned)tmp_blob.length, (unsigned)validate_blob.length));
633         }
634
635         if (memcmp(tmp_blob.data, validate_blob.data, tmp_blob.length) != 0) {
636                 ndr_err = ndr_pull_struct_blob(&validate_blob, mem_ctx, 
637                                                lp_iconv_convenience(tctx->lp_ctx), &pac_data2,
638                                                (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA);
639                 nt_status = ndr_map_error2ntstatus(ndr_err);
640                 torture_assert_ntstatus_ok(tctx, nt_status, "can't parse the PAC");
641                 
642                 NDR_PRINT_DEBUG(PAC_DATA, pac_data);
643
644                 NDR_PRINT_DEBUG(PAC_DATA, &pac_data2);
645
646                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
647                                             krbtgt_keyblock_p);
648                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
649                                             &server_keyblock);
650                 krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
651
652                 DEBUG(0, ("tmp_data:\n"));
653                 dump_data(0, tmp_blob.data, tmp_blob.length);
654                 DEBUG(0, ("validate_blob:\n"));
655                 dump_data(0, validate_blob.data, validate_blob.length);
656
657                 torture_fail(tctx, talloc_asprintf(tctx, 
658                                                    "(saved test) PAC regenerate failed: length[%u] matches, but data does not", (unsigned)tmp_blob.length));
659         }
660
661         /* Break the auth time, to ensure we check this vital detail (not setting this caused all the pain in the first place... */
662         nt_status = kerberos_decode_pac(mem_ctx, 
663                                         lp_iconv_convenience(tctx->lp_ctx),
664                                         &pac_data,
665                                         tmp_blob,
666                                         smb_krb5_context->krb5_context,
667                                         krbtgt_keyblock_p,
668                                         &server_keyblock,
669                                         client_principal, 
670                                         authtime + 1, NULL);
671         if (NT_STATUS_IS_OK(nt_status)) {
672
673                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
674                                             krbtgt_keyblock_p);
675                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
676                                             &server_keyblock);
677                 krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
678                 torture_fail(tctx, "(saved test) PAC decoding DID NOT fail on broken auth time (time + 1)");
679         }
680
681         /* Break the client principal */
682         krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
683
684         broken_principal_string = talloc_strdup(mem_ctx, principal_string);
685         broken_principal_string[0]++;
686
687         ret = krb5_parse_name(smb_krb5_context->krb5_context,
688                               broken_principal_string, &client_principal);
689         if (ret) {
690
691                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
692                                             krbtgt_keyblock_p);
693                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
694                                             &server_keyblock);
695                 torture_fail(tctx, talloc_asprintf(tctx, 
696                                                    "(saved test) parsing of broken client principal failed: %s", 
697                                                    smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx)));
698         }
699
700         nt_status = kerberos_decode_pac(mem_ctx, 
701                                         lp_iconv_convenience(tctx->lp_ctx),
702                                         &pac_data,
703                                         tmp_blob,
704                                         smb_krb5_context->krb5_context,
705                                         krbtgt_keyblock_p,
706                                         &server_keyblock,
707                                         client_principal, 
708                                         authtime, NULL);
709         if (NT_STATUS_IS_OK(nt_status)) {
710                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
711                                             krbtgt_keyblock_p);
712                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
713                                             &server_keyblock);
714                 torture_fail(tctx, "(saved test) PAC decoding DID NOT fail on modified principal");
715         }
716
717         /* Finally...  Bugger up the signature, and check we fail the checksum */
718         tmp_blob.data[tmp_blob.length - 2]++;
719
720         nt_status = kerberos_decode_pac(mem_ctx, 
721                                         lp_iconv_convenience(tctx->lp_ctx),
722                                         &pac_data,
723                                         tmp_blob,
724                                         smb_krb5_context->krb5_context,
725                                         krbtgt_keyblock_p,
726                                         &server_keyblock,
727                                         client_principal, 
728                                         authtime, NULL);
729         if (NT_STATUS_IS_OK(nt_status)) {
730                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
731                                             krbtgt_keyblock_p);
732                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
733                                             &server_keyblock);
734                 torture_fail(tctx, "(saved test) PAC decoding DID NOT fail on broken checksum");
735         }
736
737         krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
738                                     krbtgt_keyblock_p);
739         krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
740                                     &server_keyblock);
741         return true;
742 }
743
744 struct torture_suite *torture_pac(TALLOC_CTX *mem_ctx)
745 {
746         struct torture_suite *suite = torture_suite_create(mem_ctx, "PAC");
747
748         torture_suite_add_simple_test(suite, "self check", 
749                                       torture_pac_self_check);
750         torture_suite_add_simple_test(suite, "saved check",
751                                       torture_pac_saved_check);
752         return suite;
753 }