]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_codesigning/lib/SecAssessment.cpp
Security-57740.51.3.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 CFMutableDictionaryRef mcontext;
431 if (context == NULL) {
432 mcontext = makeCFMutableDictionary();
433 } else {
434 mcontext = makeCFMutableDictionary(context);
435 }
436
437 if (CFDictionaryGetValue(mcontext, kSecAssessmentUpdateKeyAuthorization) == NULL) {
438 // no authorization passed in. Make an empty one in this context
439 AuthorizationRef authorization;
440 MacOSError::check(AuthorizationCreate(NULL, NULL, kAuthorizationFlagDefaults, &authorization));
441 AuthorizationExternalForm extform;
442 MacOSError::check(AuthorizationMakeExternalForm(authorization, &extform));
443 CFDictionaryAddValue(mcontext, kSecAssessmentUpdateKeyAuthorization, CFTempData(&extform, sizeof(extform)));
444 if (!(flags & kSecAssessmentFlagDirect))
445 AuthorizationFree(authorization, kAuthorizationFlagDefaults);
446 }
447
448 if (flags & kSecAssessmentFlagDirect) {
449 if (__esp_enabled()) {
450 CFTemp<CFDictionaryRef> dict("{target=%O, flags=%d, context=%O}", target, flags, context);
451 OSStatus esp_result = __esp_check_ns("cs-assessment-update", (void *)(CFDictionaryRef)dict);
452 if (esp_result != noErr)
453 return NULL;
454 }
455
456 // ask the engine right here to do its thing
457 result = gEngine().update(target, flags, ctx);
458 } else {
459 // relay the question to our daemon for consideration
460 result = xpcEngineUpdate(target, flags, ctx);
461 }
462
463 if (__esp_enabled() && (flags & kSecAssessmentFlagDirect)) {
464 CFTemp<CFDictionaryRef> dict("{target=%O, flags=%d, context=%O, outcome=%O}", target, flags, context, (CFDictionaryRef)result);
465 __esp_notify_ns("cs-assessment-update", (void *)(CFDictionaryRef)dict);
466 }
467
468 traceUpdate(target, context, result);
469 return result.yield();
470
471 END_CSAPI_ERRORS1(NULL)
472 }
473
474
475 //
476 // The fcntl of System Policies.
477 // For those very special requests.
478 //
479 Boolean SecAssessmentControl(CFStringRef control, void *arguments, CFErrorRef *errors)
480 {
481 BEGIN_CSAPI
482
483 CFTemp<CFDictionaryRef> dict("{control=%O}", control);
484 esp_do_check("cs-assessment-control", dict);
485
486 if (CFEqual(control, CFSTR("ui-enable"))) {
487 setAssessment(true);
488 MessageTrace trace("com.apple.security.assessment.state", "enable");
489 trace.send("enable assessment outcomes");
490 return true;
491 } else if (CFEqual(control, CFSTR("ui-disable"))) {
492 setAssessment(false);
493 MessageTrace trace("com.apple.security.assessment.state", "disable");
494 trace.send("disable assessment outcomes");
495 return true;
496 } else if (CFEqual(control, CFSTR("ui-status"))) {
497 CFBooleanRef &result = *(CFBooleanRef*)(arguments);
498 if (overrideAssessment())
499 result = kCFBooleanFalse;
500 else
501 result = kCFBooleanTrue;
502 return true;
503 } else if (CFEqual(control, CFSTR("ui-enable-devid"))) {
504 CFTemp<CFDictionaryRef> ctx("{%O=%s, %O=%O}", kSecAssessmentUpdateKeyLabel, "Developer ID", kSecAssessmentContextKeyUpdate, kSecAssessmentUpdateOperationEnable);
505 SecAssessmentUpdate(NULL, kSecCSDefaultFlags, ctx, errors);
506 MessageTrace trace("com.apple.security.assessment.state", "enable-devid");
507 trace.send("enable Developer ID approval");
508 return true;
509 } else if (CFEqual(control, CFSTR("ui-disable-devid"))) {
510 CFTemp<CFDictionaryRef> ctx("{%O=%s, %O=%O}", kSecAssessmentUpdateKeyLabel, "Developer ID", kSecAssessmentContextKeyUpdate, kSecAssessmentUpdateOperationDisable);
511 SecAssessmentUpdate(NULL, kSecCSDefaultFlags, ctx, errors);
512 MessageTrace trace("com.apple.security.assessment.state", "disable-devid");
513 trace.send("disable Developer ID approval");
514 return true;
515 } else if (CFEqual(control, CFSTR("ui-get-devid"))) {
516 xpcEngineCheckDevID((CFBooleanRef*)(arguments));
517 return true;
518 } else if (CFEqual(control, CFSTR("ui-get-devid-local"))) {
519 CFBooleanRef &result = *(CFBooleanRef*)(arguments);
520 if (gEngine().value<int>("SELECT disabled FROM authority WHERE label = 'Developer ID';", true))
521 result = kCFBooleanFalse;
522 else
523 result = kCFBooleanTrue;
524 return true;
525 } else if (CFEqual(control, CFSTR("ui-record-reject"))) {
526 // send this through syspolicyd for update validation
527 xpcEngineRecord(CFDictionaryRef(arguments));
528 return true;
529 } else if (CFEqual(control, CFSTR("ui-record-reject-local"))) {
530 // perform the local operation (requires root)
531 gEngine().recordFailure(CFDictionaryRef(arguments));
532 return true;
533 } else if (CFEqual(control, CFSTR("ui-recall-reject"))) {
534 // no special privileges required for this, so read directly
535 CFDictionaryRef &result = *(CFDictionaryRef*)(arguments);
536 CFRef<CFDataRef> infoData = cfLoadFile(lastRejectFile);
537 if (infoData)
538 result = makeCFDictionaryFrom(infoData);
539 else
540 result = NULL;
541 return true;
542 } else if (CFEqual(control, CFSTR("rearm-status"))) {
543 CFTimeInterval &result = *(CFTimeInterval*)(arguments);
544 if (!queryRearmTimer(result))
545 result = 0;
546 return true;
547 } else
548 MacOSError::throwMe(errSecCSInvalidAttributeValues);
549
550 END_CSAPI_ERRORS1(false)
551 }