[GLUE] Rsync SAMBA_3_0 SVN r25598 in order to create the v3-0-test branch.
[Samba.git] / source / libads / authdata.c
blob8e951dde805755e4761524c4bd051beaa8e1f719
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
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.
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.
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.
26 #include "includes.h"
28 #ifdef HAVE_KRB5
30 static BOOL pac_io_logon_name(const char *desc, PAC_LOGON_NAME *logon_name,
31 prs_struct *ps, int depth)
33 if (NULL == logon_name)
34 return False;
36 prs_debug(ps, depth, desc, "pac_io_logon_name");
37 depth++;
39 if (!smb_io_time("logon_time", &logon_name->logon_time, ps, depth))
40 return False;
42 if (!prs_uint16("len", ps, depth, &logon_name->len))
43 return False;
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. */
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;
57 if (!prs_uint8s(True, "name", ps, depth, logon_name->username, logon_name->len))
58 return False;
60 return True;
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)
67 if (NULL == sid_and_attr)
68 return False;
70 prs_debug(ps, depth, desc, "pac_io_krb_sids");
71 depth++;
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;
81 if(!smb_io_dom_sid2("sid", sid_and_attr->sid, ps, depth))
82 return False;
84 return True;
88 static BOOL pac_io_krb_attrs(const char *desc, KRB_SID_AND_ATTRS *sid_and_attr,
89 prs_struct *ps, int depth)
91 if (NULL == sid_and_attr)
92 return False;
94 prs_debug(ps, depth, desc, "pac_io_krb_attrs");
95 depth++;
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;
102 return True;
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)
110 int i;
112 if (NULL == array)
113 return False;
115 prs_debug(ps, depth, desc, "pac_io_krb_sid_and_attr_array");
116 depth++;
119 if (!prs_uint32("count", ps, depth, &array->count))
120 return False;
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;
129 } else {
130 array->krb_sid_and_attrs = NULL;
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;
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;
149 return True;
152 #endif
154 static BOOL pac_io_group_membership(const char *desc,
155 GROUP_MEMBERSHIP *membership,
156 prs_struct *ps, int depth)
158 if (NULL == membership)
159 return False;
161 prs_debug(ps, depth, desc, "pac_io_group_membership");
162 depth++;
164 if (!prs_uint32("rid", ps, depth, &membership->rid))
165 return False;
166 if (!prs_uint32("attrs", ps, depth, &membership->attrs))
167 return False;
169 return True;
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)
178 int i;
180 if (NULL == array)
181 return False;
183 prs_debug(ps, depth, desc, "pac_io_group_membership_array");
184 depth++;
187 if (!prs_uint32("count", ps, depth, &array->count))
188 return False;
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;
197 } else {
198 array->group_membership = NULL;
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;
210 return True;
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)
218 uint32 garbage, i;
220 if (NULL == info)
221 return False;
223 prs_debug(ps, depth, desc, "pac_io_pac_logon_info");
224 depth++;
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;
237 if (!prs_uint32("pointer", ps, depth, &garbage))
238 return False;
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;
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;
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;
292 if (!prs_uint8s(False, "session_key", ps, depth, info->session_key, 16))
293 return False;
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;
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;
305 if (!prs_uint8s(False, "lm_session_key", ps, depth, info->lm_session_key, 8))
306 return False;
308 if (!prs_uint32("acct_flags", ps, depth, &info->acct_flags))
309 return False;
311 for (i = 0; i < 7; i++)
313 if (!prs_uint32("unkown", ps, depth, &info->unknown[i])) /* unknown */
314 return False;
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;
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;
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;
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;
364 if(info->ptr_dom_sid)
365 if(!smb_io_dom_sid2("dom_sid", &info->dom_sid, ps, depth))
366 return False;
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;
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;
381 if (info->ptr_res_groups) {
383 if (!(info->user_flgs & LOGON_RESOURCE_GROUPS)) {
384 DEBUG(0,("user_flgs attribute does not have LOGON_RESOURCE_GROUPS\n"));
385 /* return False; */
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;
395 return True;
397 #endif
399 static BOOL pac_io_pac_logon_info(const char *desc, PAC_LOGON_INFO *info,
400 prs_struct *ps, int depth)
402 uint32 garbage;
403 BOOL kerb_validation_info = True;
405 if (NULL == info)
406 return False;
408 prs_debug(ps, depth, desc, "pac_io_pac_logon_info");
409 depth++;
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;
422 if(!net_io_user_info3("", &info->info3, ps, depth, 3, kerb_validation_info))
423 return False;
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;
431 if (info->info3.ptr_res_groups) {
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; */
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;
445 return True;
450 static BOOL pac_io_pac_signature_data(const char *desc,
451 PAC_SIGNATURE_DATA *data, uint32 length,
452 prs_struct *ps, int depth)
454 uint32 siglen = length - sizeof(uint32);
455 prs_debug(ps, depth, desc, "pac_io_pac_signature_data");
456 depth++;
458 if (data == NULL)
459 return False;
461 if (!prs_align(ps))
462 return False;
463 if (!prs_uint32("type", ps, depth, &data->type))
464 return False;
466 if (UNMARSHALLING(ps) && length) {
467 if (siglen) {
468 data->signature.buffer = PRS_ALLOC_MEM(ps, uint8, siglen);
469 if (!data->signature.buffer) {
470 DEBUG(3, ("No memory available\n"));
471 return False;
473 } else {
474 data->signature.buffer = NULL;
478 data->signature.buf_len = siglen;
480 if (!prs_uint8s(False, "signature", ps, depth, data->signature.buffer, data->signature.buf_len))
481 return False;
484 return True;
487 static BOOL pac_io_pac_info_hdr_ctr(const char *desc, PAC_BUFFER *hdr,
488 prs_struct *ps, int depth)
490 if (NULL == hdr)
491 return False;
493 prs_debug(ps, depth, desc, "pac_io_pac_info_hdr_ctr");
494 depth++;
496 if (!prs_align(ps))
497 return False;
499 if (hdr->offset != prs_offset(ps)) {
500 DEBUG(5,("offset in header(x%x) and data(x%x) do not match, correcting\n",
501 hdr->offset, prs_offset(ps)));
502 prs_set_offset(ps, hdr->offset);
505 if (UNMARSHALLING(ps) && hdr->size > 0) {
506 hdr->ctr = PRS_ALLOC_MEM(ps, PAC_INFO_CTR, 1);
507 if (!hdr->ctr) {
508 DEBUG(3, ("No memory available\n"));
509 return False;
513 switch(hdr->type) {
514 case PAC_TYPE_LOGON_INFO:
515 DEBUG(5, ("PAC_TYPE_LOGON_INFO\n"));
516 if (UNMARSHALLING(ps))
517 hdr->ctr->pac.logon_info = PRS_ALLOC_MEM(ps, PAC_LOGON_INFO, 1);
518 if (!hdr->ctr->pac.logon_info) {
519 DEBUG(3, ("No memory available\n"));
520 return False;
522 if (!pac_io_pac_logon_info(desc, hdr->ctr->pac.logon_info,
523 ps, depth))
524 return False;
525 break;
527 case PAC_TYPE_SERVER_CHECKSUM:
528 DEBUG(5, ("PAC_TYPE_SERVER_CHECKSUM\n"));
529 if (UNMARSHALLING(ps))
530 hdr->ctr->pac.srv_cksum = PRS_ALLOC_MEM(ps, PAC_SIGNATURE_DATA, 1);
531 if (!hdr->ctr->pac.srv_cksum) {
532 DEBUG(3, ("No memory available\n"));
533 return False;
535 if (!pac_io_pac_signature_data(desc, hdr->ctr->pac.srv_cksum,
536 hdr->size, ps, depth))
537 return False;
538 break;
540 case PAC_TYPE_PRIVSVR_CHECKSUM:
541 DEBUG(5, ("PAC_TYPE_PRIVSVR_CHECKSUM\n"));
542 if (UNMARSHALLING(ps))
543 hdr->ctr->pac.privsrv_cksum = PRS_ALLOC_MEM(ps, PAC_SIGNATURE_DATA, 1);
544 if (!hdr->ctr->pac.privsrv_cksum) {
545 DEBUG(3, ("No memory available\n"));
546 return False;
548 if (!pac_io_pac_signature_data(desc,
549 hdr->ctr->pac.privsrv_cksum,
550 hdr->size, ps, depth))
551 return False;
552 break;
554 case PAC_TYPE_LOGON_NAME:
555 DEBUG(5, ("PAC_TYPE_LOGON_NAME\n"));
556 if (UNMARSHALLING(ps))
557 hdr->ctr->pac.logon_name = PRS_ALLOC_MEM(ps, PAC_LOGON_NAME, 1);
558 if (!hdr->ctr->pac.logon_name) {
559 DEBUG(3, ("No memory available\n"));
560 return False;
562 if (!pac_io_logon_name(desc, hdr->ctr->pac.logon_name,
563 ps, depth))
564 return False;
565 break;
567 default:
568 /* dont' know, so we need to skip it */
569 DEBUG(3, ("unknown PAC type %d\n", hdr->type));
570 prs_set_offset(ps, prs_offset(ps) + hdr->size);
573 #if 0
574 /* obscure pad */
575 if (!prs_uint32("pad", ps, depth, &hdr->pad))
576 return False;
577 #endif
578 return True;
581 static BOOL pac_io_pac_info_hdr(const char *desc, PAC_BUFFER *hdr,
582 prs_struct *ps, int depth)
584 if (NULL == hdr)
585 return False;
587 prs_debug(ps, depth, desc, "pac_io_pac_info_hdr");
588 depth++;
590 if (!prs_align(ps))
591 return False;
592 if (!prs_uint32("type", ps, depth, &hdr->type))
593 return False;
594 if (!prs_uint32("size", ps, depth, &hdr->size))
595 return False;
596 if (!prs_uint32("offset", ps, depth, &hdr->offset))
597 return False;
598 if (!prs_uint32("offsethi", ps, depth, &hdr->offsethi))
599 return False;
601 return True;
604 static BOOL pac_io_pac_data(const char *desc, PAC_DATA *data,
605 prs_struct *ps, int depth)
607 int i;
609 if (NULL == data)
610 return False;
612 prs_debug(ps, depth, desc, "pac_io_pac_data");
613 depth++;
615 if (!prs_align(ps))
616 return False;
617 if (!prs_uint32("num_buffers", ps, depth, &data->num_buffers))
618 return False;
619 if (!prs_uint32("version", ps, depth, &data->version))
620 return False;
622 if (UNMARSHALLING(ps) && data->num_buffers > 0) {
623 if ((data->pac_buffer = PRS_ALLOC_MEM(ps, PAC_BUFFER, data->num_buffers)) == NULL) {
624 return False;
628 for (i=0; i<data->num_buffers; i++) {
629 if (!pac_io_pac_info_hdr(desc, &data->pac_buffer[i], ps,
630 depth))
631 return False;
634 for (i=0; i<data->num_buffers; i++) {
635 if (!pac_io_pac_info_hdr_ctr(desc, &data->pac_buffer[i],
636 ps, depth))
637 return False;
640 return True;
643 static NTSTATUS check_pac_checksum(TALLOC_CTX *mem_ctx,
644 DATA_BLOB pac_data,
645 PAC_SIGNATURE_DATA *sig,
646 krb5_context context,
647 krb5_keyblock *keyblock)
649 krb5_error_code ret;
650 krb5_checksum cksum;
651 krb5_keyusage usage = 0;
653 smb_krb5_checksum_from_pac_sig(&cksum, sig);
655 #ifdef HAVE_KRB5_KU_OTHER_CKSUM /* Heimdal */
656 usage = KRB5_KU_OTHER_CKSUM;
657 #elif defined(HAVE_KRB5_KEYUSAGE_APP_DATA_CKSUM) /* MIT */
658 usage = KRB5_KEYUSAGE_APP_DATA_CKSUM;
659 #else
660 #error UNKNOWN_KRB5_KEYUSAGE
661 #endif
663 ret = smb_krb5_verify_checksum(context,
664 keyblock,
665 usage,
666 &cksum,
667 pac_data.data,
668 pac_data.length);
670 if (ret) {
671 DEBUG(2,("check_pac_checksum: PAC Verification failed: %s (%d)\n",
672 error_message(ret), ret));
673 return NT_STATUS_ACCESS_DENIED;
676 return NT_STATUS_OK;
679 static NTSTATUS parse_pac_data(TALLOC_CTX *mem_ctx, DATA_BLOB *pac_data_blob, PAC_DATA *pac_data)
681 prs_struct ps;
682 PAC_DATA *my_pac;
684 if (!prs_init(&ps, pac_data_blob->length, mem_ctx, UNMARSHALL))
685 return NT_STATUS_NO_MEMORY;
687 if (!prs_copy_data_in(&ps, (char *)pac_data_blob->data, pac_data_blob->length))
688 return NT_STATUS_INVALID_PARAMETER;
690 prs_set_offset(&ps, 0);
692 my_pac = TALLOC_ZERO_P(mem_ctx, PAC_DATA);
693 if (!pac_io_pac_data("pac data", my_pac, &ps, 0))
694 return NT_STATUS_INVALID_PARAMETER;
696 prs_mem_free(&ps);
698 *pac_data = *my_pac;
700 return NT_STATUS_OK;
703 /* just for debugging, will be removed later - Guenther */
704 char *pac_group_attr_string(uint32 attr)
706 fstring name = "";
708 if (!attr)
709 return NULL;
711 if (attr & SE_GROUP_MANDATORY) fstrcat(name, "SE_GROUP_MANDATORY ");
712 if (attr & SE_GROUP_ENABLED_BY_DEFAULT) fstrcat(name, "SE_GROUP_ENABLED_BY_DEFAULT ");
713 if (attr & SE_GROUP_ENABLED) fstrcat(name, "SE_GROUP_ENABLED ");
714 if (attr & SE_GROUP_OWNER) fstrcat(name, "SE_GROUP_OWNER ");
715 if (attr & SE_GROUP_USE_FOR_DENY_ONLY) fstrcat(name, "SE_GROUP_USE_FOR_DENY_ONLY ");
716 if (attr & SE_GROUP_LOGON_ID) fstrcat(name, "SE_GROUP_LOGON_ID ");
717 if (attr & SE_GROUP_RESOURCE) fstrcat(name, "SE_GROUP_RESOURCE ");
719 return SMB_STRDUP(name);
722 /* just for debugging, will be removed later - Guenther */
723 static void dump_pac_logon_info(PAC_LOGON_INFO *logon_info) {
725 DOM_SID dom_sid, res_group_dom_sid;
726 int i;
727 char *attr_string;
728 uint32 user_flgs = logon_info->info3.user_flgs;
730 if (logon_info->info3.ptr_res_group_dom_sid) {
731 sid_copy(&res_group_dom_sid, &logon_info->res_group_dom_sid.sid);
733 sid_copy(&dom_sid, &logon_info->info3.dom_sid.sid);
735 DEBUG(10,("The PAC:\n"));
737 DEBUGADD(10,("\tUser Flags: 0x%x (%d)\n", user_flgs, user_flgs));
738 if (user_flgs & LOGON_EXTRA_SIDS)
739 DEBUGADD(10,("\tUser Flags: LOGON_EXTRA_SIDS 0x%x (%d)\n", LOGON_EXTRA_SIDS, LOGON_EXTRA_SIDS));
740 if (user_flgs & LOGON_RESOURCE_GROUPS)
741 DEBUGADD(10,("\tUser Flags: LOGON_RESOURCE_GROUPS 0x%x (%d)\n", LOGON_RESOURCE_GROUPS, LOGON_RESOURCE_GROUPS));
742 DEBUGADD(10,("\tUser SID: %s-%d\n", sid_string_static(&dom_sid), logon_info->info3.user_rid));
743 DEBUGADD(10,("\tGroup SID: %s-%d\n", sid_string_static(&dom_sid), logon_info->info3.group_rid));
745 DEBUGADD(10,("\tGroup Membership (Global and Universal Groups of own domain):\n"));
746 for (i = 0; i < logon_info->info3.num_groups; i++) {
747 attr_string = pac_group_attr_string(logon_info->info3.gids[i].attr);
748 DEBUGADD(10,("\t\t%d: sid: %s-%d\n\t\t attr: 0x%x == %s\n",
749 i, sid_string_static(&dom_sid),
750 logon_info->info3.gids[i].g_rid,
751 logon_info->info3.gids[i].attr,
752 attr_string));
753 SAFE_FREE(attr_string);
756 DEBUGADD(10,("\tGroup Membership (Domain Local Groups and Groups from Trusted Domains):\n"));
757 for (i = 0; i < logon_info->info3.num_other_sids; i++) {
758 attr_string = pac_group_attr_string(logon_info->info3.other_sids_attrib[i]);
759 DEBUGADD(10,("\t\t%d: sid: %s\n\t\t attr: 0x%x == %s\n",
760 i, sid_string_static(&logon_info->info3.other_sids[i].sid),
761 logon_info->info3.other_sids_attrib[i],
762 attr_string));
763 SAFE_FREE(attr_string);
766 DEBUGADD(10,("\tGroup Membership (Ressource Groups (SID History ?)):\n"));
767 for (i = 0; i < logon_info->info3.res_group_count; i++) {
768 attr_string = pac_group_attr_string(logon_info->res_groups.group_membership[i].attrs);
769 DEBUGADD(10,("\t\t%d: sid: %s-%d\n\t\t attr: 0x%x == %s\n",
770 i, sid_string_static(&res_group_dom_sid),
771 logon_info->res_groups.group_membership[i].rid,
772 logon_info->res_groups.group_membership[i].attrs,
773 attr_string));
774 SAFE_FREE(attr_string);
778 NTSTATUS decode_pac_data(TALLOC_CTX *mem_ctx,
779 DATA_BLOB *pac_data_blob,
780 krb5_context context,
781 krb5_keyblock *service_keyblock,
782 krb5_const_principal client_principal,
783 time_t tgs_authtime,
784 PAC_DATA **pac_data)
787 DATA_BLOB modified_pac_blob;
788 PAC_DATA *my_pac;
789 NTSTATUS nt_status;
790 krb5_error_code ret;
791 PAC_SIGNATURE_DATA *srv_sig = NULL;
792 PAC_SIGNATURE_DATA *kdc_sig = NULL;
793 PAC_LOGON_NAME *logon_name = NULL;
794 PAC_LOGON_INFO *logon_info = NULL;
795 krb5_principal client_principal_pac = NULL;
796 NTTIME tgs_authtime_nttime;
797 int i, srv_sig_pos = 0, kdc_sig_pos = 0;
798 fstring username;
800 *pac_data = NULL;
802 my_pac = talloc(mem_ctx, PAC_DATA);
803 if (!my_pac) {
804 return NT_STATUS_NO_MEMORY;
807 nt_status = parse_pac_data(mem_ctx, pac_data_blob, my_pac);
808 if (!NT_STATUS_IS_OK(nt_status)) {
809 DEBUG(0,("decode_pac_data: failed to parse PAC\n"));
810 return nt_status;
813 modified_pac_blob = data_blob_talloc(mem_ctx, pac_data_blob->data, pac_data_blob->length);
815 if (my_pac->num_buffers < 4) {
816 nt_status = NT_STATUS_INVALID_PARAMETER;
817 goto out;
820 /* store signatures */
821 for (i=0; i < my_pac->num_buffers; i++) {
823 switch (my_pac->pac_buffer[i].type) {
825 case PAC_TYPE_SERVER_CHECKSUM:
826 if (!my_pac->pac_buffer[i].ctr->pac.srv_cksum) {
827 break;
830 srv_sig = my_pac->pac_buffer[i].ctr->pac.srv_cksum;
832 /* get position of signature buffer */
833 srv_sig_pos = my_pac->pac_buffer[i].offset;
834 srv_sig_pos += sizeof(uint32);
836 break;
838 case PAC_TYPE_PRIVSVR_CHECKSUM:
839 if (!my_pac->pac_buffer[i].ctr->pac.privsrv_cksum) {
840 break;
843 kdc_sig = my_pac->pac_buffer[i].ctr->pac.privsrv_cksum;
845 /* get position of signature buffer */
846 kdc_sig_pos = my_pac->pac_buffer[i].offset;
847 kdc_sig_pos += sizeof(uint32);
849 break;
851 case PAC_TYPE_LOGON_NAME:
852 if (!my_pac->pac_buffer[i].ctr->pac.logon_name) {
853 break;
856 logon_name = my_pac->pac_buffer[i].ctr->pac.logon_name;
857 break;
859 case PAC_TYPE_LOGON_INFO:
860 if (!my_pac->pac_buffer[i].ctr->pac.logon_info) {
861 break;
864 logon_info = my_pac->pac_buffer[i].ctr->pac.logon_info;
865 break;
870 if (!srv_sig || !kdc_sig || !logon_name || !logon_info) {
871 nt_status = NT_STATUS_INVALID_PARAMETER;
872 goto out;
875 /* zero PAC_SIGNATURE_DATA signature buffer */
876 memset(&modified_pac_blob.data[srv_sig_pos], '\0', srv_sig->signature.buf_len);
877 memset(&modified_pac_blob.data[kdc_sig_pos], '\0', kdc_sig->signature.buf_len);
879 /* check server signature */
880 nt_status = check_pac_checksum(mem_ctx, modified_pac_blob, srv_sig, context, service_keyblock);
881 if (!NT_STATUS_IS_OK(nt_status)) {
882 DEBUG(0,("decode_pac_data: failed to verify PAC server signature\n"));
883 goto out;
886 /* Convert to NT time, so as not to loose accuracy in comparison */
887 unix_to_nt_time(&tgs_authtime_nttime, tgs_authtime);
889 if (!nt_time_equals(&tgs_authtime_nttime, &logon_name->logon_time)) {
891 DEBUG(2,("decode_pac_data: Logon time mismatch between ticket and PAC!\n"));
892 DEBUGADD(2, ("decode_pac_data: PAC: %s\n",
893 http_timestring(nt_time_to_unix(logon_name->logon_time))));
894 DEBUGADD(2, ("decode_pac_data: Ticket: %s\n",
895 http_timestring(nt_time_to_unix(tgs_authtime_nttime))));
897 nt_status = NT_STATUS_ACCESS_DENIED;
898 goto out;
901 if (!logon_name->len) {
902 DEBUG(2,("decode_pac_data: No Logon Name available\n"));
903 nt_status = NT_STATUS_INVALID_PARAMETER;
904 goto out;
906 rpcstr_pull(username, logon_name->username, sizeof(username), logon_name->len, 0);
908 ret = smb_krb5_parse_name_norealm(context, username, &client_principal_pac);
909 if (ret) {
910 DEBUG(2,("decode_pac_data: Could not parse name from incoming PAC: [%s]: %s\n",
911 username, error_message(ret)));
912 nt_status = NT_STATUS_INVALID_PARAMETER;
913 goto out;
916 if (!smb_krb5_principal_compare_any_realm(context, client_principal, client_principal_pac)) {
917 DEBUG(2,("decode_pac_data: Name in PAC [%s] does not match principal name in ticket\n",
918 username));
919 nt_status = NT_STATUS_ACCESS_DENIED;
920 goto out;
923 DEBUG(10,("Successfully validated Kerberos PAC\n"));
925 dump_pac_logon_info(logon_info);
927 *pac_data = my_pac;
929 nt_status = NT_STATUS_OK;
931 out:
932 if (client_principal_pac) {
933 krb5_free_principal(context, client_principal_pac);
936 return nt_status;
939 PAC_LOGON_INFO *get_logon_info_from_pac(PAC_DATA *pac_data)
941 PAC_LOGON_INFO *logon_info = NULL;
942 int i;
944 for (i=0; i < pac_data->num_buffers; i++) {
946 if (pac_data->pac_buffer[i].type != PAC_TYPE_LOGON_INFO)
947 continue;
949 logon_info = pac_data->pac_buffer[i].ctr->pac.logon_info;
950 break;
952 return logon_info;
955 #endif