source: trunk/samba-3.0.25pre1/source/libads/authdata.c@ 1

Last change on this file since 1 was 1, checked in by Paul Smedley, 18 years ago

Initial code import

File size: 25.0 KB
Line 
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
10
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24*/
25
26#include "includes.h"
27
28#ifdef HAVE_KRB5
29
30static BOOL pac_io_logon_name(const char *desc, PAC_LOGON_NAME *logon_name,
31 prs_struct *ps, int depth)
32{
33 if (NULL == logon_name)
34 return False;
35
36 prs_debug(ps, depth, desc, "pac_io_logon_name");
37 depth++;
38
39 if (!smb_io_time("logon_time", &logon_name->logon_time, ps, depth))
40 return False;
41
42 if (!prs_uint16("len", ps, depth, &logon_name->len))
43 return False;
44
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. */
48
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;
54 }
55 }
56
57 if (!prs_uint8s(True, "name", ps, depth, logon_name->username, logon_name->len))
58 return False;
59
60 return True;
61}
62
63#if 0 /* Unused (handled now in net_io_user_info3()) - Guenther */
64static BOOL pac_io_krb_sids(const char *desc, KRB_SID_AND_ATTRS *sid_and_attr,
65 prs_struct *ps, int depth)
66{
67 if (NULL == sid_and_attr)
68 return False;
69
70 prs_debug(ps, depth, desc, "pac_io_krb_sids");
71 depth++;
72
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;
78 }
79 }
80
81 if(!smb_io_dom_sid2("sid", sid_and_attr->sid, ps, depth))
82 return False;
83
84 return True;
85}
86
87
88static BOOL pac_io_krb_attrs(const char *desc, KRB_SID_AND_ATTRS *sid_and_attr,
89 prs_struct *ps, int depth)
90{
91 if (NULL == sid_and_attr)
92 return False;
93
94 prs_debug(ps, depth, desc, "pac_io_krb_attrs");
95 depth++;
96
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;
101
102 return True;
103}
104
105static 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)
109{
110 int i;
111
112 if (NULL == array)
113 return False;
114
115 prs_debug(ps, depth, desc, "pac_io_krb_sid_and_attr_array");
116 depth++;
117
118
119 if (!prs_uint32("count", ps, depth, &array->count))
120 return False;
121
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;
127 }
128 }
129
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;
135
136 }
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;
142
143 }
144
145 return True;
146
147}
148#endif
149
150static BOOL pac_io_group_membership(const char *desc,
151 GROUP_MEMBERSHIP *membership,
152 prs_struct *ps, int depth)
153{
154 if (NULL == membership)
155 return False;
156
157 prs_debug(ps, depth, desc, "pac_io_group_membership");
158 depth++;
159
160 if (!prs_uint32("rid", ps, depth, &membership->rid))
161 return False;
162 if (!prs_uint32("attrs", ps, depth, &membership->attrs))
163 return False;
164
165 return True;
166}
167
168
169static BOOL pac_io_group_membership_array(const char *desc,
170 GROUP_MEMBERSHIP_ARRAY *array,
171 uint32 num,
172 prs_struct *ps, int depth)
173{
174 int i;
175
176 if (NULL == array)
177 return False;
178
179 prs_debug(ps, depth, desc, "pac_io_group_membership_array");
180 depth++;
181
182
183 if (!prs_uint32("count", ps, depth, &array->count))
184 return False;
185
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;
191 }
192 }
193
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;
199
200 }
201
202 return True;
203
204}
205
206#if 0 /* Unused, replaced using an expanded net_io_user_info3() now - Guenther */
207static BOOL pac_io_pac_logon_info(const char *desc, PAC_LOGON_INFO *info,
208 prs_struct *ps, int depth)
209{
210 uint32 garbage, i;
211
212 if (NULL == info)
213 return False;
214
215 prs_debug(ps, depth, desc, "pac_io_pac_logon_info");
216 depth++;
217
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;
228
229 if (!prs_uint32("pointer", ps, depth, &garbage))
230 return False;
231
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;
249
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;
264
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;
283
284 if (!prs_uint8s(False, "session_key", ps, depth, info->session_key, 16))
285 return False;
286
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;
292
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;
296
297 if (!prs_uint8s(False, "lm_session_key", ps, depth, info->lm_session_key, 8))
298 return False;
299
300 if (!prs_uint32("acct_flags", ps, depth, &info->acct_flags))
301 return False;
302
303 for (i = 0; i < 7; i++)
304 {
305 if (!prs_uint32("unkown", ps, depth, &info->unknown[i])) /* unknown */
306 return False;
307 }
308
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;
320
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;
339
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;
346 }
347
348
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;
355
356 if(info->ptr_dom_sid)
357 if(!smb_io_dom_sid2("dom_sid", &info->dom_sid, ps, depth))
358 return False;
359
360
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;
367
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;
372
373 if (info->ptr_res_groups) {
374
375 if (!(info->user_flgs & LOGON_RESOURCE_GROUPS)) {
376 DEBUG(0,("user_flgs attribute does not have LOGON_RESOURCE_GROUPS\n"));
377 /* return False; */
378 }
379
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;
385 }
386
387 return True;
388}
389#endif
390
391static BOOL pac_io_pac_logon_info(const char *desc, PAC_LOGON_INFO *info,
392 prs_struct *ps, int depth)
393{
394 uint32 garbage;
395 BOOL kerb_validation_info = True;
396
397 if (NULL == info)
398 return False;
399
400 prs_debug(ps, depth, desc, "pac_io_pac_logon_info");
401 depth++;
402
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;
413
414 if(!net_io_user_info3("", &info->info3, ps, depth, 3, kerb_validation_info))
415 return False;
416
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;
421 }
422
423 if (info->info3.ptr_res_groups) {
424
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; */
428 }
429
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;
435 }
436
437 return True;
438}
439
440
441
442static BOOL pac_io_pac_signature_data(const char *desc,
443 PAC_SIGNATURE_DATA *data, uint32 length,
444 prs_struct *ps, int depth)
445{
446 uint32 siglen = length - sizeof(uint32);
447 prs_debug(ps, depth, desc, "pac_io_pac_signature_data");
448 depth++;
449
450 if (data == NULL)
451 return False;
452
453 if (!prs_align(ps))
454 return False;
455 if (!prs_uint32("type", ps, depth, &data->type))
456 return False;
457
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;
463 }
464 }
465
466 data->signature.buf_len = siglen;
467
468 if (!prs_uint8s(False, "signature", ps, depth, data->signature.buffer, data->signature.buf_len))
469 return False;
470
471
472 return True;
473}
474
475static BOOL pac_io_pac_info_hdr_ctr(const char *desc, PAC_BUFFER *hdr,
476 prs_struct *ps, int depth)
477{
478 if (NULL == hdr)
479 return False;
480
481 prs_debug(ps, depth, desc, "pac_io_pac_info_hdr_ctr");
482 depth++;
483
484 if (!prs_align(ps))
485 return False;
486
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);
491 }
492
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;
498 }
499 }
500
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;
509 }
510 if (!pac_io_pac_logon_info(desc, hdr->ctr->pac.logon_info,
511 ps, depth))
512 return False;
513 break;
514
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;
522 }
523 if (!pac_io_pac_signature_data(desc, hdr->ctr->pac.srv_cksum,
524 hdr->size, ps, depth))
525 return False;
526 break;
527
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;
535 }
536 if (!pac_io_pac_signature_data(desc,
537 hdr->ctr->pac.privsrv_cksum,
538 hdr->size, ps, depth))
539 return False;
540 break;
541
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;
549 }
550 if (!pac_io_logon_name(desc, hdr->ctr->pac.logon_name,
551 ps, depth))
552 return False;
553 break;
554
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);
559 }
560
561#if 0
562 /* obscure pad */
563 if (!prs_uint32("pad", ps, depth, &hdr->pad))
564 return False;
565#endif
566 return True;
567}
568
569static BOOL pac_io_pac_info_hdr(const char *desc, PAC_BUFFER *hdr,
570 prs_struct *ps, int depth)
571{
572 if (NULL == hdr)
573 return False;
574
575 prs_debug(ps, depth, desc, "pac_io_pac_info_hdr");
576 depth++;
577
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;
588
589 return True;
590}
591
592static BOOL pac_io_pac_data(const char *desc, PAC_DATA *data,
593 prs_struct *ps, int depth)
594{
595 int i;
596
597 if (NULL == data)
598 return False;
599
600 prs_debug(ps, depth, desc, "pac_io_pac_data");
601 depth++;
602
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;
609
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;
613 }
614 }
615
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;
620 }
621
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;
626 }
627
628 return True;
629}
630
631static 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)
636{
637 krb5_error_code ret;
638 krb5_checksum cksum;
639 krb5_keyusage usage = 0;
640
641 smb_krb5_checksum_from_pac_sig(&cksum, sig);
642
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
650
651 ret = smb_krb5_verify_checksum(context,
652 keyblock,
653 usage,
654 &cksum,
655 pac_data.data,
656 pac_data.length);
657
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;
662 }
663
664 return NT_STATUS_OK;
665}
666
667static NTSTATUS parse_pac_data(TALLOC_CTX *mem_ctx, DATA_BLOB *pac_data_blob, PAC_DATA *pac_data)
668{
669 prs_struct ps;
670 PAC_DATA *my_pac;
671
672 if (!prs_init(&ps, pac_data_blob->length, mem_ctx, UNMARSHALL))
673 return NT_STATUS_NO_MEMORY;
674
675 if (!prs_copy_data_in(&ps, (char *)pac_data_blob->data, pac_data_blob->length))
676 return NT_STATUS_INVALID_PARAMETER;
677
678 prs_set_offset(&ps, 0);
679
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;
683
684 prs_mem_free(&ps);
685
686 *pac_data = *my_pac;
687
688 return NT_STATUS_OK;
689}
690
691/* just for debugging, will be removed later - Guenther */
692char *pac_group_attr_string(uint32 attr)
693{
694 fstring name = "";
695
696 if (!attr)
697 return NULL;
698
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 ");
706
707 return SMB_STRDUP(name);
708}
709
710/* just for debugging, will be removed later - Guenther */
711static void dump_pac_logon_info(PAC_LOGON_INFO *logon_info) {
712
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;
717
718 if (logon_info->info3.ptr_res_group_dom_sid) {
719 sid_copy(&res_group_dom_sid, &logon_info->res_group_dom_sid.sid);
720 }
721 sid_copy(&dom_sid, &logon_info->info3.dom_sid.sid);
722
723 DEBUG(10,("The PAC:\n"));
724
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));
732
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);
742 }
743
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);
752 }
753
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);
763 }
764}
765
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)
773
774{
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;
787
788 *pac_data = NULL;
789
790 my_pac = talloc(mem_ctx, PAC_DATA);
791 if (!my_pac) {
792 return NT_STATUS_NO_MEMORY;
793 }
794
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;
799 }
800
801 modified_pac_blob = data_blob_talloc(mem_ctx, pac_data_blob->data, pac_data_blob->length);
802
803 if (my_pac->num_buffers < 4) {
804 nt_status = NT_STATUS_INVALID_PARAMETER;
805 goto out;
806 }
807
808 /* store signatures */
809 for (i=0; i < my_pac->num_buffers; i++) {
810
811 switch (my_pac->pac_buffer[i].type) {
812
813 case PAC_TYPE_SERVER_CHECKSUM:
814 if (!my_pac->pac_buffer[i].ctr->pac.srv_cksum) {
815 break;
816 }
817
818 srv_sig = my_pac->pac_buffer[i].ctr->pac.srv_cksum;
819
820 /* get position of signature buffer */
821 srv_sig_pos = my_pac->pac_buffer[i].offset;
822 srv_sig_pos += sizeof(uint32);
823
824 break;
825
826 case PAC_TYPE_PRIVSVR_CHECKSUM:
827 if (!my_pac->pac_buffer[i].ctr->pac.privsrv_cksum) {
828 break;
829 }
830
831 kdc_sig = my_pac->pac_buffer[i].ctr->pac.privsrv_cksum;
832
833 /* get position of signature buffer */
834 kdc_sig_pos = my_pac->pac_buffer[i].offset;
835 kdc_sig_pos += sizeof(uint32);
836
837 break;
838
839 case PAC_TYPE_LOGON_NAME:
840 if (!my_pac->pac_buffer[i].ctr->pac.logon_name) {
841 break;
842 }
843
844 logon_name = my_pac->pac_buffer[i].ctr->pac.logon_name;
845 break;
846
847 case PAC_TYPE_LOGON_INFO:
848 if (!my_pac->pac_buffer[i].ctr->pac.logon_info) {
849 break;
850 }
851
852 logon_info = my_pac->pac_buffer[i].ctr->pac.logon_info;
853 break;
854 }
855
856 }
857
858 if (!srv_sig || !kdc_sig || !logon_name || !logon_info) {
859 nt_status = NT_STATUS_INVALID_PARAMETER;
860 goto out;
861 }
862
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);
866
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;
872 }
873
874 /* Convert to NT time, so as not to loose accuracy in comparison */
875 unix_to_nt_time(&tgs_authtime_nttime, tgs_authtime);
876
877 if (!nt_time_equals(&tgs_authtime_nttime, &logon_name->logon_time)) {
878
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))));
884
885 nt_status = NT_STATUS_ACCESS_DENIED;
886 goto out;
887 }
888
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;
893 }
894 rpcstr_pull(username, logon_name->username, sizeof(username), logon_name->len, 0);
895
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;
902 }
903
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;
909 }
910
911 DEBUG(10,("Successfully validated Kerberos PAC\n"));
912
913 dump_pac_logon_info(logon_info);
914
915 *pac_data = my_pac;
916
917 nt_status = NT_STATUS_OK;
918
919out:
920 if (client_principal_pac) {
921 krb5_free_principal(context, client_principal_pac);
922 }
923
924 return nt_status;
925}
926
927 PAC_LOGON_INFO *get_logon_info_from_pac(PAC_DATA *pac_data)
928{
929 PAC_LOGON_INFO *logon_info = NULL;
930 int i;
931
932 for (i=0; i < pac_data->num_buffers; i++) {
933
934 if (pac_data->pac_buffer[i].type != PAC_TYPE_LOGON_INFO)
935 continue;
936
937 logon_info = pac_data->pac_buffer[i].ctr->pac.logon_info;
938 break;
939 }
940 return logon_info;
941}
942
943#endif
Note: See TracBrowser for help on using the repository browser.