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