1/*
2 * Copyright (c) 2003-2006,2011-2012,2014 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25#include "dictionary.h"
26#include <ctype.h>
27#include <syslog.h>
28
29namespace Security {
30
31static uint32_t GetUInt32(unsigned char*& finger)
32{
33	uint32 result = 0;
34	unsigned i;
35
36	for (i = 0; i < sizeof(uint32); ++i)
37	{
38		result = (result << 8) | *finger++;
39	}
40
41	return result;
42}
43
44
45
46CssmData NameValuePair::CloneData (const CssmData &value)
47{
48	void* clonedData = (void*) new unsigned char [value.length ()];
49	if (clonedData != NULL)
50	{
51		memcpy (clonedData, value.data (), value.length ());
52		return CssmData (clonedData, value.length ());
53	}
54	else
55	{
56		CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR);
57	}
58}
59
60
61
62NameValuePair::NameValuePair (uint32 name, const CssmData &value) : mName (name), mValue (CloneData (value))
63{
64}
65
66
67
68NameValuePair::NameValuePair (const CssmData &data)
69{
70	// the first four bytes are the name
71	unsigned char* finger = (unsigned char*) data.data ();
72	mName = GetUInt32(finger);
73	uint32 length = GetUInt32(finger);
74
75	// what's left is the data
76	mValue = CloneData (CssmData (finger, length));
77}
78
79
80
81NameValuePair::~NameValuePair ()
82{
83	delete (unsigned char*) mValue.data ();
84}
85
86
87
88void NameValuePair::Export (CssmData &data) const
89{
90	// export the data in the format name length data
91	size_t outSize = 2 * sizeof (uint32) + mValue.length ();
92	unsigned char* d = (unsigned char*) malloc(outSize);
93	unsigned char* finger = d;
94
95	// export the name
96	uint32 intBuffer = mName;
97
98	int i;
99	for (i = sizeof (uint32) - 1; i >= 0; --i)
100	{
101		finger[i] = intBuffer & 0xFF;
102		intBuffer >>= 8;
103	}
104
105	// export the length
106	finger += sizeof (uint32);
107	intBuffer = (uint32)mValue.length ();
108	for (i = sizeof (uint32) - 1; i >= 0; --i)
109	{
110		finger[i] = intBuffer & 0xFF;
111		intBuffer >>= 8;
112	}
113
114	// export the data
115	finger += sizeof (uint32);
116	memcpy (finger, mValue.data (), mValue.length ());
117
118	data = CssmData (d, outSize);
119}
120
121
122
123NameValueDictionary::NameValueDictionary ()
124{
125}
126
127
128
129NameValueDictionary::~NameValueDictionary ()
130{
131	// to prevent leaks, delete all members of the vector
132	size_t i = mVector.size ();
133	while (i > 0)
134	{
135		delete mVector[--i];
136
137		mVector.erase (mVector.begin () + i);
138	}
139}
140
141
142
143// To work around 5964438, move code out of the constructor
144void NameValueDictionary::MakeFromData(const CssmData &data)
145{
146	// reconstruct a name value dictionary from a series of exported NameValuePair blobs
147	unsigned char* finger = (unsigned char*) data.data ();
148	unsigned char* target = finger + data.length ();
149
150	bool done = false;
151
152	do
153	{
154		// compute the length of data blob
155		unsigned int i;
156		uint32 length = 0;
157		for (i = sizeof (uint32); i < 2 * sizeof (uint32); ++i)
158		{
159			length = (length << 8) | finger[i];
160		}
161
162		if (length > data.length())
163		{
164			break;
165		}
166
167		// add the length of the "header"
168		length += 2 * sizeof (uint32);
169
170		// do some sanity checking on the data.
171		uint32 itemLength = 0;
172		unsigned char* fingerX = finger;
173
174		// extract the name in a printable format
175		char nameBuff[5];
176		char* nameFinger = nameBuff;
177
178		// work around a bug with invalid lengths coming from securityd
179		if (fingerX + sizeof(uint32) < target)
180		{
181			*nameFinger++ = (char) *fingerX++;
182			*nameFinger++ = (char) *fingerX++;
183			*nameFinger++ = (char) *fingerX++;
184			*nameFinger++ = (char) *fingerX++;
185			*nameFinger++ = 0;
186
187			itemLength = GetUInt32(fingerX);
188
189			if (fingerX + itemLength > target) // this is the bug
190			{
191				done = true;
192			}
193		}
194
195		// This shouldn't crash any more...
196		Insert (new NameValuePair (CssmData (finger, length)));
197
198		// skip to the next data
199		finger += length;
200	} while (!done && finger < target);
201}
202
203
204
205NameValueDictionary::NameValueDictionary (const CssmData &data)
206{
207	MakeFromData(data);
208}
209
210
211
212void NameValueDictionary::Insert (NameValuePair* pair)
213{
214	mVector.push_back (pair);
215}
216
217
218
219void NameValueDictionary::RemoveByName (uint32 name)
220{
221	int which = FindPositionByName (name);
222	if (which != -1)
223	{
224		NameValuePair* nvp = mVector[which];
225		mVector.erase (mVector.begin () + which);
226		delete nvp;
227	}
228}
229
230
231
232int NameValueDictionary::FindPositionByName (uint32 name) const
233{
234	int target = CountElements ();
235	int i;
236
237	for (i = 0; i < target; ++i)
238	{
239		if (mVector[i]->Name () == name)
240		{
241			return i;
242		}
243	}
244
245	return -1;
246}
247
248
249
250const NameValuePair* NameValueDictionary::FindByName (uint32 name) const
251{
252	int which = FindPositionByName (name);
253	return which == -1 ? NULL : mVector[which];
254}
255
256
257
258
259int NameValueDictionary::CountElements () const
260{
261	return (int)mVector.size ();
262}
263
264
265
266const NameValuePair* NameValueDictionary::GetElement (int which)
267{
268	return mVector[which];
269}
270
271
272
273void NameValueDictionary::Export (CssmData &outData)
274{
275	// get each element in the dictionary, and add it to the data blob
276	int i;
277	uint32 length = 0;
278	unsigned char* data = 0;
279
280	for (i = 0; i < CountElements (); ++i)
281	{
282		CssmData exportedData;
283		const NameValuePair *nvp = GetElement (i);
284		nvp->Export (exportedData);
285
286		uint32 oldLength = length;
287		length += exportedData.length ();
288		data = (unsigned char*) realloc (data, length);
289
290		memcpy (data + oldLength, exportedData.data (), exportedData.length ());
291
292		free(exportedData.data());
293	}
294
295	outData = CssmData (data, length);
296}
297
298
299
300void NameValueDictionary::MakeNameValueDictionaryFromDLDbIdentifier (const DLDbIdentifier &identifier, NameValueDictionary &nvd)
301{
302	// get the subserviceID
303	DLDbIdentifier d = identifier;
304
305	const CssmSubserviceUid &ssuid = identifier.ssuid ();
306	CSSM_SUBSERVICE_UID baseID = ssuid;
307	baseID.Version.Major = h2n (baseID.Version.Major);
308	baseID.Version.Minor = h2n (baseID.Version.Minor);
309	baseID.SubserviceId = h2n (baseID.SubserviceId);
310	baseID.SubserviceType = h2n (baseID.SubserviceType);
311
312	nvd.Insert (new NameValuePair (SSUID_KEY, CssmData::wrap(baseID)));
313
314	// get the name
315	const char* dbName = identifier.dbName ();
316	if (dbName != NULL)
317	{
318		nvd.Insert (new NameValuePair (DB_NAME, CssmData::wrap (dbName, strlen (dbName) + 1)));
319	}
320
321	// get the net address
322	const CSSM_NET_ADDRESS* add = identifier.dbLocation ();
323	if (add != NULL)
324	{
325		nvd.Insert (new NameValuePair (DB_LOCATION, CssmData::wrap (add)));
326	}
327}
328
329
330
331DLDbIdentifier NameValueDictionary::MakeDLDbIdentifierFromNameValueDictionary (const NameValueDictionary &nvd)
332{
333	/*
334		According to the code in MakeNameValueDictionaryFromDLDbIdentifier, SSUID_KEY
335		is required, but both DB_NAME and DB_LOCATION are allowed to be missing. In
336		all of these cases, it is possible that FindByName returns NULL.
337	*/
338
339	const NameValuePair *nvpSSUID = nvd.FindByName (SSUID_KEY);
340	if (nvpSSUID == NULL)
341		CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR);
342
343	CSSM_SUBSERVICE_UID* uid = (CSSM_SUBSERVICE_UID*) nvpSSUID->Value ().data ();
344	if (uid == NULL)
345	{
346		CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR);
347	}
348
349	CSSM_SUBSERVICE_UID baseID = *uid;
350
351	baseID.Version.Major = n2h (baseID.Version.Major);
352	baseID.Version.Minor = n2h (baseID.Version.Minor);
353	baseID.SubserviceId = n2h (baseID.SubserviceId);
354	baseID.SubserviceType = n2h (baseID.SubserviceType);
355
356	const NameValuePair *nvpDBNAME = nvd.FindByName (DB_NAME);
357	char* name = nvpDBNAME ? (char*) nvpDBNAME->Value ().data () : NULL;
358
359	const NameValuePair* nvp = nvd.FindByName (DB_LOCATION);
360	CSSM_NET_ADDRESS* address = nvp ? (CSSM_NET_ADDRESS*) nvp->Value ().data () : NULL;
361
362	return DLDbIdentifier (baseID, name, address);
363}
364
365}; // end Security namespace
366