r17915: Saturn fixes
[Samba/gbeck.git] / source / libads / authdata.c
blobc3c160dafbadae28d71a39fcdbf7a651e6871170
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 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;
130 for (i=0; i<num; i++) {
131 if (!pac_io_krb_attrs(desc,
132 &array->krb_sid_and_attrs[i],
133 ps, depth))
134 return False;
137 for (i=0; i<num; i++) {
138 if (!pac_io_krb_sids(desc,
139 &array->krb_sid_and_attrs[i],
140 ps, depth))
141 return False;
145 return True;
148 #endif
150 static BOOL pac_io_group_membership(const char *desc,
151 GROUP_MEMBERSHIP *membership,
152 prs_struct *ps, int depth)
154 if (NULL == membership)
155 return False;
157 prs_debug(ps, depth, desc, "pac_io_group_membership");
158 depth++;
160 if (!prs_uint32("rid", ps, depth, &membership->rid))
161 return False;
162 if (!prs_uint32("attrs", ps, depth, &membership->attrs))
163 return False;
165 return True;
169 static BOOL pac_io_group_membership_array(const char *desc,
170 GROUP_MEMBERSHIP_ARRAY *array,
171 uint32 num,
172 prs_struct *ps, int depth)
174 int i;
176 if (NULL == array)
177 return False;
179 prs_debug(ps, depth, desc, "pac_io_group_membership_array");
180 depth++;
183 if (!prs_uint32("count", ps, depth, &array->count))
184 return False;
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"));
190 return False;
194 for (i=0; i<num; i++) {
195 if (!pac_io_group_membership(desc,
196 &array->group_membership[i],
197 ps, depth))
198 return False;
202 return True;
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)
210 uint32 garbage, i;
212 if (NULL == info)
213 return False;
215 prs_debug(ps, depth, desc, "pac_io_pac_logon_info");
216 depth++;
218 if (!prs_align(ps))
219 return False;
220 if (!prs_uint32("unknown", ps, depth, &garbage)) /* 00081001 */
221 return False;
222 if (!prs_uint32("unknown", ps, depth, &garbage)) /* cccccccc */
223 return False;
224 if (!prs_uint32("bufferlen", ps, depth, &garbage))
225 return False;
226 if (!prs_uint32("bufferlenhi", ps, depth, &garbage)) /* 00000000 */
227 return False;
229 if (!prs_uint32("pointer", ps, depth, &garbage))
230 return False;
232 if (!prs_align(ps))
233 return False;
234 if (!smb_io_time("logon_time", &info->logon_time, ps, depth))
235 return False;
236 if (!smb_io_time("logoff_time", &info->logoff_time, ps, depth))
237 return False;
238 if (!smb_io_time("kickoff_time", &info->kickoff_time, ps, depth))
239 return False;
240 if (!smb_io_time("pass_last_set_time", &info->pass_last_set_time,
241 ps, depth))
242 return False;
243 if (!smb_io_time("pass_can_change_time", &info->pass_can_change_time,
244 ps, depth))
245 return False;
246 if (!smb_io_time("pass_must_change_time", &info->pass_must_change_time,
247 ps, depth))
248 return False;
250 if (!smb_io_unihdr("hdr_user_name", &info->hdr_user_name, ps, depth))
251 return False;
252 if (!smb_io_unihdr("hdr_full_name", &info->hdr_full_name, ps, depth))
253 return False;
254 if (!smb_io_unihdr("hdr_logon_script", &info->hdr_logon_script,
255 ps, depth))
256 return False;
257 if (!smb_io_unihdr("hdr_profile_path", &info->hdr_profile_path,
258 ps, depth))
259 return False;
260 if (!smb_io_unihdr("hdr_home_dir", &info->hdr_home_dir, ps, depth))
261 return False;
262 if (!smb_io_unihdr("hdr_dir_drive", &info->hdr_dir_drive, ps, depth))
263 return False;
265 if (!prs_uint16("logon_count", ps, depth, &info->logon_count))
266 return False;
267 if (!prs_uint16("bad_password_count", ps, depth, &info->bad_password_count))
268 return False;
269 if (!prs_uint32("user_rid", ps, depth, &info->user_rid))
270 return False;
271 if (!prs_uint32("group_rid", ps, depth, &info->group_rid))
272 return False;
273 if (!prs_uint32("group_count", ps, depth, &info->group_count))
274 return False;
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))
280 return False;
281 if (!prs_uint32("user_flags", ps, depth, &info->user_flags))
282 return False;
284 if (!prs_uint8s(False, "session_key", ps, depth, info->session_key, 16))
285 return False;
287 if (!smb_io_unihdr("hdr_dom_controller",
288 &info->hdr_dom_controller, ps, depth))
289 return False;
290 if (!smb_io_unihdr("hdr_dom_name", &info->hdr_dom_name, ps, depth))
291 return False;
293 /* this should be followed, but just get ptr for now */
294 if (!prs_uint32("ptr_dom_sid", ps, depth, &info->ptr_dom_sid))
295 return False;
297 if (!prs_uint8s(False, "lm_session_key", ps, depth, info->lm_session_key, 8))
298 return False;
300 if (!prs_uint32("acct_flags", ps, depth, &info->acct_flags))
301 return False;
303 for (i = 0; i < 7; i++)
305 if (!prs_uint32("unkown", ps, depth, &info->unknown[i])) /* unknown */
306 return False;
309 if (!prs_uint32("sid_count", ps, depth, &info->sid_count))
310 return False;
311 if (!prs_uint32("ptr_extra_sids", ps, depth, &info->ptr_extra_sids))
312 return False;
313 if (!prs_uint32("ptr_res_group_dom_sid", ps, depth,
314 &info->ptr_res_group_dom_sid))
315 return False;
316 if (!prs_uint32("res_group_count", ps, depth, &info->res_group_count))
317 return False;
318 if (!prs_uint32("ptr_res_groups", ps, depth, &info->ptr_res_groups))
319 return False;
321 if(!smb_io_unistr2("uni_user_name", &info->uni_user_name,
322 info->hdr_user_name.buffer, ps, depth))
323 return False;
324 if(!smb_io_unistr2("uni_full_name", &info->uni_full_name,
325 info->hdr_full_name.buffer, ps, depth))
326 return False;
327 if(!smb_io_unistr2("uni_logon_script", &info->uni_logon_script,
328 info->hdr_logon_script.buffer, ps, depth))
329 return False;
330 if(!smb_io_unistr2("uni_profile_path", &info->uni_profile_path,
331 info->hdr_profile_path.buffer, ps, depth))
332 return False;
333 if(!smb_io_unistr2("uni_home_dir", &info->uni_home_dir,
334 info->hdr_home_dir.buffer, ps, depth))
335 return False;
336 if(!smb_io_unistr2("uni_dir_drive", &info->uni_dir_drive,
337 info->hdr_dir_drive.buffer, ps, depth))
338 return False;
340 if (info->group_membership_ptr) {
341 if (!pac_io_group_membership_array("group membership",
342 &info->groups,
343 info->group_count,
344 ps, depth))
345 return False;
349 if(!smb_io_unistr2("uni_dom_controller", &info->uni_dom_controller,
350 info->hdr_dom_controller.buffer, ps, depth))
351 return False;
352 if(!smb_io_unistr2("uni_dom_name", &info->uni_dom_name,
353 info->hdr_dom_name.buffer, ps, depth))
354 return False;
356 if(info->ptr_dom_sid)
357 if(!smb_io_dom_sid2("dom_sid", &info->dom_sid, ps, depth))
358 return False;
361 if (info->sid_count && info->ptr_extra_sids)
362 if (!pac_io_krb_sid_and_attr_array("extra_sids",
363 &info->extra_sids,
364 info->sid_count,
365 ps, depth))
366 return False;
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))
371 return False;
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"));
377 /* return False; */
380 if (!pac_io_group_membership_array("res group membership",
381 &info->res_groups,
382 info->res_group_count,
383 ps, depth))
384 return False;
387 return True;
389 #endif
391 static BOOL pac_io_pac_logon_info(const char *desc, PAC_LOGON_INFO *info,
392 prs_struct *ps, int depth)
394 uint32 garbage;
395 BOOL kerb_validation_info = True;
397 if (NULL == info)
398 return False;
400 prs_debug(ps, depth, desc, "pac_io_pac_logon_info");
401 depth++;
403 if (!prs_align(ps))
404 return False;
405 if (!prs_uint32("unknown", ps, depth, &garbage)) /* 00081001 */
406 return False;
407 if (!prs_uint32("unknown", ps, depth, &garbage)) /* cccccccc */
408 return False;
409 if (!prs_uint32("bufferlen", ps, depth, &garbage))
410 return False;
411 if (!prs_uint32("bufferlenhi", ps, depth, &garbage)) /* 00000000 */
412 return False;
414 if(!net_io_user_info3("", &info->info3, ps, depth, 3, kerb_validation_info))
415 return False;
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))
420 return False;
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"));
427 /* return False; */
430 if (!pac_io_group_membership_array("res group membership",
431 &info->res_groups,
432 info->info3.res_group_count,
433 ps, depth))
434 return False;
437 return True;
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");
448 depth++;
450 if (data == NULL)
451 return False;
453 if (!prs_align(ps))
454 return False;
455 if (!prs_uint32("type", ps, depth, &data->type))
456 return False;
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"));
462 return False;
466 data->signature.buf_len = siglen;
468 if (!prs_uint8s(False, "signature", ps, depth, data->signature.buffer, data->signature.buf_len))
469 return False;
472 return True;
475 static BOOL pac_io_pac_info_hdr_ctr(const char *desc, PAC_BUFFER *hdr,
476 prs_struct *ps, int depth)
478 if (NULL == hdr)
479 return False;
481 prs_debug(ps, depth, desc, "pac_io_pac_info_hdr_ctr");
482 depth++;
484 if (!prs_align(ps))
485 return False;
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);
495 if (!hdr->ctr) {
496 DEBUG(3, ("No memory available\n"));
497 return False;
501 switch(hdr->type) {
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"));
508 return False;
510 if (!pac_io_pac_logon_info(desc, hdr->ctr->pac.logon_info,
511 ps, depth))
512 return False;
513 break;
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"));
521 return False;
523 if (!pac_io_pac_signature_data(desc, hdr->ctr->pac.srv_cksum,
524 hdr->size, ps, depth))
525 return False;
526 break;
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"));
534 return False;
536 if (!pac_io_pac_signature_data(desc,
537 hdr->ctr->pac.privsrv_cksum,
538 hdr->size, ps, depth))
539 return False;
540 break;
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"));
548 return False;
550 if (!pac_io_logon_name(desc, hdr->ctr->pac.logon_name,
551 ps, depth))
552 return False;
553 break;
555 default:
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);
561 #if 0
562 /* obscure pad */
563 if (!prs_uint32("pad", ps, depth, &hdr->pad))
564 return False;
565 #endif
566 return True;
569 static BOOL pac_io_pac_info_hdr(const char *desc, PAC_BUFFER *hdr,
570 prs_struct *ps, int depth)
572 if (NULL == hdr)
573 return False;
575 prs_debug(ps, depth, desc, "pac_io_pac_info_hdr");
576 depth++;
578 if (!prs_align(ps))
579 return False;
580 if (!prs_uint32("type", ps, depth, &hdr->type))
581 return False;
582 if (!prs_uint32("size", ps, depth, &hdr->size))
583 return False;
584 if (!prs_uint32("offset", ps, depth, &hdr->offset))
585 return False;
586 if (!prs_uint32("offsethi", ps, depth, &hdr->offsethi))
587 return False;
589 return True;
592 static BOOL pac_io_pac_data(const char *desc, PAC_DATA *data,
593 prs_struct *ps, int depth)
595 int i;
597 if (NULL == data)
598 return False;
600 prs_debug(ps, depth, desc, "pac_io_pac_data");
601 depth++;
603 if (!prs_align(ps))
604 return False;
605 if (!prs_uint32("num_buffers", ps, depth, &data->num_buffers))
606 return False;
607 if (!prs_uint32("version", ps, depth, &data->version))
608 return False;
610 if (UNMARSHALLING(ps) && data->num_buffers > 0) {
611 if ((data->pac_buffer = PRS_ALLOC_MEM(ps, PAC_BUFFER, data->num_buffers)) == NULL) {
612 return False;
616 for (i=0; i<data->num_buffers; i++) {
617 if (!pac_io_pac_info_hdr(desc, &data->pac_buffer[i], ps,
618 depth))
619 return False;
622 for (i=0; i<data->num_buffers; i++) {
623 if (!pac_io_pac_info_hdr_ctr(desc, &data->pac_buffer[i],
624 ps, depth))
625 return False;
628 return True;
631 static NTSTATUS check_pac_checksum(TALLOC_CTX *mem_ctx,
632 DATA_BLOB pac_data,
633 PAC_SIGNATURE_DATA *sig,
634 krb5_context context,
635 krb5_keyblock *keyblock)
637 krb5_error_code ret;
638 krb5_checksum cksum;
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;
647 #else
648 #error UNKNOWN_KRB5_KEYUSAGE
649 #endif
651 ret = smb_krb5_verify_checksum(context,
652 keyblock,
653 usage,
654 &cksum,
655 pac_data.data,
656 pac_data.length);
658 if (ret) {
659 DEBUG(2,("check_pac_checksum: PAC Verification failed: %s (%d)\n",
660 error_message(ret), ret));
661 return NT_STATUS_ACCESS_DENIED;
664 return NT_STATUS_OK;
667 static NTSTATUS parse_pac_data(TALLOC_CTX *mem_ctx, DATA_BLOB *pac_data_blob, PAC_DATA *pac_data)
669 prs_struct ps;
670 PAC_DATA *my_pac;
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;
684 prs_mem_free(&ps);
686 *pac_data = *my_pac;
688 return NT_STATUS_OK;
691 /* just for debugging, will be removed later - Guenther */
692 char *pac_group_attr_string(uint32 attr)
694 fstring name = "";
696 if (!attr)
697 return NULL;
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;
714 int i;
715 char *attr_string;
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,
740 attr_string));
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],
750 attr_string));
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,
761 attr_string));
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,
771 time_t tgs_authtime,
772 PAC_DATA **pac_data)
775 DATA_BLOB modified_pac_blob;
776 PAC_DATA *my_pac;
777 NTSTATUS nt_status;
778 krb5_error_code ret;
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;
786 fstring username;
788 *pac_data = NULL;
790 my_pac = talloc(mem_ctx, PAC_DATA);
791 if (!my_pac) {
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"));
798 return nt_status;
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;
805 goto out;
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) {
815 break;
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);
824 break;
826 case PAC_TYPE_PRIVSVR_CHECKSUM:
827 if (!my_pac->pac_buffer[i].ctr->pac.privsrv_cksum) {
828 break;
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);
837 break;
839 case PAC_TYPE_LOGON_NAME:
840 if (!my_pac->pac_buffer[i].ctr->pac.logon_name) {
841 break;
844 logon_name = my_pac->pac_buffer[i].ctr->pac.logon_name;
845 break;
847 case PAC_TYPE_LOGON_INFO:
848 if (!my_pac->pac_buffer[i].ctr->pac.logon_info) {
849 break;
852 logon_info = my_pac->pac_buffer[i].ctr->pac.logon_info;
853 break;
858 if (!srv_sig || !kdc_sig || !logon_name || !logon_info) {
859 nt_status = NT_STATUS_INVALID_PARAMETER;
860 goto out;
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"));
871 goto out;
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;
886 goto out;
889 if (!logon_name->len) {
890 DEBUG(2,("decode_pac_data: No Logon Name available\n"));
891 nt_status = NT_STATUS_INVALID_PARAMETER;
892 goto out;
894 rpcstr_pull(username, logon_name->username, sizeof(username), logon_name->len, 0);
896 ret = smb_krb5_parse_name_norealm(context, username, &client_principal_pac);
897 if (ret) {
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;
901 goto out;
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",
906 username));
907 nt_status = NT_STATUS_ACCESS_DENIED;
908 goto out;
911 DEBUG(10,("Successfully validated Kerberos PAC\n"));
913 dump_pac_logon_info(logon_info);
915 *pac_data = my_pac;
917 nt_status = NT_STATUS_OK;
919 out:
920 if (client_principal_pac) {
921 krb5_free_principal(context, client_principal_pac);
924 return nt_status;
927 PAC_LOGON_INFO *get_logon_info_from_pac(PAC_DATA *pac_data)
929 PAC_LOGON_INFO *logon_info = NULL;
930 int i;
932 for (i=0; i < pac_data->num_buffers; i++) {
934 if (pac_data->pac_buffer[i].type != PAC_TYPE_LOGON_INFO)
935 continue;
937 logon_info = pac_data->pac_buffer[i].ctr->pac.logon_info;
938 break;
940 return logon_info;
943 #endif