1/*
2   Unix SMB/CIFS implementation.
3   kerberos authorization data (PAC) utility library
4   Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2003
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2 of the License, or
9   (at your option) any later version.
10
11   This program is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with this program; if not, write to the Free Software
18   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19*/
20
21#include "includes.h"
22
23#ifdef HAVE_KRB5
24
25static DATA_BLOB unwrap_pac(DATA_BLOB *auth_data)
26{
27	DATA_BLOB pac_contents;
28	ASN1_DATA data;
29	int data_type;
30
31	asn1_load(&data, *auth_data);
32	asn1_start_tag(&data, ASN1_SEQUENCE(0));
33	asn1_start_tag(&data, ASN1_SEQUENCE(0));
34	asn1_start_tag(&data, ASN1_CONTEXT(0));
35	asn1_read_Integer(&data, &data_type);
36	asn1_end_tag(&data);
37	asn1_start_tag(&data, ASN1_CONTEXT(1));
38	asn1_read_OctetString(&data, &pac_contents);
39	asn1_end_tag(&data);
40	asn1_end_tag(&data);
41	asn1_end_tag(&data);
42	asn1_free(&data);
43	return pac_contents;
44}
45
46static BOOL pac_io_unknown_type_10(const char *desc, UNKNOWN_TYPE_10 *type_10,
47				   prs_struct *ps, int depth)
48{
49	if (NULL == type_10)
50		return False;
51
52	prs_debug(ps, depth, desc, "pac_io_unknown_type_10");
53	depth++;
54
55	if (!smb_io_time("unknown_time", &type_10->unknown_time, ps, depth))
56		return False;
57
58	if (!prs_uint16("len", ps, depth, &type_10->len))
59		return False;
60
61	if (UNMARSHALLING(ps) && type_10->len) {
62		type_10->username = PRS_ALLOC_MEM(ps, uint16, type_10->len);
63		if (!type_10->username) {
64			DEBUG(3, ("No memory available\n"));
65			return False;
66		}
67	}
68
69	if (!prs_uint16s(True, "name", ps, depth, type_10->username,
70			 (type_10->len / sizeof(uint16))))
71		return False;
72
73	return True;
74
75}
76
77
78static BOOL pac_io_krb_sids(const char *desc, KRB_SID_AND_ATTRS *sid_and_attr,
79			    prs_struct *ps, int depth)
80{
81	if (NULL == sid_and_attr)
82		return False;
83
84	prs_debug(ps, depth, desc, "pac_io_krb_sids");
85	depth++;
86
87	if (UNMARSHALLING(ps)) {
88		sid_and_attr->sid = PRS_ALLOC_MEM(ps, DOM_SID2, 1);
89		if (!sid_and_attr->sid) {
90			DEBUG(3, ("No memory available\n"));
91			return False;
92		}
93	}
94
95	if(!smb_io_dom_sid2("sid", sid_and_attr->sid, ps, depth))
96		return False;
97
98	return True;
99}
100
101
102static BOOL pac_io_krb_attrs(const char *desc, KRB_SID_AND_ATTRS *sid_and_attr,
103			     prs_struct *ps, int depth)
104{
105	if (NULL == sid_and_attr)
106		return False;
107
108	prs_debug(ps, depth, desc, "pac_io_krb_attrs");
109	depth++;
110
111	if (!prs_uint32("sid_ptr", ps, depth, &sid_and_attr->sid_ptr))
112		return False;
113	if (!prs_uint32("attrs", ps, depth, &sid_and_attr->attrs))
114		return False;
115
116	return True;
117}
118
119static BOOL pac_io_krb_sid_and_attr_array(const char *desc,
120					  KRB_SID_AND_ATTR_ARRAY *array,
121					  uint32 num,
122					  prs_struct *ps, int depth)
123{
124	int i;
125
126	if (NULL == array)
127		return False;
128
129	prs_debug(ps, depth, desc, "pac_io_krb_sid_and_attr_array");
130	depth++;
131
132
133	if (!prs_uint32("count", ps, depth, &array->count))
134		return False;
135
136	if (UNMARSHALLING(ps)) {
137		array->krb_sid_and_attrs = PRS_ALLOC_MEM(ps, KRB_SID_AND_ATTRS, num);
138		if (!array->krb_sid_and_attrs) {
139			DEBUG(3, ("No memory available\n"));
140			return False;
141		}
142	}
143
144	for (i=0; i<num; i++) {
145		if (!pac_io_krb_attrs(desc,
146				      &array->krb_sid_and_attrs[i],
147				      ps, depth))
148			return False;
149
150	}
151	for (i=0; i<num; i++) {
152		if (!pac_io_krb_sids(desc,
153				     &array->krb_sid_and_attrs[i],
154				     ps, depth))
155			return False;
156
157	}
158
159	return True;
160
161}
162
163static BOOL pac_io_group_membership(const char *desc,
164				    GROUP_MEMBERSHIP *membership,
165				    prs_struct *ps, int depth)
166{
167	if (NULL == membership)
168		return False;
169
170	prs_debug(ps, depth, desc, "pac_io_group_membership");
171	depth++;
172
173	if (!prs_uint32("rid", ps, depth, &membership->rid))
174		return False;
175	if (!prs_uint32("attrs", ps, depth, &membership->attrs))
176		return False;
177
178	return True;
179}
180
181
182static BOOL pac_io_group_membership_array(const char *desc,
183					  GROUP_MEMBERSHIP_ARRAY *array,
184					  uint32 num,
185					  prs_struct *ps, int depth)
186{
187	int i;
188
189	if (NULL == array)
190		return False;
191
192	prs_debug(ps, depth, desc, "pac_io_group_membership_array");
193	depth++;
194
195
196	if (!prs_uint32("count", ps, depth, &array->count))
197		return False;
198
199	if (UNMARSHALLING(ps)) {
200		array->group_membership = PRS_ALLOC_MEM(ps, GROUP_MEMBERSHIP, num);
201		if (!array->group_membership) {
202			DEBUG(3, ("No memory available\n"));
203			return False;
204		}
205	}
206
207	for (i=0; i<num; i++) {
208		if (!pac_io_group_membership(desc,
209					     &array->group_membership[i],
210					     ps, depth))
211			return False;
212
213	}
214
215	return True;
216
217}
218
219static BOOL pac_io_pac_logon_info(const char *desc, PAC_LOGON_INFO *info,
220				  prs_struct *ps, int depth)
221{
222	uint32 garbage;
223	if (NULL == info)
224		return False;
225
226	prs_debug(ps, depth, desc, "pac_io_pac_logon_info");
227	depth++;
228
229	if (!prs_uint32("unknown", ps, depth, &garbage))
230		return False;
231	if (!prs_uint32("unknown", ps, depth, &garbage))
232		return False;
233	if (!prs_uint32("bufferlen", ps, depth, &garbage))
234		return False;
235	if (!prs_uint32("bufferlenhi", ps, depth, &garbage))
236		return False;
237	if (!prs_uint32("pointer", ps, depth, &garbage))
238		return False;
239
240	if (!smb_io_time("logon_time", &info->logon_time, ps, depth))
241		return False;
242	if (!smb_io_time("logoff_time", &info->logoff_time, ps, depth))
243		return False;
244	if (!smb_io_time("kickoff_time", &info->kickoff_time, ps, depth))
245		return False;
246	if (!smb_io_time("pass_last_set_time", &info->pass_last_set_time,
247			 ps, depth))
248		return False;
249	if (!smb_io_time("pass_can_change_time", &info->pass_can_change_time,
250			 ps, depth))
251		return False;
252	if (!smb_io_time("pass_must_change_time", &info->pass_must_change_time,
253			 ps, depth))
254		return False;
255
256	if (!smb_io_unihdr("hdr_user_name", &info->hdr_user_name, ps, depth))
257		return False;
258	if (!smb_io_unihdr("hdr_full_name", &info->hdr_full_name, ps, depth))
259		return False;
260	if (!smb_io_unihdr("hdr_logon_script", &info->hdr_logon_script,
261			   ps, depth))
262		return False;
263	if (!smb_io_unihdr("hdr_profile_path", &info->hdr_profile_path,
264			   ps, depth))
265		return False;
266	if (!smb_io_unihdr("hdr_home_dir", &info->hdr_home_dir, ps, depth))
267		return False;
268	if (!smb_io_unihdr("hdr_dir_drive", &info->hdr_dir_drive, ps, depth))
269		return False;
270
271	if (!prs_uint16("logon_count", ps, depth, &info->logon_count))
272		return False;
273	if (!prs_uint16("reserved12", ps, depth, &info->reserved12))
274		return False;
275	if (!prs_uint32("user_rid", ps, depth, &info->user_rid))
276		return False;
277	if (!prs_uint32("group_rid", ps, depth, &info->group_rid))
278		return False;
279	if (!prs_uint32("group_count", ps, depth, &info->group_count))
280		return False;
281	/* I haven't seen this contain anything yet, but when it does
282	   we will have to make sure we decode the contents in the middle
283	   all the unistr2s ... */
284	if (!prs_uint32("group_mem_ptr", ps, depth,
285			&info->group_membership_ptr))
286		return False;
287	if (!prs_uint32("user_flags", ps, depth, &info->user_flags))
288		return False;
289
290	if (!prs_uint32("reserved13.0", ps, depth, &info->reserved13[0]))
291		return False;
292	if (!prs_uint32("reserved13.1", ps, depth, &info->reserved13[1]))
293		return False;
294	if (!prs_uint32("reserved13.2", ps, depth, &info->reserved13[2]))
295		return False;
296	if (!prs_uint32("reserved13.3", ps, depth, &info->reserved13[3]))
297		return False;
298
299	if (!smb_io_unihdr("hdr_dom_controller",
300			   &info->hdr_dom_controller, ps, depth))
301		return False;
302	if (!smb_io_unihdr("hdr_dom_name", &info->hdr_dom_name, ps, depth))
303		return False;
304
305	/* this should be followed, but just get ptr for now */
306	if (!prs_uint32("ptr_dom_sid", ps, depth, &info->ptr_dom_sid))
307		return False;
308
309	if (!prs_uint32("reserved16.0", ps, depth, &info->reserved16[0]))
310		return False;
311	if (!prs_uint32("reserved16.1", ps, depth, &info->reserved16[1]))
312		return False;
313
314	/* might be acb_info */
315	if (!prs_uint32("reserved17", ps, depth, &info->reserved17))
316		return False;
317
318
319	if (!prs_uint32("reserved18.0", ps, depth, &info->reserved18[0]))
320		return False;
321	if (!prs_uint32("reserved18.1", ps, depth, &info->reserved18[1]))
322		return False;
323	if (!prs_uint32("reserved18.2", ps, depth, &info->reserved18[2]))
324		return False;
325	if (!prs_uint32("reserved18.3", ps, depth, &info->reserved18[3]))
326		return False;
327	if (!prs_uint32("reserved18.4", ps, depth, &info->reserved18[4]))
328		return False;
329	if (!prs_uint32("reserved18.5", ps, depth, &info->reserved18[5]))
330		return False;
331	if (!prs_uint32("reserved18.6", ps, depth, &info->reserved18[6]))
332		return False;
333
334	if (!prs_uint32("sid_count", ps, depth, &info->sid_count))
335		return False;
336	if (!prs_uint32("ptr_extra_sids", ps, depth, &info->ptr_extra_sids))
337		return False;
338	if (!prs_uint32("ptr_res_group_dom_sid", ps, depth,
339			&info->ptr_res_group_dom_sid))
340		return False;
341	if (!prs_uint32("res_group_count", ps, depth, &info->res_group_count))
342		return False;
343	if (!prs_uint32("ptr_res_groups", ps, depth, &info->ptr_res_groups))
344		return False;
345
346	if(!smb_io_unistr2("uni_user_name", &info->uni_user_name,
347			   info->hdr_user_name.buffer, ps, depth))
348		return False;
349	if(!smb_io_unistr2("uni_full_name", &info->uni_full_name,
350			   info->hdr_full_name.buffer, ps, depth))
351		return False;
352	if(!smb_io_unistr2("uni_logon_script", &info->uni_logon_script,
353			   info->hdr_logon_script.buffer, ps, depth))
354		return False;
355	if(!smb_io_unistr2("uni_profile_path", &info->uni_profile_path,
356			   info->hdr_profile_path.buffer, ps, depth))
357		return False;
358	if(!smb_io_unistr2("uni_home_dir", &info->uni_home_dir,
359			   info->hdr_home_dir.buffer, ps, depth))
360		return False;
361	if(!smb_io_unistr2("uni_dir_drive", &info->uni_dir_drive,
362			   info->hdr_dir_drive.buffer, ps, depth))
363		return False;
364
365	if (info->group_membership_ptr) {
366		if (!pac_io_group_membership_array("group membership",
367						   &info->groups,
368						   info->group_count,
369						   ps, depth))
370			return False;
371	}
372
373
374	if(!smb_io_unistr2("uni_dom_controller", &info->uni_dom_controller,
375			   info->hdr_dom_controller.buffer, ps, depth))
376		return False;
377	if(!smb_io_unistr2("uni_dom_name", &info->uni_dom_name,
378			   info->hdr_dom_name.buffer, ps, depth))
379		return False;
380
381	if(info->ptr_dom_sid)
382		if(!smb_io_dom_sid2("dom_sid", &info->dom_sid, ps, depth))
383			return False;
384
385
386	if (info->sid_count && info->ptr_extra_sids)
387		if (!pac_io_krb_sid_and_attr_array("extra_sids",
388						   &info->extra_sids,
389						   info->sid_count,
390						   ps, depth))
391			return False;
392
393	if (info->ptr_res_group_dom_sid)
394		if (!smb_io_dom_sid2("res_group_dom_sid",
395				     &info->res_group_dom_sid, ps, depth))
396			return False;
397
398	if (info->ptr_res_groups)
399		if (!pac_io_group_membership_array("res group membership",
400						   &info->res_groups,
401						   info->res_group_count,
402						   ps, depth))
403			return False;
404
405	return True;
406}
407
408
409static BOOL pac_io_pac_signature_data(const char *desc,
410				      PAC_SIGNATURE_DATA *data, uint32 length,
411				      prs_struct *ps, int depth)
412{
413	uint32 siglen = length - sizeof(uint32);
414	if (NULL == data)
415		return False;
416
417	prs_debug(ps, depth, desc, "pac_io_pac_signature_data");
418	depth++;
419
420	if (!prs_uint32("type", ps, depth, &data->type))
421		return False;
422	if (UNMARSHALLING(ps)) {
423		data->signature = PRS_ALLOC_MEM(ps, unsigned char, siglen);
424		if (!data->signature) {
425			DEBUG(3, ("No memory available\n"));
426			return False;
427		}
428	}
429	if (!prs_uint8s(False, "signature", ps, depth, data->signature,siglen))
430		return False;
431
432	return True;
433}
434
435static BOOL pac_io_pac_info_hdr_ctr(const char *desc, PAC_INFO_HDR *hdr,
436				    prs_struct *ps, int depth)
437{
438	if (NULL == hdr)
439		return False;
440
441	prs_debug(ps, depth, desc, "pac_io_pac_info_hdr_ctr");
442	depth++;
443
444	if (!prs_align(ps))
445		return False;
446
447	if (hdr->offset != prs_offset(ps)) {
448		DEBUG(5, ("offset in header(x%x) and data(x%x) do not match\n",
449			  hdr->offset, prs_offset(ps)));
450		prs_set_offset(ps, hdr->offset);
451	}
452
453	if (UNMARSHALLING(ps) && hdr->size > 0) {
454		hdr->ctr = PRS_ALLOC_MEM(ps, PAC_INFO_CTR, 1);
455		if (!hdr->ctr) {
456			DEBUG(3, ("No memory available\n"));
457			return False;
458		}
459	}
460
461	switch(hdr->type) {
462	case PAC_TYPE_LOGON_INFO:
463		DEBUG(5, ("PAC_TYPE_LOGON_INFO\n"));
464		if (UNMARSHALLING(ps))
465			hdr->ctr->pac.logon_info = PRS_ALLOC_MEM(ps, PAC_LOGON_INFO, 1);
466		if (!hdr->ctr->pac.logon_info) {
467			DEBUG(3, ("No memory available\n"));
468			return False;
469		}
470		if (!pac_io_pac_logon_info(desc, hdr->ctr->pac.logon_info,
471					   ps, depth))
472			return False;
473		break;
474
475	case PAC_TYPE_SERVER_CHECKSUM:
476		DEBUG(5, ("PAC_TYPE_SERVER_CHECKSUM\n"));
477		if (UNMARSHALLING(ps))
478			hdr->ctr->pac.srv_cksum = PRS_ALLOC_MEM(ps, PAC_SIGNATURE_DATA, 1);
479		if (!hdr->ctr->pac.srv_cksum) {
480			DEBUG(3, ("No memory available\n"));
481			return False;
482		}
483		if (!pac_io_pac_signature_data(desc, hdr->ctr->pac.srv_cksum,
484					       hdr->size, ps, depth))
485			return False;
486		break;
487
488	case PAC_TYPE_PRIVSVR_CHECKSUM:
489		DEBUG(5, ("PAC_TYPE_PRIVSVR_CHECKSUM\n"));
490		if (UNMARSHALLING(ps))
491			hdr->ctr->pac.privsrv_cksum = PRS_ALLOC_MEM(ps, PAC_SIGNATURE_DATA, 1);
492		if (!hdr->ctr->pac.privsrv_cksum) {
493			DEBUG(3, ("No memory available\n"));
494			return False;
495		}
496		if (!pac_io_pac_signature_data(desc,
497					       hdr->ctr->pac.privsrv_cksum,
498					       hdr->size, ps, depth))
499			return False;
500		break;
501
502	case PAC_TYPE_UNKNOWN_10:
503		DEBUG(5, ("PAC_TYPE_UNKNOWN_10\n"));
504		if (UNMARSHALLING(ps))
505			hdr->ctr->pac.type_10 = PRS_ALLOC_MEM(ps, UNKNOWN_TYPE_10, 1);
506		if (!hdr->ctr->pac.type_10) {
507			DEBUG(3, ("No memory available\n"));
508			return False;
509		}
510		if (!pac_io_unknown_type_10(desc, hdr->ctr->pac.type_10,
511					    ps, depth))
512			return False;
513		break;
514
515	default:
516		/* dont' know, so we need to skip it */
517		DEBUG(3, ("unknown PAC type %d\n", hdr->type));
518		prs_set_offset(ps, prs_offset(ps) + hdr->size);
519	}
520
521	return True;
522}
523
524static BOOL pac_io_pac_info_hdr(const char *desc, PAC_INFO_HDR *hdr,
525				prs_struct *ps, int depth)
526{
527	if (NULL == hdr)
528		return False;
529
530	prs_debug(ps, depth, desc, "pac_io_pac_info_hdr");
531	depth++;
532
533	if (!prs_align(ps))
534		return False;
535	if (!prs_uint32("type", ps, depth, &hdr->type))
536		return False;
537	if (!prs_uint32("size", ps, depth, &hdr->size))
538		return False;
539	if (!prs_uint32("offset", ps, depth, &hdr->offset))
540		return False;
541	if (!prs_uint32("offsethi", ps, depth, &hdr->offsethi))
542		return False;
543
544	return True;
545}
546
547static BOOL pac_io_pac_data(const char *desc, PAC_DATA *data,
548			    prs_struct *ps, int depth)
549{
550	int i;
551
552	if (NULL == data)
553		return False;
554
555	prs_debug(ps, depth, desc, "pac_io_pac_data");
556	depth++;
557
558	if (!prs_align(ps))
559		return False;
560	if (!prs_uint32("num_buffers", ps, depth, &data->num_buffers))
561		return False;
562	if (!prs_uint32("version", ps, depth, &data->version))
563		return False;
564
565	if (UNMARSHALLING(ps) && data->num_buffers > 0) {
566		if ((data->pac_info_hdr_ptr = PRS_ALLOC_MEM(ps, PAC_INFO_HDR, data->num_buffers)) == NULL) {
567			return False;
568		}
569	}
570
571	for (i=0; i<data->num_buffers; i++) {
572		if (!pac_io_pac_info_hdr(desc, &data->pac_info_hdr_ptr[i], ps,
573					 depth))
574			return False;
575	}
576
577	for (i=0; i<data->num_buffers; i++) {
578		if (!pac_io_pac_info_hdr_ctr(desc, &data->pac_info_hdr_ptr[i],
579					     ps, depth))
580			return False;
581	}
582
583	return True;
584}
585
586PAC_DATA *decode_pac_data(DATA_BLOB *auth_data, TALLOC_CTX *ctx)
587{
588	DATA_BLOB pac_data_blob = unwrap_pac(auth_data);
589	prs_struct ps;
590	PAC_DATA *pac_data;
591
592	DEBUG(5,("dump_pac_data\n"));
593	prs_init(&ps, pac_data_blob.length, ctx, UNMARSHALL);
594	prs_copy_data_in(&ps, (char *)pac_data_blob.data, pac_data_blob.length);
595	prs_set_offset(&ps, 0);
596
597	data_blob_free(&pac_data_blob);
598
599	pac_data = TALLOC_ZERO_P(ctx, PAC_DATA);
600	pac_io_pac_data("pac data", pac_data, &ps, 0);
601
602	prs_mem_free(&ps);
603
604	return pac_data;
605}
606
607#endif
608