]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_codesigning/lib/SecAssessment.cpp
Security-57337.50.23.tar.gz
[apple/security.git] / OSX / libsecurity_codesigning / lib / SecAssessment.cpp
1 /*
2 * Copyright (c) 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 #include "cs.h"
24 #include "SecAssessment.h"
25 #include "policydb.h"
26 #include "policyengine.h"
27 #include "xpcengine.h"
28 #include "csutilities.h"
29 #include <CoreFoundation/CFRuntime.h>
30 #include <security_utilities/globalizer.h>
31 #include <security_utilities/unix++.h>
32 #include <security_utilities/cfmunge.h>
33 #include <notify.h>
34 #include <esp.h>
35
36 using namespace CodeSigning;
37
38
39 static void esp_do_check(const char *op, CFDictionaryRef dict)
40 {
41 OSStatus result = __esp_check_ns(op, (void *)(CFDictionaryRef)dict);
42 if (result != noErr)
43 MacOSError::throwMe(result);
44 }
45
46 //
47 // CF Objects
48 //
49 struct _SecAssessment : private CFRuntimeBase {
50 public:
51 _SecAssessment(CFURLRef p, AuthorityType typ, CFDictionaryRef r) : path(p), type(typ), result(r) { }
52
53 CFCopyRef<CFURLRef> path;
54 AuthorityType type;
55 CFRef<CFDictionaryRef> result;
56
57 public:
58 static _SecAssessment &ref(SecAssessmentRef r)
59 { return *(_SecAssessment *)r; }
60
61 // CF Boiler-plate
62 void *operator new (size_t size)
63 {
64 return (void *)_CFRuntimeCreateInstance(NULL, SecAssessmentGetTypeID(),
65 sizeof(_SecAssessment) - sizeof(CFRuntimeBase), NULL);
66 }
67
68 static void finalize(CFTypeRef obj)
69 { ((_SecAssessment *)obj)->~_SecAssessment(); }
70 };
71
72 typedef _SecAssessment SecAssessment;
73
74
75 static const CFRuntimeClass assessmentClass = {
76 0, // version
77 "SecAssessment", // name
78 NULL, // init
79 NULL, // copy
80 SecAssessment::finalize, // finalize
81 NULL, // equal
82 NULL, // hash
83 NULL, // formatting
84 NULL // debug string
85 };
86
87
88 static dispatch_once_t assessmentOnce;
89 CFTypeID assessmentType = _kCFRuntimeNotATypeID;
90
91 CFTypeID SecAssessmentGetTypeID()
92 {
93 dispatch_once(&assessmentOnce, ^void() {
94 if ((assessmentType = _CFRuntimeRegisterClass(&assessmentClass)) == _kCFRuntimeNotATypeID)
95 abort();
96 });
97 return assessmentType;
98 }
99
100
101 //
102 // Common dictionary constants
103 //
104 CFStringRef kSecAssessmentContextKeyOperation = CFSTR("operation");
105 CFStringRef kSecAssessmentOperationTypeExecute = CFSTR("operation:execute");
106 CFStringRef kSecAssessmentOperationTypeInstall = CFSTR("operation:install");
107 CFStringRef kSecAssessmentOperationTypeOpenDocument = CFSTR("operation:lsopen");
108
109
110 //
111 // Read-only in-process access to the policy database
112 //
113 class ReadPolicy : public PolicyDatabase {
114 public:
115 ReadPolicy() : PolicyDatabase(defaultDatabase) { }
116 };
117 ModuleNexus<ReadPolicy> gDatabase;
118
119
120 //
121 // An on-demand instance of the policy engine
122 //
123 ModuleNexus<PolicyEngine> gEngine;
124
125
126 //
127 // Policy evaluation ("assessment") operations
128 //
129 CFStringRef kSecAssessmentContextKeyUTI = CFSTR("context:uti");
130
131 CFStringRef kSecAssessmentContextKeyFeedback = CFSTR("context:feedback");
132 CFStringRef kSecAssessmentFeedbackProgress = CFSTR("feedback:progress");
133 CFStringRef kSecAssessmentFeedbackInfoCurrent = CFSTR("current");
134 CFStringRef kSecAssessmentFeedbackInfoTotal = CFSTR("total");
135
136 CFStringRef kSecAssessmentAssessmentVerdict = CFSTR("assessment:verdict");
137 CFStringRef kSecAssessmentAssessmentOriginator = CFSTR("assessment:originator");
138 CFStringRef kSecAssessmentAssessmentAuthority = CFSTR("assessment:authority");
139 CFStringRef kSecAssessmentAssessmentSource = CFSTR("assessment:authority:source");
140 CFStringRef kSecAssessmentAssessmentAuthorityRow = CFSTR("assessment:authority:row");
141 CFStringRef kSecAssessmentAssessmentAuthorityOverride = CFSTR("assessment:authority:override");
142 CFStringRef kSecAssessmentAssessmentAuthorityOriginalVerdict = CFSTR("assessment:authority:verdict");
143 CFStringRef kSecAssessmentAssessmentFromCache = CFSTR("assessment:authority:cached");
144 CFStringRef kSecAssessmentAssessmentWeakSignature = CFSTR("assessment:authority:weak");
145 CFStringRef kSecAssessmentAssessmentCodeSigningError = CFSTR("assessment:cserror");
146
147 CFStringRef kDisabledOverride = CFSTR("security disabled");
148
149 SecAssessmentRef SecAssessmentCreate(CFURLRef path,
150 SecAssessmentFlags flags,
151 CFDictionaryRef context,
152 CFErrorRef *errors)
153 {
154 BEGIN_CSAPI
155
156 if (flags & kSecAssessmentFlagAsynchronous)
157 MacOSError::throwMe(errSecCSUnimplemented);
158
159 AuthorityType type = typeFor(context, kAuthorityExecute);
160 CFRef<CFMutableDictionaryRef> result = makeCFMutableDictionary();
161
162 SYSPOLICY_ASSESS_API(cfString(path).c_str(), int(type), flags);
163
164 try {
165 if (__esp_enabled() && (flags & kSecAssessmentFlagDirect)) {
166 CFTemp<CFDictionaryRef> dict("{path=%O, flags=%d, context=%O, override=%d}", path, flags, context, overrideAssessment());
167 esp_do_check("cs-assessment-evaluate", dict);
168 }
169
170 if (flags & kSecAssessmentFlagDirect) {
171 // ask the engine right here to do its thing
172 SYSPOLICY_ASSESS_LOCAL();
173 gEngine().evaluate(path, type, flags, context, result);
174 } else {
175 // relay the question to our daemon for consideration
176 SYSPOLICY_ASSESS_REMOTE();
177 xpcEngineAssess(path, flags, context, result);
178 }
179 } catch (CommonError &error) {
180 switch (error.osStatus()) {
181 case CSSMERR_TP_CERT_REVOKED:
182 throw;
183 default:
184 if (!overrideAssessment(flags))
185 throw; // let it go as an error
186 break;
187 }
188 // record the error we would have returned
189 cfadd(result, "{%O=#F,'assessment:error'=%d}}", kSecAssessmentAssessmentVerdict, error.osStatus());
190 } catch (...) {
191 // catch stray errors not conforming to the CommonError scheme
192 if (!overrideAssessment(flags))
193 throw; // let it go as an error
194 cfadd(result, "{%O=#F}", kSecAssessmentAssessmentVerdict);
195 }
196
197 if (__esp_enabled() && (flags & kSecAssessmentFlagDirect)) {
198 CFTemp<CFDictionaryRef> dict("{path=%O, flags=%d, context=%O, override=%d, result=%O}", path, flags, context, overrideAssessment(), (CFDictionaryRef)result);
199 __esp_notify_ns("cs-assessment-evaluate", (void *)(CFDictionaryRef)dict);
200 }
201
202 return new SecAssessment(path, type, result.yield());
203
204 END_CSAPI_ERRORS1(NULL)
205 }
206
207
208 static void traceResult(CFURLRef target, MessageTrace &trace, std::string &sanitized)
209 {
210 static const char *interestingBundles[] = {
211 "UNBUNDLED",
212 "com.apple.",
213 "com.install4j.",
214 "com.MindVision.",
215 "com.yourcompany.",
216
217 "com.adobe.flashplayer.installmanager",
218 "com.adobe.Installers.Setup",
219 "com.adobe.PDApp.setup",
220 "com.bittorrent.uTorrent",
221 "com.divx.divx6formacinstaller",
222 "com.getdropbox.dropbox",
223 "com.google.Chrome",
224 "com.Google.GoogleEarthPlugin.plugin",
225 "com.Google.GoogleEarthPlus",
226 "com.hp.Installer",
227 "com.macpaw.CleanMyMac",
228 "com.microsoft.SilverlightInstaller",
229 "com.paragon-software.filesystems.NTFS.pkg",
230 "com.RealNetworks.RealPlayer",
231 "com.skype.skype",
232 "it.alfanet.squared5.MPEGStreamclip",
233 "org.mozilla.firefox",
234 "org.videolan.vlc",
235
236 NULL // sentinel
237 };
238
239 string identifier = "UNBUNDLED";
240 string version = "UNKNOWN";
241 if (CFRef<CFBundleRef> bundle = CFBundleCreate(NULL, target)) {
242 if (CFStringRef ident = CFBundleGetIdentifier(bundle))
243 identifier = cfString(ident);
244 if (CFStringRef vers = CFStringRef(CFBundleGetValueForInfoDictionaryKey(bundle, CFSTR("CFBundleShortVersionString"))))
245 version = cfString(vers);
246 }
247
248 CFRef<CFURLRef> url = CFURLCopyAbsoluteURL(target);
249 sanitized = cfString(url);
250 string::size_type rslash = sanitized.rfind('/');
251 if (rslash != string::npos)
252 sanitized = sanitized.substr(rslash+1);
253 bool keepFilename = false;
254 for (const char **pfx = interestingBundles; *pfx; pfx++) {
255 size_t pfxlen = strlen(*pfx);
256 if (identifier.compare(0, pfxlen, *pfx, pfxlen) == 0)
257 if (pfxlen == identifier.size() || (*pfx)[pfxlen-1] == '.') {
258 keepFilename = true;
259 break;
260 }
261 }
262 if (!keepFilename) {
263 string::size_type dot = sanitized.rfind('.');
264 if (dot != string::npos)
265 sanitized = sanitized.substr(dot);
266 else
267 sanitized = "(none)";
268 }
269
270 trace.add("signature2", "bundle:%s", identifier.c_str());
271 trace.add("signature3", "%s", sanitized.c_str());
272 trace.add("signature5", "%s", version.c_str());
273 }
274
275 static void traceAssessment(SecAssessment &assessment, AuthorityType type, CFDictionaryRef result)
276 {
277 if (CFDictionaryGetValue(result, CFSTR("assessment:remote")))
278 return; // just traced in syspolicyd
279
280 string authority = "UNSPECIFIED";
281 bool overridden = false;
282 bool old_overridden = false;
283 if (CFDictionaryRef authdict = CFDictionaryRef(CFDictionaryGetValue(result, kSecAssessmentAssessmentAuthority))) {
284 if (CFStringRef auth = CFStringRef(CFDictionaryGetValue(authdict, kSecAssessmentAssessmentSource)))
285 authority = cfString(auth);
286 else
287 authority = "no authority";
288 if (CFTypeRef override = CFDictionaryGetValue(authdict, kSecAssessmentAssessmentAuthorityOverride))
289 if (CFEqual(override, kDisabledOverride)) {
290 old_overridden = true;
291 if (CFDictionaryGetValue(authdict, kSecAssessmentAssessmentAuthorityOriginalVerdict) == kCFBooleanFalse)
292 overridden = true;
293 }
294 }
295
296 MessageTrace trace("com.apple.security.assessment.outcome2", NULL);
297 std::string sanitized;
298 traceResult(assessment.path, trace, sanitized);
299 trace.add("signature4", "%d", type);
300
301 if (CFDictionaryGetValue(result, kSecAssessmentAssessmentVerdict) == kCFBooleanFalse) {
302 trace.add("signature", "denied:%s", authority.c_str());
303 trace.send("assessment denied for %s", sanitized.c_str());
304 } else if (overridden) { // would have failed except for override
305 trace.add("signature", "defeated:%s", authority.c_str());
306 trace.send("assessment denied for %s but overridden", sanitized.c_str());
307 } else if (old_overridden) { // would have succeeded even without override
308 trace.add("signature", "override:%s", authority.c_str());
309 trace.send("assessment granted for %s and overridden", sanitized.c_str());
310 } else {
311 trace.add("signature", "granted:%s", authority.c_str());
312 trace.send("assessment granted for %s by %s", sanitized.c_str(), authority.c_str());
313 }
314 }
315
316 static void traceUpdate(CFTypeRef target, CFDictionaryRef context, CFDictionaryRef result)
317 {
318 // only trace add operations on URL targets
319 if (target == NULL || CFGetTypeID(target) != CFURLGetTypeID())
320 return;
321 CFStringRef edit = CFStringRef(CFDictionaryGetValue(context, kSecAssessmentContextKeyUpdate));
322 if (!CFEqual(edit, kSecAssessmentUpdateOperationAdd))
323 return;
324 MessageTrace trace("com.apple.security.assessment.update", NULL);
325 std::string sanitized;
326 traceResult(CFURLRef(target), trace, sanitized);
327 trace.send("added rule for %s", sanitized.c_str());
328 }
329
330
331 //
332 // At present, CopyResult simply retrieves the result already formed by Create.
333 // In the future, this will be more lazy.
334 //
335 CFDictionaryRef SecAssessmentCopyResult(SecAssessmentRef assessmentRef,
336 SecAssessmentFlags flags,
337 CFErrorRef *errors)
338 {
339 BEGIN_CSAPI
340
341 SecAssessment &assessment = SecAssessment::ref(assessmentRef);
342 CFCopyRef<CFDictionaryRef> result = assessment.result;
343 if (overrideAssessment(flags)) {
344 // turn rejections into approvals, but note that we did that
345 CFTypeRef verdict = CFDictionaryGetValue(result, kSecAssessmentAssessmentVerdict);
346 if (verdict == kCFBooleanFalse) {
347 CFRef<CFMutableDictionaryRef> adulterated = makeCFMutableDictionary(result.get());
348 CFDictionarySetValue(adulterated, kSecAssessmentAssessmentVerdict, kCFBooleanTrue);
349 if (CFDictionaryRef authority = CFDictionaryRef(CFDictionaryGetValue(adulterated, kSecAssessmentAssessmentAuthority))) {
350 CFRef<CFMutableDictionaryRef> authority2 = makeCFMutableDictionary(authority);
351 CFDictionarySetValue(authority2, kSecAssessmentAssessmentAuthorityOverride, kDisabledOverride);
352 CFDictionarySetValue(authority2, kSecAssessmentAssessmentAuthorityOriginalVerdict, verdict);
353 CFDictionarySetValue(adulterated, kSecAssessmentAssessmentAuthority, authority2);
354 } else {
355 cfadd(adulterated, "{%O={%O=%O}}",
356 kSecAssessmentAssessmentAuthority, kSecAssessmentAssessmentAuthorityOverride, kDisabledOverride);
357 }
358 result = adulterated.get();
359 }
360 }
361 traceAssessment(assessment, assessment.type, result);
362 return result.yield();
363
364 END_CSAPI_ERRORS1(NULL)
365 }
366
367
368 //
369 // Policy editing operations.
370 // These all make permanent changes to the system-wide authority records.
371 //
372 CFStringRef kSecAssessmentContextKeyUpdate = CFSTR("update");
373 CFStringRef kSecAssessmentUpdateOperationAdd = CFSTR("update:add");
374 CFStringRef kSecAssessmentUpdateOperationRemove = CFSTR("update:remove");
375 CFStringRef kSecAssessmentUpdateOperationEnable = CFSTR("update:enable");
376 CFStringRef kSecAssessmentUpdateOperationDisable = CFSTR("update:disable");
377 CFStringRef kSecAssessmentUpdateOperationFind = CFSTR("update:find");
378
379 CFStringRef kSecAssessmentUpdateKeyAuthorization = CFSTR("update:authorization");
380 CFStringRef kSecAssessmentUpdateKeyPriority = CFSTR("update:priority");
381 CFStringRef kSecAssessmentUpdateKeyLabel = CFSTR("update:label");
382 CFStringRef kSecAssessmentUpdateKeyExpires = CFSTR("update:expires");
383 CFStringRef kSecAssessmentUpdateKeyAllow = CFSTR("update:allow");
384 CFStringRef kSecAssessmentUpdateKeyRemarks = CFSTR("update:remarks");
385
386 CFStringRef kSecAssessmentUpdateKeyRow = CFSTR("update:row");
387 CFStringRef kSecAssessmentUpdateKeyCount = CFSTR("update:count");
388 CFStringRef kSecAssessmentUpdateKeyFound = CFSTR("update:found");
389
390 CFStringRef kSecAssessmentRuleKeyID = CFSTR("rule:id");
391 CFStringRef kSecAssessmentRuleKeyPriority = CFSTR("rule:priority");
392 CFStringRef kSecAssessmentRuleKeyAllow = CFSTR("rule:allow");
393 CFStringRef kSecAssessmentRuleKeyLabel = CFSTR("rule:label");
394 CFStringRef kSecAssessmentRuleKeyRemarks = CFSTR("rule:remarks");
395 CFStringRef kSecAssessmentRuleKeyRequirement = CFSTR("rule:requirement");
396 CFStringRef kSecAssessmentRuleKeyType = CFSTR("rule:type");
397 CFStringRef kSecAssessmentRuleKeyExpires = CFSTR("rule:expires");
398 CFStringRef kSecAssessmentRuleKeyDisabled = CFSTR("rule:disabled");
399 CFStringRef kSecAssessmentRuleKeyBookmark = CFSTR("rule:bookmark");
400
401
402 Boolean SecAssessmentUpdate(CFTypeRef target,
403 SecAssessmentFlags flags,
404 CFDictionaryRef context,
405 CFErrorRef *errors)
406 {
407 if (CFDictionaryRef outcome = SecAssessmentCopyUpdate(target, flags, context, errors)) {
408 CFRelease(outcome);
409 return true;
410 } else {
411 return false;
412 }
413 }
414
415 CFDictionaryRef SecAssessmentCopyUpdate(CFTypeRef target,
416 SecAssessmentFlags flags,
417 CFDictionaryRef context,
418 CFErrorRef *errors)
419 {
420 BEGIN_CSAPI
421
422 CFDictionary ctx(context, errSecCSInvalidAttributeValues);
423 CFRef<CFDictionaryRef> result;
424
425 // make context exist and writable
426 CFMutableDictionaryRef mcontext;
427 if (context == NULL) {
428 mcontext = makeCFMutableDictionary();
429 } else {
430 mcontext = makeCFMutableDictionary(context);
431 }
432
433 if (CFDictionaryGetValue(mcontext, kSecAssessmentUpdateKeyAuthorization) == NULL) {
434 // no authorization passed in. Make an empty one in this context
435 AuthorizationRef authorization;
436 MacOSError::check(AuthorizationCreate(NULL, NULL, kAuthorizationFlagDefaults, &authorization));
437 AuthorizationExternalForm extform;
438 MacOSError::check(AuthorizationMakeExternalForm(authorization, &extform));
439 CFDictionaryAddValue(mcontext, kSecAssessmentUpdateKeyAuthorization, CFTempData(&extform, sizeof(extform)));
440 if (!(flags & kSecAssessmentFlagDirect))
441 AuthorizationFree(authorization, kAuthorizationFlagDefaults);
442 }
443
444 if (flags & kSecAssessmentFlagDirect) {
445 if (__esp_enabled()) {
446 CFTemp<CFDictionaryRef> dict("{target=%O, flags=%d, context=%O}", target, flags, context);
447 OSStatus esp_result = __esp_check_ns("cs-assessment-update", (void *)(CFDictionaryRef)dict);
448 if (esp_result != noErr)
449 return NULL;
450 }
451
452 // ask the engine right here to do its thing
453 result = gEngine().update(target, flags, ctx);
454 } else {
455 // relay the question to our daemon for consideration
456 result = xpcEngineUpdate(target, flags, ctx);
457 }
458
459 if (__esp_enabled() && (flags & kSecAssessmentFlagDirect)) {
460 CFTemp<CFDictionaryRef> dict("{target=%O, flags=%d, context=%O, outcome=%O}", target, flags, context, (CFDictionaryRef)result);
461 __esp_notify_ns("cs-assessment-update", (void *)(CFDictionaryRef)dict);
462 }
463
464 traceUpdate(target, context, result);
465 return result.yield();
466
467 END_CSAPI_ERRORS1(false)
468 }
469
470
471 //
472 // The fcntl of System Policies.
473 // For those very special requests.
474 //
475 Boolean SecAssessmentControl(CFStringRef control, void *arguments, CFErrorRef *errors)
476 {
477 BEGIN_CSAPI
478
479 CFTemp<CFDictionaryRef> dict("{control=%O}", control);
480 esp_do_check("cs-assessment-control", dict);
481
482 if (CFEqual(control, CFSTR("ui-enable"))) {
483 setAssessment(true);
484 MessageTrace trace("com.apple.security.assessment.state", "enable");
485 trace.send("enable assessment outcomes");
486 return true;
487 } else if (CFEqual(control, CFSTR("ui-disable"))) {
488 setAssessment(false);
489 MessageTrace trace("com.apple.security.assessment.state", "disable");
490 trace.send("disable assessment outcomes");
491 return true;
492 } else if (CFEqual(control, CFSTR("ui-status"))) {
493 CFBooleanRef &result = *(CFBooleanRef*)(arguments);
494 if (overrideAssessment())
495 result = kCFBooleanFalse;
496 else
497 result = kCFBooleanTrue;
498 return true;
499 } else if (CFEqual(control, CFSTR("ui-enable-devid"))) {
500 CFTemp<CFDictionaryRef> ctx("{%O=%s}", kSecAssessmentUpdateKeyLabel, "Developer ID");
501 if (CFDictionaryRef result = gEngine().enable(NULL, kAuthorityInvalid, kSecCSDefaultFlags, ctx, false))
502 CFRelease(result);
503 MessageTrace trace("com.apple.security.assessment.state", "enable-devid");
504 trace.send("enable Developer ID approval");
505 return true;
506 } else if (CFEqual(control, CFSTR("ui-disable-devid"))) {
507 CFTemp<CFDictionaryRef> ctx("{%O=%s}", kSecAssessmentUpdateKeyLabel, "Developer ID");
508 if (CFDictionaryRef result = gEngine().disable(NULL, kAuthorityInvalid, kSecCSDefaultFlags, ctx, false))
509 CFRelease(result);
510 MessageTrace trace("com.apple.security.assessment.state", "disable-devid");
511 trace.send("disable Developer ID approval");
512 return true;
513 } else if (CFEqual(control, CFSTR("ui-get-devid"))) {
514 CFBooleanRef &result = *(CFBooleanRef*)(arguments);
515 if (gEngine().value<int>("SELECT disabled FROM authority WHERE label = 'Developer ID';", true))
516 result = kCFBooleanFalse;
517 else
518 result = kCFBooleanTrue;
519 return true;
520 } else if (CFEqual(control, CFSTR("ui-record-reject"))) {
521 // send this through syspolicyd for update validation
522 xpcEngineRecord(CFDictionaryRef(arguments));
523 return true;
524 } else if (CFEqual(control, CFSTR("ui-record-reject-local"))) {
525 // perform the local operation (requires root)
526 gEngine().recordFailure(CFDictionaryRef(arguments));
527 return true;
528 } else if (CFEqual(control, CFSTR("ui-recall-reject"))) {
529 // no special privileges required for this, so read directly
530 CFDictionaryRef &result = *(CFDictionaryRef*)(arguments);
531 CFRef<CFDataRef> infoData = cfLoadFile(lastRejectFile);
532 if (infoData)
533 result = makeCFDictionaryFrom(infoData);
534 else
535 result = NULL;
536 return true;
537 } else if (CFEqual(control, CFSTR("rearm-status"))) {
538 CFTimeInterval &result = *(CFTimeInterval*)(arguments);
539 if (!queryRearmTimer(result))
540 result = 0;
541 return true;
542 } else
543 MacOSError::throwMe(errSecCSInvalidAttributeValues);
544
545 END_CSAPI_ERRORS1(false)
546 }