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 if (UNMARSHALLING(ps
) && logon_name
->len
) {
46 logon_name
->username
= PRS_ALLOC_MEM(ps
, uint16
, logon_name
->len
);
47 if (!logon_name
->username
) {
48 DEBUG(3, ("No memory available\n"));
53 if (!prs_uint16s(True
, "name", ps
, depth
, logon_name
->username
,
54 (logon_name
->len
/ sizeof(uint16
))))
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
)) {
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"));
130 for (i
=0; i
<num
; i
++) {
131 if (!pac_io_krb_attrs(desc
,
132 &array
->krb_sid_and_attrs
[i
],
137 for (i
=0; i
<num
; i
++) {
138 if (!pac_io_krb_sids(desc
,
139 &array
->krb_sid_and_attrs
[i
],
150 static BOOL
pac_io_group_membership(const char *desc
,
151 GROUP_MEMBERSHIP
*membership
,
152 prs_struct
*ps
, int depth
)
154 if (NULL
== membership
)
157 prs_debug(ps
, depth
, desc
, "pac_io_group_membership");
160 if (!prs_uint32("rid", ps
, depth
, &membership
->rid
))
162 if (!prs_uint32("attrs", ps
, depth
, &membership
->attrs
))
169 static BOOL
pac_io_group_membership_array(const char *desc
,
170 GROUP_MEMBERSHIP_ARRAY
*array
,
172 prs_struct
*ps
, int depth
)
179 prs_debug(ps
, depth
, desc
, "pac_io_group_membership_array");
183 if (!prs_uint32("count", ps
, depth
, &array
->count
))
186 if (UNMARSHALLING(ps
)) {
187 array
->group_membership
= PRS_ALLOC_MEM(ps
, GROUP_MEMBERSHIP
, num
);
188 if (!array
->group_membership
) {
189 DEBUG(3, ("No memory available\n"));
194 for (i
=0; i
<num
; i
++) {
195 if (!pac_io_group_membership(desc
,
196 &array
->group_membership
[i
],
206 #if 0 /* Unused, replaced using an expanded net_io_user_info3() now - Guenther */
207 static BOOL
pac_io_pac_logon_info(const char *desc
, PAC_LOGON_INFO
*info
,
208 prs_struct
*ps
, int depth
)
215 prs_debug(ps
, depth
, desc
, "pac_io_pac_logon_info");
220 if (!prs_uint32("unknown", ps
, depth
, &garbage
)) /* 00081001 */
222 if (!prs_uint32("unknown", ps
, depth
, &garbage
)) /* cccccccc */
224 if (!prs_uint32("bufferlen", ps
, depth
, &garbage
))
226 if (!prs_uint32("bufferlenhi", ps
, depth
, &garbage
)) /* 00000000 */
229 if (!prs_uint32("pointer", ps
, depth
, &garbage
))
234 if (!smb_io_time("logon_time", &info
->logon_time
, ps
, depth
))
236 if (!smb_io_time("logoff_time", &info
->logoff_time
, ps
, depth
))
238 if (!smb_io_time("kickoff_time", &info
->kickoff_time
, ps
, depth
))
240 if (!smb_io_time("pass_last_set_time", &info
->pass_last_set_time
,
243 if (!smb_io_time("pass_can_change_time", &info
->pass_can_change_time
,
246 if (!smb_io_time("pass_must_change_time", &info
->pass_must_change_time
,
250 if (!smb_io_unihdr("hdr_user_name", &info
->hdr_user_name
, ps
, depth
))
252 if (!smb_io_unihdr("hdr_full_name", &info
->hdr_full_name
, ps
, depth
))
254 if (!smb_io_unihdr("hdr_logon_script", &info
->hdr_logon_script
,
257 if (!smb_io_unihdr("hdr_profile_path", &info
->hdr_profile_path
,
260 if (!smb_io_unihdr("hdr_home_dir", &info
->hdr_home_dir
, ps
, depth
))
262 if (!smb_io_unihdr("hdr_dir_drive", &info
->hdr_dir_drive
, ps
, depth
))
265 if (!prs_uint16("logon_count", ps
, depth
, &info
->logon_count
))
267 if (!prs_uint16("bad_password_count", ps
, depth
, &info
->bad_password_count
))
269 if (!prs_uint32("user_rid", ps
, depth
, &info
->user_rid
))
271 if (!prs_uint32("group_rid", ps
, depth
, &info
->group_rid
))
273 if (!prs_uint32("group_count", ps
, depth
, &info
->group_count
))
275 /* I haven't seen this contain anything yet, but when it does
276 we will have to make sure we decode the contents in the middle
277 all the unistr2s ... */
278 if (!prs_uint32("group_mem_ptr", ps
, depth
,
279 &info
->group_membership_ptr
))
281 if (!prs_uint32("user_flags", ps
, depth
, &info
->user_flags
))
284 if (!prs_uint8s(False
, "session_key", ps
, depth
, info
->session_key
, 16))
287 if (!smb_io_unihdr("hdr_dom_controller",
288 &info
->hdr_dom_controller
, ps
, depth
))
290 if (!smb_io_unihdr("hdr_dom_name", &info
->hdr_dom_name
, ps
, depth
))
293 /* this should be followed, but just get ptr for now */
294 if (!prs_uint32("ptr_dom_sid", ps
, depth
, &info
->ptr_dom_sid
))
297 if (!prs_uint8s(False
, "lm_session_key", ps
, depth
, info
->lm_session_key
, 8))
300 if (!prs_uint32("acct_flags", ps
, depth
, &info
->acct_flags
))
303 for (i
= 0; i
< 7; i
++)
305 if (!prs_uint32("unkown", ps
, depth
, &info
->unknown
[i
])) /* unknown */
309 if (!prs_uint32("sid_count", ps
, depth
, &info
->sid_count
))
311 if (!prs_uint32("ptr_extra_sids", ps
, depth
, &info
->ptr_extra_sids
))
313 if (!prs_uint32("ptr_res_group_dom_sid", ps
, depth
,
314 &info
->ptr_res_group_dom_sid
))
316 if (!prs_uint32("res_group_count", ps
, depth
, &info
->res_group_count
))
318 if (!prs_uint32("ptr_res_groups", ps
, depth
, &info
->ptr_res_groups
))
321 if(!smb_io_unistr2("uni_user_name", &info
->uni_user_name
,
322 info
->hdr_user_name
.buffer
, ps
, depth
))
324 if(!smb_io_unistr2("uni_full_name", &info
->uni_full_name
,
325 info
->hdr_full_name
.buffer
, ps
, depth
))
327 if(!smb_io_unistr2("uni_logon_script", &info
->uni_logon_script
,
328 info
->hdr_logon_script
.buffer
, ps
, depth
))
330 if(!smb_io_unistr2("uni_profile_path", &info
->uni_profile_path
,
331 info
->hdr_profile_path
.buffer
, ps
, depth
))
333 if(!smb_io_unistr2("uni_home_dir", &info
->uni_home_dir
,
334 info
->hdr_home_dir
.buffer
, ps
, depth
))
336 if(!smb_io_unistr2("uni_dir_drive", &info
->uni_dir_drive
,
337 info
->hdr_dir_drive
.buffer
, ps
, depth
))
340 if (info
->group_membership_ptr
) {
341 if (!pac_io_group_membership_array("group membership",
349 if(!smb_io_unistr2("uni_dom_controller", &info
->uni_dom_controller
,
350 info
->hdr_dom_controller
.buffer
, ps
, depth
))
352 if(!smb_io_unistr2("uni_dom_name", &info
->uni_dom_name
,
353 info
->hdr_dom_name
.buffer
, ps
, depth
))
356 if(info
->ptr_dom_sid
)
357 if(!smb_io_dom_sid2("dom_sid", &info
->dom_sid
, ps
, depth
))
361 if (info
->sid_count
&& info
->ptr_extra_sids
)
362 if (!pac_io_krb_sid_and_attr_array("extra_sids",
368 if (info
->ptr_res_group_dom_sid
)
369 if (!smb_io_dom_sid2("res_group_dom_sid",
370 &info
->res_group_dom_sid
, ps
, depth
))
373 if (info
->ptr_res_groups
) {
375 if (!(info
->user_flgs
& LOGON_RESOURCE_GROUPS
)) {
376 DEBUG(0,("user_flgs attribute does not have LOGON_RESOURCE_GROUPS\n"));
380 if (!pac_io_group_membership_array("res group membership",
382 info
->res_group_count
,
391 static BOOL
pac_io_pac_logon_info(const char *desc
, PAC_LOGON_INFO
*info
,
392 prs_struct
*ps
, int depth
)
395 BOOL kerb_validation_info
= True
;
400 prs_debug(ps
, depth
, desc
, "pac_io_pac_logon_info");
405 if (!prs_uint32("unknown", ps
, depth
, &garbage
)) /* 00081001 */
407 if (!prs_uint32("unknown", ps
, depth
, &garbage
)) /* cccccccc */
409 if (!prs_uint32("bufferlen", ps
, depth
, &garbage
))
411 if (!prs_uint32("bufferlenhi", ps
, depth
, &garbage
)) /* 00000000 */
414 if(!net_io_user_info3("", &info
->info3
, ps
, depth
, 3, kerb_validation_info
))
417 if (info
->info3
.ptr_res_group_dom_sid
) {
418 if (!smb_io_dom_sid2("res_group_dom_sid",
419 &info
->res_group_dom_sid
, ps
, depth
))
423 if (info
->info3
.ptr_res_groups
) {
425 if (!(info
->info3
.user_flgs
& LOGON_RESOURCE_GROUPS
)) {
426 DEBUG(0,("user_flgs attribute does not have LOGON_RESOURCE_GROUPS\n"));
430 if (!pac_io_group_membership_array("res group membership",
432 info
->info3
.res_group_count
,
442 static BOOL
pac_io_pac_signature_data(const char *desc
,
443 PAC_SIGNATURE_DATA
*data
, uint32 length
,
444 prs_struct
*ps
, int depth
)
446 uint32 siglen
= length
- sizeof(uint32
);
447 prs_debug(ps
, depth
, desc
, "pac_io_pac_signature_data");
455 if (!prs_uint32("type", ps
, depth
, &data
->type
))
458 if (UNMARSHALLING(ps
) && length
) {
459 data
->signature
.buffer
= PRS_ALLOC_MEM(ps
, uint8
, siglen
);
460 if (!data
->signature
.buffer
) {
461 DEBUG(3, ("No memory available\n"));
466 data
->signature
.buf_len
= siglen
;
468 if (!prs_uint8s(False
, "signature", ps
, depth
, data
->signature
.buffer
, data
->signature
.buf_len
))
475 static BOOL
pac_io_pac_info_hdr_ctr(const char *desc
, PAC_BUFFER
*hdr
,
476 prs_struct
*ps
, int depth
)
481 prs_debug(ps
, depth
, desc
, "pac_io_pac_info_hdr_ctr");
487 if (hdr
->offset
!= prs_offset(ps
)) {
488 DEBUG(5,("offset in header(x%x) and data(x%x) do not match, correcting\n",
489 hdr
->offset
, prs_offset(ps
)));
490 prs_set_offset(ps
, hdr
->offset
);
493 if (UNMARSHALLING(ps
) && hdr
->size
> 0) {
494 hdr
->ctr
= PRS_ALLOC_MEM(ps
, PAC_INFO_CTR
, 1);
496 DEBUG(3, ("No memory available\n"));
502 case PAC_TYPE_LOGON_INFO
:
503 DEBUG(5, ("PAC_TYPE_LOGON_INFO\n"));
504 if (UNMARSHALLING(ps
))
505 hdr
->ctr
->pac
.logon_info
= PRS_ALLOC_MEM(ps
, PAC_LOGON_INFO
, 1);
506 if (!hdr
->ctr
->pac
.logon_info
) {
507 DEBUG(3, ("No memory available\n"));
510 if (!pac_io_pac_logon_info(desc
, hdr
->ctr
->pac
.logon_info
,
515 case PAC_TYPE_SERVER_CHECKSUM
:
516 DEBUG(5, ("PAC_TYPE_SERVER_CHECKSUM\n"));
517 if (UNMARSHALLING(ps
))
518 hdr
->ctr
->pac
.srv_cksum
= PRS_ALLOC_MEM(ps
, PAC_SIGNATURE_DATA
, 1);
519 if (!hdr
->ctr
->pac
.srv_cksum
) {
520 DEBUG(3, ("No memory available\n"));
523 if (!pac_io_pac_signature_data(desc
, hdr
->ctr
->pac
.srv_cksum
,
524 hdr
->size
, ps
, depth
))
528 case PAC_TYPE_PRIVSVR_CHECKSUM
:
529 DEBUG(5, ("PAC_TYPE_PRIVSVR_CHECKSUM\n"));
530 if (UNMARSHALLING(ps
))
531 hdr
->ctr
->pac
.privsrv_cksum
= PRS_ALLOC_MEM(ps
, PAC_SIGNATURE_DATA
, 1);
532 if (!hdr
->ctr
->pac
.privsrv_cksum
) {
533 DEBUG(3, ("No memory available\n"));
536 if (!pac_io_pac_signature_data(desc
,
537 hdr
->ctr
->pac
.privsrv_cksum
,
538 hdr
->size
, ps
, depth
))
542 case PAC_TYPE_LOGON_NAME
:
543 DEBUG(5, ("PAC_TYPE_LOGON_NAME\n"));
544 if (UNMARSHALLING(ps
))
545 hdr
->ctr
->pac
.logon_name
= PRS_ALLOC_MEM(ps
, PAC_LOGON_NAME
, 1);
546 if (!hdr
->ctr
->pac
.logon_name
) {
547 DEBUG(3, ("No memory available\n"));
550 if (!pac_io_logon_name(desc
, hdr
->ctr
->pac
.logon_name
,
556 /* dont' know, so we need to skip it */
557 DEBUG(3, ("unknown PAC type %d\n", hdr
->type
));
558 prs_set_offset(ps
, prs_offset(ps
) + hdr
->size
);
563 if (!prs_uint32("pad", ps
, depth
, &hdr
->pad
))
569 static BOOL
pac_io_pac_info_hdr(const char *desc
, PAC_BUFFER
*hdr
,
570 prs_struct
*ps
, int depth
)
575 prs_debug(ps
, depth
, desc
, "pac_io_pac_info_hdr");
580 if (!prs_uint32("type", ps
, depth
, &hdr
->type
))
582 if (!prs_uint32("size", ps
, depth
, &hdr
->size
))
584 if (!prs_uint32("offset", ps
, depth
, &hdr
->offset
))
586 if (!prs_uint32("offsethi", ps
, depth
, &hdr
->offsethi
))
592 static BOOL
pac_io_pac_data(const char *desc
, PAC_DATA
*data
,
593 prs_struct
*ps
, int depth
)
600 prs_debug(ps
, depth
, desc
, "pac_io_pac_data");
605 if (!prs_uint32("num_buffers", ps
, depth
, &data
->num_buffers
))
607 if (!prs_uint32("version", ps
, depth
, &data
->version
))
610 if (UNMARSHALLING(ps
) && data
->num_buffers
> 0) {
611 if ((data
->pac_buffer
= PRS_ALLOC_MEM(ps
, PAC_BUFFER
, data
->num_buffers
)) == NULL
) {
616 for (i
=0; i
<data
->num_buffers
; i
++) {
617 if (!pac_io_pac_info_hdr(desc
, &data
->pac_buffer
[i
], ps
,
622 for (i
=0; i
<data
->num_buffers
; i
++) {
623 if (!pac_io_pac_info_hdr_ctr(desc
, &data
->pac_buffer
[i
],
631 static NTSTATUS
check_pac_checksum(TALLOC_CTX
*mem_ctx
,
633 PAC_SIGNATURE_DATA
*sig
,
634 krb5_context context
,
635 krb5_keyblock
*keyblock
)
639 krb5_keyusage usage
= 0;
641 smb_krb5_checksum_from_pac_sig(&cksum
, sig
);
643 #ifdef HAVE_KRB5_KU_OTHER_CKSUM /* Heimdal */
644 usage
= KRB5_KU_OTHER_CKSUM
;
645 #elif defined(HAVE_KRB5_KEYUSAGE_APP_DATA_CKSUM) /* MIT */
646 usage
= KRB5_KEYUSAGE_APP_DATA_CKSUM
;
648 #error UNKNOWN_KRB5_KEYUSAGE
651 ret
= smb_krb5_verify_checksum(context
,
659 DEBUG(2,("check_pac_checksum: PAC Verification failed: %s (%d)\n",
660 error_message(ret
), ret
));
661 return NT_STATUS_ACCESS_DENIED
;
667 static NTSTATUS
parse_pac_data(TALLOC_CTX
*mem_ctx
, DATA_BLOB
*pac_data_blob
, PAC_DATA
*pac_data
)
672 if (!prs_init(&ps
, pac_data_blob
->length
, mem_ctx
, UNMARSHALL
))
673 return NT_STATUS_NO_MEMORY
;
675 if (!prs_copy_data_in(&ps
, (char *)pac_data_blob
->data
, pac_data_blob
->length
))
676 return NT_STATUS_INVALID_PARAMETER
;
678 prs_set_offset(&ps
, 0);
680 my_pac
= TALLOC_ZERO_P(mem_ctx
, PAC_DATA
);
681 if (!pac_io_pac_data("pac data", my_pac
, &ps
, 0))
682 return NT_STATUS_INVALID_PARAMETER
;
691 /* just for debugging, will be removed later - Guenther */
692 char *pac_group_attr_string(uint32 attr
)
699 if (attr
& SE_GROUP_MANDATORY
) fstrcat(name
, "SE_GROUP_MANDATORY ");
700 if (attr
& SE_GROUP_ENABLED_BY_DEFAULT
) fstrcat(name
, "SE_GROUP_ENABLED_BY_DEFAULT ");
701 if (attr
& SE_GROUP_ENABLED
) fstrcat(name
, "SE_GROUP_ENABLED ");
702 if (attr
& SE_GROUP_OWNER
) fstrcat(name
, "SE_GROUP_OWNER ");
703 if (attr
& SE_GROUP_USE_FOR_DENY_ONLY
) fstrcat(name
, "SE_GROUP_USE_FOR_DENY_ONLY ");
704 if (attr
& SE_GROUP_LOGON_ID
) fstrcat(name
, "SE_GROUP_LOGON_ID ");
705 if (attr
& SE_GROUP_RESOURCE
) fstrcat(name
, "SE_GROUP_RESOURCE ");
707 return SMB_STRDUP(name
);
710 /* just for debugging, will be removed later - Guenther */
711 static void dump_pac_logon_info(PAC_LOGON_INFO
*logon_info
) {
713 DOM_SID dom_sid
, res_group_dom_sid
;
716 uint32 user_flgs
= logon_info
->info3
.user_flgs
;
718 if (logon_info
->info3
.ptr_res_group_dom_sid
) {
719 sid_copy(&res_group_dom_sid
, &logon_info
->res_group_dom_sid
.sid
);
721 sid_copy(&dom_sid
, &logon_info
->info3
.dom_sid
.sid
);
723 DEBUG(10,("The PAC:\n"));
725 DEBUGADD(10,("\tUser Flags: 0x%x (%d)\n", user_flgs
, user_flgs
));
726 if (user_flgs
& LOGON_EXTRA_SIDS
)
727 DEBUGADD(10,("\tUser Flags: LOGON_EXTRA_SIDS 0x%x (%d)\n", LOGON_EXTRA_SIDS
, LOGON_EXTRA_SIDS
));
728 if (user_flgs
& LOGON_RESOURCE_GROUPS
)
729 DEBUGADD(10,("\tUser Flags: LOGON_RESOURCE_GROUPS 0x%x (%d)\n", LOGON_RESOURCE_GROUPS
, LOGON_RESOURCE_GROUPS
));
730 DEBUGADD(10,("\tUser SID: %s-%d\n", sid_string_static(&dom_sid
), logon_info
->info3
.user_rid
));
731 DEBUGADD(10,("\tGroup SID: %s-%d\n", sid_string_static(&dom_sid
), logon_info
->info3
.group_rid
));
733 DEBUGADD(10,("\tGroup Membership (Global and Universal Groups of own domain):\n"));
734 for (i
= 0; i
< logon_info
->info3
.num_groups
; i
++) {
735 attr_string
= pac_group_attr_string(logon_info
->info3
.gids
[i
].attr
);
736 DEBUGADD(10,("\t\t%d: sid: %s-%d\n\t\t attr: 0x%x == %s\n",
737 i
, sid_string_static(&dom_sid
),
738 logon_info
->info3
.gids
[i
].g_rid
,
739 logon_info
->info3
.gids
[i
].attr
,
741 SAFE_FREE(attr_string
);
744 DEBUGADD(10,("\tGroup Membership (Domain Local Groups and Groups from Trusted Domains):\n"));
745 for (i
= 0; i
< logon_info
->info3
.num_other_sids
; i
++) {
746 attr_string
= pac_group_attr_string(logon_info
->info3
.other_sids_attrib
[i
]);
747 DEBUGADD(10,("\t\t%d: sid: %s\n\t\t attr: 0x%x == %s\n",
748 i
, sid_string_static(&logon_info
->info3
.other_sids
[i
].sid
),
749 logon_info
->info3
.other_sids_attrib
[i
],
751 SAFE_FREE(attr_string
);
754 DEBUGADD(10,("\tGroup Membership (Ressource Groups (SID History ?)):\n"));
755 for (i
= 0; i
< logon_info
->info3
.res_group_count
; i
++) {
756 attr_string
= pac_group_attr_string(logon_info
->res_groups
.group_membership
[i
].attrs
);
757 DEBUGADD(10,("\t\t%d: sid: %s-%d\n\t\t attr: 0x%x == %s\n",
758 i
, sid_string_static(&res_group_dom_sid
),
759 logon_info
->res_groups
.group_membership
[i
].rid
,
760 logon_info
->res_groups
.group_membership
[i
].attrs
,
762 SAFE_FREE(attr_string
);
766 NTSTATUS
decode_pac_data(TALLOC_CTX
*mem_ctx
,
767 DATA_BLOB
*pac_data_blob
,
768 krb5_context context
,
769 krb5_keyblock
*service_keyblock
,
770 krb5_const_principal client_principal
,
775 DATA_BLOB modified_pac_blob
;
779 PAC_SIGNATURE_DATA
*srv_sig
= NULL
;
780 PAC_SIGNATURE_DATA
*kdc_sig
= NULL
;
781 PAC_LOGON_NAME
*logon_name
= NULL
;
782 PAC_LOGON_INFO
*logon_info
= NULL
;
783 krb5_principal client_principal_pac
= NULL
;
784 NTTIME tgs_authtime_nttime
;
785 int i
, srv_sig_pos
= 0, kdc_sig_pos
= 0;
790 my_pac
= talloc(mem_ctx
, PAC_DATA
);
792 return NT_STATUS_NO_MEMORY
;
795 nt_status
= parse_pac_data(mem_ctx
, pac_data_blob
, my_pac
);
796 if (!NT_STATUS_IS_OK(nt_status
)) {
797 DEBUG(0,("decode_pac_data: failed to parse PAC\n"));
801 modified_pac_blob
= data_blob_talloc(mem_ctx
, pac_data_blob
->data
, pac_data_blob
->length
);
803 if (my_pac
->num_buffers
< 4) {
804 nt_status
= NT_STATUS_INVALID_PARAMETER
;
808 /* store signatures */
809 for (i
=0; i
< my_pac
->num_buffers
; i
++) {
811 switch (my_pac
->pac_buffer
[i
].type
) {
813 case PAC_TYPE_SERVER_CHECKSUM
:
814 if (!my_pac
->pac_buffer
[i
].ctr
->pac
.srv_cksum
) {
818 srv_sig
= my_pac
->pac_buffer
[i
].ctr
->pac
.srv_cksum
;
820 /* get position of signature buffer */
821 srv_sig_pos
= my_pac
->pac_buffer
[i
].offset
;
822 srv_sig_pos
+= sizeof(uint32
);
826 case PAC_TYPE_PRIVSVR_CHECKSUM
:
827 if (!my_pac
->pac_buffer
[i
].ctr
->pac
.privsrv_cksum
) {
831 kdc_sig
= my_pac
->pac_buffer
[i
].ctr
->pac
.privsrv_cksum
;
833 /* get position of signature buffer */
834 kdc_sig_pos
= my_pac
->pac_buffer
[i
].offset
;
835 kdc_sig_pos
+= sizeof(uint32
);
839 case PAC_TYPE_LOGON_NAME
:
840 if (!my_pac
->pac_buffer
[i
].ctr
->pac
.logon_name
) {
844 logon_name
= my_pac
->pac_buffer
[i
].ctr
->pac
.logon_name
;
847 case PAC_TYPE_LOGON_INFO
:
848 if (!my_pac
->pac_buffer
[i
].ctr
->pac
.logon_info
) {
852 logon_info
= my_pac
->pac_buffer
[i
].ctr
->pac
.logon_info
;
858 if (!srv_sig
|| !kdc_sig
|| !logon_name
|| !logon_info
) {
859 nt_status
= NT_STATUS_INVALID_PARAMETER
;
863 /* zero PAC_SIGNATURE_DATA signature buffer */
864 memset(&modified_pac_blob
.data
[srv_sig_pos
], '\0', srv_sig
->signature
.buf_len
);
865 memset(&modified_pac_blob
.data
[kdc_sig_pos
], '\0', kdc_sig
->signature
.buf_len
);
867 /* check server signature */
868 nt_status
= check_pac_checksum(mem_ctx
, modified_pac_blob
, srv_sig
, context
, service_keyblock
);
869 if (!NT_STATUS_IS_OK(nt_status
)) {
870 DEBUG(0,("decode_pac_data: failed to verify PAC server signature\n"));
874 /* Convert to NT time, so as not to loose accuracy in comparison */
875 unix_to_nt_time(&tgs_authtime_nttime
, tgs_authtime
);
877 if (!nt_time_equals(&tgs_authtime_nttime
, &logon_name
->logon_time
)) {
879 DEBUG(2,("decode_pac_data: Logon time mismatch between ticket and PAC!\n"));
880 DEBUGADD(2, ("decode_pac_data: PAC: %s\n",
881 http_timestring(nt_time_to_unix(&logon_name
->logon_time
))));
882 DEBUGADD(2, ("decode_pac_data: Ticket: %s\n",
883 http_timestring(nt_time_to_unix(&tgs_authtime_nttime
))));
885 nt_status
= NT_STATUS_ACCESS_DENIED
;
889 if (!logon_name
->len
) {
890 DEBUG(2,("decode_pac_data: No Logon Name available\n"));
891 nt_status
= NT_STATUS_INVALID_PARAMETER
;
894 rpcstr_pull(username
, logon_name
->username
, sizeof(username
), -1, STR_TERMINATE
);
896 ret
= smb_krb5_parse_name_norealm(context
, username
, &client_principal_pac
);
898 DEBUG(2,("decode_pac_data: Could not parse name from incoming PAC: [%s]: %s\n",
899 username
, error_message(ret
)));
900 nt_status
= NT_STATUS_INVALID_PARAMETER
;
904 if (!smb_krb5_principal_compare_any_realm(context
, client_principal
, client_principal_pac
)) {
905 DEBUG(2,("decode_pac_data: Name in PAC [%s] does not match principal name in ticket\n",
907 nt_status
= NT_STATUS_ACCESS_DENIED
;
911 DEBUG(10,("Successfully validated Kerberos PAC\n"));
913 dump_pac_logon_info(logon_info
);
917 nt_status
= NT_STATUS_OK
;
920 if (client_principal_pac
) {
921 krb5_free_principal(context
, client_principal_pac
);
927 PAC_LOGON_INFO
*get_logon_info_from_pac(PAC_DATA
*pac_data
)
929 PAC_LOGON_INFO
*logon_info
= NULL
;
932 for (i
=0; i
< pac_data
->num_buffers
; i
++) {
934 if (pac_data
->pac_buffer
[i
].type
!= PAC_TYPE_LOGON_INFO
)
937 logon_info
= pac_data
->pac_buffer
[i
].ctr
->pac
.logon_info
;