ecd35f3dfa8549bb3c4cbb4e3035d1c790f55b74
[bbaumbach/samba-autobuild/.git] / source4 / auth / kerberos / kerberos_pac.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Create and parse the krb5 PAC
5
6    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005,2008
7    Copyright (C) Andrew Tridgell 2001
8    Copyright (C) Luke Howard 2002-2003
9    Copyright (C) Stefan Metzmacher 2004-2005
10
11    This program is free software; you can redistribute it and/or modify
12    it under the terms of the GNU General Public License as published by
13    the Free Software Foundation; either version 3 of the License, or
14    (at your option) any later version.
15
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19    GNU General Public License for more details.
20
21
22    You should have received a copy of the GNU General Public License
23    along with this program.  If not, see <http://www.gnu.org/licenses/>.
24 */
25
26 #include "includes.h"
27 #include "system/kerberos.h"
28 #include "auth/auth.h"
29 #include "auth/kerberos/kerberos.h"
30 #include "librpc/gen_ndr/ndr_krb5pac.h"
31 #include "lib/ldb/include/ldb.h"
32 #include "auth/auth_sam_reply.h"
33
34 krb5_error_code check_pac_checksum(TALLOC_CTX *mem_ctx,
35                                    DATA_BLOB pac_data,
36                                    struct PAC_SIGNATURE_DATA *sig,
37                                    krb5_context context,
38                                    const krb5_keyblock *keyblock)
39 {
40         krb5_error_code ret;
41         krb5_crypto crypto;
42         Checksum cksum;
43
44         cksum.cksumtype         = (CKSUMTYPE)sig->type;
45         cksum.checksum.length   = sig->signature.length;
46         cksum.checksum.data     = sig->signature.data;
47
48         ret = krb5_crypto_init(context,
49                                keyblock,
50                                0,
51                                &crypto);
52         if (ret) {
53                 DEBUG(0,("krb5_crypto_init() failed: %s\n",
54                           smb_get_krb5_error_message(context, ret, mem_ctx)));
55                 return ret;
56         }
57         ret = krb5_verify_checksum(context,
58                                    crypto,
59                                    KRB5_KU_OTHER_CKSUM,
60                                    pac_data.data,
61                                    pac_data.length,
62                                    &cksum);
63         krb5_crypto_destroy(context, crypto);
64
65         return ret;
66 }
67
68  NTSTATUS kerberos_decode_pac(TALLOC_CTX *mem_ctx,
69                               struct smb_iconv_convenience *iconv_convenience,
70                               struct PAC_DATA **pac_data_out,
71                               DATA_BLOB blob,
72                               krb5_context context,
73                               const krb5_keyblock *krbtgt_keyblock,
74                               const krb5_keyblock *service_keyblock,
75                               krb5_const_principal client_principal,
76                               time_t tgs_authtime,
77                               krb5_error_code *k5ret)
78 {
79         krb5_error_code ret;
80         NTSTATUS status;
81         enum ndr_err_code ndr_err;
82         struct PAC_SIGNATURE_DATA *srv_sig_ptr = NULL;
83         struct PAC_SIGNATURE_DATA *kdc_sig_ptr = NULL;
84         struct PAC_SIGNATURE_DATA *srv_sig_wipe = NULL;
85         struct PAC_SIGNATURE_DATA *kdc_sig_wipe = NULL;
86         struct PAC_LOGON_INFO *logon_info = NULL;
87         struct PAC_LOGON_NAME *logon_name = NULL;
88         struct PAC_DATA *pac_data;
89         struct PAC_DATA_RAW *pac_data_raw;
90
91         DATA_BLOB *srv_sig_blob = NULL;
92         DATA_BLOB *kdc_sig_blob = NULL;
93
94         DATA_BLOB modified_pac_blob;
95         NTTIME tgs_authtime_nttime;
96         krb5_principal client_principal_pac;
97         int i;
98
99         krb5_clear_error_message(context);
100
101         if (k5ret) {
102                 *k5ret = KRB5_PARSE_MALFORMED;
103         }
104
105         pac_data = talloc(mem_ctx, struct PAC_DATA);
106         pac_data_raw = talloc(mem_ctx, struct PAC_DATA_RAW);
107         kdc_sig_wipe = talloc(mem_ctx, struct PAC_SIGNATURE_DATA);
108         srv_sig_wipe = talloc(mem_ctx, struct PAC_SIGNATURE_DATA);
109         if (!pac_data_raw || !pac_data || !kdc_sig_wipe || !srv_sig_wipe) {
110                 if (k5ret) {
111                         *k5ret = ENOMEM;
112                 }
113                 return NT_STATUS_NO_MEMORY;
114         }
115
116         ndr_err = ndr_pull_struct_blob(&blob, pac_data,
117                         iconv_convenience, pac_data,
118                        (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA);
119         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
120                 status = ndr_map_error2ntstatus(ndr_err);
121                 DEBUG(0,("can't parse the PAC: %s\n",
122                         nt_errstr(status)));
123                 return status;
124         }
125
126         if (pac_data->num_buffers < 4) {
127                 /* we need logon_ingo, service_key and kdc_key */
128                 DEBUG(0,("less than 4 PAC buffers\n"));
129                 return NT_STATUS_INVALID_PARAMETER;
130         }
131
132         ndr_err = ndr_pull_struct_blob(&blob, pac_data_raw,
133                                        iconv_convenience, pac_data_raw,
134                                        (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA_RAW);
135         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
136                 status = ndr_map_error2ntstatus(ndr_err);
137                 DEBUG(0,("can't parse the PAC: %s\n",
138                         nt_errstr(status)));
139                 return status;
140         }
141
142         if (pac_data_raw->num_buffers < 4) {
143                 /* we need logon_ingo, service_key and kdc_key */
144                 DEBUG(0,("less than 4 PAC buffers\n"));
145                 return NT_STATUS_INVALID_PARAMETER;
146         }
147
148         if (pac_data->num_buffers != pac_data_raw->num_buffers) {
149                 /* we need logon_ingo, service_key and kdc_key */
150                 DEBUG(0,("misparse!  PAC_DATA has %d buffers while PAC_DATA_RAW has %d\n",
151                          pac_data->num_buffers, pac_data_raw->num_buffers));
152                 return NT_STATUS_INVALID_PARAMETER;
153         }
154
155         for (i=0; i < pac_data->num_buffers; i++) {
156                 if (pac_data->buffers[i].type != pac_data_raw->buffers[i].type) {
157                         DEBUG(0,("misparse!  PAC_DATA buffer %d has type %d while PAC_DATA_RAW has %d\n",
158                                  i, pac_data->buffers[i].type, pac_data->buffers[i].type));
159                         return NT_STATUS_INVALID_PARAMETER;
160                 }
161                 switch (pac_data->buffers[i].type) {
162                         case PAC_TYPE_LOGON_INFO:
163                                 if (!pac_data->buffers[i].info) {
164                                         break;
165                                 }
166                                 logon_info = pac_data->buffers[i].info->logon_info.info;
167                                 break;
168                         case PAC_TYPE_SRV_CHECKSUM:
169                                 if (!pac_data->buffers[i].info) {
170                                         break;
171                                 }
172                                 srv_sig_ptr = &pac_data->buffers[i].info->srv_cksum;
173                                 srv_sig_blob = &pac_data_raw->buffers[i].info->remaining;
174                                 break;
175                         case PAC_TYPE_KDC_CHECKSUM:
176                                 if (!pac_data->buffers[i].info) {
177                                         break;
178                                 }
179                                 kdc_sig_ptr = &pac_data->buffers[i].info->kdc_cksum;
180                                 kdc_sig_blob = &pac_data_raw->buffers[i].info->remaining;
181                                 break;
182                         case PAC_TYPE_LOGON_NAME:
183                                 logon_name = &pac_data->buffers[i].info->logon_name;
184                                 break;
185                         default:
186                                 break;
187                 }
188         }
189
190         if (!logon_info) {
191                 DEBUG(0,("PAC no logon_info\n"));
192                 return NT_STATUS_INVALID_PARAMETER;
193         }
194
195         if (!logon_name) {
196                 DEBUG(0,("PAC no logon_name\n"));
197                 return NT_STATUS_INVALID_PARAMETER;
198         }
199
200         if (!srv_sig_ptr || !srv_sig_blob) {
201                 DEBUG(0,("PAC no srv_key\n"));
202                 return NT_STATUS_INVALID_PARAMETER;
203         }
204
205         if (!kdc_sig_ptr || !kdc_sig_blob) {
206                 DEBUG(0,("PAC no kdc_key\n"));
207                 return NT_STATUS_INVALID_PARAMETER;
208         }
209
210         /* Find and zero out the signatures, as required by the signing algorithm */
211
212         /* We find the data blobs above, now we parse them to get at the exact portion we should zero */
213         ndr_err = ndr_pull_struct_blob(kdc_sig_blob, kdc_sig_wipe,
214                                        iconv_convenience, kdc_sig_wipe,
215                                        (ndr_pull_flags_fn_t)ndr_pull_PAC_SIGNATURE_DATA);
216         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
217                 status = ndr_map_error2ntstatus(ndr_err);
218                 DEBUG(0,("can't parse the KDC signature: %s\n",
219                         nt_errstr(status)));
220                 return status;
221         }
222
223         ndr_err = ndr_pull_struct_blob(srv_sig_blob, srv_sig_wipe,
224                                        iconv_convenience, srv_sig_wipe,
225                                        (ndr_pull_flags_fn_t)ndr_pull_PAC_SIGNATURE_DATA);
226         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
227                 status = ndr_map_error2ntstatus(ndr_err);
228                 DEBUG(0,("can't parse the SRV signature: %s\n",
229                         nt_errstr(status)));
230                 return status;
231         }
232
233         /* Now zero the decoded structure */
234         memset(kdc_sig_wipe->signature.data, '\0', kdc_sig_wipe->signature.length);
235         memset(srv_sig_wipe->signature.data, '\0', srv_sig_wipe->signature.length);
236
237         /* and reencode, back into the same place it came from */
238         ndr_err = ndr_push_struct_blob(kdc_sig_blob, pac_data_raw,
239                                        iconv_convenience,
240                                        kdc_sig_wipe,
241                                        (ndr_push_flags_fn_t)ndr_push_PAC_SIGNATURE_DATA);
242         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
243                 status = ndr_map_error2ntstatus(ndr_err);
244                 DEBUG(0,("can't repack the KDC signature: %s\n",
245                         nt_errstr(status)));
246                 return status;
247         }
248         ndr_err = ndr_push_struct_blob(srv_sig_blob, pac_data_raw,
249                                        iconv_convenience,
250                                        srv_sig_wipe,
251                                        (ndr_push_flags_fn_t)ndr_push_PAC_SIGNATURE_DATA);
252         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
253                 status = ndr_map_error2ntstatus(ndr_err);
254                 DEBUG(0,("can't repack the SRV signature: %s\n",
255                         nt_errstr(status)));
256                 return status;
257         }
258
259         /* push out the whole structure, but now with zero'ed signatures */
260         ndr_err = ndr_push_struct_blob(&modified_pac_blob, pac_data_raw,
261                                        iconv_convenience,
262                                        pac_data_raw,
263                                        (ndr_push_flags_fn_t)ndr_push_PAC_DATA_RAW);
264         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
265                 status = ndr_map_error2ntstatus(ndr_err);
266                 DEBUG(0,("can't repack the RAW PAC: %s\n",
267                         nt_errstr(status)));
268                 return status;
269         }
270
271         /* verify by service_key */
272         ret = check_pac_checksum(mem_ctx,
273                                  modified_pac_blob, srv_sig_ptr,
274                                  context,
275                                  service_keyblock);
276         if (ret) {
277                 DEBUG(1, ("PAC Decode: Failed to verify the service signature: %s\n",
278                           smb_get_krb5_error_message(context, ret, mem_ctx)));
279                 if (k5ret) {
280                         *k5ret = ret;
281                 }
282                 return NT_STATUS_ACCESS_DENIED;
283         }
284
285         if (krbtgt_keyblock) {
286                 ret = check_pac_checksum(mem_ctx,
287                                             srv_sig_ptr->signature, kdc_sig_ptr,
288                                             context, krbtgt_keyblock);
289                 if (ret) {
290                         DEBUG(1, ("PAC Decode: Failed to verify the KDC signature: %s\n",
291                                   smb_get_krb5_error_message(context, ret, mem_ctx)));
292                         if (k5ret) {
293                                 *k5ret = ret;
294                         }
295                         return NT_STATUS_ACCESS_DENIED;
296                 }
297         }
298
299         /* Convert to NT time, so as not to loose accuracy in comparison */
300         unix_to_nt_time(&tgs_authtime_nttime, tgs_authtime);
301
302         if (tgs_authtime_nttime != logon_name->logon_time) {
303                 DEBUG(2, ("PAC Decode: Logon time mismatch between ticket and PAC!\n"));
304                 DEBUG(2, ("PAC Decode: PAC: %s\n", nt_time_string(mem_ctx, logon_name->logon_time)));
305                 DEBUG(2, ("PAC Decode: Ticket: %s\n", nt_time_string(mem_ctx, tgs_authtime_nttime)));
306                 return NT_STATUS_ACCESS_DENIED;
307         }
308
309         ret = krb5_parse_name_flags(context, logon_name->account_name, KRB5_PRINCIPAL_PARSE_NO_REALM,
310                                     &client_principal_pac);
311         if (ret) {
312                 DEBUG(2, ("Could not parse name from incoming PAC: [%s]: %s\n",
313                           logon_name->account_name,
314                           smb_get_krb5_error_message(context, ret, mem_ctx)));
315                 if (k5ret) {
316                         *k5ret = ret;
317                 }
318                 return NT_STATUS_INVALID_PARAMETER;
319         }
320
321         if (!krb5_principal_compare_any_realm(context, client_principal, client_principal_pac)) {
322                 DEBUG(2, ("Name in PAC [%s] does not match principal name in ticket\n",
323                           logon_name->account_name));
324                 return NT_STATUS_ACCESS_DENIED;
325         }
326
327 #if 0
328         if (strcasecmp(logon_info->info3.base.account_name.string,
329                        "Administrator")== 0) {
330                 file_save("tmp_pac_data-admin.dat",blob.data,blob.length);
331         }
332 #endif
333
334         DEBUG(3,("Found account name from PAC: %s [%s]\n",
335                  logon_info->info3.base.account_name.string,
336                  logon_info->info3.base.full_name.string));
337         *pac_data_out = pac_data;
338
339         return NT_STATUS_OK;
340 }
341
342 _PUBLIC_  NTSTATUS kerberos_pac_logon_info(TALLOC_CTX *mem_ctx,
343                                   struct smb_iconv_convenience *iconv_convenience,
344                                   struct PAC_LOGON_INFO **logon_info,
345                                   DATA_BLOB blob,
346                                   krb5_context context,
347                                   const krb5_keyblock *krbtgt_keyblock,
348                                   const krb5_keyblock *service_keyblock,
349                                   krb5_const_principal client_principal,
350                                   time_t tgs_authtime,
351                                   krb5_error_code *k5ret)
352 {
353         NTSTATUS nt_status;
354         struct PAC_DATA *pac_data;
355         int i;
356         nt_status = kerberos_decode_pac(mem_ctx,
357                                         iconv_convenience,
358                                         &pac_data,
359                                         blob,
360                                         context,
361                                         krbtgt_keyblock,
362                                         service_keyblock,
363                                         client_principal,
364                                         tgs_authtime,
365                                         k5ret);
366         if (!NT_STATUS_IS_OK(nt_status)) {
367                 return nt_status;
368         }
369
370         *logon_info = NULL;
371         for (i=0; i < pac_data->num_buffers; i++) {
372                 if (pac_data->buffers[i].type != PAC_TYPE_LOGON_INFO) {
373                         continue;
374                 }
375                 *logon_info = pac_data->buffers[i].info->logon_info.info;
376         }
377         if (!*logon_info) {
378                 return NT_STATUS_INVALID_PARAMETER;
379         }
380         return NT_STATUS_OK;
381 }
382
383 static krb5_error_code make_pac_checksum(TALLOC_CTX *mem_ctx,
384                                          DATA_BLOB *pac_data,
385                                          struct PAC_SIGNATURE_DATA *sig,
386                                          krb5_context context,
387                                          const krb5_keyblock *keyblock)
388 {
389         krb5_error_code ret;
390         krb5_crypto crypto;
391         Checksum cksum;
392
393
394         ret = krb5_crypto_init(context,
395                                keyblock,
396                                0,
397                                &crypto);
398         if (ret) {
399                 DEBUG(0,("krb5_crypto_init() failed: %s\n",
400                           smb_get_krb5_error_message(context, ret, mem_ctx)));
401                 return ret;
402         }
403         ret = krb5_create_checksum(context,
404                                    crypto,
405                                    KRB5_KU_OTHER_CKSUM,
406                                    0,
407                                    pac_data->data,
408                                    pac_data->length,
409                                    &cksum);
410         if (ret) {
411                 DEBUG(2, ("PAC Verification failed: %s\n",
412                           smb_get_krb5_error_message(context, ret, mem_ctx)));
413         }
414
415         krb5_crypto_destroy(context, crypto);
416
417         if (ret) {
418                 return ret;
419         }
420
421         sig->type = cksum.cksumtype;
422         sig->signature = data_blob_talloc(mem_ctx, cksum.checksum.data, cksum.checksum.length);
423         free_Checksum(&cksum);
424
425         return 0;
426 }
427
428  krb5_error_code kerberos_encode_pac(TALLOC_CTX *mem_ctx,
429                                      struct smb_iconv_convenience *iconv_convenience,
430                                     struct PAC_DATA *pac_data,
431                                     krb5_context context,
432                                     const krb5_keyblock *krbtgt_keyblock,
433                                     const krb5_keyblock *service_keyblock,
434                                     DATA_BLOB *pac)
435 {
436         NTSTATUS nt_status;
437         krb5_error_code ret;
438         enum ndr_err_code ndr_err;
439         DATA_BLOB zero_blob = data_blob(NULL, 0);
440         DATA_BLOB tmp_blob = data_blob(NULL, 0);
441         struct PAC_SIGNATURE_DATA *kdc_checksum = NULL;
442         struct PAC_SIGNATURE_DATA *srv_checksum = NULL;
443         int i;
444
445         /* First, just get the keytypes filled in (and lengths right, eventually) */
446         for (i=0; i < pac_data->num_buffers; i++) {
447                 if (pac_data->buffers[i].type != PAC_TYPE_KDC_CHECKSUM) {
448                         continue;
449                 }
450                 kdc_checksum = &pac_data->buffers[i].info->kdc_cksum,
451                 ret = make_pac_checksum(mem_ctx, &zero_blob,
452                                         kdc_checksum,
453                                         context, krbtgt_keyblock);
454                 if (ret) {
455                         DEBUG(2, ("making krbtgt PAC checksum failed: %s\n",
456                                   smb_get_krb5_error_message(context, ret, mem_ctx)));
457                         talloc_free(pac_data);
458                         return ret;
459                 }
460         }
461
462         for (i=0; i < pac_data->num_buffers; i++) {
463                 if (pac_data->buffers[i].type != PAC_TYPE_SRV_CHECKSUM) {
464                         continue;
465                 }
466                 srv_checksum = &pac_data->buffers[i].info->srv_cksum;
467                 ret = make_pac_checksum(mem_ctx, &zero_blob,
468                                         srv_checksum,
469                                         context, service_keyblock);
470                 if (ret) {
471                         DEBUG(2, ("making service PAC checksum failed: %s\n",
472                                   smb_get_krb5_error_message(context, ret, mem_ctx)));
473                         talloc_free(pac_data);
474                         return ret;
475                 }
476         }
477
478         if (!kdc_checksum) {
479                 DEBUG(2, ("Invalid PAC constructed for signing, no KDC checksum present!"));
480                 return EINVAL;
481         }
482         if (!srv_checksum) {
483                 DEBUG(2, ("Invalid PAC constructed for signing, no SRV checksum present!"));
484                 return EINVAL;
485         }
486
487         /* But wipe out the actual signatures */
488         memset(kdc_checksum->signature.data, '\0', kdc_checksum->signature.length);
489         memset(srv_checksum->signature.data, '\0', srv_checksum->signature.length);
490
491         ndr_err = ndr_push_struct_blob(&tmp_blob, mem_ctx,
492                                        iconv_convenience,
493                                        pac_data,
494                                        (ndr_push_flags_fn_t)ndr_push_PAC_DATA);
495         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
496                 nt_status = ndr_map_error2ntstatus(ndr_err);
497                 DEBUG(1, ("PAC (presig) push failed: %s\n", nt_errstr(nt_status)));
498                 talloc_free(pac_data);
499                 return EINVAL;
500         }
501
502         /* Then sign the result of the previous push, where the sig was zero'ed out */
503         ret = make_pac_checksum(mem_ctx, &tmp_blob, srv_checksum,
504                                 context, service_keyblock);
505
506         /* Then sign Server checksum */
507         ret = make_pac_checksum(mem_ctx, &srv_checksum->signature, kdc_checksum, context, krbtgt_keyblock);
508         if (ret) {
509                 DEBUG(2, ("making krbtgt PAC checksum failed: %s\n",
510                           smb_get_krb5_error_message(context, ret, mem_ctx)));
511                 talloc_free(pac_data);
512                 return ret;
513         }
514
515         /* And push it out again, this time to the world.  This relies on determanistic pointer values */
516         ndr_err = ndr_push_struct_blob(&tmp_blob, mem_ctx,
517                                        iconv_convenience,
518                                        pac_data,
519                                        (ndr_push_flags_fn_t)ndr_push_PAC_DATA);
520         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
521                 nt_status = ndr_map_error2ntstatus(ndr_err);
522                 DEBUG(1, ("PAC (final) push failed: %s\n", nt_errstr(nt_status)));
523                 talloc_free(pac_data);
524                 return EINVAL;
525         }
526
527         *pac = tmp_blob;
528
529         return ret;
530 }
531
532
533  krb5_error_code kerberos_create_pac(TALLOC_CTX *mem_ctx,
534                                      struct smb_iconv_convenience *iconv_convenience,
535                                      struct auth_serversupplied_info *server_info,
536                                      krb5_context context,
537                                      const krb5_keyblock *krbtgt_keyblock,
538                                      const krb5_keyblock *service_keyblock,
539                                      krb5_principal client_principal,
540                                      time_t tgs_authtime,
541                                      DATA_BLOB *pac)
542 {
543         NTSTATUS nt_status;
544         krb5_error_code ret;
545         struct PAC_DATA *pac_data = talloc(mem_ctx, struct PAC_DATA);
546         struct netr_SamInfo3 *sam3;
547         union PAC_INFO *u_LOGON_INFO;
548         struct PAC_LOGON_INFO *LOGON_INFO;
549         union PAC_INFO *u_LOGON_NAME;
550         struct PAC_LOGON_NAME *LOGON_NAME;
551         union PAC_INFO *u_KDC_CHECKSUM;
552         union PAC_INFO *u_SRV_CHECKSUM;
553
554         char *name;
555
556         enum {
557                 PAC_BUF_LOGON_INFO = 0,
558                 PAC_BUF_LOGON_NAME = 1,
559                 PAC_BUF_SRV_CHECKSUM = 2,
560                 PAC_BUF_KDC_CHECKSUM = 3,
561                 PAC_BUF_NUM_BUFFERS = 4
562         };
563
564         if (!pac_data) {
565                 return ENOMEM;
566         }
567
568         pac_data->num_buffers = PAC_BUF_NUM_BUFFERS;
569         pac_data->version = 0;
570
571         pac_data->buffers = talloc_array(pac_data,
572                                          struct PAC_BUFFER,
573                                          pac_data->num_buffers);
574         if (!pac_data->buffers) {
575                 talloc_free(pac_data);
576                 return ENOMEM;
577         }
578
579         /* LOGON_INFO */
580         u_LOGON_INFO = talloc_zero(pac_data->buffers, union PAC_INFO);
581         if (!u_LOGON_INFO) {
582                 talloc_free(pac_data);
583                 return ENOMEM;
584         }
585         pac_data->buffers[PAC_BUF_LOGON_INFO].type = PAC_TYPE_LOGON_INFO;
586         pac_data->buffers[PAC_BUF_LOGON_INFO].info = u_LOGON_INFO;
587
588         /* LOGON_NAME */
589         u_LOGON_NAME = talloc_zero(pac_data->buffers, union PAC_INFO);
590         if (!u_LOGON_NAME) {
591                 talloc_free(pac_data);
592                 return ENOMEM;
593         }
594         pac_data->buffers[PAC_BUF_LOGON_NAME].type = PAC_TYPE_LOGON_NAME;
595         pac_data->buffers[PAC_BUF_LOGON_NAME].info = u_LOGON_NAME;
596         LOGON_NAME = &u_LOGON_NAME->logon_name;
597
598         /* SRV_CHECKSUM */
599         u_SRV_CHECKSUM = talloc_zero(pac_data->buffers, union PAC_INFO);
600         if (!u_SRV_CHECKSUM) {
601                 talloc_free(pac_data);
602                 return ENOMEM;
603         }
604         pac_data->buffers[PAC_BUF_SRV_CHECKSUM].type = PAC_TYPE_SRV_CHECKSUM;
605         pac_data->buffers[PAC_BUF_SRV_CHECKSUM].info = u_SRV_CHECKSUM;
606
607         /* KDC_CHECKSUM */
608         u_KDC_CHECKSUM = talloc_zero(pac_data->buffers, union PAC_INFO);
609         if (!u_KDC_CHECKSUM) {
610                 talloc_free(pac_data);
611                 return ENOMEM;
612         }
613         pac_data->buffers[PAC_BUF_KDC_CHECKSUM].type = PAC_TYPE_KDC_CHECKSUM;
614         pac_data->buffers[PAC_BUF_KDC_CHECKSUM].info = u_KDC_CHECKSUM;
615
616         /* now the real work begins... */
617
618         LOGON_INFO = talloc_zero(u_LOGON_INFO, struct PAC_LOGON_INFO);
619         if (!LOGON_INFO) {
620                 talloc_free(pac_data);
621                 return ENOMEM;
622         }
623         nt_status = auth_convert_server_info_saminfo3(LOGON_INFO, server_info, &sam3);
624         if (!NT_STATUS_IS_OK(nt_status)) {
625                 DEBUG(1, ("Getting Samba info failed: %s\n", nt_errstr(nt_status)));
626                 talloc_free(pac_data);
627                 return EINVAL;
628         }
629
630         u_LOGON_INFO->logon_info.info           = LOGON_INFO;
631         LOGON_INFO->info3 = *sam3;
632
633         ret = krb5_unparse_name_flags(context, client_principal,
634                                       KRB5_PRINCIPAL_UNPARSE_NO_REALM, &name);
635         if (ret) {
636                 return ret;
637         }
638         LOGON_NAME->account_name        = talloc_strdup(LOGON_NAME, name);
639         free(name);
640         /*
641           this logon_time field is absolutely critical. This is what
642           caused all our PAC troubles :-)
643         */
644         unix_to_nt_time(&LOGON_NAME->logon_time, tgs_authtime);
645
646         ret = kerberos_encode_pac(mem_ctx,
647                                   iconv_convenience,
648                                   pac_data,
649                                   context,
650                                   krbtgt_keyblock,
651                                   service_keyblock,
652                                   pac);
653         talloc_free(pac_data);
654         return ret;
655 }
656
657 krb5_error_code kerberos_pac_to_server_info(TALLOC_CTX *mem_ctx,
658                                                 struct smb_iconv_convenience *iconv_convenience,
659                                                 krb5_pac pac,
660                                                 krb5_context context,
661                                                 struct auth_serversupplied_info **server_info)
662 {
663         NTSTATUS nt_status;
664         enum ndr_err_code ndr_err;
665         krb5_error_code ret;
666
667         DATA_BLOB pac_logon_info_in, pac_srv_checksum_in, pac_kdc_checksum_in;
668         krb5_data k5pac_logon_info_in, k5pac_srv_checksum_in, k5pac_kdc_checksum_in;
669
670         union PAC_INFO info;
671         union netr_Validation validation;
672         struct auth_serversupplied_info *server_info_out;
673
674         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
675
676         if (!tmp_ctx) {
677                 return ENOMEM;
678         }
679
680         ret = krb5_pac_get_buffer(context, pac, PAC_TYPE_LOGON_INFO, &k5pac_logon_info_in);
681         if (ret != 0) {
682                 talloc_free(tmp_ctx);
683                 return EINVAL;
684         }
685
686         pac_logon_info_in = data_blob_const(k5pac_logon_info_in.data, k5pac_logon_info_in.length);
687
688         ndr_err = ndr_pull_union_blob(&pac_logon_info_in, tmp_ctx, iconv_convenience, &info,
689                                       PAC_TYPE_LOGON_INFO,
690                                       (ndr_pull_flags_fn_t)ndr_pull_PAC_INFO);
691         krb5_data_free(&k5pac_logon_info_in);
692         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err) || !info.logon_info.info) {
693                 nt_status = ndr_map_error2ntstatus(ndr_err);
694                 DEBUG(0,("can't parse the PAC LOGON_INFO: %s\n", nt_errstr(nt_status)));
695                 talloc_free(tmp_ctx);
696                 return EINVAL;
697         }
698
699         /* Pull this right into the normal auth sysstem structures */
700         validation.sam3 = &info.logon_info.info->info3;
701         nt_status = make_server_info_netlogon_validation(mem_ctx,
702                                                          "",
703                                                          3, &validation,
704                                                          &server_info_out);
705         if (!NT_STATUS_IS_OK(nt_status)) {
706                 talloc_free(tmp_ctx);
707                 return EINVAL;
708         }
709
710         ret = krb5_pac_get_buffer(context, pac, PAC_TYPE_SRV_CHECKSUM, &k5pac_srv_checksum_in);
711         if (ret != 0) {
712                 talloc_free(tmp_ctx);
713                 return ret;
714         }
715
716         pac_srv_checksum_in = data_blob_const(k5pac_srv_checksum_in.data, k5pac_srv_checksum_in.length);
717
718         ndr_err = ndr_pull_struct_blob(&pac_srv_checksum_in, server_info_out,
719                                        iconv_convenience, &server_info_out->pac_srv_sig,
720                                        (ndr_pull_flags_fn_t)ndr_pull_PAC_SIGNATURE_DATA);
721         krb5_data_free(&k5pac_srv_checksum_in);
722         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
723                 nt_status = ndr_map_error2ntstatus(ndr_err);
724                 DEBUG(0,("can't parse the KDC signature: %s\n",
725                         nt_errstr(nt_status)));
726                 return EINVAL;
727         }
728
729         ret = krb5_pac_get_buffer(context, pac, PAC_TYPE_KDC_CHECKSUM, &k5pac_kdc_checksum_in);
730         if (ret != 0) {
731                 talloc_free(tmp_ctx);
732                 return ret;
733         }
734
735         pac_kdc_checksum_in = data_blob_const(k5pac_kdc_checksum_in.data, k5pac_kdc_checksum_in.length);
736
737         ndr_err = ndr_pull_struct_blob(&pac_kdc_checksum_in, server_info_out,
738                                        iconv_convenience, &server_info_out->pac_kdc_sig,
739                                        (ndr_pull_flags_fn_t)ndr_pull_PAC_SIGNATURE_DATA);
740         krb5_data_free(&k5pac_kdc_checksum_in);
741         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
742                 nt_status = ndr_map_error2ntstatus(ndr_err);
743                 DEBUG(0,("can't parse the KDC signature: %s\n",
744                         nt_errstr(nt_status)));
745                 return EINVAL;
746         }
747
748         *server_info = server_info_out;
749
750         return 0;
751 }
752
753
754 NTSTATUS kerberos_pac_blob_to_server_info(TALLOC_CTX *mem_ctx,
755                                                      struct smb_iconv_convenience *iconv_convenience,
756                                                      DATA_BLOB pac_blob,
757                                                      krb5_context context,
758                                                      struct auth_serversupplied_info **server_info)
759 {
760         krb5_error_code ret;
761         krb5_pac pac;
762         ret = krb5_pac_parse(context,
763                              pac_blob.data, pac_blob.length,
764                              &pac);
765         if (ret) {
766                 return map_nt_error_from_unix(ret);
767         }
768
769
770         ret = kerberos_pac_to_server_info(mem_ctx, iconv_convenience, pac, context, server_info);
771         krb5_pac_free(context, pac);
772         if (ret) {
773                 return map_nt_error_from_unix(ret);
774         }
775         return NT_STATUS_OK;
776 }