lib: Give lib/util/util_file.c its own header file
[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 "lib/util/util_file.h"
25 #include "system/kerberos.h"
26 #include "auth/auth.h"
27 #include "auth/kerberos/kerberos.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 #include "librpc/gen_ndr/ndr_krb5pac.h"
34 #include "torture/auth/proto.h"
35 #include "auth/kerberos/pac_utils.h"
36
37 static bool torture_pac_self_check(struct torture_context *tctx)
38 {
39         NTSTATUS nt_status;
40         DATA_BLOB tmp_blob;
41         struct PAC_DATA *pac_data;
42         struct PAC_LOGON_INFO *logon_info;
43         union netr_Validation validation;
44
45         /* Generate a nice, arbitrary keyblock */
46         uint8_t server_bytes[16];
47         uint8_t krbtgt_bytes[16];
48         krb5_keyblock server_keyblock;
49         krb5_keyblock krbtgt_keyblock;
50         
51         krb5_error_code ret;
52
53         struct smb_krb5_context *smb_krb5_context;
54
55         struct auth_user_info_dc *user_info_dc;
56         struct auth_user_info_dc *user_info_dc_out;
57
58         krb5_principal client_principal;
59         time_t logon_time = time(NULL);
60
61         TALLOC_CTX *mem_ctx = tctx;
62
63         torture_assert(tctx, 0 == smb_krb5_init_context(mem_ctx, 
64                                                         tctx->lp_ctx,
65                                                         &smb_krb5_context), 
66                        "smb_krb5_init_context");
67
68         generate_random_buffer(server_bytes, 16);
69         generate_random_buffer(krbtgt_bytes, 16);
70
71         ret = smb_krb5_keyblock_init_contents(smb_krb5_context->krb5_context,
72                                  ENCTYPE_ARCFOUR_HMAC,
73                                  server_bytes, sizeof(server_bytes),
74                                  &server_keyblock);
75         torture_assert(tctx, !ret, talloc_asprintf(tctx, 
76                                                    "(self test) Server Keyblock encoding failed: %s", 
77                                                    smb_get_krb5_error_message(smb_krb5_context->krb5_context, 
78                                                                               ret, mem_ctx)));
79
80         ret = smb_krb5_keyblock_init_contents(smb_krb5_context->krb5_context,
81                                  ENCTYPE_ARCFOUR_HMAC,
82                                  krbtgt_bytes, sizeof(krbtgt_bytes),
83                                  &krbtgt_keyblock);
84         if (ret) {
85                 char *err = smb_get_krb5_error_message(smb_krb5_context->krb5_context, 
86                                                        ret, mem_ctx);
87         
88                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
89                                             &server_keyblock);
90
91                 torture_fail(tctx, talloc_asprintf(tctx, 
92                                                    "(self test) KRBTGT Keyblock encoding failed: %s", err));
93         }
94
95         /* We need an input, and this one requires no underlying database */
96         nt_status = auth_anonymous_user_info_dc(mem_ctx, lpcfg_netbios_name(tctx->lp_ctx), &user_info_dc);
97
98         if (!NT_STATUS_IS_OK(nt_status)) {
99                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
100                                             &server_keyblock);
101                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
102                                             &krbtgt_keyblock);
103                 torture_fail(tctx, "auth_anonymous_user_info_dc");
104         }
105
106         ret = krb5_parse_name_flags(smb_krb5_context->krb5_context, 
107                                     user_info_dc->info->account_name,
108                                     KRB5_PRINCIPAL_PARSE_NO_REALM, 
109                                     &client_principal);
110         if (ret) {
111                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
112                                             &server_keyblock);
113                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
114                                             &krbtgt_keyblock);
115                 torture_fail(tctx, "krb5_parse_name_flags(norealm)");
116         }
117
118         /* OK, go ahead and make a PAC */
119         ret = kerberos_create_pac(mem_ctx, 
120                                   user_info_dc,
121                                   smb_krb5_context->krb5_context,  
122                                   &krbtgt_keyblock,
123                                   &server_keyblock,
124                                   client_principal,
125                                   logon_time,
126                                   &tmp_blob);
127         
128         if (ret) {
129                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
130                                             &krbtgt_keyblock);
131                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
132                                             &server_keyblock);
133                 krb5_free_principal(smb_krb5_context->krb5_context, 
134                                     client_principal);
135
136                 torture_fail(tctx, talloc_asprintf(tctx,
137                                                    "(self test) PAC encoding failed: %s", 
138                                                    smb_get_krb5_error_message(smb_krb5_context->krb5_context, 
139                                                                               ret, mem_ctx)));
140         }
141
142         dump_data(10,tmp_blob.data,tmp_blob.length);
143
144         /* Now check that we can read it back (using full decode and validate) */
145         nt_status = kerberos_decode_pac(mem_ctx, 
146                                         tmp_blob,
147                                         smb_krb5_context->krb5_context,
148                                         &krbtgt_keyblock,
149                                         &server_keyblock,
150                                         client_principal, 
151                                         logon_time,
152                                         &pac_data);
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_user_info_dc(mem_ctx,
169                                                      tmp_blob, 
170                                                      smb_krb5_context->krb5_context,
171                                                       &user_info_dc_out, NULL, NULL);
172
173         /* The user's SID is the first element in the list */
174         if (!dom_sid_equal(&user_info_dc->sids[PRIMARY_USER_SID_INDEX].sid,
175                            &user_info_dc_out->sids[PRIMARY_USER_SID_INDEX].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, &user_info_dc->sids[PRIMARY_USER_SID_INDEX].sid),
187                                              dom_sid_string(mem_ctx, &user_info_dc_out->sids[PRIMARY_USER_SID_INDEX].sid)));
188         }
189         talloc_free(user_info_dc_out);
190
191         /* Now check that we can read it back (yet again) */
192         nt_status = kerberos_pac_logon_info(mem_ctx, 
193                                             tmp_blob,
194                                             smb_krb5_context->krb5_context,
195                                             &krbtgt_keyblock,
196                                             &server_keyblock,
197                                             client_principal, 
198                                             logon_time, 
199                                             &logon_info);
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                                                           true, /* This user was authenticated */
228                                                  &user_info_dc_out);
229         if (!NT_STATUS_IS_OK(nt_status)) {
230                 torture_fail(tctx, 
231                              talloc_asprintf(tctx, 
232                                              "(self test) PAC decoding (make server info) failed: %s", 
233                                              nt_errstr(nt_status)));
234         }
235         
236         if (!dom_sid_equal(&user_info_dc->sids[PRIMARY_USER_SID_INDEX].sid,
237                            &user_info_dc_out->sids[PRIMARY_USER_SID_INDEX].sid)) {
238                 torture_fail(tctx,  
239                              talloc_asprintf(tctx, 
240                                              "(self test) PAC Decode resulted in *different* domain SID: %s != %s",
241                                              dom_sid_string(mem_ctx, &user_info_dc->sids[PRIMARY_USER_SID_INDEX].sid),
242                                              dom_sid_string(mem_ctx, &user_info_dc_out->sids[PRIMARY_USER_SID_INDEX].sid)));
243         }
244         return true;
245 }
246
247
248 /* This is the PAC generated on my test network, by my test Win2k3 server.
249    -- abartlet 2005-07-04
250 */
251
252 static const uint8_t saved_pac[] = {
253         0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xd8, 0x01, 0x00, 0x00, 
254         0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
255         0x20, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
256         0x40, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
257         0x58, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc,
258         0xc8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x30, 0xdf, 0xa6, 0xcb, 
259         0x4f, 0x7d, 0xc5, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 
260         0xff, 0xff, 0xff, 0x7f, 0xc0, 0x3c, 0x4e, 0x59, 0x62, 0x73, 0xc5, 0x01, 0xc0, 0x3c, 0x4e, 0x59,
261         0x62, 0x73, 0xc5, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x16, 0x00, 0x16, 0x00,
262         0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
263         0x0c, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 
264         0x14, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x02, 0x00, 0x65, 0x00, 0x00, 0x00, 
265         0xed, 0x03, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x02, 0x00,
266         0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
267         0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x16, 0x00, 0x20, 0x00, 0x02, 0x00, 0x16, 0x00, 0x18, 0x00,
268         0x24, 0x00, 0x02, 0x00, 0x28, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
269         0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
270         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
271         0x01, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
272         0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
273         0x57, 0x00, 0x32, 0x00, 0x30, 0x00, 0x30, 0x00, 0x33, 0x00, 0x46, 0x00, 0x49, 0x00, 0x4e, 0x00,
274         0x41, 0x00, 0x4c, 0x00, 0x24, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
278         0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
279         0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x57, 0x00, 0x32, 0x00,
280         0x30, 0x00, 0x30, 0x00, 0x33, 0x00, 0x46, 0x00, 0x49, 0x00, 0x4e, 0x00, 0x41, 0x00, 0x4c, 0x00,
281         0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x57, 0x00, 0x49, 0x00,
282         0x4e, 0x00, 0x32, 0x00, 0x4b, 0x00, 0x33, 0x00, 0x54, 0x00, 0x48, 0x00, 0x49, 0x00, 0x4e, 0x00,
283         0x4b, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
284         0x15, 0x00, 0x00, 0x00, 0x11, 0x2f, 0xaf, 0xb5, 0x90, 0x04, 0x1b, 0xec, 0x50, 0x3b, 0xec, 0xdc,
285         0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x02, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
286         0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
287         0x80, 0x66, 0x28, 0xea, 0x37, 0x80, 0xc5, 0x01, 0x16, 0x00, 0x77, 0x00, 0x32, 0x00, 0x30, 0x00,
288         0x30, 0x00, 0x33, 0x00, 0x66, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x24, 0x00,
289         0x76, 0xff, 0xff, 0xff, 0x37, 0xd5, 0xb0, 0xf7, 0x24, 0xf0, 0xd6, 0xd4, 0xec, 0x09, 0x86, 0x5a,
290         0xa0, 0xe8, 0xc3, 0xa9, 0x00, 0x00, 0x00, 0x00, 0x76, 0xff, 0xff, 0xff, 0xb4, 0xd8, 0xb8, 0xfe,
291         0x83, 0xb3, 0x13, 0x3f, 0xfc, 0x5c, 0x41, 0xad, 0xe2, 0x64, 0x83, 0xe0, 0x00, 0x00, 0x00, 0x00
292 };
293
294 /* Check with a known 'well formed' PAC, from my test server */
295 static bool torture_pac_saved_check(struct torture_context *tctx)
296 {
297         NTSTATUS nt_status;
298         enum ndr_err_code ndr_err;
299         DATA_BLOB tmp_blob, validate_blob;
300         struct PAC_DATA *pac_data, pac_data2;
301         struct PAC_LOGON_INFO *logon_info;
302         union netr_Validation validation;
303         const char *pac_file, *pac_kdc_key, *pac_member_key;
304         struct auth_user_info_dc *user_info_dc_out;
305
306         krb5_keyblock server_keyblock;
307         krb5_keyblock krbtgt_keyblock, *krbtgt_keyblock_p;
308         struct samr_Password *krbtgt_bytes, *krbsrv_bytes;
309         
310         krb5_error_code ret;
311         struct smb_krb5_context *smb_krb5_context;
312
313         const char *principal_string;
314         char *broken_principal_string;
315         krb5_principal client_principal;
316         const char *authtime_string;
317         time_t authtime;
318         TALLOC_CTX *mem_ctx = tctx;
319
320         torture_assert(tctx, 0 == smb_krb5_init_context(mem_ctx,
321                                                         tctx->lp_ctx,
322                                                         &smb_krb5_context),
323                        "smb_krb5_init_context");
324
325         pac_kdc_key = torture_setting_string(tctx, "pac_kdc_key", 
326                                              "B286757148AF7FD252C53603A150B7E7");
327
328         pac_member_key = torture_setting_string(tctx, "pac_member_key", 
329                                                 "D217FAEAE5E6B5F95CCC94077AB8A5FC");
330
331         torture_comment(tctx, "Using pac_kdc_key '%s'\n", pac_kdc_key);
332         torture_comment(tctx, "Using pac_member_key '%s'\n", pac_member_key);
333
334         /* The krbtgt key in use when the above PAC was generated.
335          * This is an arcfour-hmac-md5 key, extracted with our 'net
336          * samdump' tool. */
337         if (*pac_kdc_key == 0) {
338                 krbtgt_bytes = NULL;
339         } else {
340                 krbtgt_bytes = smbpasswd_gethexpwd(mem_ctx, pac_kdc_key);
341                 if (!krbtgt_bytes) {
342                         torture_fail(tctx, "(saved test) Could not interpret krbtgt key");
343                 }
344         }
345
346         krbsrv_bytes = smbpasswd_gethexpwd(mem_ctx, pac_member_key);
347         if (!krbsrv_bytes) {
348                 torture_fail(tctx, "(saved test) Could not interpret krbsrv key");
349         }
350
351         ret = smb_krb5_keyblock_init_contents(smb_krb5_context->krb5_context,
352                                  ENCTYPE_ARCFOUR_HMAC,
353                                  krbsrv_bytes->hash, sizeof(krbsrv_bytes->hash),
354                                  &server_keyblock);
355         torture_assert(tctx, !ret,
356                        talloc_asprintf(tctx,
357                                        "(saved test) Server Keyblock encoding failed: %s", 
358                                        smb_get_krb5_error_message(smb_krb5_context->krb5_context, 
359                                                                   ret, mem_ctx)));
360
361         if (krbtgt_bytes) {
362                 ret = smb_krb5_keyblock_init_contents(smb_krb5_context->krb5_context,
363                                          ENCTYPE_ARCFOUR_HMAC,
364                                          krbtgt_bytes->hash, sizeof(krbtgt_bytes->hash),
365                                          &krbtgt_keyblock);
366                 if (ret) {
367                         krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
368                                                     &server_keyblock);
369                         torture_fail(tctx, 
370                                      talloc_asprintf(tctx, 
371                                                      "(saved test) Server Keyblock encoding failed: %s", 
372                                                      smb_get_krb5_error_message(smb_krb5_context->krb5_context, 
373                                                                                 ret, mem_ctx)));
374                 }
375                 krbtgt_keyblock_p = &krbtgt_keyblock;
376         } else {
377                 krbtgt_keyblock_p = NULL;
378         }
379
380         pac_file = torture_setting_string(tctx, "pac_file", NULL);
381         if (pac_file) {
382                 tmp_blob.data = (uint8_t *)file_load(pac_file, &tmp_blob.length, 0, mem_ctx);
383                 torture_comment(tctx, "(saved test) Loaded pac of size %ld from %s\n", (long)tmp_blob.length, pac_file);
384         } else {
385                 tmp_blob = data_blob_talloc(mem_ctx, saved_pac, sizeof(saved_pac));
386         }
387         
388         dump_data(10,tmp_blob.data,tmp_blob.length);
389
390         principal_string = torture_setting_string(tctx, "pac_client_principal", 
391                                                   "w2003final$@WIN2K3.THINKER.LOCAL");
392
393         authtime_string = torture_setting_string(tctx, "pac_authtime", "1120440609");
394         authtime = strtoull(authtime_string, NULL, 0);
395
396         ret = krb5_parse_name(smb_krb5_context->krb5_context, principal_string, 
397                               &client_principal);
398         if (ret) {
399                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
400                                             krbtgt_keyblock_p);
401                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
402                                             &server_keyblock);
403                 torture_fail(tctx,  
404                              talloc_asprintf(tctx, 
405                                              "(saved test) parsing of client principal [%s] failed: %s", 
406                                              principal_string, 
407                                              smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx)));
408         }
409
410         /* Decode and verify the signaure on the PAC */
411         nt_status = kerberos_decode_pac(mem_ctx, 
412                                         tmp_blob,
413                                         smb_krb5_context->krb5_context,
414                                         krbtgt_keyblock_p,
415                                         &server_keyblock, 
416                                         client_principal, authtime, &pac_data);
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[PRIMARY_USER_SID_INDEX].sid)) {
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[PRIMARY_USER_SID_INDEX].sid)));
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                                             tmp_blob,
470                                             smb_krb5_context->krb5_context,
471                                             krbtgt_keyblock_p,
472                                             &server_keyblock,
473                                             client_principal, authtime, &logon_info);
474
475         if (!NT_STATUS_IS_OK(nt_status)) {
476                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
477                                             krbtgt_keyblock_p);
478                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
479                                             &server_keyblock);
480                 krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
481         
482                 torture_fail(tctx,  
483                              talloc_asprintf(tctx, 
484                                              "(saved test) PAC decoding (for logon info) failed: %s", 
485                                              nt_errstr(nt_status)));
486         }
487
488         validation.sam3 = &logon_info->info3;
489         nt_status = make_user_info_dc_netlogon_validation(mem_ctx,
490                                                          "",
491                                                          3, &validation,
492                                                           true, /* This user was authenticated */
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[PRIMARY_USER_SID_INDEX].sid)) {
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[PRIMARY_USER_SID_INDEX].sid)));
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                                         tmp_blob,
658                                         smb_krb5_context->krb5_context,
659                                         krbtgt_keyblock_p,
660                                         &server_keyblock,
661                                         client_principal, 
662                                         authtime + 1, &pac_data);
663         if (NT_STATUS_IS_OK(nt_status)) {
664
665                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
666                                             krbtgt_keyblock_p);
667                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
668                                             &server_keyblock);
669                 krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
670                 torture_fail(tctx, "(saved test) PAC decoding DID NOT fail on broken auth time (time + 1)");
671         }
672
673         /* Break the client principal */
674         krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
675
676         broken_principal_string = talloc_strdup(mem_ctx, principal_string);
677         broken_principal_string[0]++;
678
679         ret = krb5_parse_name(smb_krb5_context->krb5_context,
680                               broken_principal_string, &client_principal);
681         if (ret) {
682
683                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
684                                             krbtgt_keyblock_p);
685                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
686                                             &server_keyblock);
687                 torture_fail(tctx, talloc_asprintf(tctx, 
688                                                    "(saved test) parsing of broken client principal failed: %s", 
689                                                    smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx)));
690         }
691
692         nt_status = kerberos_decode_pac(mem_ctx, 
693                                         tmp_blob,
694                                         smb_krb5_context->krb5_context,
695                                         krbtgt_keyblock_p,
696                                         &server_keyblock,
697                                         client_principal, 
698                                         authtime, &pac_data);
699         if (NT_STATUS_IS_OK(nt_status)) {
700                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
701                                             krbtgt_keyblock_p);
702                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
703                                             &server_keyblock);
704                 torture_fail(tctx, "(saved test) PAC decoding DID NOT fail on modified principal");
705         }
706
707         /* Finally...  Bugger up the signature, and check we fail the checksum */
708         tmp_blob.data[tmp_blob.length - 2]++;
709
710         nt_status = kerberos_decode_pac(mem_ctx, 
711                                         tmp_blob,
712                                         smb_krb5_context->krb5_context,
713                                         krbtgt_keyblock_p,
714                                         &server_keyblock,
715                                         client_principal, 
716                                         authtime,
717                                         &pac_data);
718         if (NT_STATUS_IS_OK(nt_status)) {
719                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
720                                             krbtgt_keyblock_p);
721                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
722                                             &server_keyblock);
723                 torture_fail(tctx, "(saved test) PAC decoding DID NOT fail on broken checksum");
724         }
725
726         krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
727                                     krbtgt_keyblock_p);
728         krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
729                                     &server_keyblock);
730         return true;
731 }
732
733 struct torture_suite *torture_pac(TALLOC_CTX *mem_ctx)
734 {
735         struct torture_suite *suite = torture_suite_create(mem_ctx, "pac");
736
737         torture_suite_add_simple_test(suite, "self check", 
738                                       torture_pac_self_check);
739         torture_suite_add_simple_test(suite, "saved check",
740                                       torture_pac_saved_check);
741         return suite;
742 }