8ba8ed43c37cdefeb9f17afa28392b9e062cac73
[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 #include "auth/kerberos/pac_utils.h"
35
36 static bool torture_pac_self_check(struct torture_context *tctx)
37 {
38         NTSTATUS nt_status;
39         DATA_BLOB tmp_blob;
40         struct PAC_DATA *pac_data;
41         struct PAC_LOGON_INFO *logon_info;
42         union netr_Validation validation;
43
44         /* Generate a nice, arbitrary keyblock */
45         uint8_t server_bytes[16];
46         uint8_t krbtgt_bytes[16];
47         krb5_keyblock server_keyblock;
48         krb5_keyblock krbtgt_keyblock;
49         
50         krb5_error_code ret;
51
52         struct smb_krb5_context *smb_krb5_context;
53
54         struct auth_user_info_dc *user_info_dc;
55         struct auth_user_info_dc *user_info_dc_out;
56
57         krb5_principal client_principal;
58         time_t logon_time = time(NULL);
59
60         TALLOC_CTX *mem_ctx = tctx;
61
62         torture_assert(tctx, 0 == smb_krb5_init_context(mem_ctx, 
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 = smb_krb5_keyblock_init_contents(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 = smb_krb5_keyblock_init_contents(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[PRIMARY_USER_SID_INDEX].sid,
174                            &user_info_dc_out->sids[PRIMARY_USER_SID_INDEX].sid)) {
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[PRIMARY_USER_SID_INDEX].sid),
186                                              dom_sid_string(mem_ctx, &user_info_dc_out->sids[PRIMARY_USER_SID_INDEX].sid)));
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                                                           true, /* This user was authenticated */
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[PRIMARY_USER_SID_INDEX].sid,
236                            &user_info_dc_out->sids[PRIMARY_USER_SID_INDEX].sid)) {
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[PRIMARY_USER_SID_INDEX].sid),
241                                              dom_sid_string(mem_ctx, &user_info_dc_out->sids[PRIMARY_USER_SID_INDEX].sid)));
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,
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 = smb_krb5_keyblock_init_contents(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 = smb_krb5_keyblock_init_contents(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                                         tmp_blob,
412                                         smb_krb5_context->krb5_context,
413                                         krbtgt_keyblock_p,
414                                         &server_keyblock, 
415                                         client_principal, authtime, &pac_data);
416         if (!NT_STATUS_IS_OK(nt_status)) {
417                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
418                                             krbtgt_keyblock_p);
419                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
420                                             &server_keyblock);
421                 krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
422                 
423                 torture_fail(tctx, talloc_asprintf(tctx, 
424                                                    "(saved test) PAC decoding failed: %s", 
425                                                    nt_errstr(nt_status)));
426         }
427
428         /* Now check we can read it back (using Heimdal's pac parsing) */
429         nt_status = kerberos_pac_blob_to_user_info_dc(mem_ctx,
430                                                      tmp_blob, 
431                                                      smb_krb5_context->krb5_context,
432                                                       &user_info_dc_out,
433                                                       NULL, NULL);
434
435         if (!NT_STATUS_IS_OK(nt_status)) {
436                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
437                                             krbtgt_keyblock_p);
438                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
439                                             &server_keyblock);
440                 krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
441                 
442                 torture_fail(tctx, talloc_asprintf(tctx, 
443                                                    "(saved test) Heimdal PAC decoding failed: %s", 
444                                                    nt_errstr(nt_status)));
445         }
446
447         if (!pac_file &&
448             !dom_sid_equal(dom_sid_parse_talloc(mem_ctx, 
449                                                 "S-1-5-21-3048156945-3961193616-3706469200-1005"), 
450                            &user_info_dc_out->sids[PRIMARY_USER_SID_INDEX].sid)) {
451                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
452                                             krbtgt_keyblock_p);
453                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
454                                             &server_keyblock);
455                 krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
456
457                 torture_fail(tctx,  
458                              talloc_asprintf(tctx, 
459                                              "(saved test) Heimdal PAC Decode resulted in *different* domain SID: %s != %s",
460                                              "S-1-5-21-3048156945-3961193616-3706469200-1005", 
461                                              dom_sid_string(mem_ctx, &user_info_dc_out->sids[PRIMARY_USER_SID_INDEX].sid)));
462         }
463
464         talloc_free(user_info_dc_out);
465
466         /* Parse the PAC again, for the logon info this time (using Samba4's parsing) */
467         nt_status = kerberos_pac_logon_info(mem_ctx, 
468                                             tmp_blob,
469                                             smb_krb5_context->krb5_context,
470                                             krbtgt_keyblock_p,
471                                             &server_keyblock,
472                                             client_principal, authtime, &logon_info);
473
474         if (!NT_STATUS_IS_OK(nt_status)) {
475                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
476                                             krbtgt_keyblock_p);
477                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
478                                             &server_keyblock);
479                 krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
480         
481                 torture_fail(tctx,  
482                              talloc_asprintf(tctx, 
483                                              "(saved test) PAC decoding (for logon info) failed: %s", 
484                                              nt_errstr(nt_status)));
485         }
486
487         validation.sam3 = &logon_info->info3;
488         nt_status = make_user_info_dc_netlogon_validation(mem_ctx,
489                                                          "",
490                                                          3, &validation,
491                                                           true, /* This user was authenticated */
492                                                          &user_info_dc_out);
493         if (!NT_STATUS_IS_OK(nt_status)) {
494                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
495                                             krbtgt_keyblock_p);
496                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
497                                             &server_keyblock);
498                 krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
499
500                 torture_fail(tctx,  
501                              talloc_asprintf(tctx, 
502                                              "(saved test) PAC decoding (make server info) failed: %s", 
503                                              nt_errstr(nt_status)));
504         }
505
506         if (!pac_file &&
507             !dom_sid_equal(dom_sid_parse_talloc(mem_ctx, 
508                                                 "S-1-5-21-3048156945-3961193616-3706469200-1005"), 
509                            &user_info_dc_out->sids[PRIMARY_USER_SID_INDEX].sid)) {
510                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
511                                             krbtgt_keyblock_p);
512                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
513                                             &server_keyblock);
514                 krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
515
516                 torture_fail(tctx,  
517                              talloc_asprintf(tctx, 
518                                              "(saved test) PAC Decode resulted in *different* domain SID: %s != %s",
519                                              "S-1-5-21-3048156945-3961193616-3706469200-1005", 
520                                              dom_sid_string(mem_ctx, &user_info_dc_out->sids[PRIMARY_USER_SID_INDEX].sid)));
521         }
522
523         if (krbtgt_bytes == NULL) {
524                 torture_comment(tctx, "skipping PAC encoding tests as non kdc key\n");
525                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
526                                             &server_keyblock);
527                 krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
528                 return true;
529         }
530
531         ret = kerberos_encode_pac(mem_ctx, 
532                                   pac_data,
533                                   smb_krb5_context->krb5_context,
534                                   krbtgt_keyblock_p,
535                                   &server_keyblock,
536                                   &validate_blob);
537
538         if (ret != 0) {
539                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
540                                             krbtgt_keyblock_p);
541                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
542                                             &server_keyblock);
543                 krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
544
545                 torture_fail(tctx, "(saved test) PAC push failed");
546         }
547
548         dump_data(10, validate_blob.data, validate_blob.length);
549
550         /* compare both the length and the data bytes after a
551          * pull/push cycle.  This ensures we use the exact same
552          * pointer, padding etc algorithms as win2k3.
553          */
554         if (tmp_blob.length != validate_blob.length) {
555                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
556                                             krbtgt_keyblock_p);
557                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
558                                             &server_keyblock);
559                 krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
560
561                 torture_fail(tctx, 
562                              talloc_asprintf(tctx, 
563                                              "(saved test) PAC push failed: original buffer length[%u] != created buffer length[%u]",
564                                              (unsigned)tmp_blob.length, (unsigned)validate_blob.length));
565         }
566
567         if (memcmp(tmp_blob.data, validate_blob.data, tmp_blob.length) != 0) {
568                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
569                                             krbtgt_keyblock_p);
570                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
571                                             &server_keyblock);
572                 krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
573
574                 DEBUG(0, ("tmp_data:\n"));
575                 dump_data(0, tmp_blob.data, tmp_blob.length);
576                 DEBUG(0, ("validate_blob:\n"));
577                 dump_data(0, validate_blob.data, validate_blob.length);
578
579                 torture_fail(tctx, talloc_asprintf(tctx, "(saved test) PAC push failed: length[%u] matches, but data does not", (unsigned)tmp_blob.length));
580         }
581
582         ret = kerberos_create_pac(mem_ctx, 
583                                   user_info_dc_out,
584                                   smb_krb5_context->krb5_context,
585                                   krbtgt_keyblock_p,
586                                   &server_keyblock,
587                                   client_principal, authtime,
588                                   &validate_blob);
589
590         if (ret != 0) {
591                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
592                                             krbtgt_keyblock_p);
593                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
594                                             &server_keyblock);
595                 krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
596
597                 torture_fail(tctx, "(saved test) regnerated PAC create failed");
598         }
599
600         dump_data(10,validate_blob.data,validate_blob.length);
601
602         /* compare both the length and the data bytes after a
603          * pull/push cycle.  This ensures we use the exact same
604          * pointer, padding etc algorithms as win2k3.
605          */
606         if (tmp_blob.length != validate_blob.length) {
607                 ndr_err = ndr_pull_struct_blob(&validate_blob, mem_ctx, 
608                                                &pac_data2,
609                                                (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA);
610                 nt_status = ndr_map_error2ntstatus(ndr_err);
611                 torture_assert_ntstatus_ok(tctx, nt_status, "can't parse the PAC");
612                 
613                 NDR_PRINT_DEBUG(PAC_DATA, pac_data);
614
615                 NDR_PRINT_DEBUG(PAC_DATA, &pac_data2);
616
617                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
618                                             krbtgt_keyblock_p);
619                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
620                                             &server_keyblock);
621                 krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
622
623                 torture_fail(tctx, talloc_asprintf(tctx, 
624                                                    "(saved test) PAC regenerate failed: original buffer length[%u] != created buffer length[%u]",
625                                                    (unsigned)tmp_blob.length, (unsigned)validate_blob.length));
626         }
627
628         if (memcmp(tmp_blob.data, validate_blob.data, tmp_blob.length) != 0) {
629                 ndr_err = ndr_pull_struct_blob(&validate_blob, mem_ctx, 
630                                                &pac_data2,
631                                                (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA);
632                 nt_status = ndr_map_error2ntstatus(ndr_err);
633                 torture_assert_ntstatus_ok(tctx, nt_status, "can't parse the PAC");
634                 
635                 NDR_PRINT_DEBUG(PAC_DATA, pac_data);
636
637                 NDR_PRINT_DEBUG(PAC_DATA, &pac_data2);
638
639                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
640                                             krbtgt_keyblock_p);
641                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
642                                             &server_keyblock);
643                 krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
644
645                 DEBUG(0, ("tmp_data:\n"));
646                 dump_data(0, tmp_blob.data, tmp_blob.length);
647                 DEBUG(0, ("validate_blob:\n"));
648                 dump_data(0, validate_blob.data, validate_blob.length);
649
650                 torture_fail(tctx, talloc_asprintf(tctx, 
651                                                    "(saved test) PAC regenerate failed: length[%u] matches, but data does not", (unsigned)tmp_blob.length));
652         }
653
654         /* Break the auth time, to ensure we check this vital detail (not setting this caused all the pain in the first place... */
655         nt_status = kerberos_decode_pac(mem_ctx, 
656                                         tmp_blob,
657                                         smb_krb5_context->krb5_context,
658                                         krbtgt_keyblock_p,
659                                         &server_keyblock,
660                                         client_principal, 
661                                         authtime + 1, &pac_data);
662         if (NT_STATUS_IS_OK(nt_status)) {
663
664                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
665                                             krbtgt_keyblock_p);
666                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
667                                             &server_keyblock);
668                 krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
669                 torture_fail(tctx, "(saved test) PAC decoding DID NOT fail on broken auth time (time + 1)");
670         }
671
672         /* Break the client principal */
673         krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
674
675         broken_principal_string = talloc_strdup(mem_ctx, principal_string);
676         broken_principal_string[0]++;
677
678         ret = krb5_parse_name(smb_krb5_context->krb5_context,
679                               broken_principal_string, &client_principal);
680         if (ret) {
681
682                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
683                                             krbtgt_keyblock_p);
684                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
685                                             &server_keyblock);
686                 torture_fail(tctx, talloc_asprintf(tctx, 
687                                                    "(saved test) parsing of broken client principal failed: %s", 
688                                                    smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx)));
689         }
690
691         nt_status = kerberos_decode_pac(mem_ctx, 
692                                         tmp_blob,
693                                         smb_krb5_context->krb5_context,
694                                         krbtgt_keyblock_p,
695                                         &server_keyblock,
696                                         client_principal, 
697                                         authtime, &pac_data);
698         if (NT_STATUS_IS_OK(nt_status)) {
699                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
700                                             krbtgt_keyblock_p);
701                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
702                                             &server_keyblock);
703                 torture_fail(tctx, "(saved test) PAC decoding DID NOT fail on modified principal");
704         }
705
706         /* Finally...  Bugger up the signature, and check we fail the checksum */
707         tmp_blob.data[tmp_blob.length - 2]++;
708
709         nt_status = kerberos_decode_pac(mem_ctx, 
710                                         tmp_blob,
711                                         smb_krb5_context->krb5_context,
712                                         krbtgt_keyblock_p,
713                                         &server_keyblock,
714                                         client_principal, 
715                                         authtime,
716                                         &pac_data);
717         if (NT_STATUS_IS_OK(nt_status)) {
718                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
719                                             krbtgt_keyblock_p);
720                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
721                                             &server_keyblock);
722                 torture_fail(tctx, "(saved test) PAC decoding DID NOT fail on broken checksum");
723         }
724
725         krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
726                                     krbtgt_keyblock_p);
727         krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
728                                     &server_keyblock);
729         return true;
730 }
731
732 struct torture_suite *torture_pac(TALLOC_CTX *mem_ctx)
733 {
734         struct torture_suite *suite = torture_suite_create(mem_ctx, "pac");
735
736         torture_suite_add_simple_test(suite, "self check", 
737                                       torture_pac_self_check);
738         torture_suite_add_simple_test(suite, "saved check",
739                                       torture_pac_saved_check);
740         return suite;
741 }