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