]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_codesigning/lib/SecAssessment.cpp
Security-57336.1.9.tar.gz
[apple/security.git] / OSX / libsecurity_codesigning / lib / SecAssessment.cpp
1 /*
2 * Copyright (c) 2011-2014 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23 #include "cs.h"
24 #include "SecAssessment.h"
25 #include "policydb.h"
26 #include "policyengine.h"
27 #include "xpcengine.h"
28 #include "csutilities.h"
29 #include <CoreFoundation/CFRuntime.h>
30 #include <security_utilities/globalizer.h>
31 #include <security_utilities/unix++.h>
32 #include <security_utilities/cfmunge.h>
33 #include <notify.h>
34 #include <esp.h>
35
36 using namespace CodeSigning;
37
38
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
46 //
47 // CF Objects
48 //
49 struct _SecAssessment : private CFRuntimeBase {
50 public:
51 _SecAssessment(CFURLRef p, AuthorityType typ, CFDictionaryRef r) : path(p), type(typ), result(r) { }
52
53 CFCopyRef<CFURLRef> path;
54 AuthorityType type;
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 {
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 kSecAssessmentContextKeyFeedback = CFSTR("context:feedback");
130 CFStringRef kSecAssessmentFeedbackProgress = CFSTR("feedback:progress");
131 CFStringRef kSecAssessmentFeedbackInfoCurrent = CFSTR("current");
132 CFStringRef kSecAssessmentFeedbackInfoTotal = CFSTR("total");
133
134 CFStringRef kSecAssessmentAssessmentVerdict = CFSTR("assessment:verdict");
135 CFStringRef kSecAssessmentAssessmentOriginator = CFSTR("assessment:originator");
136 CFStringRef kSecAssessmentAssessmentAuthority = CFSTR("assessment:authority");
137 CFStringRef kSecAssessmentAssessmentSource = CFSTR("assessment:authority:source");
138 CFStringRef kSecAssessmentAssessmentAuthorityRow = CFSTR("assessment:authority:row");
139 CFStringRef kSecAssessmentAssessmentAuthorityOverride = CFSTR("assessment:authority:override");
140 CFStringRef kSecAssessmentAssessmentAuthorityOriginalVerdict = CFSTR("assessment:authority:verdict");
141 CFStringRef kSecAssessmentAssessmentFromCache = CFSTR("assessment:authority:cached");
142 CFStringRef kSecAssessmentAssessmentWeakSignature = CFSTR("assessment:authority:weak");
143 CFStringRef kSecAssessmentAssessmentCodeSigningError = CFSTR("assessment:cserror");
144
145 CFStringRef kDisabledOverride = CFSTR("security disabled");
146
147 SecAssessmentRef SecAssessmentCreate(CFURLRef path,
148 SecAssessmentFlags flags,
149 CFDictionaryRef context,
150 CFErrorRef *errors)
151 {
152 BEGIN_CSAPI
153
154 if (flags & kSecAssessmentFlagAsynchronous)
155 MacOSError::throwMe(errSecCSUnimplemented);
156
157 AuthorityType type = typeFor(context, kAuthorityExecute);
158 CFRef<CFMutableDictionaryRef> result = makeCFMutableDictionary();
159
160 SYSPOLICY_ASSESS_API(cfString(path).c_str(), int(type), flags);
161
162 try {
163 if (__esp_enabled() && (flags & kSecAssessmentFlagDirect)) {
164 CFTemp<CFDictionaryRef> dict("{path=%O, flags=%d, context=%O, override=%d}", path, flags, context, overrideAssessment());
165 esp_do_check("cs-assessment-evaluate", dict);
166 }
167
168 if (flags & kSecAssessmentFlagDirect) {
169 // ask the engine right here to do its thing
170 SYSPOLICY_ASSESS_LOCAL();
171 gEngine().evaluate(path, type, flags, context, result);
172 } else {
173 // relay the question to our daemon for consideration
174 SYSPOLICY_ASSESS_REMOTE();
175 xpcEngineAssess(path, flags, context, result);
176 }
177 } catch (CommonError &error) {
178 switch (error.osStatus()) {
179 case CSSMERR_TP_CERT_REVOKED:
180 throw;
181 default:
182 if (!overrideAssessment(flags))
183 throw; // let it go as an error
184 break;
185 }
186 // record the error we would have returned
187 cfadd(result, "{%O=#F,'assessment:error'=%d}}", kSecAssessmentAssessmentVerdict, error.osStatus());
188 } catch (...) {
189 // catch stray errors not conforming to the CommonError scheme
190 if (!overrideAssessment(flags))
191 throw; // let it go as an error
192 cfadd(result, "{%O=#F}", kSecAssessmentAssessmentVerdict);
193 }
194
195 if (__esp_enabled() && (flags & kSecAssessmentFlagDirect)) {
196 CFTemp<CFDictionaryRef> dict("{path=%O, flags=%d, context=%O, override=%d, result=%O}", path, flags, context, overrideAssessment(), (CFDictionaryRef)result);
197 __esp_notify_ns("cs-assessment-evaluate", (void *)(CFDictionaryRef)dict);
198 }
199
200 return new SecAssessment(path, type, result.yield());
201
202 END_CSAPI_ERRORS1(NULL)
203 }
204
205
206 static void traceResult(CFURLRef target, MessageTrace &trace, std::string &sanitized)
207 {
208 static const char *interestingBundles[] = {
209 "UNBUNDLED",
210 "com.apple.",
211 "com.install4j.",
212 "com.MindVision.",
213 "com.yourcompany.",
214
215 "com.adobe.flashplayer.installmanager",
216 "com.adobe.Installers.Setup",
217 "com.adobe.PDApp.setup",
218 "com.bittorrent.uTorrent",
219 "com.divx.divx6formacinstaller",
220 "com.getdropbox.dropbox",
221 "com.google.Chrome",
222 "com.Google.GoogleEarthPlugin.plugin",
223 "com.Google.GoogleEarthPlus",
224 "com.hp.Installer",
225 "com.macpaw.CleanMyMac",
226 "com.microsoft.SilverlightInstaller",
227 "com.paragon-software.filesystems.NTFS.pkg",
228 "com.RealNetworks.RealPlayer",
229 "com.skype.skype",
230 "it.alfanet.squared5.MPEGStreamclip",
231 "org.mozilla.firefox",
232 "org.videolan.vlc",
233
234 NULL // sentinel
235 };
236
237 string identifier = "UNBUNDLED";
238 string version = "UNKNOWN";
239 if (CFRef<CFBundleRef> bundle = CFBundleCreate(NULL, target)) {
240 if (CFStringRef ident = CFBundleGetIdentifier(bundle))
241 identifier = cfString(ident);
242 if (CFStringRef vers = CFStringRef(CFBundleGetValueForInfoDictionaryKey(bundle, CFSTR("CFBundleShortVersionString"))))
243 version = cfString(vers);
244 }
245
246 CFRef<CFURLRef> url = CFURLCopyAbsoluteURL(target);
247 sanitized = cfString(url);
248 string::size_type rslash = sanitized.rfind('/');
249 if (rslash != string::npos)
250 sanitized = sanitized.substr(rslash+1);
251 bool keepFilename = false;
252 for (const char **pfx = interestingBundles; *pfx; pfx++) {
253 size_t pfxlen = strlen(*pfx);
254 if (identifier.compare(0, pfxlen, *pfx, pfxlen) == 0)
255 if (pfxlen == identifier.size() || (*pfx)[pfxlen-1] == '.') {
256 keepFilename = true;
257 break;
258 }
259 }
260 if (!keepFilename) {
261 string::size_type dot = sanitized.rfind('.');
262 if (dot != string::npos)
263 sanitized = sanitized.substr(dot);
264 else
265 sanitized = "(none)";
266 }
267
268 trace.add("signature2", "bundle:%s", identifier.c_str());
269 trace.add("signature3", "%s", sanitized.c_str());
270 trace.add("signature5", "%s", version.c_str());
271 }
272
273 static void traceAssessment(SecAssessment &assessment, AuthorityType type, CFDictionaryRef result)
274 {
275 if (CFDictionaryGetValue(result, CFSTR("assessment:remote")))
276 return; // just traced in syspolicyd
277
278 string authority = "UNSPECIFIED";
279 bool overridden = false;
280 bool old_overridden = false;
281 if (CFDictionaryRef authdict = CFDictionaryRef(CFDictionaryGetValue(result, kSecAssessmentAssessmentAuthority))) {
282 if (CFStringRef auth = CFStringRef(CFDictionaryGetValue(authdict, kSecAssessmentAssessmentSource)))
283 authority = cfString(auth);
284 else
285 authority = "no authority";
286 if (CFTypeRef override = CFDictionaryGetValue(authdict, kSecAssessmentAssessmentAuthorityOverride))
287 if (CFEqual(override, kDisabledOverride)) {
288 old_overridden = true;
289 if (CFDictionaryGetValue(authdict, kSecAssessmentAssessmentAuthorityOriginalVerdict) == kCFBooleanFalse)
290 overridden = true;
291 }
292 }
293
294 MessageTrace trace("com.apple.security.assessment.outcome2", NULL);
295 std::string sanitized;
296 traceResult(assessment.path, trace, sanitized);
297 trace.add("signature4", "%d", type);
298
299 if (CFDictionaryGetValue(result, kSecAssessmentAssessmentVerdict) == kCFBooleanFalse) {
300 trace.add("signature", "denied:%s", authority.c_str());
301 trace.send("assessment denied for %s", sanitized.c_str());
302 } else if (overridden) { // would have failed except for override
303 trace.add("signature", "defeated:%s", authority.c_str());
304 trace.send("assessment denied for %s but overridden", sanitized.c_str());
305 } else if (old_overridden) { // would have succeeded even without override
306 trace.add("signature", "override:%s", authority.c_str());
307 trace.send("assessment granted for %s and overridden", sanitized.c_str());
308 } else {
309 trace.add("signature", "granted:%s", authority.c_str());
310 trace.send("assessment granted for %s by %s", sanitized.c_str(), authority.c_str());
311 }
312 }
313
314 static void traceUpdate(CFTypeRef target, CFDictionaryRef context, CFDictionaryRef result)
315 {
316 // only trace add operations on URL targets
317 if (target == NULL || CFGetTypeID(target) != CFURLGetTypeID())
318 return;
319 CFStringRef edit = CFStringRef(CFDictionaryGetValue(context, kSecAssessmentContextKeyUpdate));
320 if (!CFEqual(edit, kSecAssessmentUpdateOperationAdd))
321 return;
322 MessageTrace trace("com.apple.security.assessment.update", NULL);
323 std::string sanitized;
324 traceResult(CFURLRef(target), trace, sanitized);
325 trace.send("added rule for %s", sanitized.c_str());
326 }
327
328
329 //
330 // At present, CopyResult simply retrieves the result already formed by Create.
331 // In the future, this will be more lazy.
332 //
333 CFDictionaryRef SecAssessmentCopyResult(SecAssessmentRef assessmentRef,
334 SecAssessmentFlags flags,
335 CFErrorRef *errors)
336 {
337 BEGIN_CSAPI
338
339 SecAssessment &assessment = SecAssessment::ref(assessmentRef);
340 CFCopyRef<CFDictionaryRef> result = assessment.result;
341 if (overrideAssessment(flags)) {
342 // turn rejections into approvals, but note that we did that
343 CFTypeRef verdict = CFDictionaryGetValue(result, kSecAssessmentAssessmentVerdict);
344 if (verdict == kCFBooleanFalse) {
345 CFRef<CFMutableDictionaryRef> adulterated = makeCFMutableDictionary(result.get());
346 CFDictionarySetValue(adulterated, kSecAssessmentAssessmentVerdict, kCFBooleanTrue);
347 if (CFDictionaryRef authority = CFDictionaryRef(CFDictionaryGetValue(adulterated, kSecAssessmentAssessmentAuthority))) {
348 CFRef<CFMutableDictionaryRef> authority2 = makeCFMutableDictionary(authority);
349 CFDictionarySetValue(authority2, kSecAssessmentAssessmentAuthorityOverride, kDisabledOverride);
350 CFDictionarySetValue(authority2, kSecAssessmentAssessmentAuthorityOriginalVerdict, verdict);
351 CFDictionarySetValue(adulterated, kSecAssessmentAssessmentAuthority, authority2);
352 } else {
353 cfadd(adulterated, "{%O={%O=%O}}",
354 kSecAssessmentAssessmentAuthority, kSecAssessmentAssessmentAuthorityOverride, kDisabledOverride);
355 }
356 result = adulterated.get();
357 }
358 }
359 traceAssessment(assessment, assessment.type, result);
360 return result.yield();
361
362 END_CSAPI_ERRORS1(NULL)
363 }
364
365
366 //
367 // Policy editing operations.
368 // These all make permanent changes to the system-wide authority records.
369 //
370 CFStringRef kSecAssessmentContextKeyUpdate = CFSTR("update");
371 CFStringRef kSecAssessmentUpdateOperationAdd = CFSTR("update:add");
372 CFStringRef kSecAssessmentUpdateOperationRemove = CFSTR("update:remove");
373 CFStringRef kSecAssessmentUpdateOperationEnable = CFSTR("update:enable");
374 CFStringRef kSecAssessmentUpdateOperationDisable = CFSTR("update:disable");
375 CFStringRef kSecAssessmentUpdateOperationFind = CFSTR("update:find");
376
377 CFStringRef kSecAssessmentUpdateKeyAuthorization = CFSTR("update:authorization");
378 CFStringRef kSecAssessmentUpdateKeyPriority = CFSTR("update:priority");
379 CFStringRef kSecAssessmentUpdateKeyLabel = CFSTR("update:label");
380 CFStringRef kSecAssessmentUpdateKeyExpires = CFSTR("update:expires");
381 CFStringRef kSecAssessmentUpdateKeyAllow = CFSTR("update:allow");
382 CFStringRef kSecAssessmentUpdateKeyRemarks = CFSTR("update:remarks");
383
384 CFStringRef kSecAssessmentUpdateKeyRow = CFSTR("update:row");
385 CFStringRef kSecAssessmentUpdateKeyCount = CFSTR("update:count");
386 CFStringRef kSecAssessmentUpdateKeyFound = CFSTR("update:found");
387
388 CFStringRef kSecAssessmentRuleKeyID = CFSTR("rule:id");
389 CFStringRef kSecAssessmentRuleKeyPriority = CFSTR("rule:priority");
390 CFStringRef kSecAssessmentRuleKeyAllow = CFSTR("rule:allow");
391 CFStringRef kSecAssessmentRuleKeyLabel = CFSTR("rule:label");
392 CFStringRef kSecAssessmentRuleKeyRemarks = CFSTR("rule:remarks");
393 CFStringRef kSecAssessmentRuleKeyRequirement = CFSTR("rule:requirement");
394 CFStringRef kSecAssessmentRuleKeyType = CFSTR("rule:type");
395 CFStringRef kSecAssessmentRuleKeyExpires = CFSTR("rule:expires");
396 CFStringRef kSecAssessmentRuleKeyDisabled = CFSTR("rule:disabled");
397 CFStringRef kSecAssessmentRuleKeyBookmark = CFSTR("rule:bookmark");
398
399
400 Boolean SecAssessmentUpdate(CFTypeRef target,
401 SecAssessmentFlags flags,
402 CFDictionaryRef context,
403 CFErrorRef *errors)
404 {
405 if (CFDictionaryRef outcome = SecAssessmentCopyUpdate(target, flags, context, errors)) {
406 CFRelease(outcome);
407 return true;
408 } else {
409 return false;
410 }
411 }
412
413 CFDictionaryRef SecAssessmentCopyUpdate(CFTypeRef target,
414 SecAssessmentFlags flags,
415 CFDictionaryRef context,
416 CFErrorRef *errors)
417 {
418 BEGIN_CSAPI
419
420 CFDictionary ctx(context, errSecCSInvalidAttributeValues);
421 CFRef<CFDictionaryRef> result;
422
423 // make context exist and writable
424 CFMutableDictionaryRef mcontext;
425 if (context == NULL) {
426 mcontext = makeCFMutableDictionary();
427 } else {
428 mcontext = makeCFMutableDictionary(context);
429 }
430
431 if (CFDictionaryGetValue(mcontext, kSecAssessmentUpdateKeyAuthorization) == NULL) {
432 // no authorization passed in. Make an empty one in this context
433 AuthorizationRef authorization;
434 MacOSError::check(AuthorizationCreate(NULL, NULL, kAuthorizationFlagDefaults, &authorization));
435 AuthorizationExternalForm extform;
436 MacOSError::check(AuthorizationMakeExternalForm(authorization, &extform));
437 CFDictionaryAddValue(mcontext, kSecAssessmentUpdateKeyAuthorization, CFTempData(&extform, sizeof(extform)));
438 if (!(flags & kSecAssessmentFlagDirect))
439 AuthorizationFree(authorization, kAuthorizationFlagDefaults);
440 }
441
442 if (flags & kSecAssessmentFlagDirect) {
443 if (__esp_enabled()) {
444 CFTemp<CFDictionaryRef> dict("{target=%O, flags=%d, context=%O}", target, flags, context);
445 OSStatus esp_result = __esp_check_ns("cs-assessment-update", (void *)(CFDictionaryRef)dict);
446 if (esp_result != noErr)
447 return NULL;
448 }
449
450 // ask the engine right here to do its thing
451 result = gEngine().update(target, flags, ctx);
452 } else {
453 // relay the question to our daemon for consideration
454 result = xpcEngineUpdate(target, flags, ctx);
455 }
456
457 if (__esp_enabled() && (flags & kSecAssessmentFlagDirect)) {
458 CFTemp<CFDictionaryRef> dict("{target=%O, flags=%d, context=%O, outcome=%O}", target, flags, context, (CFDictionaryRef)result);
459 __esp_notify_ns("cs-assessment-update", (void *)(CFDictionaryRef)dict);
460 }
461
462 traceUpdate(target, context, result);
463 return result.yield();
464
465 END_CSAPI_ERRORS1(false)
466 }
467
468
469 //
470 // The fcntl of System Policies.
471 // For those very special requests.
472 //
473 Boolean SecAssessmentControl(CFStringRef control, void *arguments, CFErrorRef *errors)
474 {
475 BEGIN_CSAPI
476
477 CFTemp<CFDictionaryRef> dict("{control=%O}", control);
478 esp_do_check("cs-assessment-control", dict);
479
480 if (CFEqual(control, CFSTR("ui-enable"))) {
481 setAssessment(true);
482 MessageTrace trace("com.apple.security.assessment.state", "enable");
483 trace.send("enable assessment outcomes");
484 return true;
485 } else if (CFEqual(control, CFSTR("ui-disable"))) {
486 setAssessment(false);
487 MessageTrace trace("com.apple.security.assessment.state", "disable");
488 trace.send("disable assessment outcomes");
489 return true;
490 } else if (CFEqual(control, CFSTR("ui-status"))) {
491 CFBooleanRef &result = *(CFBooleanRef*)(arguments);
492 if (overrideAssessment())
493 result = kCFBooleanFalse;
494 else
495 result = kCFBooleanTrue;
496 return true;
497 } else if (CFEqual(control, CFSTR("ui-enable-devid"))) {
498 CFTemp<CFDictionaryRef> ctx("{%O=%s}", kSecAssessmentUpdateKeyLabel, "Developer ID");
499 if (CFDictionaryRef result = gEngine().enable(NULL, kAuthorityInvalid, kSecCSDefaultFlags, ctx, false))
500 CFRelease(result);
501 MessageTrace trace("com.apple.security.assessment.state", "enable-devid");
502 trace.send("enable Developer ID approval");
503 return true;
504 } else if (CFEqual(control, CFSTR("ui-disable-devid"))) {
505 CFTemp<CFDictionaryRef> ctx("{%O=%s}", kSecAssessmentUpdateKeyLabel, "Developer ID");
506 if (CFDictionaryRef result = gEngine().disable(NULL, kAuthorityInvalid, kSecCSDefaultFlags, ctx, false))
507 CFRelease(result);
508 MessageTrace trace("com.apple.security.assessment.state", "disable-devid");
509 trace.send("disable Developer ID approval");
510 return true;
511 } else if (CFEqual(control, CFSTR("ui-get-devid"))) {
512 CFBooleanRef &result = *(CFBooleanRef*)(arguments);
513 if (gEngine().value<int>("SELECT disabled FROM authority WHERE label = 'Developer ID';", true))
514 result = kCFBooleanFalse;
515 else
516 result = kCFBooleanTrue;
517 return true;
518 } else if (CFEqual(control, CFSTR("ui-record-reject"))) {
519 // send this through syspolicyd for update validation
520 xpcEngineRecord(CFDictionaryRef(arguments));
521 return true;
522 } else if (CFEqual(control, CFSTR("ui-record-reject-local"))) {
523 // perform the local operation (requires root)
524 gEngine().recordFailure(CFDictionaryRef(arguments));
525 return true;
526 } else if (CFEqual(control, CFSTR("ui-recall-reject"))) {
527 // no special privileges required for this, so read directly
528 CFDictionaryRef &result = *(CFDictionaryRef*)(arguments);
529 CFRef<CFDataRef> infoData = cfLoadFile(lastRejectFile);
530 if (infoData)
531 result = makeCFDictionaryFrom(infoData);
532 else
533 result = NULL;
534 return true;
535 } else if (CFEqual(control, CFSTR("rearm-status"))) {
536 CFTimeInterval &result = *(CFTimeInterval*)(arguments);
537 if (!queryRearmTimer(result))
538 result = 0;
539 return true;
540 } else
541 MacOSError::throwMe(errSecCSInvalidAttributeValues);
542
543 END_CSAPI_ERRORS1(false)
544 }