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