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