1/*
2 * Copyright (c) 2000-2004,2011-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#include <security_utilities/seccfobject.h>
25#include <security_utilities/cfclass.h>
26#include <security_utilities/errors.h>
27#include <security_utilities/debugging.h>
28
29#include <list>
30#include <security_utilities/globalizer.h>
31#include <auto_zone.h>
32
33SecPointerBase::SecPointerBase(const SecPointerBase& p)
34{
35	if (p.ptr)
36	{
37		CFRetain(p.ptr->operator CFTypeRef());
38	}
39	ptr = p.ptr;
40}
41
42
43
44
45static void CheckForRelease(SecCFObject* ptr)
46{
47	CFTypeRef tr = ptr->operator CFTypeRef();
48	CFIndex retainCount = CFGetRetainCount(tr);
49	if (retainCount == 1 || retainCount == -1)
50	{
51		ptr->aboutToDestruct();
52	}
53}
54
55
56
57SecPointerBase::SecPointerBase(SecCFObject *p)
58{
59	if (p && !p->isNew())
60	{
61		CFRetain(p->operator CFTypeRef());
62	}
63	ptr = p;
64}
65
66
67
68SecPointerBase::~SecPointerBase()
69{
70	if (ptr)
71	{
72		CheckForRelease(ptr);
73		CFRelease(ptr->operator CFTypeRef());
74	}
75}
76
77
78
79SecPointerBase& SecPointerBase::operator = (const SecPointerBase& p)
80{
81	if (p.ptr)
82	{
83		CFTypeRef tr = p.ptr->operator CFTypeRef();
84		CFRetain(tr);
85	}
86	if (ptr)
87	{
88		CheckForRelease(ptr);
89		CFRelease(ptr->operator CFTypeRef());
90	}
91	ptr = p.ptr;
92	return *this;
93}
94
95
96
97void SecPointerBase::assign(SecCFObject * p)
98{
99	if (p && !p->isNew())
100	{
101		CFRetain(p->operator CFTypeRef());
102	}
103	if (ptr)
104	{
105		CheckForRelease(ptr);
106		CFRelease(ptr->operator CFTypeRef());
107	}
108	ptr = p;
109}
110
111
112
113void SecPointerBase::copy(SecCFObject * p)
114{
115	if (ptr)
116	{
117		CheckForRelease(ptr);
118		CFRelease(ptr->operator CFTypeRef());
119	}
120
121	ptr = p;
122}
123
124
125
126//
127// SecCFObject
128//
129SecCFObject *
130SecCFObject::optional(CFTypeRef cfTypeRef) throw()
131{
132	if (!cfTypeRef)
133		return NULL;
134
135	return const_cast<SecCFObject *>(reinterpret_cast<const SecCFObject *>(reinterpret_cast<const uint8_t *>(cfTypeRef) + kAlignedRuntimeSize));
136}
137
138SecCFObject *
139SecCFObject::required(CFTypeRef cfTypeRef, OSStatus error)
140{
141	SecCFObject *object = optional(cfTypeRef);
142	if (!object)
143		MacOSError::throwMe(error);
144
145	return object;
146}
147
148void *
149SecCFObject::allocate(size_t size, const CFClass &cfclass) throw(std::bad_alloc)
150{
151	CFTypeRef p = _CFRuntimeCreateInstance(NULL, cfclass.typeID,
152		size + kAlignedRuntimeSize - sizeof(CFRuntimeBase), NULL);
153	if (p == NULL)
154		throw std::bad_alloc();
155
156	((SecRuntimeBase*) p)->isNew = true;
157
158	void *q = ((u_int8_t*) p) + kAlignedRuntimeSize;
159
160	if (SECURITY_DEBUG_SEC_CREATE_ENABLED()) {
161		const CFRuntimeClass *rtc = _CFRuntimeGetClassWithTypeID(cfclass.typeID);
162		SECURITY_DEBUG_SEC_CREATE(q, rtc ? (char *)rtc->className : NULL, (unsigned int)cfclass.typeID);
163	}
164	return q;
165}
166
167void
168SecCFObject::operator delete(void *object) throw()
169{
170	CFTypeRef cfType = reinterpret_cast<CFTypeRef>(reinterpret_cast<const uint8_t *>(object) - kAlignedRuntimeSize);
171    if (CF_IS_COLLECTABLE(cfType))
172    {
173        return;
174    }
175
176    CFAllocatorRef allocator = CFGetAllocator(cfType);
177    CFAllocatorDeallocate(allocator, (void*) cfType);
178}
179
180SecCFObject::SecCFObject()
181{
182    mRetainCount = 1;
183    mRetainSpinLock = OS_SPINLOCK_INIT;
184}
185
186uint32_t SecCFObject::updateRetainCount(intptr_t direction, uint32_t *oldCount)
187{
188    OSSpinLockLock(&mRetainSpinLock);
189
190    if (oldCount != NULL)
191    {
192        *oldCount = mRetainCount;
193    }
194
195    if (direction != -1 || mRetainCount != 0)
196    {
197        // if we are decrementing
198        if (direction == -1 || UINT32_MAX != mRetainCount)
199        {
200            mRetainCount += direction;
201        }
202    }
203
204    uint32_t result = mRetainCount;
205
206    OSSpinLockUnlock(&mRetainSpinLock);
207
208    return result;
209}
210
211
212
213SecCFObject::~SecCFObject()
214{
215	SECURITY_DEBUG_SEC_DESTROY(this);
216}
217
218bool
219SecCFObject::equal(SecCFObject &other)
220{
221	return this == &other;
222}
223
224CFHashCode
225SecCFObject::hash()
226{
227	return CFHashCode(this);
228}
229
230CFStringRef
231SecCFObject::copyFormattingDesc(CFDictionaryRef dict)
232{
233	return NULL;
234}
235
236CFStringRef
237SecCFObject::copyDebugDesc()
238{
239	return NULL;
240}
241
242CFTypeRef
243SecCFObject::handle(bool retain) throw()
244{
245	CFTypeRef cfType = *this;
246	if (retain && !isNew()) CFRetain(cfType);
247	return cfType;
248}
249
250
251
252void
253SecCFObject::aboutToDestruct()
254{
255}
256
257
258
259Mutex*
260SecCFObject::getMutexForObject()
261{
262	return NULL; // we only worry about descendants of KeychainImpl and ItemImpl
263}
264
265
266
267bool SecCFObject::mayDelete()
268{
269    return true;
270}
271