r13585: Sorry Gunther, had to revert this. It's got a buffer
[tprouty/samba.git] / source / libads / authdata.c
1 /* 
2    Unix SMB/CIFS implementation.
3    kerberos authorization data (PAC) utility library
4    Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2003   
5    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
6    Copyright (C) Andrew Tridgell 2001
7    Copyright (C) Luke Howard 2002-2003
8    Copyright (C) Stefan Metzmacher 2004-2005
9    Copyright (C) Guenther Deschner 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 2 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    You should have received a copy of the GNU General Public License
22    along with this program; if not, write to the Free Software
23    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26 #include "includes.h"
27
28 #ifdef HAVE_KRB5
29
30 static BOOL pac_io_logon_name(const char *desc, PAC_LOGON_NAME *logon_name,
31                               prs_struct *ps, int depth)
32 {
33         if (NULL == logon_name)
34                 return False;
35
36         prs_debug(ps, depth, desc, "pac_io_logon_name");
37         depth++;
38
39         if (!smb_io_time("logon_time", &logon_name->logon_time, ps, depth))
40                 return False;
41
42         if (!prs_uint16("len", ps, depth, &logon_name->len))
43                 return False;
44
45         if (UNMARSHALLING(ps) && logon_name->len) {
46                 logon_name->username = PRS_ALLOC_MEM(ps, uint16, logon_name->len);
47                 if (!logon_name->username) {
48                         DEBUG(3, ("No memory available\n"));
49                         return False;
50                 }
51         }
52
53         if (!prs_uint16s(True, "name", ps, depth, logon_name->username, 
54                          (logon_name->len / sizeof(uint16))))
55                 return False;
56
57         return True;
58
59 }
60
61
62
63 #if 0 /* Unused (handled now in net_io_user_info3()) - Guenther */
64 static BOOL pac_io_krb_sids(const char *desc, KRB_SID_AND_ATTRS *sid_and_attr,
65                             prs_struct *ps, int depth)
66 {
67         if (NULL == sid_and_attr)
68                 return False;
69
70         prs_debug(ps, depth, desc, "pac_io_krb_sids");
71         depth++;
72
73         if (UNMARSHALLING(ps)) {
74                 sid_and_attr->sid = PRS_ALLOC_MEM(ps, DOM_SID2, 1);
75                 if (!sid_and_attr->sid) {
76                         DEBUG(3, ("No memory available\n"));
77                         return False;
78                 }
79         }
80
81         if(!smb_io_dom_sid2("sid", sid_and_attr->sid, ps, depth))
82                 return False;
83
84         return True;
85 }
86
87
88 static BOOL pac_io_krb_attrs(const char *desc, KRB_SID_AND_ATTRS *sid_and_attr,
89                              prs_struct *ps, int depth)
90 {
91         if (NULL == sid_and_attr)
92                 return False;
93
94         prs_debug(ps, depth, desc, "pac_io_krb_attrs");
95         depth++;
96
97         if (!prs_uint32("sid_ptr", ps, depth, &sid_and_attr->sid_ptr))
98                 return False;
99         if (!prs_uint32("attrs", ps, depth, &sid_and_attr->attrs))
100                 return False;
101
102         return True;
103 }
104
105 static BOOL pac_io_krb_sid_and_attr_array(const char *desc, 
106                                           KRB_SID_AND_ATTR_ARRAY *array,
107                                           uint32 num,
108                                           prs_struct *ps, int depth)
109 {
110         int i;
111
112         if (NULL == array)
113                 return False;
114
115         prs_debug(ps, depth, desc, "pac_io_krb_sid_and_attr_array");
116         depth++;
117
118
119         if (!prs_uint32("count", ps, depth, &array->count))
120                 return False;
121
122         if (UNMARSHALLING(ps)) {
123                 array->krb_sid_and_attrs = PRS_ALLOC_MEM(ps, KRB_SID_AND_ATTRS, num);
124                 if (!array->krb_sid_and_attrs) {
125                         DEBUG(3, ("No memory available\n"));
126                         return False;
127                 }
128         }
129
130         for (i=0; i<num; i++) {
131                 if (!pac_io_krb_attrs(desc, 
132                                       &array->krb_sid_and_attrs[i],
133                                       ps, depth))
134                         return False;
135
136         }
137         for (i=0; i<num; i++) {
138                 if (!pac_io_krb_sids(desc, 
139                                      &array->krb_sid_and_attrs[i],
140                                      ps, depth))
141                         return False;
142
143         }
144
145         return True;
146
147 }
148 #endif
149
150 static BOOL pac_io_group_membership(const char *desc, 
151                                     GROUP_MEMBERSHIP *membership,
152                                     prs_struct *ps, int depth)
153 {
154         if (NULL == membership)
155                 return False;
156
157         prs_debug(ps, depth, desc, "pac_io_group_membership");
158         depth++;
159
160         if (!prs_uint32("rid", ps, depth, &membership->rid))
161                 return False;
162         if (!prs_uint32("attrs", ps, depth, &membership->attrs))
163                 return False;
164
165         return True;
166 }
167
168
169 static BOOL pac_io_group_membership_array(const char *desc, 
170                                           GROUP_MEMBERSHIP_ARRAY *array,
171                                           uint32 num,
172                                           prs_struct *ps, int depth)
173 {
174         int i;
175
176         if (NULL == array)
177                 return False;
178
179         prs_debug(ps, depth, desc, "pac_io_group_membership_array");
180         depth++;
181
182
183         if (!prs_uint32("count", ps, depth, &array->count))
184                 return False;
185
186         if (UNMARSHALLING(ps)) {
187                 array->group_membership = PRS_ALLOC_MEM(ps, GROUP_MEMBERSHIP, num);
188                 if (!array->group_membership) {
189                         DEBUG(3, ("No memory available\n"));
190                         return False;
191                 }
192         }
193
194         for (i=0; i<num; i++) {
195                 if (!pac_io_group_membership(desc, 
196                                              &array->group_membership[i],
197                                              ps, depth))
198                         return False;
199
200         }
201
202         return True;
203
204 }
205
206 #if 0 /* Unused, replaced using an expanded net_io_user_info3() now - Guenther */
207 static BOOL pac_io_pac_logon_info(const char *desc, PAC_LOGON_INFO *info, 
208                                   prs_struct *ps, int depth)
209 {
210         uint32 garbage, i;
211
212         if (NULL == info)
213                 return False;
214
215         prs_debug(ps, depth, desc, "pac_io_pac_logon_info");
216         depth++;
217
218         if (!prs_align(ps))
219                 return False;
220         if (!prs_uint32("unknown", ps, depth, &garbage)) /* 00081001 */
221                 return False;
222         if (!prs_uint32("unknown", ps, depth, &garbage)) /* cccccccc */
223                 return False;
224         if (!prs_uint32("bufferlen", ps, depth, &garbage))
225                 return False;
226         if (!prs_uint32("bufferlenhi", ps, depth, &garbage)) /* 00000000 */
227                 return False;
228
229         if (!prs_uint32("pointer", ps, depth, &garbage))
230                 return False;
231
232         if (!prs_align(ps))
233                 return False;
234         if (!smb_io_time("logon_time", &info->logon_time, ps, depth))
235                 return False;
236         if (!smb_io_time("logoff_time", &info->logoff_time, ps, depth))
237                 return False;
238         if (!smb_io_time("kickoff_time", &info->kickoff_time, ps, depth))
239                 return False;
240         if (!smb_io_time("pass_last_set_time", &info->pass_last_set_time, 
241                          ps, depth))
242                 return False;
243         if (!smb_io_time("pass_can_change_time", &info->pass_can_change_time, 
244                          ps, depth))
245                 return False;
246         if (!smb_io_time("pass_must_change_time", &info->pass_must_change_time,
247                          ps, depth))
248                 return False;
249
250         if (!smb_io_unihdr("hdr_user_name", &info->hdr_user_name, ps, depth))
251                 return False;
252         if (!smb_io_unihdr("hdr_full_name", &info->hdr_full_name, ps, depth))
253                 return False;
254         if (!smb_io_unihdr("hdr_logon_script", &info->hdr_logon_script, 
255                            ps, depth))
256                 return False;
257         if (!smb_io_unihdr("hdr_profile_path", &info->hdr_profile_path, 
258                            ps, depth))
259                 return False;
260         if (!smb_io_unihdr("hdr_home_dir", &info->hdr_home_dir, ps, depth))
261                 return False;
262         if (!smb_io_unihdr("hdr_dir_drive", &info->hdr_dir_drive, ps, depth))
263                 return False;
264
265         if (!prs_uint16("logon_count", ps, depth, &info->logon_count))
266                 return False;
267         if (!prs_uint16("bad_password_count", ps, depth, &info->bad_password_count))
268                 return False;
269         if (!prs_uint32("user_rid", ps, depth, &info->user_rid))
270                 return False;
271         if (!prs_uint32("group_rid", ps, depth, &info->group_rid))
272                 return False;
273         if (!prs_uint32("group_count", ps, depth, &info->group_count))
274                 return False;
275         /* I haven't seen this contain anything yet, but when it does
276            we will have to make sure we decode the contents in the middle
277            all the unistr2s ... */
278         if (!prs_uint32("group_mem_ptr", ps, depth, 
279                         &info->group_membership_ptr))
280                 return False;
281         if (!prs_uint32("user_flags", ps, depth, &info->user_flags))
282                 return False;
283
284         if (!prs_uint8s(False, "session_key", ps, depth, info->session_key, 16)) 
285                 return False;
286         
287         if (!smb_io_unihdr("hdr_dom_controller", 
288                            &info->hdr_dom_controller, ps, depth))
289                 return False;
290         if (!smb_io_unihdr("hdr_dom_name", &info->hdr_dom_name, ps, depth))
291                 return False;
292
293         /* this should be followed, but just get ptr for now */
294         if (!prs_uint32("ptr_dom_sid", ps, depth, &info->ptr_dom_sid))
295                 return False;
296
297         if (!prs_uint8s(False, "lm_session_key", ps, depth, info->lm_session_key, 8)) 
298                 return False;
299
300         if (!prs_uint32("acct_flags", ps, depth, &info->acct_flags))
301                 return False;
302
303         for (i = 0; i < 7; i++)
304         {
305                 if (!prs_uint32("unkown", ps, depth, &info->unknown[i])) /* unknown */
306                         return False;
307         }
308
309         if (!prs_uint32("sid_count", ps, depth, &info->sid_count))
310                 return False;
311         if (!prs_uint32("ptr_extra_sids", ps, depth, &info->ptr_extra_sids))
312                 return False;
313         if (!prs_uint32("ptr_res_group_dom_sid", ps, depth, 
314                         &info->ptr_res_group_dom_sid))
315                 return False;
316         if (!prs_uint32("res_group_count", ps, depth, &info->res_group_count))
317                 return False;
318         if (!prs_uint32("ptr_res_groups", ps, depth, &info->ptr_res_groups))
319                 return False;
320
321         if(!smb_io_unistr2("uni_user_name", &info->uni_user_name, 
322                            info->hdr_user_name.buffer, ps, depth))
323                 return False;
324         if(!smb_io_unistr2("uni_full_name", &info->uni_full_name, 
325                            info->hdr_full_name.buffer, ps, depth))
326                 return False;
327         if(!smb_io_unistr2("uni_logon_script", &info->uni_logon_script, 
328                            info->hdr_logon_script.buffer, ps, depth))
329                 return False;
330         if(!smb_io_unistr2("uni_profile_path", &info->uni_profile_path,
331                            info->hdr_profile_path.buffer, ps, depth))
332                 return False;
333         if(!smb_io_unistr2("uni_home_dir", &info->uni_home_dir,
334                            info->hdr_home_dir.buffer, ps, depth))
335                 return False;
336         if(!smb_io_unistr2("uni_dir_drive", &info->uni_dir_drive,
337                            info->hdr_dir_drive.buffer, ps, depth))
338                 return False;
339
340         if (info->group_membership_ptr) {
341                 if (!pac_io_group_membership_array("group membership",
342                                                    &info->groups,
343                                                    info->group_count,
344                                                    ps, depth))
345                         return False;
346         }
347
348
349         if(!smb_io_unistr2("uni_dom_controller", &info->uni_dom_controller,
350                            info->hdr_dom_controller.buffer, ps, depth))
351                 return False;
352         if(!smb_io_unistr2("uni_dom_name", &info->uni_dom_name, 
353                            info->hdr_dom_name.buffer, ps, depth))
354                 return False;
355
356         if(info->ptr_dom_sid)
357                 if(!smb_io_dom_sid2("dom_sid", &info->dom_sid, ps, depth))
358                         return False;
359
360         
361         if (info->sid_count && info->ptr_extra_sids)
362                 if (!pac_io_krb_sid_and_attr_array("extra_sids", 
363                                                    &info->extra_sids,
364                                                    info->sid_count,
365                                                    ps, depth))
366                         return False;
367
368         if (info->ptr_res_group_dom_sid)
369                 if (!smb_io_dom_sid2("res_group_dom_sid", 
370                                      &info->res_group_dom_sid, ps, depth))
371                         return False;
372
373         if (info->ptr_res_groups) {
374
375                 if (!(info->user_flgs & LOGON_RESOURCE_GROUPS)) {
376                         DEBUG(0,("user_flgs attribute does not have LOGON_RESOURCE_GROUPS\n"));
377                         /* return False; */
378                 }
379
380                 if (!pac_io_group_membership_array("res group membership",
381                                                    &info->res_groups,
382                                                    info->res_group_count,
383                                                    ps, depth))
384                         return False;
385         }
386
387         return True;
388 }
389 #endif
390
391 static BOOL pac_io_pac_logon_info(const char *desc, PAC_LOGON_INFO *info, 
392                                   prs_struct *ps, int depth)
393 {
394         uint32 garbage;
395         BOOL kerb_validation_info = True;
396
397         if (NULL == info)
398                 return False;
399
400         prs_debug(ps, depth, desc, "pac_io_pac_logon_info");
401         depth++;
402
403         if (!prs_align(ps))
404                 return False;
405         if (!prs_uint32("unknown", ps, depth, &garbage)) /* 00081001 */
406                 return False;
407         if (!prs_uint32("unknown", ps, depth, &garbage)) /* cccccccc */
408                 return False;
409         if (!prs_uint32("bufferlen", ps, depth, &garbage))
410                 return False;
411         if (!prs_uint32("bufferlenhi", ps, depth, &garbage)) /* 00000000 */
412                 return False;
413
414         if(!net_io_user_info3("", &info->info3, ps, depth, 3, kerb_validation_info))
415                 return False;
416
417         if (info->info3.ptr_res_group_dom_sid) {
418                 if (!smb_io_dom_sid2("res_group_dom_sid", 
419                                      &info->res_group_dom_sid, ps, depth))
420                         return False;
421         }
422
423         if (info->info3.ptr_res_groups) {
424
425                 if (!(info->info3.user_flgs & LOGON_RESOURCE_GROUPS)) {
426                         DEBUG(0,("user_flgs attribute does not have LOGON_RESOURCE_GROUPS\n"));
427                         /* return False; */
428                 }
429
430                 if (!pac_io_group_membership_array("res group membership",
431                                                    &info->res_groups,
432                                                    info->info3.res_group_count,
433                                                    ps, depth))
434                         return False;
435         }
436
437         return True;
438 }
439
440
441
442 static BOOL pac_io_pac_signature_data(const char *desc, 
443                                       PAC_SIGNATURE_DATA *data, uint32 length,
444                                       prs_struct *ps, int depth)
445 {
446         uint32 siglen = length - sizeof(uint32);
447         prs_debug(ps, depth, desc, "pac_io_pac_signature_data");
448         depth++;
449         
450         if (data == NULL)
451                 return False;
452
453         if (!prs_align(ps))
454                 return False;
455         if (!prs_uint32("type", ps, depth, &data->type))
456                 return False;
457
458         if (UNMARSHALLING(ps) && length) {
459                 data->signature.buffer = PRS_ALLOC_MEM(ps, uint8, siglen);
460                 if (!data->signature.buffer) {
461                         DEBUG(3, ("No memory available\n"));
462                         return False;
463                 }
464         }
465
466         data->signature.buf_len = siglen;
467
468         if (!prs_uint8s(False, "signature", ps, depth, data->signature.buffer, data->signature.buf_len))
469                 return False;
470
471
472         return True;
473 }
474
475 static BOOL pac_io_pac_info_hdr_ctr(const char *desc, PAC_BUFFER *hdr,
476                                     prs_struct *ps, int depth)
477 {
478         if (NULL == hdr)
479                 return False;
480
481         prs_debug(ps, depth, desc, "pac_io_pac_info_hdr_ctr");
482         depth++;
483
484         if (!prs_align(ps))
485                 return False;
486
487         if (hdr->offset != prs_offset(ps)) {
488                 DEBUG(5,("offset in header(x%x) and data(x%x) do not match, correcting\n",
489                          hdr->offset, prs_offset(ps)));
490                 prs_set_offset(ps, hdr->offset);
491         }
492
493         if (UNMARSHALLING(ps) && hdr->size > 0) {
494                 hdr->ctr = PRS_ALLOC_MEM(ps, PAC_INFO_CTR, 1);
495                 if (!hdr->ctr) {
496                         DEBUG(3, ("No memory available\n"));
497                         return False;
498                 }
499         }
500
501         switch(hdr->type) {
502         case PAC_TYPE_LOGON_INFO:
503                 DEBUG(5, ("PAC_TYPE_LOGON_INFO\n"));
504                 if (UNMARSHALLING(ps))
505                         hdr->ctr->pac.logon_info = PRS_ALLOC_MEM(ps, PAC_LOGON_INFO, 1);
506                 if (!hdr->ctr->pac.logon_info) {
507                         DEBUG(3, ("No memory available\n"));
508                         return False;
509                 }
510                 if (!pac_io_pac_logon_info(desc, hdr->ctr->pac.logon_info,
511                                            ps, depth))
512                         return False;
513                 break;
514
515         case PAC_TYPE_SERVER_CHECKSUM:
516                 DEBUG(5, ("PAC_TYPE_SERVER_CHECKSUM\n"));
517                 if (UNMARSHALLING(ps))
518                         hdr->ctr->pac.srv_cksum = PRS_ALLOC_MEM(ps, PAC_SIGNATURE_DATA, 1);
519                 if (!hdr->ctr->pac.srv_cksum) {
520                         DEBUG(3, ("No memory available\n"));
521                         return False;
522                 }
523                 if (!pac_io_pac_signature_data(desc, hdr->ctr->pac.srv_cksum,
524                                                hdr->size, ps, depth))
525                         return False;
526                 break;
527
528         case PAC_TYPE_PRIVSVR_CHECKSUM:
529                 DEBUG(5, ("PAC_TYPE_PRIVSVR_CHECKSUM\n"));
530                 if (UNMARSHALLING(ps))
531                         hdr->ctr->pac.privsrv_cksum = PRS_ALLOC_MEM(ps, PAC_SIGNATURE_DATA, 1);
532                 if (!hdr->ctr->pac.privsrv_cksum) {
533                         DEBUG(3, ("No memory available\n"));
534                         return False;
535                 }
536                 if (!pac_io_pac_signature_data(desc, 
537                                                hdr->ctr->pac.privsrv_cksum,
538                                                hdr->size, ps, depth))
539                         return False;
540                 break;
541
542         case PAC_TYPE_LOGON_NAME:
543                 DEBUG(5, ("PAC_TYPE_LOGON_NAME\n"));
544                 if (UNMARSHALLING(ps))
545                         hdr->ctr->pac.logon_name = PRS_ALLOC_MEM(ps, PAC_LOGON_NAME, 1);
546                 if (!hdr->ctr->pac.logon_name) {
547                         DEBUG(3, ("No memory available\n"));
548                         return False;
549                 }
550                 if (!pac_io_logon_name(desc, hdr->ctr->pac.logon_name,
551                                             ps, depth))
552                         return False;
553                 break;
554
555         default:
556                 /* dont' know, so we need to skip it */
557                 DEBUG(3, ("unknown PAC type %d\n", hdr->type));
558                 prs_set_offset(ps, prs_offset(ps) + hdr->size);
559         }
560
561 #if 0
562         /* obscure pad */
563         if (!prs_uint32("pad", ps, depth, &hdr->pad))
564                 return False;
565 #endif
566         return True;
567 }
568
569 static BOOL pac_io_pac_info_hdr(const char *desc, PAC_BUFFER *hdr, 
570                                 prs_struct *ps, int depth)
571 {
572         if (NULL == hdr)
573                 return False;
574
575         prs_debug(ps, depth, desc, "pac_io_pac_info_hdr");
576         depth++;
577
578         if (!prs_align(ps))
579                 return False;
580         if (!prs_uint32("type", ps, depth, &hdr->type))
581                 return False;
582         if (!prs_uint32("size", ps, depth, &hdr->size))
583                 return False;
584         if (!prs_uint32("offset", ps, depth, &hdr->offset))
585                 return False;
586         if (!prs_uint32("offsethi", ps, depth, &hdr->offsethi))
587                 return False;
588
589         return True;
590 }
591
592 static BOOL pac_io_pac_data(const char *desc, PAC_DATA *data, 
593                             prs_struct *ps, int depth)
594 {
595         int i;
596
597         if (NULL == data)
598                 return False;
599
600         prs_debug(ps, depth, desc, "pac_io_pac_data");
601         depth++;
602
603         if (!prs_align(ps))
604                 return False;
605         if (!prs_uint32("num_buffers", ps, depth, &data->num_buffers))
606                 return False;
607         if (!prs_uint32("version", ps, depth, &data->version))
608                 return False;
609
610         if (UNMARSHALLING(ps) && data->num_buffers > 0) {
611                 if ((data->pac_buffer = PRS_ALLOC_MEM(ps, PAC_BUFFER, data->num_buffers)) == NULL) {
612                         return False;
613                 }
614         }
615
616         for (i=0; i<data->num_buffers; i++) {
617                 if (!pac_io_pac_info_hdr(desc, &data->pac_buffer[i], ps, 
618                                          depth))
619                         return False;
620         }
621
622         for (i=0; i<data->num_buffers; i++) {
623                 if (!pac_io_pac_info_hdr_ctr(desc, &data->pac_buffer[i],
624                                              ps, depth))
625                         return False;
626         }
627
628         return True;
629 }
630
631 static NTSTATUS check_pac_checksum(TALLOC_CTX *mem_ctx, 
632                                    DATA_BLOB pac_data,
633                                    PAC_SIGNATURE_DATA *sig,
634                                    krb5_context context,
635                                    krb5_keyblock *keyblock)
636 {
637         krb5_error_code ret;
638         krb5_checksum cksum;
639         krb5_keyusage usage = 0;
640
641         smb_krb5_checksum_from_pac_sig(&cksum, sig);
642
643 #ifdef HAVE_KRB5_KU_OTHER_CKSUM /* Heimdal */
644         usage = KRB5_KU_OTHER_CKSUM;
645 #elif defined(HAVE_KRB5_KEYUSAGE_APP_DATA_CKSUM) /* MIT */
646         usage = KRB5_KEYUSAGE_APP_DATA_CKSUM;
647 #else
648 #error UNKNOWN_KRB5_KEYUSAGE
649 #endif
650
651         ret = smb_krb5_verify_checksum(context, 
652                                        keyblock, 
653                                        usage, 
654                                        &cksum,
655                                        pac_data.data, 
656                                        pac_data.length);
657
658         if (ret) {
659                 DEBUG(2,("check_pac_checksum: PAC Verification failed: %s (%d)\n", 
660                         error_message(ret), ret));
661                 return NT_STATUS_ACCESS_DENIED;
662         }
663
664         return NT_STATUS_OK;
665 }
666
667 static NTSTATUS parse_pac_data(TALLOC_CTX *mem_ctx, DATA_BLOB *pac_data_blob, PAC_DATA *pac_data)
668 {
669         prs_struct ps;
670         PAC_DATA *my_pac;
671
672         if (!prs_init(&ps, pac_data_blob->length, mem_ctx, UNMARSHALL))
673                 return NT_STATUS_NO_MEMORY;
674
675         if (!prs_copy_data_in(&ps, (char *)pac_data_blob->data, pac_data_blob->length))
676                 return NT_STATUS_INVALID_PARAMETER;
677
678         prs_set_offset(&ps, 0);
679
680         my_pac = TALLOC_ZERO_P(mem_ctx, PAC_DATA);
681         if (!pac_io_pac_data("pac data", my_pac, &ps, 0))
682                 return NT_STATUS_INVALID_PARAMETER;
683
684         prs_mem_free(&ps);
685
686         *pac_data = *my_pac;
687
688         return NT_STATUS_OK;
689 }
690
691 /* just for debugging, will be removed later - Guenther */
692 char *pac_group_attr_string(uint32 attr)
693 {
694         fstring name = "";
695
696         if (!attr)
697                 return NULL;
698
699         if (attr & SE_GROUP_MANDATORY)                  fstrcat(name, "SE_GROUP_MANDATORY ");
700         if (attr & SE_GROUP_ENABLED_BY_DEFAULT)         fstrcat(name, "SE_GROUP_ENABLED_BY_DEFAULT ");
701         if (attr & SE_GROUP_ENABLED)                    fstrcat(name, "SE_GROUP_ENABLED ");
702         if (attr & SE_GROUP_OWNER)                      fstrcat(name, "SE_GROUP_OWNER ");
703         if (attr & SE_GROUP_USE_FOR_DENY_ONLY)          fstrcat(name, "SE_GROUP_USE_FOR_DENY_ONLY ");
704         if (attr & SE_GROUP_LOGON_ID)                   fstrcat(name, "SE_GROUP_LOGON_ID ");
705         if (attr & SE_GROUP_RESOURCE)                   fstrcat(name, "SE_GROUP_RESOURCE ");
706
707         return SMB_STRDUP(name);
708 }
709
710 /* just for debugging, will be removed later - Guenther */
711 static void dump_pac_logon_info(PAC_LOGON_INFO *logon_info) {
712
713         DOM_SID dom_sid, res_group_dom_sid;
714         int i;
715         char *attr_string;
716         uint32 user_flgs = logon_info->info3.user_flgs;
717
718         if (logon_info->info3.ptr_res_group_dom_sid) {
719                 sid_copy(&res_group_dom_sid, &logon_info->res_group_dom_sid.sid);
720         }
721         sid_copy(&dom_sid, &logon_info->info3.dom_sid.sid);
722         
723         DEBUG(10,("The PAC:\n"));
724         
725         DEBUGADD(10,("\tUser Flags: 0x%x (%d)\n", user_flgs, user_flgs));
726         if (user_flgs & LOGON_EXTRA_SIDS)
727                 DEBUGADD(10,("\tUser Flags: LOGON_EXTRA_SIDS 0x%x (%d)\n", LOGON_EXTRA_SIDS, LOGON_EXTRA_SIDS));
728         if (user_flgs & LOGON_RESOURCE_GROUPS)
729                 DEBUGADD(10,("\tUser Flags: LOGON_RESOURCE_GROUPS 0x%x (%d)\n", LOGON_RESOURCE_GROUPS, LOGON_RESOURCE_GROUPS));
730         DEBUGADD(10,("\tUser SID: %s-%d\n", sid_string_static(&dom_sid), logon_info->info3.user_rid));
731         DEBUGADD(10,("\tGroup SID: %s-%d\n", sid_string_static(&dom_sid), logon_info->info3.group_rid));
732
733         DEBUGADD(10,("\tGroup Membership (Global and Universal Groups of own domain):\n"));
734         for (i = 0; i < logon_info->info3.num_groups; i++) {
735                 attr_string = pac_group_attr_string(logon_info->info3.gids[i].attr);
736                 DEBUGADD(10,("\t\t%d: sid: %s-%d\n\t\t   attr: 0x%x == %s\n", 
737                         i, sid_string_static(&dom_sid), 
738                         logon_info->info3.gids[i].g_rid,
739                         logon_info->info3.gids[i].attr,
740                         attr_string));
741                 SAFE_FREE(attr_string);
742         }
743
744         DEBUGADD(10,("\tGroup Membership (Domain Local Groups and Groups from Trusted Domains):\n"));
745         for (i = 0; i < logon_info->info3.num_other_sids; i++) {
746                 attr_string = pac_group_attr_string(logon_info->info3.other_sids_attrib[i]);
747                 DEBUGADD(10,("\t\t%d: sid: %s\n\t\t   attr: 0x%x == %s\n", 
748                         i, sid_string_static(&logon_info->info3.other_sids[i].sid), 
749                         logon_info->info3.other_sids_attrib[i],
750                         attr_string));
751                 SAFE_FREE(attr_string);
752         }
753
754         DEBUGADD(10,("\tGroup Membership (Ressource Groups (SID History ?)):\n"));
755         for (i = 0; i < logon_info->info3.res_group_count; i++) {
756                 attr_string = pac_group_attr_string(logon_info->res_groups.group_membership[i].attrs);
757                 DEBUGADD(10,("\t\t%d: sid: %s-%d\n\t\t   attr: 0x%x == %s\n", 
758                         i, sid_string_static(&res_group_dom_sid),
759                         logon_info->res_groups.group_membership[i].rid,
760                         logon_info->res_groups.group_membership[i].attrs,
761                         attr_string));
762                 SAFE_FREE(attr_string);
763         }
764 }
765
766  NTSTATUS decode_pac_data(TALLOC_CTX *mem_ctx,
767                          DATA_BLOB *pac_data_blob,
768                          krb5_context context, 
769                          krb5_keyblock *service_keyblock,
770                          krb5_const_principal client_principal,
771                          time_t tgs_authtime,
772                          PAC_DATA **pac_data)
773                          
774 {
775         DATA_BLOB modified_pac_blob;
776         PAC_DATA *my_pac;
777         NTSTATUS nt_status;
778         krb5_error_code ret;
779         PAC_SIGNATURE_DATA *srv_sig = NULL;
780         PAC_SIGNATURE_DATA *kdc_sig = NULL;
781         PAC_LOGON_NAME *logon_name = NULL;
782         PAC_LOGON_INFO *logon_info = NULL;
783         krb5_principal client_principal_pac = NULL;
784         NTTIME tgs_authtime_nttime;
785         int i, srv_sig_pos = 0, kdc_sig_pos = 0;
786         fstring username;
787
788         *pac_data = NULL;
789
790         my_pac = talloc(mem_ctx, PAC_DATA);
791         if (!my_pac) {
792                 return NT_STATUS_NO_MEMORY;
793         }
794
795         nt_status = parse_pac_data(mem_ctx, pac_data_blob, my_pac);
796         if (!NT_STATUS_IS_OK(nt_status)) {
797                 DEBUG(0,("decode_pac_data: failed to parse PAC\n"));
798                 return nt_status;
799         }
800
801         modified_pac_blob = data_blob_talloc(mem_ctx, pac_data_blob->data, pac_data_blob->length);
802
803         if (my_pac->num_buffers < 4) {
804                 nt_status = NT_STATUS_INVALID_PARAMETER;
805                 goto out;
806         }
807
808         /* store signatures */
809         for (i=0; i < my_pac->num_buffers; i++) {
810         
811                 switch (my_pac->pac_buffer[i].type) {
812                 
813                         case PAC_TYPE_SERVER_CHECKSUM:
814                                 if (!my_pac->pac_buffer[i].ctr->pac.srv_cksum) {
815                                         break;
816                                 }
817                                 
818                                 srv_sig = my_pac->pac_buffer[i].ctr->pac.srv_cksum;
819                                 
820                                 /* get position of signature buffer */
821                                 srv_sig_pos = my_pac->pac_buffer[i].offset;
822                                 srv_sig_pos += sizeof(uint32);
823                                 
824                                 break;
825                                 
826                         case PAC_TYPE_PRIVSVR_CHECKSUM:
827                                 if (!my_pac->pac_buffer[i].ctr->pac.privsrv_cksum) {
828                                         break;
829                                 }
830
831                                 kdc_sig = my_pac->pac_buffer[i].ctr->pac.privsrv_cksum;
832                                 
833                                 /* get position of signature buffer */
834                                 kdc_sig_pos = my_pac->pac_buffer[i].offset;
835                                 kdc_sig_pos += sizeof(uint32);
836                                 
837                                 break;
838                                 
839                         case PAC_TYPE_LOGON_NAME:
840                                 if (!my_pac->pac_buffer[i].ctr->pac.logon_name) {
841                                         break;
842                                 }
843
844                                 logon_name = my_pac->pac_buffer[i].ctr->pac.logon_name;
845                                 break;
846
847                         case PAC_TYPE_LOGON_INFO:
848                                 if (!my_pac->pac_buffer[i].ctr->pac.logon_info) {
849                                         break;
850                                 }
851
852                                 logon_info = my_pac->pac_buffer[i].ctr->pac.logon_info;
853                                 break;
854                         }
855
856         }
857
858         if (!srv_sig || !kdc_sig || !logon_name || !logon_info) {
859                 nt_status = NT_STATUS_INVALID_PARAMETER;
860                 goto out;
861         }
862
863         /* zero PAC_SIGNATURE_DATA signature buffer */
864         memset(&modified_pac_blob.data[srv_sig_pos], '\0', srv_sig->signature.buf_len);
865         memset(&modified_pac_blob.data[kdc_sig_pos], '\0', kdc_sig->signature.buf_len);
866
867         /* check server signature */
868         nt_status = check_pac_checksum(mem_ctx, modified_pac_blob, srv_sig, context, service_keyblock);
869         if (!NT_STATUS_IS_OK(nt_status)) {
870                 DEBUG(0,("decode_pac_data: failed to verify PAC server signature\n"));
871                 goto out;
872         }
873
874         /* Convert to NT time, so as not to loose accuracy in comparison */
875         unix_to_nt_time(&tgs_authtime_nttime, tgs_authtime);
876
877         if (!nt_time_equals(&tgs_authtime_nttime, &logon_name->logon_time)) {
878         
879                 DEBUG(2,("decode_pac_data: Logon time mismatch between ticket and PAC!\n"));
880                 DEBUGADD(2, ("decode_pac_data: PAC: %s\n", 
881                         http_timestring(nt_time_to_unix(&logon_name->logon_time))));
882                 DEBUGADD(2, ("decode_pac_data: Ticket: %s\n", 
883                         http_timestring(nt_time_to_unix(&tgs_authtime_nttime))));
884                 
885                 nt_status = NT_STATUS_ACCESS_DENIED;
886                 goto out;
887         }
888
889         if (!logon_name->len) {
890                 DEBUG(2,("decode_pac_data: No Logon Name available\n"));
891                 nt_status = NT_STATUS_INVALID_PARAMETER;
892                 goto out;
893         }
894         rpcstr_pull(username, logon_name->username, sizeof(username), -1, STR_TERMINATE);
895
896         ret = smb_krb5_parse_name_norealm(context, username, &client_principal_pac);
897         if (ret) {
898                 DEBUG(2,("decode_pac_data: Could not parse name from incoming PAC: [%s]: %s\n", 
899                         username, error_message(ret)));
900                 nt_status = NT_STATUS_INVALID_PARAMETER;
901                 goto out;
902         }
903
904         if (!smb_krb5_principal_compare_any_realm(context, client_principal, client_principal_pac)) {
905                 DEBUG(2,("decode_pac_data: Name in PAC [%s] does not match principal name in ticket\n", 
906                         username));
907                 nt_status = NT_STATUS_ACCESS_DENIED;
908                 goto out;
909         }
910
911         DEBUG(10,("Successfully validated Kerberos PAC\n"));
912
913         dump_pac_logon_info(logon_info);
914
915         *pac_data = my_pac;
916
917         nt_status = NT_STATUS_OK;
918
919 out:
920         if (client_principal_pac) {
921                 krb5_free_principal(context, client_principal_pac);
922         }
923
924         return nt_status;
925 }
926
927  PAC_LOGON_INFO *get_logon_info_from_pac(PAC_DATA *pac_data) 
928 {
929         PAC_LOGON_INFO *logon_info = NULL;
930         int i;
931         
932         for (i=0; i < pac_data->num_buffers; i++) {
933
934                 if (pac_data->pac_buffer[i].type != PAC_TYPE_LOGON_INFO)
935                         continue;
936
937                 logon_info = pac_data->pac_buffer[i].ctr->pac.logon_info;
938                 break;
939         }
940         return logon_info;
941 }
942
943 #endif