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.
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
)
36 prs_debug(ps
, depth
, desc
, "pac_io_logon_name");
39 if (!smb_io_time("logon_time", &logon_name
->logon_time
, ps
, depth
))
42 if (!prs_uint16("len", ps
, depth
, &logon_name
->len
))
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"));
57 if (!prs_uint8s(True
, "name", ps
, depth
, logon_name
->username
, logon_name
->len
))
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
)
70 prs_debug(ps
, depth
, desc
, "pac_io_krb_sids");
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"));
81 if(!smb_io_dom_sid2("sid", sid_and_attr
->sid
, ps
, depth
))
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
)
94 prs_debug(ps
, depth
, desc
, "pac_io_krb_attrs");
97 if (!prs_uint32("sid_ptr", ps
, depth
, &sid_and_attr
->sid_ptr
))
99 if (!prs_uint32("attrs", ps
, depth
, &sid_and_attr
->attrs
))
105 static BOOL
pac_io_krb_sid_and_attr_array(const char *desc
,
106 KRB_SID_AND_ATTR_ARRAY
*array
,
108 prs_struct
*ps
, int depth
)
115 prs_debug(ps
, depth
, desc
, "pac_io_krb_sid_and_attr_array");
119 if (!prs_uint32("count", ps
, depth
, &array
->count
))
122 if (UNMARSHALLING(ps
)) {
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"));
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
],
141 for (i
=0; i
<num
; i
++) {
142 if (!pac_io_krb_sids(desc
,
143 &array
->krb_sid_and_attrs
[i
],
154 static BOOL
pac_io_group_membership(const char *desc
,
155 GROUP_MEMBERSHIP
*membership
,
156 prs_struct
*ps
, int depth
)
158 if (NULL
== membership
)
161 prs_debug(ps
, depth
, desc
, "pac_io_group_membership");
164 if (!prs_uint32("rid", ps
, depth
, &membership
->rid
))
166 if (!prs_uint32("attrs", ps
, depth
, &membership
->attrs
))
173 static BOOL
pac_io_group_membership_array(const char *desc
,
174 GROUP_MEMBERSHIP_ARRAY
*array
,
176 prs_struct
*ps
, int depth
)
183 prs_debug(ps
, depth
, desc
, "pac_io_group_membership_array");
187 if (!prs_uint32("count", ps
, depth
, &array
->count
))
190 if (UNMARSHALLING(ps
)) {
192 array
->group_membership
= PRS_ALLOC_MEM(ps
, GROUP_MEMBERSHIP
, num
);
193 if (!array
->group_membership
) {
194 DEBUG(3, ("No memory available\n"));
198 array
->group_membership
= NULL
;
202 for (i
=0; i
<num
; i
++) {
203 if (!pac_io_group_membership(desc
,
204 &array
->group_membership
[i
],
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
)
223 prs_debug(ps
, depth
, desc
, "pac_io_pac_logon_info");
228 if (!prs_uint32("unknown", ps
, depth
, &garbage
)) /* 00081001 */
230 if (!prs_uint32("unknown", ps
, depth
, &garbage
)) /* cccccccc */
232 if (!prs_uint32("bufferlen", ps
, depth
, &garbage
))
234 if (!prs_uint32("bufferlenhi", ps
, depth
, &garbage
)) /* 00000000 */
237 if (!prs_uint32("pointer", ps
, depth
, &garbage
))
242 if (!smb_io_time("logon_time", &info
->logon_time
, ps
, depth
))
244 if (!smb_io_time("logoff_time", &info
->logoff_time
, ps
, depth
))
246 if (!smb_io_time("kickoff_time", &info
->kickoff_time
, ps
, depth
))
248 if (!smb_io_time("pass_last_set_time", &info
->pass_last_set_time
,
251 if (!smb_io_time("pass_can_change_time", &info
->pass_can_change_time
,
254 if (!smb_io_time("pass_must_change_time", &info
->pass_must_change_time
,
258 if (!smb_io_unihdr("hdr_user_name", &info
->hdr_user_name
, ps
, depth
))
260 if (!smb_io_unihdr("hdr_full_name", &info
->hdr_full_name
, ps
, depth
))
262 if (!smb_io_unihdr("hdr_logon_script", &info
->hdr_logon_script
,
265 if (!smb_io_unihdr("hdr_profile_path", &info
->hdr_profile_path
,
268 if (!smb_io_unihdr("hdr_home_dir", &info
->hdr_home_dir
, ps
, depth
))
270 if (!smb_io_unihdr("hdr_dir_drive", &info
->hdr_dir_drive
, ps
, depth
))
273 if (!prs_uint16("logon_count", ps
, depth
, &info
->logon_count
))
275 if (!prs_uint16("bad_password_count", ps
, depth
, &info
->bad_password_count
))
277 if (!prs_uint32("user_rid", ps
, depth
, &info
->user_rid
))
279 if (!prs_uint32("group_rid", ps
, depth
, &info
->group_rid
))
281 if (!prs_uint32("group_count", ps
, depth
, &info
->group_count
))
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
))
289 if (!prs_uint32("user_flags", ps
, depth
, &info
->user_flags
))
292 if (!prs_uint8s(False
, "session_key", ps
, depth
, info
->session_key
, 16))
295 if (!smb_io_unihdr("hdr_dom_controller",
296 &info
->hdr_dom_controller
, ps
, depth
))
298 if (!smb_io_unihdr("hdr_dom_name", &info
->hdr_dom_name
, ps
, depth
))
301 /* this should be followed, but just get ptr for now */
302 if (!prs_uint32("ptr_dom_sid", ps
, depth
, &info
->ptr_dom_sid
))
305 if (!prs_uint8s(False
, "lm_session_key", ps
, depth
, info
->lm_session_key
, 8))
308 if (!prs_uint32("acct_flags", ps
, depth
, &info
->acct_flags
))
311 for (i
= 0; i
< 7; i
++)
313 if (!prs_uint32("unkown", ps
, depth
, &info
->unknown
[i
])) /* unknown */
317 if (!prs_uint32("sid_count", ps
, depth
, &info
->sid_count
))
319 if (!prs_uint32("ptr_extra_sids", ps
, depth
, &info
->ptr_extra_sids
))
321 if (!prs_uint32("ptr_res_group_dom_sid", ps
, depth
,
322 &info
->ptr_res_group_dom_sid
))
324 if (!prs_uint32("res_group_count", ps
, depth
, &info
->res_group_count
))
326 if (!prs_uint32("ptr_res_groups", ps
, depth
, &info
->ptr_res_groups
))
329 if(!smb_io_unistr2("uni_user_name", &info
->uni_user_name
,
330 info
->hdr_user_name
.buffer
, ps
, depth
))
332 if(!smb_io_unistr2("uni_full_name", &info
->uni_full_name
,
333 info
->hdr_full_name
.buffer
, ps
, depth
))
335 if(!smb_io_unistr2("uni_logon_script", &info
->uni_logon_script
,
336 info
->hdr_logon_script
.buffer
, ps
, depth
))
338 if(!smb_io_unistr2("uni_profile_path", &info
->uni_profile_path
,
339 info
->hdr_profile_path
.buffer
, ps
, depth
))
341 if(!smb_io_unistr2("uni_home_dir", &info
->uni_home_dir
,
342 info
->hdr_home_dir
.buffer
, ps
, depth
))
344 if(!smb_io_unistr2("uni_dir_drive", &info
->uni_dir_drive
,
345 info
->hdr_dir_drive
.buffer
, ps
, depth
))
348 if (info
->group_membership_ptr
) {
349 if (!pac_io_group_membership_array("group membership",
357 if(!smb_io_unistr2("uni_dom_controller", &info
->uni_dom_controller
,
358 info
->hdr_dom_controller
.buffer
, ps
, depth
))
360 if(!smb_io_unistr2("uni_dom_name", &info
->uni_dom_name
,
361 info
->hdr_dom_name
.buffer
, ps
, depth
))
364 if(info
->ptr_dom_sid
)
365 if(!smb_io_dom_sid2("dom_sid", &info
->dom_sid
, ps
, depth
))
369 if (info
->sid_count
&& info
->ptr_extra_sids
)
370 if (!pac_io_krb_sid_and_attr_array("extra_sids",
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
))
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"));
388 if (!pac_io_group_membership_array("res group membership",
390 info
->res_group_count
,
399 static BOOL
pac_io_pac_logon_info(const char *desc
, PAC_LOGON_INFO
*info
,
400 prs_struct
*ps
, int depth
)
403 BOOL kerb_validation_info
= True
;
408 prs_debug(ps
, depth
, desc
, "pac_io_pac_logon_info");
413 if (!prs_uint32("unknown", ps
, depth
, &garbage
)) /* 00081001 */
415 if (!prs_uint32("unknown", ps
, depth
, &garbage
)) /* cccccccc */
417 if (!prs_uint32("bufferlen", ps
, depth
, &garbage
))
419 if (!prs_uint32("bufferlenhi", ps
, depth
, &garbage
)) /* 00000000 */
422 if(!net_io_user_info3("", &info
->info3
, ps
, depth
, 3, kerb_validation_info
))
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
))
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"));
438 if (!pac_io_group_membership_array("res group membership",
440 info
->info3
.res_group_count
,
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");
463 if (!prs_uint32("type", ps
, depth
, &data
->type
))
466 if (UNMARSHALLING(ps
) && length
) {
468 data
->signature
.buffer
= PRS_ALLOC_MEM(ps
, uint8
, siglen
);
469 if (!data
->signature
.buffer
) {
470 DEBUG(3, ("No memory available\n"));
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
))
487 static BOOL
pac_io_pac_info_hdr_ctr(const char *desc
, PAC_BUFFER
*hdr
,
488 prs_struct
*ps
, int depth
)
493 prs_debug(ps
, depth
, desc
, "pac_io_pac_info_hdr_ctr");
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);
508 DEBUG(3, ("No memory available\n"));
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"));
522 if (!pac_io_pac_logon_info(desc
, hdr
->ctr
->pac
.logon_info
,
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"));
535 if (!pac_io_pac_signature_data(desc
, hdr
->ctr
->pac
.srv_cksum
,
536 hdr
->size
, ps
, depth
))
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"));
548 if (!pac_io_pac_signature_data(desc
,
549 hdr
->ctr
->pac
.privsrv_cksum
,
550 hdr
->size
, ps
, depth
))
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"));
562 if (!pac_io_logon_name(desc
, hdr
->ctr
->pac
.logon_name
,
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
);
575 if (!prs_uint32("pad", ps
, depth
, &hdr
->pad
))
581 static BOOL
pac_io_pac_info_hdr(const char *desc
, PAC_BUFFER
*hdr
,
582 prs_struct
*ps
, int depth
)
587 prs_debug(ps
, depth
, desc
, "pac_io_pac_info_hdr");
592 if (!prs_uint32("type", ps
, depth
, &hdr
->type
))
594 if (!prs_uint32("size", ps
, depth
, &hdr
->size
))
596 if (!prs_uint32("offset", ps
, depth
, &hdr
->offset
))
598 if (!prs_uint32("offsethi", ps
, depth
, &hdr
->offsethi
))
604 static BOOL
pac_io_pac_data(const char *desc
, PAC_DATA
*data
,
605 prs_struct
*ps
, int depth
)
612 prs_debug(ps
, depth
, desc
, "pac_io_pac_data");
617 if (!prs_uint32("num_buffers", ps
, depth
, &data
->num_buffers
))
619 if (!prs_uint32("version", ps
, depth
, &data
->version
))
622 if (UNMARSHALLING(ps
) && data
->num_buffers
> 0) {
623 if ((data
->pac_buffer
= PRS_ALLOC_MEM(ps
, PAC_BUFFER
, data
->num_buffers
)) == NULL
) {
628 for (i
=0; i
<data
->num_buffers
; i
++) {
629 if (!pac_io_pac_info_hdr(desc
, &data
->pac_buffer
[i
], ps
,
634 for (i
=0; i
<data
->num_buffers
; i
++) {
635 if (!pac_io_pac_info_hdr_ctr(desc
, &data
->pac_buffer
[i
],
643 static NTSTATUS
check_pac_checksum(TALLOC_CTX
*mem_ctx
,
645 PAC_SIGNATURE_DATA
*sig
,
646 krb5_context context
,
647 krb5_keyblock
*keyblock
)
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
;
660 #error UNKNOWN_KRB5_KEYUSAGE
663 ret
= smb_krb5_verify_checksum(context
,
671 DEBUG(2,("check_pac_checksum: PAC Verification failed: %s (%d)\n",
672 error_message(ret
), ret
));
673 return NT_STATUS_ACCESS_DENIED
;
679 static NTSTATUS
parse_pac_data(TALLOC_CTX
*mem_ctx
, DATA_BLOB
*pac_data_blob
, PAC_DATA
*pac_data
)
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
;
703 /* just for debugging, will be removed later - Guenther */
704 char *pac_group_attr_string(uint32 attr
)
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
;
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
,
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
],
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
,
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
,
787 DATA_BLOB modified_pac_blob
;
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;
802 my_pac
= talloc(mem_ctx
, PAC_DATA
);
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"));
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
;
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
) {
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
);
838 case PAC_TYPE_PRIVSVR_CHECKSUM
:
839 if (!my_pac
->pac_buffer
[i
].ctr
->pac
.privsrv_cksum
) {
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
);
851 case PAC_TYPE_LOGON_NAME
:
852 if (!my_pac
->pac_buffer
[i
].ctr
->pac
.logon_name
) {
856 logon_name
= my_pac
->pac_buffer
[i
].ctr
->pac
.logon_name
;
859 case PAC_TYPE_LOGON_INFO
:
860 if (!my_pac
->pac_buffer
[i
].ctr
->pac
.logon_info
) {
864 logon_info
= my_pac
->pac_buffer
[i
].ctr
->pac
.logon_info
;
870 if (!srv_sig
|| !kdc_sig
|| !logon_name
|| !logon_info
) {
871 nt_status
= NT_STATUS_INVALID_PARAMETER
;
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"));
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
;
901 if (!logon_name
->len
) {
902 DEBUG(2,("decode_pac_data: No Logon Name available\n"));
903 nt_status
= NT_STATUS_INVALID_PARAMETER
;
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
);
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
;
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",
919 nt_status
= NT_STATUS_ACCESS_DENIED
;
923 DEBUG(10,("Successfully validated Kerberos PAC\n"));
925 dump_pac_logon_info(logon_info
);
929 nt_status
= NT_STATUS_OK
;
932 if (client_principal_pac
) {
933 krb5_free_principal(context
, client_principal_pac
);
939 PAC_LOGON_INFO
*get_logon_info_from_pac(PAC_DATA
*pac_data
)
941 PAC_LOGON_INFO
*logon_info
= NULL
;
944 for (i
=0; i
< pac_data
->num_buffers
; i
++) {
946 if (pac_data
->pac_buffer
[i
].type
!= PAC_TYPE_LOGON_INFO
)
949 logon_info
= pac_data
->pac_buffer
[i
].ctr
->pac
.logon_info
;