Heimdal provides Kerberos PAC parsing routines. Use them.
[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 "librpc/gen_ndr/ndr_krb5pac.h"
28 #include "samba3/samba3.h"
29 #include "libcli/security/security.h"
30 #include "torture/torture.h"
31 #include "auth/session_proto.h"
32
33 static bool torture_pac_self_check(struct torture_context *tctx)
34 {
35         NTSTATUS nt_status;
36         DATA_BLOB tmp_blob;
37         struct PAC_DATA *pac_data;
38         struct PAC_LOGON_INFO *logon_info;
39         union netr_Validation validation;
40
41         /* Generate a nice, arbitary keyblock */
42         uint8_t server_bytes[16];
43         uint8_t krbtgt_bytes[16];
44         krb5_keyblock server_keyblock;
45         krb5_keyblock krbtgt_keyblock;
46         
47         krb5_error_code ret;
48
49         struct smb_krb5_context *smb_krb5_context;
50
51         struct auth_serversupplied_info *server_info;
52         struct auth_serversupplied_info *server_info_out;
53
54         krb5_principal client_principal;
55         time_t logon_time = time(NULL);
56
57         TALLOC_CTX *mem_ctx = tctx;
58
59         torture_assert(tctx, 0 == smb_krb5_init_context(mem_ctx, 
60                                                         NULL,
61                                                         tctx->lp_ctx,
62                                                         &smb_krb5_context), 
63                        "smb_krb5_init_context");
64
65         generate_random_buffer(server_bytes, 16);
66         generate_random_buffer(krbtgt_bytes, 16);
67
68         ret = krb5_keyblock_init(smb_krb5_context->krb5_context,
69                                  ENCTYPE_ARCFOUR_HMAC,
70                                  server_bytes, sizeof(server_bytes),
71                                  &server_keyblock);
72         torture_assert(tctx, !ret, talloc_asprintf(tctx, 
73                                                    "(self test) Server Keyblock encoding failed: %s", 
74                                                    smb_get_krb5_error_message(smb_krb5_context->krb5_context, 
75                                                                               ret, mem_ctx)));
76
77         ret = krb5_keyblock_init(smb_krb5_context->krb5_context,
78                                  ENCTYPE_ARCFOUR_HMAC,
79                                  krbtgt_bytes, sizeof(krbtgt_bytes),
80                                  &krbtgt_keyblock);
81         if (ret) {
82                 char *err = smb_get_krb5_error_message(smb_krb5_context->krb5_context, 
83                                                        ret, mem_ctx);
84         
85                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
86                                             &server_keyblock);
87
88                 torture_fail(tctx, talloc_asprintf(tctx, 
89                                                    "(self test) KRBTGT Keyblock encoding failed: %s", err));
90         }
91
92         /* We need an input, and this one requires no underlying database */
93         nt_status = auth_anonymous_server_info(mem_ctx, lp_netbios_name(tctx->lp_ctx), &server_info);
94
95         if (!NT_STATUS_IS_OK(nt_status)) {
96                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
97                                             &server_keyblock);
98                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
99                                             &krbtgt_keyblock);
100                 torture_fail(tctx, "auth_anonymous_server_info");
101         }
102
103         ret = krb5_parse_name_flags(smb_krb5_context->krb5_context, 
104                                     server_info->account_name, 
105                                     KRB5_PRINCIPAL_PARSE_NO_REALM, 
106                                     &client_principal);
107         if (ret) {
108                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
109                                             &server_keyblock);
110                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
111                                             &krbtgt_keyblock);
112                 torture_fail(tctx, "krb5_parse_name_flags(norealm)");
113         }
114
115         /* OK, go ahead and make a PAC */
116         ret = kerberos_create_pac(mem_ctx, 
117                                   lp_iconv_convenience(tctx->lp_ctx),
118                                   server_info, 
119                                   smb_krb5_context->krb5_context,  
120                                   &krbtgt_keyblock,
121                                   &server_keyblock,
122                                   client_principal,
123                                   logon_time,
124                                   &tmp_blob);
125         
126         if (ret) {
127                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
128                                             &krbtgt_keyblock);
129                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
130                                             &server_keyblock);
131                 krb5_free_principal(smb_krb5_context->krb5_context, 
132                                     client_principal);
133
134                 torture_fail(tctx, talloc_asprintf(tctx,
135                                                    "(self test) PAC encoding failed: %s", 
136                                                    smb_get_krb5_error_message(smb_krb5_context->krb5_context, 
137                                                                               ret, mem_ctx)));
138         }
139
140         dump_data(10,tmp_blob.data,tmp_blob.length);
141
142         /* Now check that we can read it back (using full decode and validate) */
143         nt_status = kerberos_decode_pac(mem_ctx, 
144                                         lp_iconv_convenience(tctx->lp_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_server_info(mem_ctx, 
168                                                      lp_iconv_convenience(tctx->lp_ctx),
169                                                      tmp_blob, 
170                                                      smb_krb5_context->krb5_context,
171                                                      &server_info_out);
172
173         if (!dom_sid_equal(server_info->account_sid, 
174                            server_info_out->account_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, server_info->account_sid), 
186                                              dom_sid_string(mem_ctx, server_info_out->account_sid)));
187         }
188         talloc_free(server_info_out);
189
190         /* Now check that we can read it back (yet again) */
191         nt_status = kerberos_pac_logon_info(mem_ctx, 
192                                             lp_iconv_convenience(tctx->lp_ctx),
193                                             &logon_info,
194                                             tmp_blob,
195                                             smb_krb5_context->krb5_context,
196                                             &krbtgt_keyblock,
197                                             &server_keyblock,
198                                             client_principal, 
199                                             logon_time, 
200                                             NULL);
201         
202         if (!NT_STATUS_IS_OK(nt_status)) {
203                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
204                                             &krbtgt_keyblock);
205                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
206                                             &server_keyblock);
207                 krb5_free_principal(smb_krb5_context->krb5_context, 
208                                     client_principal);
209                 
210                 torture_fail(tctx,  
211                              talloc_asprintf(tctx, 
212                                              "(self test) PAC decoding (for logon info) failed: %s", 
213                                              nt_errstr(nt_status)));
214         }
215         
216         krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
217                                     &krbtgt_keyblock);
218         krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
219                                     &server_keyblock);
220         krb5_free_principal(smb_krb5_context->krb5_context, 
221                             client_principal);
222
223         /* And make a server info from the samba-parsed PAC */
224         validation.sam3 = &logon_info->info3;
225         nt_status = make_server_info_netlogon_validation(mem_ctx,
226                                                          "",
227                                                          3, &validation,
228                                                          &server_info_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(server_info->account_sid, 
237                            server_info_out->account_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, server_info->account_sid), 
242                                              dom_sid_string(mem_ctx, server_info_out->account_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_serversupplied_info *server_info_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, NULL,
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 = krb5_keyblock_init(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 = krb5_keyblock_init(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, 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                                         lp_iconv_convenience(tctx->lp_ctx),
413                                         &pac_data,
414                                         tmp_blob,
415                                         smb_krb5_context->krb5_context,
416                                         krbtgt_keyblock_p,
417                                         &server_keyblock, 
418                                         client_principal, authtime, NULL);
419         if (!NT_STATUS_IS_OK(nt_status)) {
420                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
421                                             krbtgt_keyblock_p);
422                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
423                                             &server_keyblock);
424                 krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
425                 
426                 torture_fail(tctx, talloc_asprintf(tctx, 
427                                                    "(saved test) PAC decoding failed: %s", 
428                                                    nt_errstr(nt_status)));
429         }
430
431         /* Now check we can read it back (using Heimdal's pac parsing) */
432         nt_status = kerberos_pac_blob_to_server_info(mem_ctx, 
433                                                      lp_iconv_convenience(tctx->lp_ctx),
434                                                      tmp_blob, 
435                                                      smb_krb5_context->krb5_context,
436                                                      &server_info_out);
437
438         if (!NT_STATUS_IS_OK(nt_status)) {
439                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
440                                             krbtgt_keyblock_p);
441                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
442                                             &server_keyblock);
443                 krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
444                 
445                 torture_fail(tctx, talloc_asprintf(tctx, 
446                                                    "(saved test) Heimdal PAC decoding failed: %s", 
447                                                    nt_errstr(nt_status)));
448         }
449
450         if (!pac_file &&
451             !dom_sid_equal(dom_sid_parse_talloc(mem_ctx, 
452                                                 "S-1-5-21-3048156945-3961193616-3706469200-1005"), 
453                            server_info_out->account_sid)) {
454                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
455                                             krbtgt_keyblock_p);
456                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
457                                             &server_keyblock);
458                 krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
459
460                 torture_fail(tctx,  
461                              talloc_asprintf(tctx, 
462                                              "(saved test) Heimdal PAC Decode resulted in *different* domain SID: %s != %s",
463                                              "S-1-5-21-3048156945-3961193616-3706469200-1005", 
464                                              dom_sid_string(mem_ctx, server_info_out->account_sid)));
465         }
466
467         talloc_free(server_info_out);
468
469         /* Parse the PAC again, for the logon info this time (using Samba4's parsing) */
470         nt_status = kerberos_pac_logon_info(mem_ctx, 
471                                             lp_iconv_convenience(tctx->lp_ctx),
472                                             &logon_info,
473                                             tmp_blob,
474                                             smb_krb5_context->krb5_context,
475                                             krbtgt_keyblock_p,
476                                             &server_keyblock,
477                                             client_principal, authtime, NULL);
478
479         if (!NT_STATUS_IS_OK(nt_status)) {
480                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
481                                             krbtgt_keyblock_p);
482                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
483                                             &server_keyblock);
484                 krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
485         
486                 torture_fail(tctx,  
487                              talloc_asprintf(tctx, 
488                                              "(saved test) PAC decoding (for logon info) failed: %s", 
489                                              nt_errstr(nt_status)));
490         }
491
492         validation.sam3 = &logon_info->info3;
493         nt_status = make_server_info_netlogon_validation(mem_ctx,
494                                                          "",
495                                                          3, &validation,
496                                                          &server_info_out); 
497         if (!NT_STATUS_IS_OK(nt_status)) {
498                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
499                                             krbtgt_keyblock_p);
500                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
501                                             &server_keyblock);
502                 krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
503
504                 torture_fail(tctx,  
505                              talloc_asprintf(tctx, 
506                                              "(saved test) PAC decoding (make server info) failed: %s", 
507                                              nt_errstr(nt_status)));
508         }
509
510         if (!pac_file &&
511             !dom_sid_equal(dom_sid_parse_talloc(mem_ctx, 
512                                                 "S-1-5-21-3048156945-3961193616-3706469200-1005"), 
513                            server_info_out->account_sid)) {
514                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
515                                             krbtgt_keyblock_p);
516                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
517                                             &server_keyblock);
518                 krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
519
520                 torture_fail(tctx,  
521                              talloc_asprintf(tctx, 
522                                              "(saved test) PAC Decode resulted in *different* domain SID: %s != %s",
523                                              "S-1-5-21-3048156945-3961193616-3706469200-1005", 
524                                              dom_sid_string(mem_ctx, server_info_out->account_sid)));
525         }
526
527         if (krbtgt_bytes == NULL) {
528                 torture_comment(tctx, "skipping PAC encoding tests as non kdc key\n");
529                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
530                                             &server_keyblock);
531                 krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
532                 return true;
533         }
534
535         ret = kerberos_encode_pac(mem_ctx, 
536                                   lp_iconv_convenience(tctx->lp_ctx),
537                                   pac_data,
538                                   smb_krb5_context->krb5_context,
539                                   krbtgt_keyblock_p,
540                                   &server_keyblock,
541                                   &validate_blob);
542
543         if (ret != 0) {
544                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
545                                             krbtgt_keyblock_p);
546                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
547                                             &server_keyblock);
548                 krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
549
550                 torture_fail(tctx, "(saved test) PAC push failed");
551         }
552
553         dump_data(10, validate_blob.data, validate_blob.length);
554
555         /* compare both the length and the data bytes after a
556          * pull/push cycle.  This ensures we use the exact same
557          * pointer, padding etc algorithms as win2k3.
558          */
559         if (tmp_blob.length != validate_blob.length) {
560                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
561                                             krbtgt_keyblock_p);
562                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
563                                             &server_keyblock);
564                 krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
565
566                 torture_fail(tctx, 
567                              talloc_asprintf(tctx, 
568                                              "(saved test) PAC push failed: original buffer length[%u] != created buffer length[%u]",
569                                              (unsigned)tmp_blob.length, (unsigned)validate_blob.length));
570         }
571
572         if (memcmp(tmp_blob.data, validate_blob.data, tmp_blob.length) != 0) {
573                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
574                                             krbtgt_keyblock_p);
575                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
576                                             &server_keyblock);
577                 krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
578
579                 DEBUG(0, ("tmp_data:\n"));
580                 dump_data(0, tmp_blob.data, tmp_blob.length);
581                 DEBUG(0, ("validate_blob:\n"));
582                 dump_data(0, validate_blob.data, validate_blob.length);
583
584                 torture_fail(tctx, talloc_asprintf(tctx, "(saved test) PAC push failed: length[%u] matches, but data does not", (unsigned)tmp_blob.length));
585         }
586
587         ret = kerberos_create_pac(mem_ctx, 
588                                   lp_iconv_convenience(tctx->lp_ctx),
589                                   server_info_out,
590                                   smb_krb5_context->krb5_context,
591                                   krbtgt_keyblock_p,
592                                   &server_keyblock,
593                                   client_principal, authtime,
594                                   &validate_blob);
595
596         if (ret != 0) {
597                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
598                                             krbtgt_keyblock_p);
599                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
600                                             &server_keyblock);
601                 krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
602
603                 torture_fail(tctx, "(saved test) regnerated PAC create failed");
604         }
605
606         dump_data(10,validate_blob.data,validate_blob.length);
607
608         /* compare both the length and the data bytes after a
609          * pull/push cycle.  This ensures we use the exact same
610          * pointer, padding etc algorithms as win2k3.
611          */
612         if (tmp_blob.length != validate_blob.length) {
613                 ndr_err = ndr_pull_struct_blob(&validate_blob, mem_ctx, 
614                                                lp_iconv_convenience(tctx->lp_ctx), &pac_data2,
615                                                (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA);
616                 nt_status = ndr_map_error2ntstatus(ndr_err);
617                 torture_assert_ntstatus_ok(tctx, nt_status, "can't parse the PAC");
618                 
619                 NDR_PRINT_DEBUG(PAC_DATA, pac_data);
620
621                 NDR_PRINT_DEBUG(PAC_DATA, &pac_data2);
622
623                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
624                                             krbtgt_keyblock_p);
625                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
626                                             &server_keyblock);
627                 krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
628
629                 torture_fail(tctx, talloc_asprintf(tctx, 
630                                                    "(saved test) PAC regenerate failed: original buffer length[%u] != created buffer length[%u]",
631                                                    (unsigned)tmp_blob.length, (unsigned)validate_blob.length));
632         }
633
634         if (memcmp(tmp_blob.data, validate_blob.data, tmp_blob.length) != 0) {
635                 ndr_err = ndr_pull_struct_blob(&validate_blob, mem_ctx, 
636                                                lp_iconv_convenience(tctx->lp_ctx), &pac_data2,
637                                                (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA);
638                 nt_status = ndr_map_error2ntstatus(ndr_err);
639                 torture_assert_ntstatus_ok(tctx, nt_status, "can't parse the PAC");
640                 
641                 NDR_PRINT_DEBUG(PAC_DATA, pac_data);
642
643                 NDR_PRINT_DEBUG(PAC_DATA, &pac_data2);
644
645                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
646                                             krbtgt_keyblock_p);
647                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
648                                             &server_keyblock);
649                 krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
650
651                 DEBUG(0, ("tmp_data:\n"));
652                 dump_data(0, tmp_blob.data, tmp_blob.length);
653                 DEBUG(0, ("validate_blob:\n"));
654                 dump_data(0, validate_blob.data, validate_blob.length);
655
656                 torture_fail(tctx, talloc_asprintf(tctx, 
657                                                    "(saved test) PAC regenerate failed: length[%u] matches, but data does not", (unsigned)tmp_blob.length));
658         }
659
660         /* Break the auth time, to ensure we check this vital detail (not setting this caused all the pain in the first place... */
661         nt_status = kerberos_decode_pac(mem_ctx, 
662                                         lp_iconv_convenience(tctx->lp_ctx),
663                                         &pac_data,
664                                         tmp_blob,
665                                         smb_krb5_context->krb5_context,
666                                         krbtgt_keyblock_p,
667                                         &server_keyblock,
668                                         client_principal, 
669                                         authtime + 1, NULL);
670         if (NT_STATUS_IS_OK(nt_status)) {
671
672                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
673                                             krbtgt_keyblock_p);
674                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
675                                             &server_keyblock);
676                 krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
677                 torture_fail(tctx, "(saved test) PAC decoding DID NOT fail on broken auth time (time + 1)");
678         }
679
680         /* Break the client principal */
681         krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
682
683         broken_principal_string = talloc_strdup(mem_ctx, principal_string);
684         broken_principal_string[0]++;
685
686         ret = krb5_parse_name(smb_krb5_context->krb5_context,
687                               broken_principal_string, &client_principal);
688         if (ret) {
689
690                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
691                                             krbtgt_keyblock_p);
692                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
693                                             &server_keyblock);
694                 torture_fail(tctx, talloc_asprintf(tctx, 
695                                                    "(saved test) parsing of broken client principal failed: %s", 
696                                                    smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx)));
697         }
698
699         nt_status = kerberos_decode_pac(mem_ctx, 
700                                         lp_iconv_convenience(tctx->lp_ctx),
701                                         &pac_data,
702                                         tmp_blob,
703                                         smb_krb5_context->krb5_context,
704                                         krbtgt_keyblock_p,
705                                         &server_keyblock,
706                                         client_principal, 
707                                         authtime, NULL);
708         if (NT_STATUS_IS_OK(nt_status)) {
709                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
710                                             krbtgt_keyblock_p);
711                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
712                                             &server_keyblock);
713                 torture_fail(tctx, "(saved test) PAC decoding DID NOT fail on modified principal");
714         }
715
716         /* Finally...  Bugger up the signature, and check we fail the checksum */
717         tmp_blob.data[tmp_blob.length - 2]++;
718
719         nt_status = kerberos_decode_pac(mem_ctx, 
720                                         lp_iconv_convenience(tctx->lp_ctx),
721                                         &pac_data,
722                                         tmp_blob,
723                                         smb_krb5_context->krb5_context,
724                                         krbtgt_keyblock_p,
725                                         &server_keyblock,
726                                         client_principal, 
727                                         authtime, NULL);
728         if (NT_STATUS_IS_OK(nt_status)) {
729                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
730                                             krbtgt_keyblock_p);
731                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
732                                             &server_keyblock);
733                 torture_fail(tctx, "(saved test) PAC decoding DID NOT fail on broken checksum");
734         }
735
736         krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
737                                     krbtgt_keyblock_p);
738         krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
739                                     &server_keyblock);
740         return true;
741 }
742
743 struct torture_suite *torture_pac(TALLOC_CTX *mem_ctx)
744 {
745         struct torture_suite *suite = torture_suite_create(mem_ctx, "PAC");
746
747         torture_suite_add_simple_test(suite, "self check", 
748                                       torture_pac_self_check);
749         torture_suite_add_simple_test(suite, "saved check",
750                                       torture_pac_saved_check);
751         return suite;
752 }