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