]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 | 1 | /* |
d8f41ccd | 2 | * Copyright (c) 2011-2014 Apple Inc. All Rights Reserved. |
b1ab9ed8 A |
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> | |
fa7225c8 | 30 | #include <CoreFoundation/CFBundlePriv.h> |
b1ab9ed8 A |
31 | #include <security_utilities/globalizer.h> |
32 | #include <security_utilities/unix++.h> | |
33 | #include <security_utilities/cfmunge.h> | |
34 | #include <notify.h> | |
427c49bc | 35 | #include <esp.h> |
b1ab9ed8 A |
36 | |
37 | using namespace CodeSigning; | |
38 | ||
39 | ||
427c49bc A |
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 | ||
b1ab9ed8 A |
47 | // |
48 | // CF Objects | |
49 | // | |
50 | struct _SecAssessment : private CFRuntimeBase { | |
51 | public: | |
d8f41ccd | 52 | _SecAssessment(CFURLRef p, AuthorityType typ, CFDictionaryRef r) : path(p), type(typ), result(r) { } |
b1ab9ed8 A |
53 | |
54 | CFCopyRef<CFURLRef> path; | |
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 | ||
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 | // | |
641423b6 A |
130 | CFStringRef kSecAssessmentContextKeyUTI = CFSTR("context:uti"); |
131 | ||
d8f41ccd A |
132 | CFStringRef kSecAssessmentContextKeyFeedback = CFSTR("context:feedback"); |
133 | CFStringRef kSecAssessmentFeedbackProgress = CFSTR("feedback:progress"); | |
134 | CFStringRef kSecAssessmentFeedbackInfoCurrent = CFSTR("current"); | |
135 | CFStringRef kSecAssessmentFeedbackInfoTotal = CFSTR("total"); | |
136 | ||
fa7225c8 A |
137 | CFStringRef kSecAssessmentContextKeyPrimarySignature = CFSTR("context:primary-signature"); |
138 | ||
b1ab9ed8 A |
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"); | |
427c49bc | 145 | CFStringRef kSecAssessmentAssessmentAuthorityOriginalVerdict = CFSTR("assessment:authority:verdict"); |
fa7225c8 | 146 | CFStringRef kSecAssessmentAssessmentAuthorityFlags = CFSTR("assessment:authority:flags"); |
b1ab9ed8 | 147 | CFStringRef kSecAssessmentAssessmentFromCache = CFSTR("assessment:authority:cached"); |
80e23899 A |
148 | CFStringRef kSecAssessmentAssessmentWeakSignature = CFSTR("assessment:authority:weak"); |
149 | CFStringRef kSecAssessmentAssessmentCodeSigningError = CFSTR("assessment:cserror"); | |
b1ab9ed8 A |
150 | |
151 | CFStringRef kDisabledOverride = CFSTR("security disabled"); | |
152 | ||
b1ab9ed8 A |
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 { | |
427c49bc A |
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 | ||
b1ab9ed8 A |
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: | |
427c49bc | 188 | if (!overrideAssessment(flags)) |
b1ab9ed8 A |
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 | |
427c49bc | 196 | if (!overrideAssessment(flags)) |
b1ab9ed8 A |
197 | throw; // let it go as an error |
198 | cfadd(result, "{%O=#F}", kSecAssessmentAssessmentVerdict); | |
199 | } | |
427c49bc A |
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 | ||
d8f41ccd | 206 | return new SecAssessment(path, type, result.yield()); |
b1ab9ed8 A |
207 | |
208 | END_CSAPI_ERRORS1(NULL) | |
209 | } | |
210 | ||
211 | ||
427c49bc | 212 | static void traceResult(CFURLRef target, MessageTrace &trace, std::string &sanitized) |
b1ab9ed8 | 213 | { |
427c49bc A |
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 | }; | |
b1ab9ed8 A |
242 | |
243 | string identifier = "UNBUNDLED"; | |
427c49bc | 244 | string version = "UNKNOWN"; |
fa7225c8 | 245 | if (CFRef<CFBundleRef> bundle = _CFBundleCreateUnique(NULL, target)) { |
b1ab9ed8 A |
246 | if (CFStringRef ident = CFBundleGetIdentifier(bundle)) |
247 | identifier = cfString(ident); | |
427c49bc A |
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 | } | |
d8f41ccd | 278 | |
427c49bc A |
279 | static void traceAssessment(SecAssessment &assessment, AuthorityType type, CFDictionaryRef result) |
280 | { | |
281 | if (CFDictionaryGetValue(result, CFSTR("assessment:remote"))) | |
282 | return; // just traced in syspolicyd | |
b1ab9ed8 A |
283 | |
284 | string authority = "UNSPECIFIED"; | |
285 | bool overridden = false; | |
427c49bc | 286 | bool old_overridden = false; |
b1ab9ed8 A |
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)) | |
427c49bc A |
293 | if (CFEqual(override, kDisabledOverride)) { |
294 | old_overridden = true; | |
295 | if (CFDictionaryGetValue(authdict, kSecAssessmentAssessmentAuthorityOriginalVerdict) == kCFBooleanFalse) | |
296 | overridden = true; | |
297 | } | |
b1ab9ed8 | 298 | } |
427c49bc A |
299 | |
300 | MessageTrace trace("com.apple.security.assessment.outcome2", NULL); | |
301 | std::string sanitized; | |
302 | traceResult(assessment.path, trace, sanitized); | |
313fa17b | 303 | trace.add("signature4", "%d", type); |
427c49bc | 304 | |
b1ab9ed8 A |
305 | if (CFDictionaryGetValue(result, kSecAssessmentAssessmentVerdict) == kCFBooleanFalse) { |
306 | trace.add("signature", "denied:%s", authority.c_str()); | |
b1ab9ed8 | 307 | trace.send("assessment denied for %s", sanitized.c_str()); |
427c49bc A |
308 | } else if (overridden) { // would have failed except for override |
309 | trace.add("signature", "defeated:%s", authority.c_str()); | |
b1ab9ed8 | 310 | trace.send("assessment denied for %s but overridden", sanitized.c_str()); |
427c49bc A |
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()); | |
b1ab9ed8 A |
314 | } else { |
315 | trace.add("signature", "granted:%s", authority.c_str()); | |
b1ab9ed8 A |
316 | trace.send("assessment granted for %s by %s", sanitized.c_str(), authority.c_str()); |
317 | } | |
318 | } | |
319 | ||
427c49bc A |
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 | ||
b1ab9ed8 A |
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; | |
427c49bc | 347 | if (overrideAssessment(flags)) { |
b1ab9ed8 | 348 | // turn rejections into approvals, but note that we did that |
427c49bc A |
349 | CFTypeRef verdict = CFDictionaryGetValue(result, kSecAssessmentAssessmentVerdict); |
350 | if (verdict == kCFBooleanFalse) { | |
b1ab9ed8 A |
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); | |
427c49bc | 356 | CFDictionarySetValue(authority2, kSecAssessmentAssessmentAuthorityOriginalVerdict, verdict); |
b1ab9ed8 A |
357 | CFDictionarySetValue(adulterated, kSecAssessmentAssessmentAuthority, authority2); |
358 | } else { | |
359 | cfadd(adulterated, "{%O={%O=%O}}", | |
360 | kSecAssessmentAssessmentAuthority, kSecAssessmentAssessmentAuthorityOverride, kDisabledOverride); | |
361 | } | |
362 | result = adulterated.get(); | |
363 | } | |
364 | } | |
d8f41ccd | 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 | 428 | |
5c19dc3a A |
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 | ||
b1ab9ed8 | 448 | if (flags & kSecAssessmentFlagDirect) { |
427c49bc A |
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 | ||
b1ab9ed8 | 456 | // ask the engine right here to do its thing |
427c49bc | 457 | result = gEngine().update(target, flags, ctx); |
b1ab9ed8 A |
458 | } else { |
459 | // relay the question to our daemon for consideration | |
427c49bc | 460 | result = xpcEngineUpdate(target, flags, ctx); |
b1ab9ed8 A |
461 | } |
462 | ||
427c49bc A |
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 | ||
b1ab9ed8 A |
471 | END_CSAPI_ERRORS1(false) |
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 | ||
427c49bc A |
483 | CFTemp<CFDictionaryRef> dict("{control=%O}", control); |
484 | esp_do_check("cs-assessment-control", dict); | |
485 | ||
b1ab9ed8 A |
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"))) { | |
fa7225c8 A |
504 | CFTemp<CFDictionaryRef> ctx("{%O=%s, %O=%O}", kSecAssessmentUpdateKeyLabel, "Developer ID", kSecAssessmentContextKeyUpdate, kSecAssessmentUpdateOperationEnable); |
505 | SecAssessmentUpdate(NULL, kSecCSDefaultFlags, ctx, errors); | |
313fa17b A |
506 | MessageTrace trace("com.apple.security.assessment.state", "enable-devid"); |
507 | trace.send("enable Developer ID approval"); | |
b1ab9ed8 A |
508 | return true; |
509 | } else if (CFEqual(control, CFSTR("ui-disable-devid"))) { | |
fa7225c8 A |
510 | CFTemp<CFDictionaryRef> ctx("{%O=%s, %O=%O}", kSecAssessmentUpdateKeyLabel, "Developer ID", kSecAssessmentContextKeyUpdate, kSecAssessmentUpdateOperationDisable); |
511 | SecAssessmentUpdate(NULL, kSecCSDefaultFlags, ctx, errors); | |
313fa17b A |
512 | MessageTrace trace("com.apple.security.assessment.state", "disable-devid"); |
513 | trace.send("disable Developer ID approval"); | |
b1ab9ed8 | 514 | return true; |
fa7225c8 A |
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"))) { | |
b1ab9ed8 A |
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; | |
427c49bc A |
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; | |
d8f41ccd A |
542 | } else if (CFEqual(control, CFSTR("rearm-status"))) { |
543 | CFTimeInterval &result = *(CFTimeInterval*)(arguments); | |
544 | if (!queryRearmTimer(result)) | |
545 | result = 0; | |
546 | return true; | |
b1ab9ed8 A |
547 | } else |
548 | MacOSError::throwMe(errSecCSInvalidAttributeValues); | |
549 | ||
550 | END_CSAPI_ERRORS1(false) | |
551 | } |