1 | /* |
2 | * Copyright (c) 1998-2020 Apple Computer, Inc. All rights reserved. |
3 | * |
4 | * @APPLE_OSREFERENCE_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. The rights granted to you under the License |
10 | * may not be used to create, or enable the creation or redistribution of, |
11 | * unlawful or unlicensed copies of an Apple operating system, or to |
12 | * circumvent, violate, or enable the circumvention or violation of, any |
13 | * terms of an Apple operating system software license agreement. |
14 | * |
15 | * Please obtain a copy of the License at |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. |
17 | * |
18 | * The Original Code and all software distributed under the License are |
19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, |
22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. |
23 | * Please see the License for the specific language governing rights and |
24 | * limitations under the License. |
25 | * |
26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ |
27 | */ |
28 | /* |
29 | * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. |
30 | * |
31 | */ |
32 | |
33 | #include <IOKit/assert.h> |
34 | #include <IOKit/IOLib.h> |
35 | #include <IOKit/IOKitKeys.h> |
36 | #include <IOKit/IOBufferMemoryDescriptor.h> |
37 | #include "RootDomainUserClient.h" |
38 | #include <IOKit/pwr_mgt/IOPMLibDefs.h> |
39 | #include <IOKit/pwr_mgt/IOPMPrivate.h> |
40 | #include <sys/proc.h> |
41 | |
42 | #define super IOUserClient2022 |
43 | |
44 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
45 | |
46 | OSDefineMetaClassAndStructors(RootDomainUserClient, IOUserClient2022) |
47 | |
48 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
49 | |
50 | bool |
51 | RootDomainUserClient::initWithTask(task_t owningTask, void *security_id, |
52 | UInt32 type, OSDictionary * properties) |
53 | { |
54 | if (properties) { |
55 | properties->setObject(kIOUserClientCrossEndianCompatibleKey, anObject: kOSBooleanTrue); |
56 | } |
57 | |
58 | if (!super::initWithTask(owningTask, securityToken: security_id, type, properties)) { |
59 | return false; |
60 | } |
61 | |
62 | fOwningTask = owningTask; |
63 | task_reference(fOwningTask); |
64 | return true; |
65 | } |
66 | |
67 | |
68 | bool |
69 | RootDomainUserClient::start( IOService * provider ) |
70 | { |
71 | assert(OSDynamicCast(IOPMrootDomain, provider)); |
72 | if (!super::start(provider)) { |
73 | return false; |
74 | } |
75 | fOwner = (IOPMrootDomain *)provider; |
76 | |
77 | setProperty(kIOUserClientDefaultLockingKey, anObject: kOSBooleanTrue); |
78 | setProperty(kIOUserClientDefaultLockingSetPropertiesKey, anObject: kOSBooleanTrue); |
79 | setProperty(kIOUserClientDefaultLockingSingleThreadExternalMethodKey, anObject: kOSBooleanFalse); |
80 | |
81 | setProperty(kIOUserClientEntitlementsKey, anObject: kOSBooleanFalse); |
82 | |
83 | return true; |
84 | } |
85 | |
86 | IOReturn |
87 | RootDomainUserClient::secureSleepSystem( uint32_t *return_code ) |
88 | { |
89 | return secureSleepSystemOptions(NULL, inOptionsSize: 0, returnCode: return_code); |
90 | } |
91 | |
92 | IOReturn |
93 | RootDomainUserClient::secureSleepSystemOptions( |
94 | const void *inOptions, |
95 | IOByteCount inOptionsSize, |
96 | uint32_t *returnCode) |
97 | { |
98 | int local_priv = 0; |
99 | int admin_priv = 0; |
100 | IOReturn ret = kIOReturnNotPrivileged; |
101 | |
102 | ret = clientHasPrivilege(securityToken: fOwningTask, kIOClientPrivilegeLocalUser); |
103 | local_priv = (kIOReturnSuccess == ret); |
104 | |
105 | ret = clientHasPrivilege(securityToken: fOwningTask, kIOClientPrivilegeAdministrator); |
106 | admin_priv = (kIOReturnSuccess == ret); |
107 | |
108 | if ((local_priv || admin_priv) && fOwner) { |
109 | OSString *unserializeErrorString = NULL; |
110 | OSObject *unserializedObject = NULL; |
111 | OSDictionary *sleepOptionsDict = NULL; // do not release |
112 | |
113 | proc_t p; |
114 | p = (proc_t)get_bsdtask_info(fOwningTask); |
115 | if (p) { |
116 | fOwner->setProperty(aKey: "SleepRequestedByPID" , aValue: proc_pid(p), aNumberOfBits: 32); |
117 | } |
118 | |
119 | if (inOptions) { |
120 | unserializedObject = OSUnserializeXML(buffer: (const char *)inOptions, bufferSize: inOptionsSize, errorString: &unserializeErrorString); |
121 | sleepOptionsDict = OSDynamicCast( OSDictionary, unserializedObject); |
122 | if (!sleepOptionsDict) { |
123 | IOLog(format: "IOPMRootDomain SleepSystem unserialization failure: %s\n" , |
124 | unserializeErrorString ? unserializeErrorString->getCStringNoCopy() : "Unknown" ); |
125 | } |
126 | } |
127 | |
128 | if (sleepOptionsDict) { |
129 | // Publish Sleep Options in registry under root_domain |
130 | fOwner->setProperty( kRootDomainSleepOptionsKey, anObject: sleepOptionsDict); |
131 | } else { |
132 | // No options |
133 | // Clear any pre-existing options |
134 | fOwner->removeProperty( kRootDomainSleepOptionsKey ); |
135 | } |
136 | |
137 | *returnCode = fOwner->sleepSystemOptions( options: sleepOptionsDict ); |
138 | OSSafeReleaseNULL(unserializedObject); |
139 | OSSafeReleaseNULL(unserializeErrorString); |
140 | } else { |
141 | *returnCode = kIOReturnNotPrivileged; |
142 | } |
143 | |
144 | return kIOReturnSuccess; |
145 | } |
146 | |
147 | IOReturn |
148 | RootDomainUserClient::secureSetAggressiveness( |
149 | unsigned long type, |
150 | unsigned long newLevel, |
151 | int *return_code ) |
152 | { |
153 | int local_priv = 0; |
154 | int admin_priv = 0; |
155 | IOReturn ret = kIOReturnNotPrivileged; |
156 | |
157 | ret = clientHasPrivilege(securityToken: fOwningTask, kIOClientPrivilegeLocalUser); |
158 | local_priv = (kIOReturnSuccess == ret); |
159 | |
160 | ret = clientHasPrivilege(securityToken: fOwningTask, kIOClientPrivilegeAdministrator); |
161 | admin_priv = (kIOReturnSuccess == ret); |
162 | |
163 | if ((local_priv || admin_priv) && fOwner) { |
164 | *return_code = fOwner->setAggressiveness(type, newLevel); |
165 | } else { |
166 | *return_code = kIOReturnNotPrivileged; |
167 | } |
168 | return kIOReturnSuccess; |
169 | } |
170 | |
171 | IOReturn |
172 | RootDomainUserClient::secureSetMaintenanceWakeCalendar( |
173 | IOPMCalendarStruct *inCalendar, |
174 | uint32_t *returnCode) |
175 | { |
176 | int admin_priv = 0; |
177 | IOReturn ret = kIOReturnNotPrivileged; |
178 | |
179 | ret = clientHasPrivilege(securityToken: fOwningTask, kIOClientPrivilegeAdministrator); |
180 | admin_priv = (kIOReturnSuccess == ret); |
181 | |
182 | if (admin_priv && fOwner) { |
183 | *returnCode = fOwner->setMaintenanceWakeCalendar(inCalendar); |
184 | } else { |
185 | *returnCode = kIOReturnNotPrivileged; |
186 | } |
187 | return kIOReturnSuccess; |
188 | } |
189 | |
190 | IOReturn |
191 | RootDomainUserClient::secureSetUserAssertionLevels( |
192 | uint32_t assertionBitfield) |
193 | { |
194 | int admin_priv = 0; |
195 | IOReturn ret = kIOReturnNotPrivileged; |
196 | |
197 | ret = clientHasPrivilege(securityToken: fOwningTask, kIOClientPrivilegeAdministrator); |
198 | admin_priv = (kIOReturnSuccess == ret); |
199 | |
200 | if (admin_priv && fOwner) { |
201 | ret = fOwner->setPMAssertionUserLevels(assertionBitfield); |
202 | } else { |
203 | ret = kIOReturnNotPrivileged; |
204 | } |
205 | return kIOReturnSuccess; |
206 | } |
207 | |
208 | IOReturn |
209 | RootDomainUserClient::secureGetSystemSleepType( |
210 | uint32_t *outSleepType, uint32_t *sleepTimer) |
211 | { |
212 | int admin_priv = 0; |
213 | IOReturn ret; |
214 | |
215 | ret = clientHasPrivilege(securityToken: fOwningTask, kIOClientPrivilegeAdministrator); |
216 | admin_priv = (kIOReturnSuccess == ret); |
217 | |
218 | if (admin_priv && fOwner) { |
219 | ret = fOwner->getSystemSleepType(sleepType: outSleepType, standbyTimer: sleepTimer); |
220 | } else { |
221 | ret = kIOReturnNotPrivileged; |
222 | } |
223 | return ret; |
224 | } |
225 | |
226 | IOReturn |
227 | RootDomainUserClient::clientClose( void ) |
228 | { |
229 | terminate(); |
230 | |
231 | return kIOReturnSuccess; |
232 | } |
233 | |
234 | void |
235 | RootDomainUserClient::stop( IOService *provider) |
236 | { |
237 | if (fOwningTask) { |
238 | task_deallocate(fOwningTask); |
239 | fOwningTask = NULL; |
240 | } |
241 | |
242 | super::stop(provider); |
243 | } |
244 | |
245 | IOReturn |
246 | RootDomainUserClient::externalMethod(uint32_t selector, IOExternalMethodArgumentsOpaque * args ) |
247 | { |
248 | static const IOExternalMethodDispatch2022 dispatchArray[] = { |
249 | [kPMSetAggressiveness] = { |
250 | .function = &RootDomainUserClient::externalMethodDispatched, |
251 | .checkScalarInputCount = 2, |
252 | .checkStructureInputSize = 0, |
253 | .checkScalarOutputCount = 1, |
254 | .checkStructureOutputSize = 0, |
255 | .allowAsync = false, |
256 | .checkEntitlement = NULL, |
257 | }, |
258 | [kPMGetAggressiveness] = { |
259 | .function = &RootDomainUserClient::externalMethodDispatched, |
260 | .checkScalarInputCount = 1, |
261 | .checkStructureInputSize = 0, |
262 | .checkScalarOutputCount = 1, |
263 | .checkStructureOutputSize = 0, |
264 | .allowAsync = false, |
265 | .checkEntitlement = NULL, |
266 | }, |
267 | [kPMSleepSystem] = { |
268 | .function = &RootDomainUserClient::externalMethodDispatched, |
269 | .checkScalarInputCount = 0, |
270 | .checkStructureInputSize = 0, |
271 | .checkScalarOutputCount = 1, |
272 | .checkStructureOutputSize = 0, |
273 | .allowAsync = false, |
274 | .checkEntitlement = NULL, |
275 | }, |
276 | [kPMAllowPowerChange] = { |
277 | .function = &RootDomainUserClient::externalMethodDispatched, |
278 | .checkScalarInputCount = 1, |
279 | .checkStructureInputSize = 0, |
280 | .checkScalarOutputCount = 0, |
281 | .checkStructureOutputSize = 0, |
282 | .allowAsync = false, |
283 | .checkEntitlement = NULL, |
284 | }, |
285 | [kPMCancelPowerChange] = { |
286 | .function = &RootDomainUserClient::externalMethodDispatched, |
287 | .checkScalarInputCount = 1, |
288 | .checkStructureInputSize = 0, |
289 | .checkScalarOutputCount = 0, |
290 | .checkStructureOutputSize = 0, |
291 | .allowAsync = false, |
292 | .checkEntitlement = NULL, |
293 | }, |
294 | [kPMShutdownSystem] = { |
295 | .function = &RootDomainUserClient::externalMethodDispatched, |
296 | .checkScalarInputCount = 0, |
297 | .checkStructureInputSize = 0, |
298 | .checkScalarOutputCount = 0, |
299 | .checkStructureOutputSize = 0, |
300 | .allowAsync = false, |
301 | .checkEntitlement = NULL, |
302 | }, |
303 | [kPMRestartSystem] = { |
304 | .function = &RootDomainUserClient::externalMethodDispatched, |
305 | .checkScalarInputCount = 0, |
306 | .checkStructureInputSize = 0, |
307 | .checkScalarOutputCount = 0, |
308 | .checkStructureOutputSize = 0, |
309 | .allowAsync = false, |
310 | .checkEntitlement = NULL, |
311 | }, |
312 | [kPMSleepSystemOptions] = { |
313 | .function = &RootDomainUserClient::externalMethodDispatched, |
314 | .checkScalarInputCount = 0, |
315 | .checkStructureInputSize = kIOUCVariableStructureSize, |
316 | .checkScalarOutputCount = 0, |
317 | .checkStructureOutputSize = sizeof(uint32_t), |
318 | .allowAsync = false, |
319 | .checkEntitlement = NULL, |
320 | }, |
321 | [kPMSetMaintenanceWakeCalendar] = { |
322 | .function = &RootDomainUserClient::externalMethodDispatched, |
323 | .checkScalarInputCount = 0, |
324 | .checkStructureInputSize = sizeof(IOPMCalendarStruct), |
325 | .checkScalarOutputCount = 0, |
326 | .checkStructureOutputSize = sizeof(uint32_t), |
327 | .allowAsync = false, |
328 | .checkEntitlement = NULL, |
329 | }, |
330 | [kPMSetUserAssertionLevels] = { |
331 | .function = &RootDomainUserClient::externalMethodDispatched, |
332 | .checkScalarInputCount = 1, |
333 | .checkStructureInputSize = 0, |
334 | .checkScalarOutputCount = 0, |
335 | .checkStructureOutputSize = 0, |
336 | .allowAsync = false, |
337 | .checkEntitlement = NULL, |
338 | }, |
339 | [kPMActivityTickle] = { |
340 | .function = &RootDomainUserClient::externalMethodDispatched, |
341 | .checkScalarInputCount = 0, |
342 | .checkStructureInputSize = 0, |
343 | .checkScalarOutputCount = 0, |
344 | .checkStructureOutputSize = 0, |
345 | .allowAsync = false, |
346 | .checkEntitlement = NULL, |
347 | }, |
348 | [kPMSetClamshellSleepState] = { |
349 | .function = &RootDomainUserClient::externalMethodDispatched, |
350 | .checkScalarInputCount = 1, |
351 | .checkStructureInputSize = 0, |
352 | .checkScalarOutputCount = 0, |
353 | .checkStructureOutputSize = 0, |
354 | .allowAsync = false, |
355 | .checkEntitlement = NULL, |
356 | }, |
357 | [kPMGetSystemSleepType] = { |
358 | .function = &RootDomainUserClient::externalMethodDispatched, |
359 | .checkScalarInputCount = 0, |
360 | .checkStructureInputSize = 0, |
361 | .checkScalarOutputCount = 2, |
362 | .checkStructureOutputSize = 0, |
363 | .allowAsync = false, |
364 | .checkEntitlement = NULL, |
365 | }, |
366 | [kPMSleepWakeWatchdogEnable] = { |
367 | .function = &RootDomainUserClient::externalMethodDispatched, |
368 | .checkScalarInputCount = 0, |
369 | .checkStructureInputSize = 0, |
370 | .checkScalarOutputCount = 0, |
371 | .checkStructureOutputSize = 0, |
372 | .allowAsync = false, |
373 | .checkEntitlement = NULL, |
374 | }, |
375 | [kPMSleepWakeDebugTrig] = { |
376 | .function = &RootDomainUserClient::externalMethodDispatched, |
377 | .checkScalarInputCount = 0, |
378 | .checkStructureInputSize = 0, |
379 | .checkScalarOutputCount = 0, |
380 | .checkStructureOutputSize = 0, |
381 | .allowAsync = false, |
382 | .checkEntitlement = NULL, |
383 | }, |
384 | [kPMSetDisplayPowerOn] = { |
385 | .function = &RootDomainUserClient::externalMethodDispatched, |
386 | .checkScalarInputCount = 1, |
387 | .checkStructureInputSize = 0, |
388 | .checkScalarOutputCount = 0, |
389 | .checkStructureOutputSize = 0, |
390 | .allowAsync = false, |
391 | .checkEntitlement = NULL, |
392 | }, |
393 | }; |
394 | |
395 | return dispatchExternalMethod(selector, arguments: args, dispatchArray, dispatchArrayCount: sizeof(dispatchArray) / sizeof(dispatchArray[0]), target: this, NULL); |
396 | } |
397 | IOReturn |
398 | RootDomainUserClient::externalMethodDispatched(OSObject * target, void * reference, IOExternalMethodArguments * arguments) |
399 | { |
400 | IOReturn ret = kIOReturnBadArgument; |
401 | RootDomainUserClient * me = (typeof(me))target; |
402 | switch (arguments->selector) { |
403 | case kPMSetAggressiveness: |
404 | ret = me->secureSetAggressiveness( |
405 | type: (unsigned long)arguments->scalarInput[0], |
406 | newLevel: (unsigned long)arguments->scalarInput[1], |
407 | return_code: (int *)&arguments->scalarOutput[0]); |
408 | break; |
409 | |
410 | case kPMGetAggressiveness: |
411 | ret = me->fOwner->getAggressiveness( |
412 | (unsigned long)arguments->scalarInput[0], |
413 | (unsigned long *)&arguments->scalarOutput[0]); |
414 | break; |
415 | |
416 | case kPMSleepSystem: |
417 | ret = me->secureSleepSystem( |
418 | return_code: (uint32_t *)&arguments->scalarOutput[0]); |
419 | break; |
420 | |
421 | case kPMAllowPowerChange: |
422 | ret = me->fOwner->allowPowerChange( |
423 | refcon: arguments->scalarInput[0]); |
424 | break; |
425 | |
426 | case kPMCancelPowerChange: |
427 | ret = me->fOwner->cancelPowerChange( |
428 | refcon: arguments->scalarInput[0]); |
429 | break; |
430 | |
431 | case kPMShutdownSystem: |
432 | // deprecated interface |
433 | ret = kIOReturnUnsupported; |
434 | break; |
435 | |
436 | case kPMRestartSystem: |
437 | // deprecated interface |
438 | ret = kIOReturnUnsupported; |
439 | break; |
440 | |
441 | case kPMSleepSystemOptions: |
442 | ret = me->secureSleepSystemOptions( |
443 | inOptions: arguments->structureInput, |
444 | inOptionsSize: arguments->structureInputSize, |
445 | returnCode: (uint32_t *)&arguments->structureOutput); |
446 | break; |
447 | case kPMSetMaintenanceWakeCalendar: |
448 | ret = me->secureSetMaintenanceWakeCalendar( |
449 | inCalendar: (IOPMCalendarStruct *)arguments->structureInput, |
450 | returnCode: (uint32_t *)&arguments->structureOutput); |
451 | arguments->structureOutputSize = sizeof(uint32_t); |
452 | break; |
453 | |
454 | case kPMSetUserAssertionLevels: |
455 | ret = me->secureSetUserAssertionLevels( |
456 | assertionBitfield: (uint32_t)arguments->scalarInput[0]); |
457 | break; |
458 | |
459 | case kPMActivityTickle: |
460 | if (me->fOwner->checkSystemCanSustainFullWake()) { |
461 | me->fOwner->reportUserInput(); |
462 | me->fOwner->setProperty(kIOPMRootDomainWakeTypeKey, aString: "UserActivity Assertion" ); |
463 | } |
464 | ret = kIOReturnSuccess; |
465 | break; |
466 | |
467 | case kPMSetClamshellSleepState: |
468 | me->fOwner->setClamShellSleepDisable(disable: arguments->scalarInput[0] ? true : false, |
469 | bitmask: IOPMrootDomain::kClamshellSleepDisablePowerd); |
470 | ret = kIOReturnSuccess; |
471 | break; |
472 | |
473 | case kPMGetSystemSleepType: |
474 | ret = me->secureGetSystemSleepType( |
475 | outSleepType: (uint32_t *) &arguments->scalarOutput[0], |
476 | sleepTimer: (uint32_t *) &arguments->scalarOutput[1]); |
477 | break; |
478 | |
479 | #if defined(__i386__) || defined(__x86_64__) |
480 | case kPMSleepWakeWatchdogEnable: |
481 | ret = clientHasPrivilege(me->fOwningTask, kIOClientPrivilegeAdministrator); |
482 | if (ret == kIOReturnSuccess) { |
483 | me->fOwner->sleepWakeDebugEnableWdog(); |
484 | } |
485 | break; |
486 | |
487 | |
488 | case kPMSleepWakeDebugTrig: |
489 | ret = clientHasPrivilege(me->fOwningTask, kIOClientPrivilegeAdministrator); |
490 | if (ret == kIOReturnSuccess) { |
491 | me->fOwner->sleepWakeDebugTrig(false); |
492 | } |
493 | break; |
494 | #endif |
495 | |
496 | case kPMSetDisplayPowerOn: |
497 | ret = clientHasPrivilege(securityToken: me->fOwningTask, kIOClientPrivilegeAdministrator); |
498 | if (ret == kIOReturnSuccess) { |
499 | me->fOwner->setDisplayPowerOn((uint32_t)arguments->scalarInput[0]); |
500 | } |
501 | break; |
502 | |
503 | default: |
504 | // bad selector |
505 | return kIOReturnBadArgument; |
506 | } |
507 | |
508 | return ret; |
509 | } |
510 | |
511 | /* getTargetAndMethodForIndex |
512 | * Not used. We prefer to use externalMethod() for user client invocations. |
513 | * We maintain getTargetAndExternalMethod since it's an exported symbol, |
514 | * and only for that reason. |
515 | */ |
516 | IOExternalMethod * |
517 | RootDomainUserClient::getTargetAndMethodForIndex( |
518 | IOService ** targetP, UInt32 index ) |
519 | { |
520 | // DO NOT EDIT |
521 | return super::getTargetAndMethodForIndex(targetP, index); |
522 | } |
523 | |
524 | /* setPreventative |
525 | * Does nothing. Exists only for exported symbol compatibility. |
526 | */ |
527 | void |
528 | RootDomainUserClient::setPreventative(UInt32 on_off, UInt32 types_of_sleep) |
529 | { |
530 | return; |
531 | } // DO NOT EDIT |
532 | |