Coverity 512, uninitialized var.
[ab/samba.git/.git] / source3 / 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,2007
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    You should have received a copy of the GNU General Public License
22    along with this program.  If not, see <http://www.gnu.org/licenses/>.
23 */
24
25 #include "includes.h"
26
27 #ifdef HAVE_KRB5
28
29 static bool pac_io_logon_name(const char *desc, PAC_LOGON_NAME *logon_name,
30                               prs_struct *ps, int depth)
31 {
32         if (NULL == logon_name)
33                 return False;
34
35         prs_debug(ps, depth, desc, "pac_io_logon_name");
36         depth++;
37
38         if (!smb_io_time("logon_time", &logon_name->logon_time, ps, depth))
39                 return False;
40
41         if (!prs_uint16("len", ps, depth, &logon_name->len))
42                 return False;
43
44         /* The following string is always in little endian 16 bit values,
45            copy as 8 bits to avoid endian reversal on big-endian machines.
46            len is the length in bytes. */
47
48         if (UNMARSHALLING(ps) && logon_name->len) {
49                 logon_name->username = PRS_ALLOC_MEM(ps, uint8, logon_name->len);
50                 if (!logon_name->username) {
51                         DEBUG(3, ("No memory available\n"));
52                         return False;
53                 }
54         }
55
56         if (!prs_uint8s(True, "name", ps, depth, logon_name->username, logon_name->len))
57                 return False;
58
59         return True;
60 }
61
62 #if 0 /* Unused (handled now in net_io_user_info3()) - Guenther */
63 static bool pac_io_krb_sids(const char *desc, KRB_SID_AND_ATTRS *sid_and_attr,
64                             prs_struct *ps, int depth)
65 {
66         if (NULL == sid_and_attr)
67                 return False;
68
69         prs_debug(ps, depth, desc, "pac_io_krb_sids");
70         depth++;
71
72         if (UNMARSHALLING(ps)) {
73                 sid_and_attr->sid = PRS_ALLOC_MEM(ps, DOM_SID2, 1);
74                 if (!sid_and_attr->sid) {
75                         DEBUG(3, ("No memory available\n"));
76                         return False;
77                 }
78         }
79
80         if(!smb_io_dom_sid2("sid", sid_and_attr->sid, ps, depth))
81                 return False;
82
83         return True;
84 }
85
86
87 static bool pac_io_krb_attrs(const char *desc, KRB_SID_AND_ATTRS *sid_and_attr,
88                              prs_struct *ps, int depth)
89 {
90         if (NULL == sid_and_attr)
91                 return False;
92
93         prs_debug(ps, depth, desc, "pac_io_krb_attrs");
94         depth++;
95
96         if (!prs_uint32("sid_ptr", ps, depth, &sid_and_attr->sid_ptr))
97                 return False;
98         if (!prs_uint32("attrs", ps, depth, &sid_and_attr->attrs))
99                 return False;
100
101         return True;
102 }
103
104 static bool pac_io_krb_sid_and_attr_array(const char *desc, 
105                                           KRB_SID_AND_ATTR_ARRAY *array,
106                                           uint32 num,
107                                           prs_struct *ps, int depth)
108 {
109         int i;
110
111         if (NULL == array)
112                 return False;
113
114         prs_debug(ps, depth, desc, "pac_io_krb_sid_and_attr_array");
115         depth++;
116
117
118         if (!prs_uint32("count", ps, depth, &array->count))
119                 return False;
120
121         if (UNMARSHALLING(ps)) {
122                 if (num) {
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                 } else {
129                         array->krb_sid_and_attrs = NULL;
130                 }
131         }
132
133         for (i=0; i<num; i++) {
134                 if (!pac_io_krb_attrs(desc, 
135                                       &array->krb_sid_and_attrs[i],
136                                       ps, depth))
137                         return False;
138
139         }
140         for (i=0; i<num; i++) {
141                 if (!pac_io_krb_sids(desc, 
142                                      &array->krb_sid_and_attrs[i],
143                                      ps, depth))
144                         return False;
145
146         }
147
148         return True;
149
150 }
151 #endif
152
153 static bool pac_io_group_membership(const char *desc, 
154                                     GROUP_MEMBERSHIP *membership,
155                                     prs_struct *ps, int depth)
156 {
157         if (NULL == membership)
158                 return False;
159
160         prs_debug(ps, depth, desc, "pac_io_group_membership");
161         depth++;
162
163         if (!prs_uint32("rid", ps, depth, &membership->rid))
164                 return False;
165         if (!prs_uint32("attrs", ps, depth, &membership->attrs))
166                 return False;
167
168         return True;
169 }
170
171
172 static bool pac_io_group_membership_array(const char *desc, 
173                                           GROUP_MEMBERSHIP_ARRAY *array,
174                                           uint32 num,
175                                           prs_struct *ps, int depth)
176 {
177         int i;
178
179         if (NULL == array)
180                 return False;
181
182         prs_debug(ps, depth, desc, "pac_io_group_membership_array");
183         depth++;
184
185
186         if (!prs_uint32("count", ps, depth, &array->count))
187                 return False;
188
189         if (UNMARSHALLING(ps)) {
190                 if (num) {
191                         array->group_membership = PRS_ALLOC_MEM(ps, GROUP_MEMBERSHIP, num);
192                         if (!array->group_membership) {
193                                 DEBUG(3, ("No memory available\n"));
194                                 return False;
195                         }
196                 } else {
197                         array->group_membership = NULL;
198                 }
199         }
200
201         for (i=0; i<num; i++) {
202                 if (!pac_io_group_membership(desc, 
203                                              &array->group_membership[i],
204                                              ps, depth))
205                         return False;
206
207         }
208
209         return True;
210
211 }
212
213 #if 0 /* Unused, replaced using an expanded net_io_user_info3() now - Guenther */
214 static bool pac_io_pac_logon_info(const char *desc, PAC_LOGON_INFO *info, 
215                                   prs_struct *ps, int depth)
216 {
217         uint32 garbage = 0, i;
218
219         if (NULL == info)
220                 return False;
221
222         prs_debug(ps, depth, desc, "pac_io_pac_logon_info");
223         depth++;
224
225         if (!prs_align(ps))
226                 return False;
227         if (!prs_uint32("unknown", ps, depth, &garbage)) /* 00081001 */
228                 return False;
229         if (!prs_uint32("unknown", ps, depth, &garbage)) /* cccccccc */
230                 return False;
231         if (!prs_uint32("bufferlen", ps, depth, &garbage))
232                 return False;
233         if (!prs_uint32("bufferlenhi", ps, depth, &garbage)) /* 00000000 */
234                 return False;
235
236         if (!prs_uint32("pointer", ps, depth, &garbage))
237                 return False;
238
239         if (!prs_align(ps))
240                 return False;
241         if (!smb_io_time("logon_time", &info->logon_time, ps, depth))
242                 return False;
243         if (!smb_io_time("logoff_time", &info->logoff_time, ps, depth))
244                 return False;
245         if (!smb_io_time("kickoff_time", &info->kickoff_time, ps, depth))
246                 return False;
247         if (!smb_io_time("pass_last_set_time", &info->pass_last_set_time, 
248                          ps, depth))
249                 return False;
250         if (!smb_io_time("pass_can_change_time", &info->pass_can_change_time, 
251                          ps, depth))
252                 return False;
253         if (!smb_io_time("pass_must_change_time", &info->pass_must_change_time,
254                          ps, depth))
255                 return False;
256
257         if (!smb_io_unihdr("hdr_user_name", &info->hdr_user_name, ps, depth))
258                 return False;
259         if (!smb_io_unihdr("hdr_full_name", &info->hdr_full_name, ps, depth))
260                 return False;
261         if (!smb_io_unihdr("hdr_logon_script", &info->hdr_logon_script, 
262                            ps, depth))
263                 return False;
264         if (!smb_io_unihdr("hdr_profile_path", &info->hdr_profile_path, 
265                            ps, depth))
266                 return False;
267         if (!smb_io_unihdr("hdr_home_dir", &info->hdr_home_dir, ps, depth))
268                 return False;
269         if (!smb_io_unihdr("hdr_dir_drive", &info->hdr_dir_drive, ps, depth))
270                 return False;
271
272         if (!prs_uint16("logon_count", ps, depth, &info->logon_count))
273                 return False;
274         if (!prs_uint16("bad_password_count", ps, depth, &info->bad_password_count))
275                 return False;
276         if (!prs_uint32("user_rid", ps, depth, &info->user_rid))
277                 return False;
278         if (!prs_uint32("group_rid", ps, depth, &info->group_rid))
279                 return False;
280         if (!prs_uint32("group_count", ps, depth, &info->group_count))
281                 return False;
282         /* I haven't seen this contain anything yet, but when it does
283            we will have to make sure we decode the contents in the middle
284            all the unistr2s ... */
285         if (!prs_uint32("group_mem_ptr", ps, depth, 
286                         &info->group_membership_ptr))
287                 return False;
288         if (!prs_uint32("user_flags", ps, depth, &info->user_flags))
289                 return False;
290
291         if (!prs_uint8s(False, "session_key", ps, depth, info->session_key, 16)) 
292                 return False;
293         
294         if (!smb_io_unihdr("hdr_dom_controller", 
295                            &info->hdr_dom_controller, ps, depth))
296                 return False;
297         if (!smb_io_unihdr("hdr_dom_name", &info->hdr_dom_name, ps, depth))
298                 return False;
299
300         /* this should be followed, but just get ptr for now */
301         if (!prs_uint32("ptr_dom_sid", ps, depth, &info->ptr_dom_sid))
302                 return False;
303
304         if (!prs_uint8s(False, "lm_session_key", ps, depth, info->lm_session_key, 8)) 
305                 return False;
306
307         if (!prs_uint32("acct_flags", ps, depth, &info->acct_flags))
308                 return False;
309
310         for (i = 0; i < 7; i++)
311         {
312                 if (!prs_uint32("unkown", ps, depth, &info->unknown[i])) /* unknown */
313                         return False;
314         }
315
316         if (!prs_uint32("sid_count", ps, depth, &info->sid_count))
317                 return False;
318         if (!prs_uint32("ptr_extra_sids", ps, depth, &info->ptr_extra_sids))
319                 return False;
320         if (!prs_uint32("ptr_res_group_dom_sid", ps, depth, 
321                         &info->ptr_res_group_dom_sid))
322                 return False;
323         if (!prs_uint32("res_group_count", ps, depth, &info->res_group_count))
324                 return False;
325         if (!prs_uint32("ptr_res_groups", ps, depth, &info->ptr_res_groups))
326                 return False;
327
328         if(!smb_io_unistr2("uni_user_name", &info->uni_user_name, 
329                            info->hdr_user_name.buffer, ps, depth))
330                 return False;
331         if(!smb_io_unistr2("uni_full_name", &info->uni_full_name, 
332                            info->hdr_full_name.buffer, ps, depth))
333                 return False;
334         if(!smb_io_unistr2("uni_logon_script", &info->uni_logon_script, 
335                            info->hdr_logon_script.buffer, ps, depth))
336                 return False;
337         if(!smb_io_unistr2("uni_profile_path", &info->uni_profile_path,
338                            info->hdr_profile_path.buffer, ps, depth))
339                 return False;
340         if(!smb_io_unistr2("uni_home_dir", &info->uni_home_dir,
341                            info->hdr_home_dir.buffer, ps, depth))
342                 return False;
343         if(!smb_io_unistr2("uni_dir_drive", &info->uni_dir_drive,
344                            info->hdr_dir_drive.buffer, ps, depth))
345                 return False;
346
347         if (info->group_membership_ptr) {
348                 if (!pac_io_group_membership_array("group membership",
349                                                    &info->groups,
350                                                    info->group_count,
351                                                    ps, depth))
352                         return False;
353         }
354
355
356         if(!smb_io_unistr2("uni_dom_controller", &info->uni_dom_controller,
357                            info->hdr_dom_controller.buffer, ps, depth))
358                 return False;
359         if(!smb_io_unistr2("uni_dom_name", &info->uni_dom_name, 
360                            info->hdr_dom_name.buffer, ps, depth))
361                 return False;
362
363         if(info->ptr_dom_sid)
364                 if(!smb_io_dom_sid2("dom_sid", &info->dom_sid, ps, depth))
365                         return False;
366
367         
368         if (info->sid_count && info->ptr_extra_sids)
369                 if (!pac_io_krb_sid_and_attr_array("extra_sids", 
370                                                    &info->extra_sids,
371                                                    info->sid_count,
372                                                    ps, depth))
373                         return False;
374
375         if (info->ptr_res_group_dom_sid)
376                 if (!smb_io_dom_sid2("res_group_dom_sid", 
377                                      &info->res_group_dom_sid, ps, depth))
378                         return False;
379
380         if (info->ptr_res_groups) {
381
382                 if (!(info->user_flgs & LOGON_RESOURCE_GROUPS)) {
383                         DEBUG(0,("user_flgs attribute does not have LOGON_RESOURCE_GROUPS\n"));
384                         /* return False; */
385                 }
386
387                 if (!pac_io_group_membership_array("res group membership",
388                                                    &info->res_groups,
389                                                    info->res_group_count,
390                                                    ps, depth))
391                         return False;
392         }
393
394         return True;
395 }
396 #endif
397
398 static bool pac_io_pac_logon_info(const char *desc, PAC_LOGON_INFO *info, 
399                                   prs_struct *ps, int depth)
400 {
401         uint32 garbage = 0;
402         bool kerb_validation_info = True;
403
404         if (NULL == info)
405                 return False;
406
407         prs_debug(ps, depth, desc, "pac_io_pac_logon_info");
408         depth++;
409
410         if (!prs_align(ps))
411                 return False;
412         if (!prs_uint32("unknown", ps, depth, &garbage)) /* 00081001 */
413                 return False;
414         if (!prs_uint32("unknown", ps, depth, &garbage)) /* cccccccc */
415                 return False;
416         if (!prs_uint32("bufferlen", ps, depth, &garbage))
417                 return False;
418         if (!prs_uint32("bufferlenhi", ps, depth, &garbage)) /* 00000000 */
419                 return False;
420
421         if(!net_io_user_info3("", &info->info3, ps, depth, 3, kerb_validation_info))
422                 return False;
423
424         if (info->info3.ptr_res_group_dom_sid) {
425                 if (!smb_io_dom_sid2("res_group_dom_sid", 
426                                      &info->res_group_dom_sid, ps, depth))
427                         return False;
428         }
429
430         if (info->info3.ptr_res_groups) {
431
432                 if (!(info->info3.user_flgs & LOGON_RESOURCE_GROUPS)) {
433                         DEBUG(0,("user_flgs attribute does not have LOGON_RESOURCE_GROUPS\n"));
434                         /* return False; */
435                 }
436
437                 if (!pac_io_group_membership_array("res group membership",
438                                                    &info->res_groups,
439                                                    info->info3.res_group_count,
440                                                    ps, depth))
441                         return False;
442         }
443
444         return True;
445 }
446
447
448
449 static bool pac_io_pac_signature_data(const char *desc, 
450                                       PAC_SIGNATURE_DATA *data, uint32 length,
451                                       prs_struct *ps, int depth)
452 {
453         uint32 siglen = 0;
454
455         prs_debug(ps, depth, desc, "pac_io_pac_signature_data");
456         depth++;
457
458         if (data == NULL)
459                 return False;
460
461         if (!prs_align(ps))
462                 return False;
463         if (!prs_uint32("type", ps, depth, &data->type))
464                 return False;
465
466         if ( length > sizeof(uint32) )
467                 siglen = length - sizeof(uint32);       
468
469         if (UNMARSHALLING(ps) && length) {
470                 if (siglen) {
471                         data->signature.buffer = PRS_ALLOC_MEM(ps, uint8, siglen);
472                         if (!data->signature.buffer) {
473                                 DEBUG(3, ("No memory available\n"));
474                                 return False;
475                         }
476                 } else {
477                         data->signature.buffer = NULL;
478                 }
479         }
480
481         data->signature.buf_len = siglen;
482
483         if (!prs_uint8s(False, "signature", ps, depth, data->signature.buffer, data->signature.buf_len))
484                 return False;
485
486
487         return True;
488 }
489
490 static bool pac_io_pac_info_hdr_ctr(const char *desc, PAC_BUFFER *hdr,
491                                     prs_struct *ps, int depth)
492 {
493         if (NULL == hdr)
494                 return False;
495
496         prs_debug(ps, depth, desc, "pac_io_pac_info_hdr_ctr");
497         depth++;
498
499         if (!prs_align(ps))
500                 return False;
501
502         if (hdr->offset != prs_offset(ps)) {
503                 DEBUG(5,("offset in header(x%x) and data(x%x) do not match, correcting\n",
504                          hdr->offset, prs_offset(ps)));
505                 prs_set_offset(ps, hdr->offset);
506         }
507
508         if (UNMARSHALLING(ps) && hdr->size > 0) {
509                 hdr->ctr = PRS_ALLOC_MEM(ps, PAC_INFO_CTR, 1);
510                 if (!hdr->ctr) {
511                         DEBUG(3, ("No memory available\n"));
512                         return False;
513                 }
514         }
515
516         switch(hdr->type) {
517         case PAC_TYPE_LOGON_INFO:
518                 DEBUG(5, ("PAC_TYPE_LOGON_INFO\n"));
519                 if (UNMARSHALLING(ps))
520                         hdr->ctr->pac.logon_info = PRS_ALLOC_MEM(ps, PAC_LOGON_INFO, 1);
521                 if (!hdr->ctr->pac.logon_info) {
522                         DEBUG(3, ("No memory available\n"));
523                         return False;
524                 }
525                 if (!pac_io_pac_logon_info(desc, hdr->ctr->pac.logon_info,
526                                            ps, depth))
527                         return False;
528                 break;
529
530         case PAC_TYPE_SERVER_CHECKSUM:
531                 DEBUG(5, ("PAC_TYPE_SERVER_CHECKSUM\n"));
532                 if (UNMARSHALLING(ps))
533                         hdr->ctr->pac.srv_cksum = PRS_ALLOC_MEM(ps, PAC_SIGNATURE_DATA, 1);
534                 if (!hdr->ctr->pac.srv_cksum) {
535                         DEBUG(3, ("No memory available\n"));
536                         return False;
537                 }
538                 if (!pac_io_pac_signature_data(desc, hdr->ctr->pac.srv_cksum,
539                                                hdr->size, ps, depth))
540                         return False;
541                 break;
542
543         case PAC_TYPE_PRIVSVR_CHECKSUM:
544                 DEBUG(5, ("PAC_TYPE_PRIVSVR_CHECKSUM\n"));
545                 if (UNMARSHALLING(ps))
546                         hdr->ctr->pac.privsrv_cksum = PRS_ALLOC_MEM(ps, PAC_SIGNATURE_DATA, 1);
547                 if (!hdr->ctr->pac.privsrv_cksum) {
548                         DEBUG(3, ("No memory available\n"));
549                         return False;
550                 }
551                 if (!pac_io_pac_signature_data(desc, 
552                                                hdr->ctr->pac.privsrv_cksum,
553                                                hdr->size, ps, depth))
554                         return False;
555                 break;
556
557         case PAC_TYPE_LOGON_NAME:
558                 DEBUG(5, ("PAC_TYPE_LOGON_NAME\n"));
559                 if (UNMARSHALLING(ps))
560                         hdr->ctr->pac.logon_name = PRS_ALLOC_MEM(ps, PAC_LOGON_NAME, 1);
561                 if (!hdr->ctr->pac.logon_name) {
562                         DEBUG(3, ("No memory available\n"));
563                         return False;
564                 }
565                 if (!pac_io_logon_name(desc, hdr->ctr->pac.logon_name,
566                                             ps, depth))
567                         return False;
568                 break;
569
570         default:
571                 /* dont' know, so we need to skip it */
572                 DEBUG(3, ("unknown PAC type %d\n", hdr->type));
573                 prs_set_offset(ps, prs_offset(ps) + hdr->size);
574         }
575
576 #if 0
577         /* obscure pad */
578         if (!prs_uint32("pad", ps, depth, &hdr->pad))
579                 return False;
580 #endif
581         return True;
582 }
583
584 static bool pac_io_pac_info_hdr(const char *desc, PAC_BUFFER *hdr, 
585                                 prs_struct *ps, int depth)
586 {
587         if (NULL == hdr)
588                 return False;
589
590         prs_debug(ps, depth, desc, "pac_io_pac_info_hdr");
591         depth++;
592
593         if (!prs_align(ps))
594                 return False;
595         if (!prs_uint32("type", ps, depth, &hdr->type))
596                 return False;
597         if (!prs_uint32("size", ps, depth, &hdr->size))
598                 return False;
599         if (!prs_uint32("offset", ps, depth, &hdr->offset))
600                 return False;
601         if (!prs_uint32("offsethi", ps, depth, &hdr->offsethi))
602                 return False;
603
604         return True;
605 }
606
607 static bool pac_io_pac_data(const char *desc, PAC_DATA *data, 
608                             prs_struct *ps, int depth)
609 {
610         int i;
611
612         if (NULL == data)
613                 return False;
614
615         prs_debug(ps, depth, desc, "pac_io_pac_data");
616         depth++;
617
618         if (!prs_align(ps))
619                 return False;
620         if (!prs_uint32("num_buffers", ps, depth, &data->num_buffers))
621                 return False;
622         if (!prs_uint32("version", ps, depth, &data->version))
623                 return False;
624
625         if (UNMARSHALLING(ps) && data->num_buffers > 0) {
626                 if ((data->pac_buffer = PRS_ALLOC_MEM(ps, PAC_BUFFER, data->num_buffers)) == NULL) {
627                         return False;
628                 }
629         }
630
631         for (i=0; i<data->num_buffers; i++) {
632                 if (!pac_io_pac_info_hdr(desc, &data->pac_buffer[i], ps, 
633                                          depth))
634                         return False;
635         }
636
637         for (i=0; i<data->num_buffers; i++) {
638                 if (!pac_io_pac_info_hdr_ctr(desc, &data->pac_buffer[i],
639                                              ps, depth))
640                         return False;
641         }
642
643         return True;
644 }
645
646 static NTSTATUS check_pac_checksum(TALLOC_CTX *mem_ctx, 
647                                    DATA_BLOB pac_data,
648                                    PAC_SIGNATURE_DATA *sig,
649                                    krb5_context context,
650                                    krb5_keyblock *keyblock)
651 {
652         krb5_error_code ret;
653         krb5_checksum cksum;
654         krb5_keyusage usage = 0;
655
656         smb_krb5_checksum_from_pac_sig(&cksum, sig);
657
658 #ifdef HAVE_KRB5_KU_OTHER_CKSUM /* Heimdal */
659         usage = KRB5_KU_OTHER_CKSUM;
660 #elif defined(HAVE_KRB5_KEYUSAGE_APP_DATA_CKSUM) /* MIT */
661         usage = KRB5_KEYUSAGE_APP_DATA_CKSUM;
662 #else
663 #error UNKNOWN_KRB5_KEYUSAGE
664 #endif
665
666         ret = smb_krb5_verify_checksum(context, 
667                                        keyblock, 
668                                        usage, 
669                                        &cksum,
670                                        pac_data.data, 
671                                        pac_data.length);
672
673         if (ret) {
674                 DEBUG(2,("check_pac_checksum: PAC Verification failed: %s (%d)\n", 
675                         error_message(ret), ret));
676                 return NT_STATUS_ACCESS_DENIED;
677         }
678
679         return NT_STATUS_OK;
680 }
681
682 static NTSTATUS parse_pac_data(TALLOC_CTX *mem_ctx, DATA_BLOB *pac_data_blob, PAC_DATA *pac_data)
683 {
684         prs_struct ps;
685         PAC_DATA *my_pac;
686
687         if (!prs_init(&ps, pac_data_blob->length, mem_ctx, UNMARSHALL))
688                 return NT_STATUS_NO_MEMORY;
689
690         if (!prs_copy_data_in(&ps, (char *)pac_data_blob->data, pac_data_blob->length))
691                 return NT_STATUS_INVALID_PARAMETER;
692
693         prs_set_offset(&ps, 0);
694
695         my_pac = TALLOC_ZERO_P(mem_ctx, PAC_DATA);
696         if (!pac_io_pac_data("pac data", my_pac, &ps, 0))
697                 return NT_STATUS_INVALID_PARAMETER;
698
699         prs_mem_free(&ps);
700
701         *pac_data = *my_pac;
702
703         return NT_STATUS_OK;
704 }
705
706 /* just for debugging, will be removed later - Guenther */
707 char *pac_group_attr_string(uint32 attr)
708 {
709         fstring name = "";
710
711         if (!attr)
712                 return NULL;
713
714         if (attr & SE_GROUP_MANDATORY)                  fstrcat(name, "SE_GROUP_MANDATORY ");
715         if (attr & SE_GROUP_ENABLED_BY_DEFAULT)         fstrcat(name, "SE_GROUP_ENABLED_BY_DEFAULT ");
716         if (attr & SE_GROUP_ENABLED)                    fstrcat(name, "SE_GROUP_ENABLED ");
717         if (attr & SE_GROUP_OWNER)                      fstrcat(name, "SE_GROUP_OWNER ");
718         if (attr & SE_GROUP_USE_FOR_DENY_ONLY)          fstrcat(name, "SE_GROUP_USE_FOR_DENY_ONLY ");
719         if (attr & SE_GROUP_LOGON_ID)                   fstrcat(name, "SE_GROUP_LOGON_ID ");
720         if (attr & SE_GROUP_RESOURCE)                   fstrcat(name, "SE_GROUP_RESOURCE ");
721
722         return SMB_STRDUP(name);
723 }
724
725 /* just for debugging, will be removed later - Guenther */
726 void dump_pac_logon_info(int lvl, PAC_LOGON_INFO *logon_info)
727 {
728         DOM_SID dom_sid, res_group_dom_sid;
729         int i;
730         char *attr_string;
731         uint32 user_flgs = logon_info->info3.user_flgs;
732
733         if (logon_info->info3.ptr_res_group_dom_sid) {
734                 sid_copy(&res_group_dom_sid, &logon_info->res_group_dom_sid.sid);
735         }
736         sid_copy(&dom_sid, &logon_info->info3.dom_sid.sid);
737
738         DEBUG(lvl,("The PAC:\n"));
739
740         DEBUGADD(lvl,("\tUser Flags: 0x%x (%d)\n", user_flgs, user_flgs));
741         if (user_flgs & LOGON_EXTRA_SIDS)
742                 DEBUGADD(lvl,("\tUser Flags: LOGON_EXTRA_SIDS 0x%x (%d)\n", LOGON_EXTRA_SIDS, LOGON_EXTRA_SIDS));
743         if (user_flgs & LOGON_RESOURCE_GROUPS)
744                 DEBUGADD(lvl,("\tUser Flags: LOGON_RESOURCE_GROUPS 0x%x (%d)\n", LOGON_RESOURCE_GROUPS, LOGON_RESOURCE_GROUPS));
745         DEBUGADD(lvl,("\tUser SID: %s-%d\n", sid_string_dbg(&dom_sid),
746                       logon_info->info3.user_rid));
747         DEBUGADD(lvl,("\tGroup SID: %s-%d\n", sid_string_dbg(&dom_sid),
748                       logon_info->info3.group_rid));
749
750         DEBUGADD(lvl,("\tGroup Membership (Global and Universal Groups of own domain):\n"));
751         for (i = 0; i < logon_info->info3.num_groups; i++) {
752                 attr_string = pac_group_attr_string(logon_info->info3.gids[i].attr);
753                 DEBUGADD(lvl,("\t\t%d: sid: %s-%d\n\t\t   attr: 0x%x == %s\n",
754                         i, sid_string_dbg(&dom_sid),
755                         logon_info->info3.gids[i].g_rid,
756                         logon_info->info3.gids[i].attr,
757                         attr_string));
758                 SAFE_FREE(attr_string);
759         }
760
761         DEBUGADD(lvl,("\tGroup Membership (Domain Local Groups and Groups from Trusted Domains):\n"));
762         for (i = 0; i < logon_info->info3.num_other_sids; i++) {
763                 attr_string = pac_group_attr_string(logon_info->info3.other_sids_attrib[i]);
764                 DEBUGADD(lvl,("\t\t%d: sid: %s\n\t\t   attr: 0x%x == %s\n",
765                         i, sid_string_dbg(
766                                 &logon_info->info3.other_sids[i].sid),
767                         logon_info->info3.other_sids_attrib[i],
768                         attr_string));
769                 SAFE_FREE(attr_string);
770         }
771
772         DEBUGADD(lvl,("\tGroup Membership (Resource Groups (SID History ?)):\n"));
773         for (i = 0; i < logon_info->info3.res_group_count; i++) {
774                 attr_string = pac_group_attr_string(logon_info->res_groups.group_membership[i].attrs);
775                 DEBUGADD(lvl,("\t\t%d: sid: %s-%d\n\t\t   attr: 0x%x == %s\n",
776                         i, sid_string_dbg(&res_group_dom_sid),
777                         logon_info->res_groups.group_membership[i].rid,
778                         logon_info->res_groups.group_membership[i].attrs,
779                         attr_string));
780                 SAFE_FREE(attr_string);
781         }
782 }
783
784  NTSTATUS decode_pac_data(TALLOC_CTX *mem_ctx,
785                          DATA_BLOB *pac_data_blob,
786                          krb5_context context, 
787                          krb5_keyblock *service_keyblock,
788                          krb5_const_principal client_principal,
789                          time_t tgs_authtime,
790                          PAC_DATA **pac_data)
791                          
792 {
793         DATA_BLOB modified_pac_blob;
794         PAC_DATA *my_pac;
795         NTSTATUS nt_status;
796         krb5_error_code ret;
797         PAC_SIGNATURE_DATA *srv_sig = NULL;
798         PAC_SIGNATURE_DATA *kdc_sig = NULL;
799         PAC_LOGON_NAME *logon_name = NULL;
800         PAC_LOGON_INFO *logon_info = NULL;
801         krb5_principal client_principal_pac = NULL;
802         NTTIME tgs_authtime_nttime;
803         int i, srv_sig_pos = 0, kdc_sig_pos = 0;
804         fstring username;
805
806         *pac_data = NULL;
807
808         my_pac = talloc(mem_ctx, PAC_DATA);
809         if (!my_pac) {
810                 return NT_STATUS_NO_MEMORY;
811         }
812
813         nt_status = parse_pac_data(mem_ctx, pac_data_blob, my_pac);
814         if (!NT_STATUS_IS_OK(nt_status)) {
815                 DEBUG(0,("decode_pac_data: failed to parse PAC\n"));
816                 return nt_status;
817         }
818
819         modified_pac_blob = data_blob_talloc(mem_ctx, pac_data_blob->data, pac_data_blob->length);
820
821         if (my_pac->num_buffers < 4) {
822                 nt_status = NT_STATUS_INVALID_PARAMETER;
823                 goto out;
824         }
825
826         /* store signatures */
827         for (i=0; i < my_pac->num_buffers; i++) {
828         
829                 switch (my_pac->pac_buffer[i].type) {
830                 
831                         case PAC_TYPE_SERVER_CHECKSUM:
832                                 if (!my_pac->pac_buffer[i].ctr->pac.srv_cksum) {
833                                         break;
834                                 }
835                                 
836                                 srv_sig = my_pac->pac_buffer[i].ctr->pac.srv_cksum;
837                                 
838                                 /* get position of signature buffer */
839                                 srv_sig_pos = my_pac->pac_buffer[i].offset;
840                                 srv_sig_pos += sizeof(uint32);
841                                 
842                                 break;
843                                 
844                         case PAC_TYPE_PRIVSVR_CHECKSUM:
845                                 if (!my_pac->pac_buffer[i].ctr->pac.privsrv_cksum) {
846                                         break;
847                                 }
848
849                                 kdc_sig = my_pac->pac_buffer[i].ctr->pac.privsrv_cksum;
850                                 
851                                 /* get position of signature buffer */
852                                 kdc_sig_pos = my_pac->pac_buffer[i].offset;
853                                 kdc_sig_pos += sizeof(uint32);
854                                 
855                                 break;
856                                 
857                         case PAC_TYPE_LOGON_NAME:
858                                 if (!my_pac->pac_buffer[i].ctr->pac.logon_name) {
859                                         break;
860                                 }
861
862                                 logon_name = my_pac->pac_buffer[i].ctr->pac.logon_name;
863                                 break;
864
865                         case PAC_TYPE_LOGON_INFO:
866                                 if (!my_pac->pac_buffer[i].ctr->pac.logon_info) {
867                                         break;
868                                 }
869
870                                 logon_info = my_pac->pac_buffer[i].ctr->pac.logon_info;
871                                 break;
872                         }
873
874         }
875
876         if (!srv_sig || !kdc_sig || !logon_name || !logon_info) {
877                 nt_status = NT_STATUS_INVALID_PARAMETER;
878                 goto out;
879         }
880
881         /* zero PAC_SIGNATURE_DATA signature buffer */
882         memset(&modified_pac_blob.data[srv_sig_pos], '\0', srv_sig->signature.buf_len);
883         memset(&modified_pac_blob.data[kdc_sig_pos], '\0', kdc_sig->signature.buf_len);
884
885         /* check server signature */
886         nt_status = check_pac_checksum(mem_ctx, modified_pac_blob, srv_sig, context, service_keyblock);
887         if (!NT_STATUS_IS_OK(nt_status)) {
888                 DEBUG(0,("decode_pac_data: failed to verify PAC server signature\n"));
889                 goto out;
890         }
891
892         /* Convert to NT time, so as not to loose accuracy in comparison */
893         unix_to_nt_time(&tgs_authtime_nttime, tgs_authtime);
894
895         if (!nt_time_equals(&tgs_authtime_nttime, &logon_name->logon_time)) {
896         
897                 DEBUG(2,("decode_pac_data: Logon time mismatch between ticket and PAC!\n"));
898                 DEBUGADD(2, ("decode_pac_data: PAC: %s\n", 
899                         http_timestring(nt_time_to_unix(logon_name->logon_time))));
900                 DEBUGADD(2, ("decode_pac_data: Ticket: %s\n", 
901                         http_timestring(nt_time_to_unix(tgs_authtime_nttime))));
902                 
903                 nt_status = NT_STATUS_ACCESS_DENIED;
904                 goto out;
905         }
906
907         if (!logon_name->len) {
908                 DEBUG(2,("decode_pac_data: No Logon Name available\n"));
909                 nt_status = NT_STATUS_INVALID_PARAMETER;
910                 goto out;
911         }
912         rpcstr_pull(username, logon_name->username, sizeof(username), logon_name->len, 0);
913
914         ret = smb_krb5_parse_name_norealm(context, username, &client_principal_pac);
915         if (ret) {
916                 DEBUG(2,("decode_pac_data: Could not parse name from incoming PAC: [%s]: %s\n", 
917                         username, error_message(ret)));
918                 nt_status = NT_STATUS_INVALID_PARAMETER;
919                 goto out;
920         }
921
922         if (!smb_krb5_principal_compare_any_realm(context, client_principal, client_principal_pac)) {
923                 DEBUG(2,("decode_pac_data: Name in PAC [%s] does not match principal name in ticket\n", 
924                         username));
925                 nt_status = NT_STATUS_ACCESS_DENIED;
926                 goto out;
927         }
928
929         DEBUG(10,("Successfully validated Kerberos PAC\n"));
930
931         dump_pac_logon_info(10, logon_info);
932
933         *pac_data = my_pac;
934
935         nt_status = NT_STATUS_OK;
936
937 out:
938         if (client_principal_pac) {
939                 krb5_free_principal(context, client_principal_pac);
940         }
941
942         return nt_status;
943 }
944
945  PAC_LOGON_INFO *get_logon_info_from_pac(PAC_DATA *pac_data) 
946 {
947         PAC_LOGON_INFO *logon_info = NULL;
948         int i;
949         
950         for (i=0; i < pac_data->num_buffers; i++) {
951
952                 if (pac_data->pac_buffer[i].type != PAC_TYPE_LOGON_INFO)
953                         continue;
954
955                 logon_info = pac_data->pac_buffer[i].ctr->pac.logon_info;
956                 break;
957         }
958         return logon_info;
959 }
960
961 /****************************************************************
962 ****************************************************************/
963
964 NTSTATUS kerberos_return_pac(TALLOC_CTX *mem_ctx,
965                              const char *name,
966                              const char *pass,
967                              time_t time_offset,
968                              time_t *expire_time,
969                              time_t *renew_till_time,
970                              const char *cache_name,
971                              bool request_pac,
972                              bool add_netbios_addr,
973                              time_t renewable_time,
974                              PAC_DATA **pac_ret)
975 {
976         krb5_error_code ret;
977         NTSTATUS status = NT_STATUS_INVALID_PARAMETER;
978         DATA_BLOB tkt, ap_rep, sesskey1, sesskey2;
979         PAC_DATA *pac_data = NULL;
980         char *client_princ_out = NULL;
981         const char *auth_princ = NULL;
982         const char *local_service = NULL;
983         const char *cc = "MEMORY:kerberos_return_pac";
984
985         ZERO_STRUCT(tkt);
986         ZERO_STRUCT(ap_rep);
987         ZERO_STRUCT(sesskey1);
988         ZERO_STRUCT(sesskey2);
989
990         if (!name || !pass) {
991                 return NT_STATUS_INVALID_PARAMETER;
992         }
993
994         if (cache_name) {
995                 cc = cache_name;
996         }
997
998         if (!strchr_m(name, '@')) {
999                 auth_princ = talloc_asprintf(mem_ctx, "%s@%s", name,
1000                         lp_realm());
1001         } else {
1002                 auth_princ = name;
1003         }
1004         NT_STATUS_HAVE_NO_MEMORY(auth_princ);
1005
1006         local_service = talloc_asprintf(mem_ctx, "%s$@%s",
1007                                         global_myname(), lp_realm());
1008         NT_STATUS_HAVE_NO_MEMORY(local_service);
1009
1010         ret = kerberos_kinit_password_ext(auth_princ,
1011                                           pass,
1012                                           time_offset,
1013                                           expire_time,
1014                                           renew_till_time,
1015                                           cc,
1016                                           request_pac,
1017                                           add_netbios_addr,
1018                                           renewable_time,
1019                                           &status);
1020         if (ret) {
1021                 DEBUG(1,("kinit failed for '%s' with: %s (%d)\n",
1022                         auth_princ, error_message(ret), ret));
1023                 /* status already set */
1024                 goto out;
1025         }
1026
1027         DEBUG(10,("got TGT for %s in %s\n", auth_princ, cc));
1028         if (expire_time) {
1029                 DEBUGADD(10,("\tvalid until: %s (%d)\n",
1030                         http_timestring(*expire_time),
1031                         (int)*expire_time));
1032         }
1033         if (renew_till_time) {
1034                 DEBUGADD(10,("\trenewable till: %s (%d)\n",
1035                         http_timestring(*renew_till_time),
1036                         (int)*renew_till_time));
1037         }
1038
1039         /* we cannot continue with krb5 when UF_DONT_REQUIRE_PREAUTH is set,
1040          * in that case fallback to NTLM - gd */
1041
1042         if (expire_time && renew_till_time &&
1043             (*expire_time == 0) && (*renew_till_time == 0)) {
1044                 return NT_STATUS_INVALID_LOGON_TYPE;
1045         }
1046
1047
1048         ret = cli_krb5_get_ticket(local_service,
1049                                   time_offset,
1050                                   &tkt,
1051                                   &sesskey1,
1052                                   0,
1053                                   cc,
1054                                   NULL);
1055         if (ret) {
1056                 DEBUG(1,("failed to get ticket for %s: %s\n",
1057                         local_service, error_message(ret)));
1058                 status = krb5_to_nt_status(ret);
1059                 goto out;
1060         }
1061
1062         status = ads_verify_ticket(mem_ctx,
1063                                    lp_realm(),
1064                                    time_offset,
1065                                    &tkt,
1066                                    &client_princ_out,
1067                                    &pac_data,
1068                                    &ap_rep,
1069                                    &sesskey2,
1070                                    False);
1071         if (!NT_STATUS_IS_OK(status)) {
1072                 DEBUG(1,("ads_verify_ticket failed: %s\n",
1073                         nt_errstr(status)));
1074                 goto out;
1075         }
1076
1077         if (!pac_data) {
1078                 DEBUG(1,("no PAC\n"));
1079                 status = NT_STATUS_INVALID_PARAMETER;
1080                 goto out;
1081         }
1082
1083         *pac_ret = pac_data;
1084
1085 out:
1086         if (cc != cache_name) {
1087                 ads_kdestroy(cc);
1088         }
1089
1090         data_blob_free(&tkt);
1091         data_blob_free(&ap_rep);
1092         data_blob_free(&sesskey1);
1093         data_blob_free(&sesskey2);
1094
1095         SAFE_FREE(client_princ_out);
1096
1097         return status;
1098 }
1099
1100 /****************************************************************
1101 ****************************************************************/
1102
1103 static NTSTATUS kerberos_return_pac_logon_info(TALLOC_CTX *mem_ctx,
1104                                                const char *name,
1105                                                const char *pass,
1106                                                time_t time_offset,
1107                                                time_t *expire_time,
1108                                                time_t *renew_till_time,
1109                                                const char *cache_name,
1110                                                bool request_pac,
1111                                                bool add_netbios_addr,
1112                                                time_t renewable_time,
1113                                                PAC_LOGON_INFO **logon_info)
1114 {
1115         NTSTATUS status;
1116         PAC_DATA *pac_data = NULL;
1117         PAC_LOGON_INFO *info = NULL;
1118
1119         status = kerberos_return_pac(mem_ctx,
1120                                      name,
1121                                      pass,
1122                                      time_offset,
1123                                      expire_time,
1124                                      renew_till_time,
1125                                      cache_name,
1126                                      request_pac,
1127                                      add_netbios_addr,
1128                                      renewable_time,
1129                                      &pac_data);
1130         if (!NT_STATUS_IS_OK(status)) {
1131                 return status;
1132         }
1133
1134         if (!pac_data) {
1135                 DEBUG(3,("no pac\n"));
1136                 return NT_STATUS_INVALID_USER_BUFFER;
1137         }
1138
1139         info = get_logon_info_from_pac(pac_data);
1140         if (!info) {
1141                 DEBUG(1,("no logon_info\n"));
1142                 return NT_STATUS_INVALID_USER_BUFFER;
1143         }
1144
1145         *logon_info = info;
1146
1147         return NT_STATUS_OK;
1148 }
1149
1150 /****************************************************************
1151 ****************************************************************/
1152
1153 NTSTATUS kerberos_return_info3_from_pac(TALLOC_CTX *mem_ctx,
1154                                         const char *name,
1155                                         const char *pass,
1156                                         time_t time_offset,
1157                                         time_t *expire_time,
1158                                         time_t *renew_till_time,
1159                                         const char *cache_name,
1160                                         bool request_pac,
1161                                         bool add_netbios_addr,
1162                                         time_t renewable_time,
1163                                         NET_USER_INFO_3 **info3)
1164 {
1165         NTSTATUS status;
1166         PAC_LOGON_INFO *logon_info = NULL;
1167
1168         status = kerberos_return_pac_logon_info(mem_ctx,
1169                                                 name,
1170                                                 pass,
1171                                                 time_offset,
1172                                                 expire_time,
1173                                                 renew_till_time,
1174                                                 cache_name,
1175                                                 request_pac,
1176                                                 add_netbios_addr,
1177                                                 renewable_time,
1178                                                 &logon_info);
1179         if (!NT_STATUS_IS_OK(status)) {
1180                 return status;
1181         }
1182
1183         *info3 = &logon_info->info3;
1184
1185         return NT_STATUS_OK;
1186 }
1187 #endif