2 * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 #include <utilities/SecCFError.h>
26 #include <utilities/SecCFRelease.h>
27 #include <utilities/debugging.h>
32 // OSStatus values we magically know
35 parameterError
= -50, /* One or more parameters passed to a function were not valid. */
36 allocationError
= -108, /* Failed to allocate memory. */
39 bool SecKernError(kern_return_t result
, CFErrorRef
*error
, CFStringRef format
, ...) {
40 if (!result
) return true;
43 CFIndex code
= result
;
44 CFErrorRef previousError
= *error
;
47 va_start(args
, format
);
48 SecCFCreateErrorWithFormatAndArguments(code
, kSecKernDomain
, previousError
, error
, NULL
, format
, args
);
54 bool SecCheckErrno(int result
, CFErrorRef
*error
, CFStringRef format
, ...) {
55 if (result
== 0) return true;
59 CFIndex code
= errnum
;
60 CFErrorRef previousError
= *error
;
63 va_start(args
, format
);
64 CFStringRef message
= CFStringCreateWithFormatAndArguments(kCFAllocatorDefault
, NULL
, format
, args
);
66 SecCFCreateErrorWithFormat(code
, kSecErrnoDomain
, previousError
, error
, NULL
, CFSTR("%@: [%d] %s"), message
, errnum
, strerror(errnum
));
67 CFReleaseSafe(message
);
72 bool SecPOSIXError(int error
, CFErrorRef
*cferror
, CFStringRef format
, ...)
74 if (error
== 0) return true;
78 CFErrorRef previousError
= *cferror
;
81 va_start(args
, format
);
82 SecCFCreateErrorWithFormatAndArguments(code
, kSecErrnoDomain
, previousError
, cferror
, NULL
, format
, args
);
88 bool SecCoreCryptoError(int error
, CFErrorRef
*cferror
, CFStringRef format
, ...)
90 if (error
== 0) return true;
94 CFErrorRef previousError
= *cferror
;
97 va_start(args
, format
);
98 SecCFCreateErrorWithFormatAndArguments(code
, kSecCoreCryptoDomain
, previousError
, cferror
, NULL
, format
, args
);
105 bool SecNotifyError(uint32_t result
, CFErrorRef
*error
, CFStringRef format
, ...) {
106 if (result
== NOTIFY_STATUS_OK
) return true;
109 CFIndex code
= result
;
110 CFErrorRef previousError
= *error
;
113 va_start(args
, format
);
114 SecCFCreateErrorWithFormatAndArguments(code
, kSecNotifyDomain
, previousError
, error
, NULL
, format
, args
);
120 bool SecError(OSStatus status
, CFErrorRef
*error
, CFStringRef format
, ...) {
121 if (status
== 0) return true;
124 CFIndex code
= status
;
125 CFErrorRef previousError
= *error
;
128 va_start(args
, format
);
129 SecCFCreateErrorWithFormatAndArguments(code
, kSecErrorDomain
, previousError
, error
, NULL
, format
, args
);
136 bool SecRequirementError(bool requirement
, CFErrorRef
*error
, CFStringRef format
, ...) {
137 if (requirement
) return true;
140 CFErrorRef previousError
= *error
;
143 va_start(args
, format
);
144 SecCFCreateErrorWithFormatAndArguments(parameterError
, kSecErrorDomain
, previousError
, error
, NULL
, format
, args
);
150 // Allocation failure
151 bool SecAllocationError(const void *allocated
, CFErrorRef
*error
, CFStringRef format
, ...) {
152 if (allocated
) return true;
155 CFErrorRef previousError
= *error
;
158 va_start(args
, format
);
159 SecCFCreateErrorWithFormatAndArguments(allocationError
, kSecErrorDomain
, previousError
, error
, NULL
, format
, args
);
165 bool SecCFCreateErrorWithFormat(CFIndex errorCode
, CFStringRef domain
, CFErrorRef previousError
, CFErrorRef
*newError
,
166 CFDictionaryRef formatoptions
, CFStringRef format
, ...)
169 va_start(args
, format
);
171 bool result
= SecCFCreateErrorWithFormatAndArguments(errorCode
, domain
, previousError
, newError
, formatoptions
, format
, args
);
178 // Also consumes whatever newError points to
179 bool SecCFCreateErrorWithFormatAndArguments(CFIndex errorCode
, CFStringRef domain
,
180 CF_CONSUMED CFErrorRef previousError
, CFErrorRef
*newError
,
181 CFDictionaryRef formatoptions
, CFStringRef format
, va_list args
)
183 if (newError
&& !(*newError
)) {
184 CFStringRef formattedString
= CFStringCreateWithFormatAndArguments(NULL
, formatoptions
, format
, args
);
186 const void* keys
[2] = { kCFErrorDescriptionKey
, kCFErrorUnderlyingErrorKey
};
187 const void* values
[2] = { formattedString
, previousError
};
188 const CFIndex numEntriesToUse
= (previousError
!= NULL
) ? 2 : 1;
190 // Prepare to release whatever we replaced, as long as they didn't tell us to do so via previousError
191 // In a sane world, this function wouldn't have a previousError argument, since it should always release what it's replacing,
192 // but changing all callsites is a huge change
193 CFErrorRef replacing
= ((*newError
) == previousError
) ? NULL
: *newError
;
195 *newError
= CFErrorCreateWithUserInfoKeysAndValues(kCFAllocatorDefault
, domain
, errorCode
,
196 keys
, values
, numEntriesToUse
);
198 CFReleaseNull(formattedString
);
200 secdebug("error_thee_well", "encapsulated %@ with new error: %@", previousError
, *newError
);
202 CFReleaseNull(replacing
);
203 CFReleaseNull(previousError
);
205 if (previousError
&& newError
&& (previousError
!= *newError
)) {
206 secdebug("error_thee_well", "dropping %@", previousError
);
207 CFRelease(previousError
);
212 secdebug("error_thee_well", "SecError: %@", *newError
);