+ if (p && (cred = kauth_cred_proc_ref(p)))
+ {
+ user = CopyUserOnConsole();
+ if (user)
+ {
+ OSNumber * num;
+ if ((num = OSDynamicCast(OSNumber, user->getObject(gIOConsoleSessionAuditIDKey)))
+ && (cred->cr_audit.as_aia_p->ai_asid == (au_asid_t) num->unsigned32BitValue()))
+ {
+ kr = kIOReturnSuccess;
+ }
+ user->release();
+ }
+ kauth_cred_unref(&cred);
+ }
+ return (kr);
+ }
+
+ if ((secureConsole = !strncmp(privilegeName, kIOClientPrivilegeSecureConsoleProcess,
+ sizeof(kIOClientPrivilegeSecureConsoleProcess))))
+ task = (task_t)((IOUCProcessToken *)securityToken)->token;
+ else
+ task = (task_t)securityToken;
+
+ count = TASK_SECURITY_TOKEN_COUNT;
+ kr = task_info( task, TASK_SECURITY_TOKEN, (task_info_t) &token, &count );
+
+ if (KERN_SUCCESS != kr)
+ {}
+ else if (!strncmp(privilegeName, kIOClientPrivilegeAdministrator,
+ sizeof(kIOClientPrivilegeAdministrator))) {
+ if (0 != token.val[0])
+ kr = kIOReturnNotPrivileged;
+ } else if (!strncmp(privilegeName, kIOClientPrivilegeLocalUser,
+ sizeof(kIOClientPrivilegeLocalUser))) {
+ user = CopyConsoleUser(token.val[0]);
+ if ( user )
+ user->release();
+ else
+ kr = kIOReturnNotPrivileged;
+ } else if (secureConsole || !strncmp(privilegeName, kIOClientPrivilegeConsoleUser,
+ sizeof(kIOClientPrivilegeConsoleUser))) {
+ user = CopyConsoleUser(token.val[0]);
+ if ( user ) {
+ if (user->getObject(gIOConsoleSessionOnConsoleKey) != kOSBooleanTrue)
+ kr = kIOReturnNotPrivileged;
+ else if ( secureConsole ) {
+ OSNumber * pid = OSDynamicCast(OSNumber, user->getObject(gIOConsoleSessionSecureInputPIDKey));
+ if ( pid && pid->unsigned32BitValue() != ((IOUCProcessToken *)securityToken)->pid)
+ kr = kIOReturnNotPrivileged;
+ }
+ user->release();
+ }
+ else
+ kr = kIOReturnNotPrivileged;
+ } else
+ kr = kIOReturnUnsupported;
+
+ return (kr);
+}
+
+OSObject * IOUserClient::copyClientEntitlement( task_t task,
+ const char * entitlement )
+{
+#define MAX_ENTITLEMENTS_LEN (128 * 1024)
+
+ proc_t p = NULL;
+ pid_t pid = 0;
+ char procname[MAXCOMLEN + 1] = "";
+ size_t len = 0;
+ void *entitlements_blob = NULL;
+ char *entitlements_data = NULL;
+ OSObject *entitlements_obj = NULL;
+ OSDictionary *entitlements = NULL;
+ OSString *errorString = NULL;
+ OSObject *value = NULL;
+
+ p = (proc_t)get_bsdtask_info(task);
+ if (p == NULL)
+ goto fail;
+ pid = proc_pid(p);
+ proc_name(pid, procname, (int)sizeof(procname));
+
+ if (cs_entitlements_blob_get(p, &entitlements_blob, &len) != 0)
+ goto fail;
+
+ if (len <= offsetof(CS_GenericBlob, data))
+ goto fail;
+
+ /*
+ * Per <rdar://problem/11593877>, enforce a limit on the amount of XML
+ * we'll try to parse in the kernel.
+ */
+ len -= offsetof(CS_GenericBlob, data);
+ if (len > MAX_ENTITLEMENTS_LEN) {
+ IOLog("failed to parse entitlements for %s[%u]: %lu bytes of entitlements exceeds maximum of %u\n", procname, pid, len, MAX_ENTITLEMENTS_LEN);
+ goto fail;
+ }
+
+ /*
+ * OSUnserializeXML() expects a nul-terminated string, but that isn't
+ * what is stored in the entitlements blob. Copy the string and
+ * terminate it.
+ */
+ entitlements_data = (char *)IOMalloc(len + 1);
+ if (entitlements_data == NULL)
+ goto fail;
+ memcpy(entitlements_data, ((CS_GenericBlob *)entitlements_blob)->data, len);
+ entitlements_data[len] = '\0';
+
+ entitlements_obj = OSUnserializeXML(entitlements_data, len + 1, &errorString);
+ if (errorString != NULL) {
+ IOLog("failed to parse entitlements for %s[%u]: %s\n", procname, pid, errorString->getCStringNoCopy());
+ goto fail;
+ }
+ if (entitlements_obj == NULL)
+ goto fail;
+
+ entitlements = OSDynamicCast(OSDictionary, entitlements_obj);
+ if (entitlements == NULL)
+ goto fail;
+
+ /* Fetch the entitlement value from the dictionary. */
+ value = entitlements->getObject(entitlement);
+ if (value != NULL)
+ value->retain();
+
+fail:
+ if (entitlements_data != NULL)
+ IOFree(entitlements_data, len + 1);
+ if (entitlements_obj != NULL)
+ entitlements_obj->release();
+ if (errorString != NULL)
+ errorString->release();
+ return value;
+}
+
+bool IOUserClient::init()
+{
+ if (getPropertyTable() || super::init())
+ return reserve();
+
+ return false;
+}
+
+bool IOUserClient::init(OSDictionary * dictionary)
+{
+ if (getPropertyTable() || super::init(dictionary))
+ return reserve();
+
+ return false;
+}
+
+bool IOUserClient::initWithTask(task_t owningTask,
+ void * securityID,
+ UInt32 type )
+{
+ if (getPropertyTable() || super::init())
+ return reserve();
+
+ return false;
+}
+
+bool IOUserClient::initWithTask(task_t owningTask,
+ void * securityID,
+ UInt32 type,
+ OSDictionary * properties )
+{
+ bool ok;
+
+ ok = super::init( properties );
+ ok &= initWithTask( owningTask, securityID, type );
+
+ return( ok );
+}
+
+bool IOUserClient::reserve()
+{
+ if(!reserved) {
+ reserved = IONew(ExpansionData, 1);
+ if (!reserved) {
+ return false;
+ }
+ }
+ setTerminateDefer(NULL, true);
+ IOStatisticsRegisterCounter();
+
+ return true;
+}
+
+struct IOUserClientOwner
+{
+ task_t task;
+ queue_chain_t taskLink;
+ IOUserClient * uc;
+ queue_chain_t ucLink;
+};
+
+IOReturn
+IOUserClient::registerOwner(task_t task)
+{
+ IOUserClientOwner * owner;
+ IOReturn ret;
+ bool newOwner;
+
+ IOLockLock(gIOUserClientOwnersLock);
+
+ newOwner = true;
+ ret = kIOReturnSuccess;
+
+ if (!owners.next) queue_init(&owners);
+ else
+ {
+ queue_iterate(&owners, owner, IOUserClientOwner *, ucLink)
+ {
+ if (task != owner->task) continue;
+ newOwner = false;
+ break;
+ }
+ }
+ if (newOwner)
+ {
+ owner = IONew(IOUserClientOwner, 1);
+ if (!newOwner) ret = kIOReturnNoMemory;
+ else
+ {
+ owner->task = task;
+ owner->uc = this;
+ queue_enter_first(&owners, owner, IOUserClientOwner *, ucLink);
+ queue_enter_first(task_io_user_clients(task), owner, IOUserClientOwner *, taskLink);
+ }
+ }
+
+ IOLockUnlock(gIOUserClientOwnersLock);
+
+ return (ret);
+}
+
+void
+IOUserClient::noMoreSenders(void)
+{
+ IOUserClientOwner * owner;
+
+ IOLockLock(gIOUserClientOwnersLock);
+
+ if (owners.next)
+ {
+ while (!queue_empty(&owners))
+ {
+ owner = (IOUserClientOwner *)(void *) queue_first(&owners);
+ queue_remove(task_io_user_clients(owner->task), owner, IOUserClientOwner *, taskLink);
+ queue_remove(&owners, owner, IOUserClientOwner *, ucLink);
+ IODelete(owner, IOUserClientOwner, 1);
+ }
+ owners.next = owners.prev = NULL;
+ }
+
+ IOLockUnlock(gIOUserClientOwnersLock);
+}
+
+extern "C" kern_return_t
+iokit_task_terminate(task_t task)
+{
+ IOUserClientOwner * owner;
+ IOUserClient * dead;
+ IOUserClient * uc;
+ queue_head_t * taskque;
+
+ IOLockLock(gIOUserClientOwnersLock);
+
+ taskque = task_io_user_clients(task);
+ dead = NULL;
+ while (!queue_empty(taskque))
+ {
+ owner = (IOUserClientOwner *)(void *) queue_first(taskque);
+ uc = owner->uc;
+ queue_remove(taskque, owner, IOUserClientOwner *, taskLink);
+ queue_remove(&uc->owners, owner, IOUserClientOwner *, ucLink);
+ if (queue_empty(&uc->owners))
+ {
+ uc->retain();
+ IOLog("destroying out of band connect for %s\n", uc->getName());
+ // now using the uc queue head as a singly linked queue,
+ // leaving .next as NULL to mark it empty
+ uc->owners.next = NULL;
+ uc->owners.prev = (queue_entry_t) dead;
+ dead = uc;
+ }
+ IODelete(owner, IOUserClientOwner, 1);
+ }
+
+ IOLockUnlock(gIOUserClientOwnersLock);
+
+ while (dead)
+ {
+ uc = dead;
+ dead = (IOUserClient *)(void *) dead->owners.prev;
+ uc->owners.prev = NULL;
+ if (uc->sharedInstance || !uc->closed) uc->clientDied();
+ uc->release();
+ }
+
+ return (KERN_SUCCESS);
+}
+
+void IOUserClient::free()
+{
+ if( mappings) mappings->release();
+
+ IOStatisticsUnregisterCounter();
+
+ assert(!owners.next);
+ assert(!owners.prev);
+
+ if (reserved) IODelete(reserved, ExpansionData, 1);
+
+ super::free();
+}
+
+IOReturn IOUserClient::clientDied( void )
+{
+ IOReturn ret = kIOReturnNotReady;
+
+ if (sharedInstance || OSCompareAndSwap8(0, 1, &closed))
+ {
+ ret = clientClose();
+ }
+
+ return (ret);