]>
Commit | Line | Data |
---|---|---|
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 | |
36 | using namespace CodeSigning; | |
37 | ||
38 | ||
427c49bc A |
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 | ||
b1ab9ed8 A |
46 | // |
47 | // CF Objects | |
48 | // | |
49 | struct _SecAssessment : private CFRuntimeBase { | |
50 | public: | |
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 | ||
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 | { | |
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 | // | |
105 | CFStringRef kSecAssessmentContextKeyOperation = CFSTR("operation"); | |
106 | CFStringRef kSecAssessmentOperationTypeExecute = CFSTR("operation:execute"); | |
107 | CFStringRef kSecAssessmentOperationTypeInstall = CFSTR("operation:install"); | |
108 | CFStringRef kSecAssessmentOperationTypeOpenDocument = CFSTR("operation:lsopen"); | |
109 | ||
80e23899 A |
110 | CFStringRef kSecAssessmentContextQuarantineFlags = CFSTR("context:qtnflags"); |
111 | ||
b1ab9ed8 A |
112 | |
113 | // | |
114 | // Read-only in-process access to the policy database | |
115 | // | |
116 | class ReadPolicy : public PolicyDatabase { | |
117 | public: | |
118 | ReadPolicy() : PolicyDatabase(defaultDatabase) { } | |
119 | }; | |
120 | ModuleNexus<ReadPolicy> gDatabase; | |
121 | ||
122 | ||
123 | // | |
124 | // An on-demand instance of the policy engine | |
125 | // | |
126 | ModuleNexus<PolicyEngine> gEngine; | |
127 | ||
128 | ||
129 | // | |
130 | // Policy evaluation ("assessment") operations | |
131 | // | |
132 | CFStringRef kSecAssessmentAssessmentVerdict = CFSTR("assessment:verdict"); | |
133 | CFStringRef kSecAssessmentAssessmentOriginator = CFSTR("assessment:originator"); | |
134 | CFStringRef kSecAssessmentAssessmentAuthority = CFSTR("assessment:authority"); | |
135 | CFStringRef kSecAssessmentAssessmentSource = CFSTR("assessment:authority:source"); | |
136 | CFStringRef kSecAssessmentAssessmentAuthorityRow = CFSTR("assessment:authority:row"); | |
137 | CFStringRef kSecAssessmentAssessmentAuthorityOverride = CFSTR("assessment:authority:override"); | |
427c49bc | 138 | CFStringRef kSecAssessmentAssessmentAuthorityOriginalVerdict = CFSTR("assessment:authority:verdict"); |
b1ab9ed8 | 139 | CFStringRef kSecAssessmentAssessmentFromCache = CFSTR("assessment:authority:cached"); |
80e23899 A |
140 | CFStringRef kSecAssessmentAssessmentWeakSignature = CFSTR("assessment:authority:weak"); |
141 | CFStringRef kSecAssessmentAssessmentCodeSigningError = CFSTR("assessment:cserror"); | |
b1ab9ed8 A |
142 | |
143 | CFStringRef kDisabledOverride = CFSTR("security disabled"); | |
144 | ||
b1ab9ed8 A |
145 | SecAssessmentRef 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 | 210 | static 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 |
277 | static 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 |
318 | static 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 | // | |
337 | CFDictionaryRef 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 | // | |
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); | |
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 | // | |
460 | Boolean 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 | } |