]>
Commit | Line | Data |
---|---|---|
55e303ae | 1 | /* |
39236c6e | 2 | * Copyright (c) 1998-2012 Apple Computer, Inc. All rights reserved. |
55e303ae | 3 | * |
2d21ac55 | 4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ |
55e303ae | 5 | * |
2d21ac55 A |
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. | |
8f6c56a5 | 14 | * |
2d21ac55 A |
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 | |
8f6c56a5 A |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
2d21ac55 A |
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. | |
8f6c56a5 | 25 | * |
2d21ac55 | 26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ |
55e303ae A |
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> | |
0c530ab8 | 35 | #include <IOKit/IOKitKeys.h> |
55e303ae A |
36 | #include <IOKit/IOBufferMemoryDescriptor.h> |
37 | #include "RootDomainUserClient.h" | |
38 | #include <IOKit/pwr_mgt/IOPMLibDefs.h> | |
316670eb | 39 | #include <IOKit/pwr_mgt/IOPMPrivate.h> |
39236c6e | 40 | #include <sys/proc.h> |
55e303ae A |
41 | |
42 | #define super IOUserClient | |
43 | ||
44 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
45 | ||
46 | OSDefineMetaClassAndStructors(RootDomainUserClient, IOUserClient) | |
47 | ||
48 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
49 | ||
0c530ab8 A |
50 | bool RootDomainUserClient::initWithTask(task_t owningTask, void *security_id, |
51 | UInt32 type, OSDictionary * properties) | |
91447636 | 52 | { |
0c530ab8 A |
53 | if (properties) |
54 | properties->setObject(kIOUserClientCrossEndianCompatibleKey, kOSBooleanTrue); | |
55 | ||
56 | if (!super::initWithTask(owningTask, security_id, type, properties)) | |
91447636 A |
57 | return false; |
58 | ||
59 | fOwningTask = owningTask; | |
60 | task_reference (fOwningTask); | |
61 | return true; | |
62 | } | |
63 | ||
64 | ||
55e303ae A |
65 | bool RootDomainUserClient::start( IOService * provider ) |
66 | { | |
67 | assert(OSDynamicCast(IOPMrootDomain, provider)); | |
68 | if(!super::start(provider)) | |
69 | return false; | |
70 | fOwner = (IOPMrootDomain *)provider; | |
71 | ||
72 | ||
73 | return true; | |
74 | } | |
75 | ||
2d21ac55 | 76 | IOReturn RootDomainUserClient::secureSleepSystem( uint32_t *return_code ) |
91447636 | 77 | { |
6d2010ae | 78 | return secureSleepSystemOptions(NULL, 0, return_code); |
2d21ac55 A |
79 | } |
80 | ||
81 | IOReturn RootDomainUserClient::secureSleepSystemOptions( | |
6d2010ae | 82 | const void *inOptions, |
39236c6e | 83 | IOByteCount inOptionsSize, |
6d2010ae | 84 | uint32_t *returnCode) |
2d21ac55 | 85 | { |
2d21ac55 | 86 | |
91447636 A |
87 | int local_priv = 0; |
88 | int admin_priv = 0; | |
89 | IOReturn ret = kIOReturnNotPrivileged; | |
2d21ac55 A |
90 | OSDictionary *unserializedOptions = NULL; |
91 | OSString *unserializeErrorString = NULL; | |
91447636 A |
92 | |
93 | ret = clientHasPrivilege(fOwningTask, kIOClientPrivilegeLocalUser); | |
94 | local_priv = (kIOReturnSuccess == ret); | |
95 | ||
96 | ret = clientHasPrivilege(fOwningTask, kIOClientPrivilegeAdministrator); | |
97 | admin_priv = (kIOReturnSuccess == ret); | |
2d21ac55 | 98 | |
2d21ac55 A |
99 | |
100 | if (inOptions) | |
101 | { | |
102 | unserializedOptions = OSDynamicCast( OSDictionary, | |
39236c6e | 103 | OSUnserializeXML((const char *)inOptions, inOptionsSize, &unserializeErrorString)); |
2d21ac55 A |
104 | |
105 | if (!unserializedOptions) { | |
106 | IOLog("IOPMRootDomain SleepSystem unserialization failure: %s\n", | |
107 | unserializeErrorString ? unserializeErrorString->getCStringNoCopy() : "Unknown"); | |
108 | } | |
109 | } | |
110 | ||
39236c6e | 111 | if ( (local_priv || admin_priv) && fOwner ) |
2d21ac55 | 112 | { |
39236c6e A |
113 | proc_t p; |
114 | p = (proc_t)get_bsdtask_info(fOwningTask); | |
115 | if (p) { | |
116 | fOwner->setProperty("SleepRequestedByPID", proc_pid(p), 32); | |
117 | } | |
118 | ||
2d21ac55 A |
119 | if (unserializedOptions) |
120 | { | |
121 | // Publish Sleep Options in registry under root_domain | |
122 | fOwner->setProperty( kRootDomainSleepOptionsKey, unserializedOptions); | |
123 | ||
124 | *returnCode = fOwner->sleepSystemOptions( unserializedOptions ); | |
125 | ||
126 | unserializedOptions->release(); | |
127 | } else { | |
128 | // No options | |
129 | // Clear any pre-existing options | |
130 | fOwner->removeProperty( kRootDomainSleepOptionsKey ); | |
131 | ||
132 | *returnCode = fOwner->sleepSystemOptions( NULL ); | |
133 | } | |
91447636 | 134 | |
91447636 | 135 | } else { |
2d21ac55 | 136 | *returnCode = kIOReturnNotPrivileged; |
91447636 A |
137 | } |
138 | ||
2d21ac55 | 139 | return kIOReturnSuccess; |
91447636 A |
140 | } |
141 | ||
142 | IOReturn RootDomainUserClient::secureSetAggressiveness( | |
143 | unsigned long type, | |
144 | unsigned long newLevel, | |
145 | int *return_code ) | |
146 | { | |
147 | int local_priv = 0; | |
148 | int admin_priv = 0; | |
149 | IOReturn ret = kIOReturnNotPrivileged; | |
150 | ||
151 | ret = clientHasPrivilege(fOwningTask, kIOClientPrivilegeLocalUser); | |
152 | local_priv = (kIOReturnSuccess == ret); | |
153 | ||
154 | ret = clientHasPrivilege(fOwningTask, kIOClientPrivilegeAdministrator); | |
155 | admin_priv = (kIOReturnSuccess == ret); | |
156 | ||
157 | if((local_priv || admin_priv) && fOwner) { | |
158 | *return_code = fOwner->setAggressiveness(type, newLevel); | |
91447636 A |
159 | } else { |
160 | *return_code = kIOReturnNotPrivileged; | |
91447636 | 161 | } |
6d2010ae | 162 | return kIOReturnSuccess; |
91447636 A |
163 | } |
164 | ||
6d2010ae A |
165 | IOReturn RootDomainUserClient::secureSetMaintenanceWakeCalendar( |
166 | IOPMCalendarStruct *inCalendar, | |
167 | uint32_t *returnCode) | |
b0d623f7 | 168 | { |
b0d623f7 A |
169 | int admin_priv = 0; |
170 | IOReturn ret = kIOReturnNotPrivileged; | |
171 | ||
172 | ret = clientHasPrivilege(fOwningTask, kIOClientPrivilegeAdministrator); | |
173 | admin_priv = (kIOReturnSuccess == ret); | |
174 | ||
b0d623f7 A |
175 | if (admin_priv && fOwner) { |
176 | *returnCode = fOwner->setMaintenanceWakeCalendar(inCalendar); | |
b0d623f7 A |
177 | } else { |
178 | *returnCode = kIOReturnNotPrivileged; | |
b0d623f7 | 179 | } |
6d2010ae | 180 | return kIOReturnSuccess; |
b0d623f7 | 181 | } |
55e303ae | 182 | |
0b4c1975 | 183 | IOReturn RootDomainUserClient::secureSetUserAssertionLevels( |
6d2010ae | 184 | uint32_t assertionBitfield) |
0b4c1975 A |
185 | { |
186 | int admin_priv = 0; | |
187 | IOReturn ret = kIOReturnNotPrivileged; | |
188 | ||
189 | ret = clientHasPrivilege(fOwningTask, kIOClientPrivilegeAdministrator); | |
190 | admin_priv = (kIOReturnSuccess == ret); | |
191 | ||
192 | if (admin_priv && fOwner) { | |
6d2010ae | 193 | ret = fOwner->setPMAssertionUserLevels(assertionBitfield); |
0b4c1975 A |
194 | } else { |
195 | ret = kIOReturnNotPrivileged; | |
196 | } | |
197 | return kIOReturnSuccess; | |
198 | } | |
199 | ||
db609669 A |
200 | IOReturn RootDomainUserClient::secureGetSystemSleepType( |
201 | uint32_t *outSleepType) | |
202 | { | |
203 | int admin_priv = 0; | |
204 | IOReturn ret; | |
205 | ||
206 | ret = clientHasPrivilege(fOwningTask, kIOClientPrivilegeAdministrator); | |
207 | admin_priv = (kIOReturnSuccess == ret); | |
208 | ||
209 | if (admin_priv && fOwner) { | |
210 | ret = fOwner->getSystemSleepType(outSleepType); | |
211 | } else { | |
212 | ret = kIOReturnNotPrivileged; | |
213 | } | |
214 | return ret; | |
215 | } | |
216 | ||
55e303ae A |
217 | IOReturn RootDomainUserClient::clientClose( void ) |
218 | { | |
219 | detach(fOwner); | |
91447636 A |
220 | |
221 | if(fOwningTask) { | |
222 | task_deallocate(fOwningTask); | |
223 | fOwningTask = 0; | |
224 | } | |
225 | ||
55e303ae A |
226 | return kIOReturnSuccess; |
227 | } | |
228 | ||
6d2010ae A |
229 | IOReturn RootDomainUserClient::clientMemoryForType( |
230 | UInt32 type, | |
231 | IOOptionBits *options, | |
232 | IOMemoryDescriptor ** memory) | |
55e303ae | 233 | { |
6d2010ae A |
234 | if (!fOwner) |
235 | return kIOReturnNotReady; | |
236 | ||
237 | if (kPMRootDomainMapTraceBuffer == type) | |
238 | { | |
239 | *memory = fOwner->getPMTraceMemoryDescriptor(); | |
240 | if (*memory) { | |
241 | (*memory)->retain(); | |
242 | *options = 0; | |
243 | return kIOReturnSuccess; | |
244 | } else { | |
245 | return kIOReturnNotFound; | |
2d21ac55 | 246 | } |
6d2010ae | 247 | |
55e303ae | 248 | } |
6d2010ae | 249 | return kIOReturnUnsupported; |
55e303ae A |
250 | } |
251 | ||
6d2010ae A |
252 | IOReturn RootDomainUserClient::externalMethod( |
253 | uint32_t selector, | |
254 | IOExternalMethodArguments * arguments, | |
255 | IOExternalMethodDispatch * dispatch __unused, | |
256 | OSObject * target __unused, | |
257 | void * reference __unused ) | |
2d21ac55 | 258 | { |
6d2010ae A |
259 | IOReturn ret = kIOReturnBadArgument; |
260 | ||
261 | switch (selector) | |
262 | { | |
263 | case kPMSetAggressiveness: | |
264 | if ((2 == arguments->scalarInputCount) | |
265 | && (1 == arguments->scalarOutputCount)) | |
266 | { | |
267 | ret = this->secureSetAggressiveness( | |
268 | (unsigned long)arguments->scalarInput[0], | |
269 | (unsigned long)arguments->scalarInput[1], | |
270 | (int *)&arguments->scalarOutput[0]); | |
271 | } | |
272 | break; | |
273 | ||
274 | case kPMGetAggressiveness: | |
275 | if ((1 == arguments->scalarInputCount) | |
276 | && (1 == arguments->scalarOutputCount)) | |
277 | { | |
278 | ret = fOwner->getAggressiveness( | |
279 | (unsigned long)arguments->scalarInput[0], | |
280 | (unsigned long *)&arguments->scalarOutput[0]); | |
281 | } | |
282 | break; | |
283 | ||
284 | case kPMSleepSystem: | |
285 | if (1 == arguments->scalarOutputCount) | |
286 | { | |
287 | ret = this->secureSleepSystem( | |
288 | (uint32_t *)&arguments->scalarOutput[0]); | |
289 | } | |
290 | break; | |
291 | ||
292 | case kPMAllowPowerChange: | |
293 | if (1 == arguments->scalarInputCount) | |
294 | { | |
295 | ret = fOwner->allowPowerChange( | |
296 | arguments->scalarInput[0]); | |
297 | } | |
298 | break; | |
299 | ||
300 | case kPMCancelPowerChange: | |
301 | if (1 == arguments->scalarInputCount) | |
302 | { | |
303 | ret = fOwner->cancelPowerChange( | |
304 | arguments->scalarInput[0]); | |
305 | } | |
306 | break; | |
307 | ||
308 | case kPMShutdownSystem: | |
309 | // deperecated interface | |
310 | ret = kIOReturnUnsupported; | |
311 | break; | |
312 | ||
313 | case kPMRestartSystem: | |
314 | // deperecated interface | |
315 | ret = kIOReturnUnsupported; | |
316 | break; | |
317 | ||
318 | case kPMSleepSystemOptions: | |
319 | ret = this->secureSleepSystemOptions( | |
320 | arguments->structureInput, | |
321 | arguments->structureInputSize, | |
322 | (uint32_t *)&arguments->scalarOutput[0]); | |
323 | break; | |
324 | case kPMSetMaintenanceWakeCalendar: | |
325 | ret = this->secureSetMaintenanceWakeCalendar( | |
326 | (IOPMCalendarStruct *)arguments->structureInput, | |
327 | (uint32_t *)&arguments->structureOutput); | |
328 | arguments->structureOutputSize = sizeof(uint32_t); | |
329 | break; | |
330 | ||
331 | case kPMSetUserAssertionLevels: | |
332 | ret = this->secureSetUserAssertionLevels( | |
333 | (uint32_t)arguments->scalarInput[0]); | |
334 | break; | |
335 | ||
7ddcb079 | 336 | case kPMActivityTickle: |
db609669 A |
337 | if ( fOwner->checkSystemCanSustainFullWake() ) |
338 | { | |
339 | fOwner->reportUserInput( ); | |
340 | fOwner->setProperty(kIOPMRootDomainWakeTypeKey, "UserActivity Assertion"); | |
341 | } | |
7ddcb079 A |
342 | ret = kIOReturnSuccess; |
343 | break; | |
db609669 A |
344 | |
345 | case kPMSetClamshellSleepState: | |
346 | fOwner->setDisableClamShellSleep(arguments->scalarInput[0] ? true : false); | |
347 | ret = kIOReturnSuccess; | |
348 | break; | |
349 | ||
350 | case kPMGetSystemSleepType: | |
351 | if (1 == arguments->scalarOutputCount) | |
352 | { | |
353 | ret = this->secureGetSystemSleepType( | |
354 | (uint32_t *) &arguments->scalarOutput[0]); | |
355 | } | |
356 | break; | |
39236c6e A |
357 | |
358 | case kPMSleepWakeWatchdogEnable: | |
359 | ret = clientHasPrivilege(fOwningTask, kIOClientPrivilegeAdministrator); | |
360 | if (ret == kIOReturnSuccess) | |
361 | fOwner->sleepWakeDebugEnableWdog(); | |
362 | break; | |
363 | ||
364 | ||
365 | case kPMSleepWakeDebugTrig: | |
366 | ret = clientHasPrivilege(fOwningTask, kIOClientPrivilegeAdministrator); | |
367 | if (ret == kIOReturnSuccess) | |
368 | fOwner->sleepWakeDebugTrig(false); | |
369 | break; | |
370 | ||
371 | case kPMSetDisplayPowerOn: | |
372 | if (1 == arguments->scalarInputCount) | |
373 | { | |
374 | ret = clientHasPrivilege(fOwningTask, kIOClientPrivilegeAdministrator); | |
375 | if (ret == kIOReturnSuccess) | |
376 | fOwner->setDisplayPowerOn((uint32_t)arguments->scalarInput[0]); | |
377 | } | |
378 | break; | |
6d2010ae A |
379 | /* |
380 | case kPMMethodCopySystemTimeline: | |
381 | // intentional fallthrough | |
382 | case kPMMethodCopyDetailedTimeline: | |
383 | ||
384 | if (!arguments->structureOutputDescriptor) | |
385 | { | |
386 | // TODO: Force IOKit.framework to always send this data out | |
387 | // of line; so I don't have to create a MemoryDescriptor here. | |
388 | mem_size = arguments->structureOutputSize; | |
389 | mem = IOMemoryDescriptor::withAddressRange( | |
390 | (mach_vm_address_t)arguments->structureOutput, | |
391 | (mach_vm_size_t)mem_size, | |
392 | kIODirectionIn, current_task()); | |
393 | } else { | |
394 | mem_size = arguments->structureOutputDescriptorSize; | |
395 | if (( mem = arguments->structureOutputDescriptor )) | |
396 | mem->retain(); | |
397 | } | |
398 | ||
399 | if (mem) | |
400 | { | |
401 | mem->prepare(kIODirectionNone); | |
402 | ||
403 | if (kPMMethodCopySystemTimeline == selector) { | |
404 | arguments->scalarOutput[0] = fOwner->copySystemTimeline( | |
405 | mem, &mem_size); | |
406 | } | |
407 | else | |
408 | if (kPMMethodCopyDetailedTimeline == selector) { | |
409 | arguments->scalarOutput[0] = fOwner->copyDetailedTimeline( | |
410 | mem, &mem_size); | |
411 | } | |
412 | ||
413 | if (arguments->structureOutputDescriptor) { | |
414 | arguments->structureOutputDescriptorSize = mem_size; | |
415 | } else { | |
416 | arguments->structureOutputSize = mem_size; | |
417 | } | |
418 | ||
419 | mem->release(); | |
420 | ||
421 | ret = kIOReturnSuccess; | |
422 | } else { | |
423 | ret = kIOReturnCannotWire; | |
424 | } | |
425 | ||
426 | break; | |
427 | */ | |
428 | default: | |
429 | // bad selector | |
430 | return kIOReturnBadArgument; | |
431 | } | |
432 | ||
433 | return ret; | |
2d21ac55 | 434 | } |
2d21ac55 | 435 | |
6d2010ae A |
436 | /* getTargetAndMethodForIndex |
437 | * Not used. We prefer to use externalMethod() for user client invocations. | |
438 | * We maintain getTargetAndExternalMethod since it's an exported symbol, | |
439 | * and only for that reason. | |
440 | */ | |
441 | IOExternalMethod * RootDomainUserClient::getTargetAndMethodForIndex( | |
442 | IOService ** targetP, UInt32 index ) | |
55e303ae | 443 | { |
6d2010ae A |
444 | // DO NOT EDIT |
445 | return super::getTargetAndMethodForIndex(targetP, index); | |
55e303ae A |
446 | } |
447 | ||
6d2010ae A |
448 | /* setPreventative |
449 | * Does nothing. Exists only for exported symbol compatibility. | |
450 | */ | |
451 | void | |
452 | RootDomainUserClient::setPreventative(UInt32 on_off, UInt32 types_of_sleep) | |
453 | { return; } // DO NOT EDIT |