1/*
2 * Copyright (c) 2000-2004,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// cssmdb.cpp
26//
27//
28#include <security_cdsa_utilities/cssmdb.h>
29
30bool DLDbIdentifier::Impl::operator < (const DLDbIdentifier::Impl &other) const
31{
32    if (mCssmSubserviceUid < other.mCssmSubserviceUid)
33        return true;
34    if (mCssmSubserviceUid != other.mCssmSubserviceUid) // i.e. greater than
35        return false;
36
37    // This test will produce unreproducible results,
38    // depending on what items are being compared.  To do this properly, we need to
39    // assign a lexical value to NULL.
40    //
41    // if (mDbName.canonicalName() == NULL || other.mDbName.canonicalName() == NULL)
42    // {
43    //     return false;
44    // }
45
46    // this is the correct way
47    const char* a = mDbName.canonicalName();
48    const char* b = other.mDbName.canonicalName();
49
50    if (a == NULL && b != NULL)
51    {
52        return true; // NULL is always < something
53    }
54
55    if (a != NULL && b == NULL)
56    {
57        return false; // something is always >= NULL
58    }
59
60    if (a == NULL && b == NULL)
61    {
62        return false; // since == is not <
63    }
64
65    // if we get to this point, both are not null.  No crash and the lexical value is correct.
66    return strcmp(a, b) < 0;
67}
68
69bool DLDbIdentifier::Impl::operator == (const Impl &other) const
70{
71    bool subserviceIdEqual = mCssmSubserviceUid == other.mCssmSubserviceUid;
72    if (!subserviceIdEqual)
73    {
74        return false;
75    }
76
77    const char* a = mDbName.canonicalName();
78    const char* b = other.mDbName.canonicalName();
79
80    if (a == NULL && b != NULL)
81    {
82        return false;
83    }
84
85    if (a !=  NULL && b == NULL)
86    {
87        return false;
88    }
89
90    if (a == NULL && b == NULL)
91    {
92        return true;
93    }
94
95    bool namesEqual = strcmp(a, b) == 0;
96    return namesEqual;
97}
98
99//
100// CssmDLPolyData
101//
102CssmDLPolyData::operator CSSM_DATE () const
103{
104	assert(mFormat == CSSM_DB_ATTRIBUTE_FORMAT_BLOB);
105	if (mData.Length != 8)
106		CssmError::throwMe(CSSMERR_DL_DATABASE_CORRUPT);
107
108	CSSM_DATE date;
109	memcpy(date.Year, mData.Data, 4);
110	memcpy(date.Month, mData.Data + 4, 2);
111	memcpy(date.Day, mData.Data + 6, 2);
112	return date;
113}
114
115CssmDLPolyData::operator Guid () const
116{
117	assert(mFormat == CSSM_DB_ATTRIBUTE_FORMAT_BLOB);
118	if (mData.Length != Guid::stringRepLength + 1)
119		CssmError::throwMe(CSSMERR_DL_DATABASE_CORRUPT);
120
121	return Guid(reinterpret_cast<const char *>(mData.Data));
122}
123
124
125//
126// CssmDbAttributeInfo
127//
128CssmDbAttributeInfo::CssmDbAttributeInfo(const char *name, CSSM_DB_ATTRIBUTE_FORMAT vFormat)
129{
130	clearPod();
131	AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING;
132	Label.AttributeName = const_cast<char *>(name); // silly CDSA
133	AttributeFormat = vFormat;
134}
135
136CssmDbAttributeInfo::CssmDbAttributeInfo(const CSSM_OID &oid, CSSM_DB_ATTRIBUTE_FORMAT vFormat)
137{
138	clearPod();
139	AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_OID;
140	Label.AttributeOID = oid;
141	AttributeFormat = vFormat;
142}
143
144CssmDbAttributeInfo::CssmDbAttributeInfo(uint32 id, CSSM_DB_ATTRIBUTE_FORMAT vFormat)
145{
146	clearPod();
147	AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER;
148	Label.AttributeID = id;
149	AttributeFormat = vFormat;
150}
151
152
153bool
154CssmDbAttributeInfo::operator <(const CssmDbAttributeInfo& other) const
155{
156	if (nameFormat() < other.nameFormat()) return true;
157	if (other.nameFormat() < nameFormat()) return false;
158	// nameFormat's are equal.
159	switch (nameFormat())
160	{
161	case CSSM_DB_ATTRIBUTE_NAME_AS_STRING:
162	{
163		int res = strcmp(static_cast<const char *>(*this), static_cast<const char *>(other));
164		if (res < 0) return true;
165		if (res > 0) return false;
166		break;
167	}
168	case CSSM_DB_ATTRIBUTE_NAME_AS_OID:
169		if (static_cast<const CssmOid &>(*this) < static_cast<const CssmOid &>(other)) return true;
170		if (static_cast<const CssmOid &>(other) < static_cast<const CssmOid &>(*this)) return false;
171		break;
172	case CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER:
173		if (static_cast<uint32>(*this) < static_cast<uint32>(other)) return true;
174		if (static_cast<uint32>(other) < static_cast<uint32>(*this)) return false;
175		break;
176	default:
177		CssmError::throwMe(CSSMERR_DL_INVALID_FIELD_NAME);
178	}
179
180	return format() < other.format();
181}
182
183bool
184CssmDbAttributeInfo::operator ==(const CssmDbAttributeInfo& other) const
185{
186	if (nameFormat() != other.nameFormat()) return false;
187	if (format() != other.format()) return false;
188	switch (nameFormat())
189	{
190	case CSSM_DB_ATTRIBUTE_NAME_AS_STRING:
191		return !strcmp(static_cast<const char *>(*this), static_cast<const char *>(other));
192	case CSSM_DB_ATTRIBUTE_NAME_AS_OID:
193		return static_cast<const CssmOid &>(*this) == static_cast<const CssmOid &>(other);
194	case CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER:
195		return static_cast<uint32>(*this) == static_cast<uint32>(other);
196	default:
197		CssmError::throwMe(CSSMERR_DL_INVALID_FIELD_NAME);
198	}
199}
200
201//
202// CssmDbAttributeData
203//
204CssmDbAttributeData::operator string() const
205{
206	switch (format()) {
207	case CSSM_DB_ATTRIBUTE_FORMAT_STRING:
208	case CSSM_DB_ATTRIBUTE_FORMAT_BLOB:
209		return at(0).toString();
210	default:
211		CssmError::throwMe(CSSMERR_DL_INCOMPATIBLE_FIELD_FORMAT);
212	}
213}
214CssmDbAttributeData::operator const Guid &() const
215{
216	if (format() == CSSM_DB_ATTRIBUTE_FORMAT_BLOB)
217		return *at(0).interpretedAs<Guid>();
218	else
219		CssmError::throwMe(CSSMERR_DL_INCOMPATIBLE_FIELD_FORMAT);
220}
221
222CssmDbAttributeData::operator bool() const
223{
224	switch (format()) {
225	case CSSM_DB_ATTRIBUTE_FORMAT_UINT32:
226	case CSSM_DB_ATTRIBUTE_FORMAT_SINT32:
227		return *at(0).interpretedAs<uint32>();
228	default:
229		CssmError::throwMe(CSSMERR_DL_INCOMPATIBLE_FIELD_FORMAT);
230	}
231}
232
233CssmDbAttributeData::operator uint32() const
234{
235	if (format() == CSSM_DB_ATTRIBUTE_FORMAT_UINT32)
236		return *at(0).interpretedAs<uint32>();
237	else
238		CssmError::throwMe(CSSMERR_DL_INCOMPATIBLE_FIELD_FORMAT);
239}
240
241CssmDbAttributeData::operator const uint32 *() const
242{
243	if (format() == CSSM_DB_ATTRIBUTE_FORMAT_MULTI_UINT32)
244		return reinterpret_cast<const uint32 *>(Value[0].Data);
245	else
246		CssmError::throwMe(CSSMERR_DL_INCOMPATIBLE_FIELD_FORMAT);
247}
248
249CssmDbAttributeData::operator sint32() const
250{
251	if (format() == CSSM_DB_ATTRIBUTE_FORMAT_SINT32)
252		return *at(0).interpretedAs<sint32>();
253	else
254		CssmError::throwMe(CSSMERR_DL_INCOMPATIBLE_FIELD_FORMAT);
255}
256
257CssmDbAttributeData::operator double() const
258{
259	if (format() == CSSM_DB_ATTRIBUTE_FORMAT_REAL)
260		return *at(0).interpretedAs<double>();
261	else
262		CssmError::throwMe(CSSMERR_DL_INCOMPATIBLE_FIELD_FORMAT);
263}
264
265CssmDbAttributeData::operator const CssmData &() const
266{
267	switch (format()) {
268	case CSSM_DB_ATTRIBUTE_FORMAT_STRING:
269	case CSSM_DB_ATTRIBUTE_FORMAT_BIG_NUM:
270	case CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE:
271	case CSSM_DB_ATTRIBUTE_FORMAT_BLOB:
272	case CSSM_DB_ATTRIBUTE_FORMAT_MULTI_UINT32:
273		return at(0);
274	default:
275		CssmError::throwMe(CSSMERR_DL_INCOMPATIBLE_FIELD_FORMAT);
276	}
277}
278
279void CssmDbAttributeData::set(const CSSM_DB_ATTRIBUTE_INFO &inInfo, const CssmPolyData &inValue,
280		 Allocator &inAllocator)
281{
282	info(inInfo);
283	NumberOfValues = 0;
284	Value = inAllocator.alloc<CSSM_DATA>();
285	Value[0].Length = 0;
286	Value[0].Data = inAllocator.alloc<uint8>((UInt32)inValue.Length);
287	Value[0].Length = inValue.Length;
288	memcpy(Value[0].Data, inValue.Data, inValue.Length);
289	NumberOfValues = 1;
290}
291
292void CssmDbAttributeData::add(const CssmPolyData &inValue, Allocator &inAllocator)
293{
294	Value = reinterpret_cast<CSSM_DATA *>(inAllocator.realloc(Value, sizeof(*Value) * (NumberOfValues + 1)));
295	CssmAutoData valueCopy(inAllocator, inValue);
296	Value[NumberOfValues++] = valueCopy.release();
297}
298
299
300void CssmDbAttributeData::copyValues(const CssmDbAttributeData &source, Allocator &alloc)
301{
302	assert(size() == 0);	// must start out empty
303
304	// we're too lazy to arrange for exception safety here
305	CssmData *vector = alloc.alloc<CssmData>(source.size());
306	for (uint32 n = 0; n < source.size(); n++)
307		vector[n] = CssmAutoData(alloc, source[n]).release();
308
309	// atomic set results
310	info().format(source.info().format());
311	NumberOfValues = source.size();
312	values() = vector;
313}
314
315void CssmDbAttributeData::deleteValues(Allocator &alloc)
316{
317	// Loop over all values and delete each one.
318	if (values())
319	{
320		for (uint32 n = 0; n < size(); n++)
321		{
322			alloc.free(at(n).data());
323		}
324		alloc.free(values());
325	}
326	NumberOfValues = 0;
327	values() = NULL;
328}
329
330bool CssmDbAttributeData::operator <(const CssmDbAttributeData &other) const
331{
332	if (info() < other.info()) return true;
333	if (other.info() < info()) return false;
334
335	uint32 minSize = min(size(), other.size());
336	for (uint32 ix = 0; ix < minSize; ++ix)
337	{
338		if (at<const CssmData &>(ix) < other.at<const CssmData &>(ix))
339			return true;
340		if (other.at<const CssmData &>(ix) < at<const CssmData &>(ix))
341			return false;
342	}
343
344	return size() < other.size();
345}
346
347void
348CssmDbAttributeData::add(const CssmDbAttributeData &src, Allocator &inAllocator)
349{
350	// Add all the values from another attribute into this attribute.
351
352	Value = reinterpret_cast<CSSM_DATA *>(inAllocator.realloc(Value,
353		sizeof(*Value) * (NumberOfValues + src.NumberOfValues)));
354
355	for (uint32 srcIndex = 0; srcIndex < src.NumberOfValues; srcIndex++) {
356		uint32 destIndex = NumberOfValues + srcIndex;
357
358		Value[destIndex].Length = 0;
359		Value[destIndex].Data = inAllocator.alloc<uint8>((UInt32)src.Value[srcIndex].Length);
360		Value[destIndex].Length = src.Value[srcIndex].Length;
361		memcpy(Value[destIndex].Data, src.Value[srcIndex].Data, src.Value[srcIndex].Length);
362	}
363
364	NumberOfValues += src.NumberOfValues;
365}
366
367bool
368CssmDbAttributeData::deleteValue(const CssmData &src, Allocator &inAllocator)
369{
370	// Delete a single value from this attribute, if it is present.
371
372	for (uint32 i = 0; i < NumberOfValues; i++)
373		if (CssmData::overlay(Value[i]) == src)
374		{
375			inAllocator.free(Value[i].Data);
376			Value[i].Length = 0;
377
378			NumberOfValues--;
379			Value[i].Data = Value[NumberOfValues].Data;
380			Value[i].Length = Value[NumberOfValues].Length;
381
382			return true;
383		}
384
385	return false;
386}
387
388// Delete those values found in src from this object, if they are present.
389// Warning: This is O(N^2) worst case; if this becomes a performance bottleneck
390// then it will need to be changed.
391
392void
393CssmDbAttributeData::deleteValues(const CssmDbAttributeData &src, Allocator &inAllocator)
394{
395	for (uint32 i = 0; i < src.NumberOfValues; i++)
396		deleteValue(CssmData::overlay(src.Value[i]), inAllocator);
397}
398
399//
400// CssmDbRecordAttributeData
401//
402CssmDbAttributeData *
403CssmDbRecordAttributeData::find(const CSSM_DB_ATTRIBUTE_INFO &inInfo)
404{
405	const CssmDbAttributeInfo &anInfo = CssmDbAttributeInfo::overlay(inInfo);
406	for (uint32 ix = 0; ix < size(); ++ix)
407	{
408		if (at(ix).info() == anInfo)
409			return &at(ix);
410	}
411
412	return NULL;
413}
414
415bool
416CssmDbRecordAttributeData::operator <(const CssmDbRecordAttributeData &other) const
417{
418	if (recordType() < other.recordType()) return true;
419	if (other.recordType() < recordType()) return false;
420	if (semanticInformation() < other.semanticInformation()) return true;
421	if (other.semanticInformation() < semanticInformation()) return false;
422
423	uint32 minSize = min(size(), other.size());
424	for (uint32 ix = 0; ix < minSize; ++ix)
425	{
426		if (at(ix) < other.at(ix))
427			return true;
428		if (other.at(ix) < at(ix))
429			return false;
430	}
431
432	return size() < other.size();
433}
434
435
436//
437// CssmAutoDbRecordAttributeData
438//
439CssmAutoDbRecordAttributeData::~CssmAutoDbRecordAttributeData()
440{
441	clear();
442}
443
444void
445CssmAutoDbRecordAttributeData::invalidate()
446{
447	NumberOfAttributes = 0;
448}
449
450
451
452void
453CssmAutoDbRecordAttributeData::clear()
454{
455	deleteValues();
456	ArrayBuilder<CssmDbAttributeData>::clear();
457}
458
459
460
461static bool CompareAttributeInfos (const CSSM_DB_ATTRIBUTE_INFO &a, const CSSM_DB_ATTRIBUTE_INFO &b)
462{
463	// check the format of the names
464	if (a.AttributeNameFormat != b.AttributeNameFormat)
465	{
466		return false;
467	}
468
469	switch (a.AttributeNameFormat)
470	{
471		case CSSM_DB_ATTRIBUTE_NAME_AS_STRING:
472		{
473			return strcmp (a.Label.AttributeName, b.Label.AttributeName) == 0;
474		}
475
476		case CSSM_DB_ATTRIBUTE_NAME_AS_OID:
477		{
478			if (a.Label.AttributeOID.Length != b.Label.AttributeOID.Length)
479			{
480				return false;
481			}
482
483			return memcmp (a.Label.AttributeOID.Data, b.Label.AttributeOID.Data, a.Label.AttributeOID.Length) == 0;
484		}
485
486
487		case CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER:
488		{
489			return a.Label.AttributeID == b.Label.AttributeID;
490		}
491	}
492
493	return true; // just to keep the compiler from complaining
494}
495
496
497
498CssmDbAttributeData* CssmAutoDbRecordAttributeData::findAttribute (const CSSM_DB_ATTRIBUTE_INFO &info)
499{
500	// walk through the data, looking for an attribute of the same type
501	unsigned i;
502	for (i = 0; i < size (); ++i)
503	{
504		CssmDbAttributeData& d = at (i);
505		CSSM_DB_ATTRIBUTE_INFO &inInfo = d.info ();
506
507		if (CompareAttributeInfos (info, inInfo))
508		{
509			return &d;
510		}
511	}
512
513	// found nothing?
514	return NULL;
515}
516
517
518
519CssmDbAttributeData& CssmAutoDbRecordAttributeData::getAttributeReference (const CSSM_DB_ATTRIBUTE_INFO &info)
520{
521	// Either find an existing reference to an attribute in the list, or make a new one.
522	CssmDbAttributeData *anAttr = findAttribute (info);
523	if (anAttr) // was this already in the list?
524	{
525		// clean it up
526		anAttr->deleteValues (mValueAllocator);
527	}
528	else
529	{
530		// make a new one
531		anAttr = &add();
532	}
533
534	return *anAttr;
535}
536
537
538
539CssmDbAttributeData &
540CssmAutoDbRecordAttributeData::add(const CSSM_DB_ATTRIBUTE_INFO &info)
541{
542	CssmDbAttributeData& anAttr = getAttributeReference (info);
543	anAttr.info(info);
544	return anAttr;
545}
546
547CssmDbAttributeData &
548CssmAutoDbRecordAttributeData::add(const CSSM_DB_ATTRIBUTE_INFO &info, const CssmPolyData &value)
549{
550	CssmDbAttributeData &anAttr = getAttributeReference (info);
551	anAttr.set(info, value, mValueAllocator);
552	return anAttr;
553}
554
555//
556// CssmAutoQuery
557//
558CssmAutoQuery::CssmAutoQuery(const CSSM_QUERY &query, Allocator &allocator)
559: ArrayBuilder<CssmSelectionPredicate>(CssmSelectionPredicate::overlayVar(SelectionPredicate),
560									   NumSelectionPredicates,
561									   query.NumSelectionPredicates, allocator)
562{
563	RecordType = query.RecordType;
564	Conjunctive = query.Conjunctive;
565	QueryLimits =  query.QueryLimits;
566	QueryFlags = query.QueryFlags;
567	for (uint32 ix = 0; ix < query.NumSelectionPredicates; ++ix)
568		add().set(query.SelectionPredicate[ix], allocator);
569}
570
571CssmAutoQuery::~CssmAutoQuery()
572{
573	clear();
574}
575
576void
577CssmAutoQuery::clear()
578{
579	deleteValues();
580	ArrayBuilder<CssmSelectionPredicate>::clear();
581}
582
583CssmSelectionPredicate &
584CssmAutoQuery::add(CSSM_DB_OPERATOR dbOperator, const CSSM_DB_ATTRIBUTE_INFO &info, const CssmPolyData &value)
585{
586	CssmSelectionPredicate &predicate = add();
587	predicate.dbOperator(dbOperator);
588	predicate.set(info, value, allocator());
589	return predicate;
590}
591