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