X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/Security/libsecurity_utilities/lib/iodevices.cpp diff --git a/Security/libsecurity_utilities/lib/iodevices.cpp b/Security/libsecurity_utilities/lib/iodevices.cpp new file mode 100644 index 00000000..28633d3e --- /dev/null +++ b/Security/libsecurity_utilities/lib/iodevices.cpp @@ -0,0 +1,272 @@ +/* + * Copyright (c) 2004-2007,2011 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +// +// iodevices - code for finding and tracking devices via IOKit +// +#include "iodevices.h" +#include +#include +#include + +using namespace MachPlusPlus; + + +namespace Security { +namespace IOKit { + + +// +// Master Ports. +// Note that multiple MasterPort objects may refer to the same Mach port. +// +MasterPort::MasterPort() +{ + Error::check(::IOMasterPort(MACH_PORT_NULL, &port())); +} + + +// +// IOKit Devices (a small subset of functionality) +// +Device::~Device() +{ + ::IOObjectRelease(mService); +} + +string Device::name() const +{ + io_name_t tName; + Error::check(::IORegistryEntryGetName(mService, tName)); + return tName; +} + +string Device::name(const char *plane) const +{ + io_name_t tName; + Error::check(::IORegistryEntryGetNameInPlane(mService, plane, tName)); + return tName; +} + +string Device::path(const char *plane) const +{ + io_string_t tPath; + Error::check(::IORegistryEntryGetPath(mService, plane, tPath)); + return tPath; +} + +CFDictionaryRef Device::properties() const +{ + CFMutableDictionaryRef dict; + Error::check(::IORegistryEntryCreateCFProperties(mService, &dict, NULL, 0)); + return dict; +} + +CFTypeRef Device::property(const char *name) const +{ + return ::IORegistryEntryCreateCFProperty(mService, CFTempString(name), NULL, 0); +} + + +// +// DeviceIterators +// +DeviceIterator::~DeviceIterator() +{ + // drain the iterator to avoid port leakage + while (Device dev = (*this)()) + ; +} + + +io_service_t DeviceIterator::operator () () +{ + io_service_t dev = ::IOIteratorNext(mIterator); + mAtEnd = !dev; + return dev; +} + + +// +// DeviceMatches +// +DeviceMatch::DeviceMatch() + : CFRef(makeCFMutableDictionary()) +{ + CFError::check(*this); +} + +DeviceMatch::DeviceMatch(const char *cls) + : CFRef(::IOServiceMatching(cls)) +{ + CFError::check(*this); +} + +DeviceMatch::DeviceMatch(const char *cls, const char *name, uint32_t value, ...) + : CFRef(::IOServiceMatching(cls)) +{ + CFError::check(*this); + + va_list args; + va_start(args, value); + while (name) { + add(name, value); + name = va_arg(args, const char *); + if (!name) + break; + value = va_arg(args, uint32_t); + } +} + +void DeviceMatch::add(const char *name, uint32_t value) +{ + CFRef number = CFNumberCreate(NULL, kCFNumberSInt32Type, &value); + CFDictionarySetValue(*this, CFTempString(name), number); +} + + +// +// NotificationPorts +// +NotificationPort::NotificationPort() +{ + CFError::check(mPortRef = ::IONotificationPortCreate(MasterPort())); +} + +NotificationPort::NotificationPort(const MasterPort &master) +{ + CFError::check(mPortRef = ::IONotificationPortCreate(master)); +} + +NotificationPort::~NotificationPort() +{ + ::IONotificationPortDestroy(mPortRef); +} + + +mach_port_t NotificationPort::port() const +{ + mach_port_t p = ::IONotificationPortGetMachPort(mPortRef); + CFError::check(p); + return p; +} + +CFRunLoopSourceRef NotificationPort::source() const +{ + CFRunLoopSourceRef rls = ::IONotificationPortGetRunLoopSource(mPortRef); + CFError::check(rls); + return rls; +} + + +void NotificationPort::add(const DeviceMatch &match, Receiver &receiver, const char *type) +{ + io_iterator_t iterator; + CFRetain(match); // compensate for IOSAMN not retaining its argument + Error::check(::IOServiceAddMatchingNotification(mPortRef, type, + match, + ioNotify, &receiver, + &iterator)); + + // run initial iterator to process existing devices + secdebug("iokit", "dispatching initial device match iterator %d", iterator); + DeviceIterator it(iterator); + receiver.ioChange(it); +} + +void NotificationPort::addInterestNotification(Receiver &receiver, io_service_t service, + const io_name_t interestType) +{ + io_iterator_t iterator; + mach_port_t pp = NotificationPort::port(); + + secdebug("iokit", "NotificationPort::addInterest - type: %s [port: %p (0x%08X), service: 0x%08X]", + interestType, mPortRef, pp, service); + + // We cannot throw if we get an error here since we will receive notifications + // from each plane, and not all planes have the necessary information to be + // able to add an interest notification + kern_return_t kr = ::IOServiceAddInterestNotification(mPortRef, + service, interestType, ioDeviceNotification, &receiver, &iterator); + const char *msgstr = mach_error_string(kr); + const char *msgtyp = mach_error_type(kr); + if (msgstr && msgtyp) + secdebug("iokit", " msg: %s, typ: %s", msgstr, msgtyp); +} + +void NotificationPort::ioNotify(void *refCon, io_iterator_t iterator) +{ + secdebug("iokit", "dispatching new device match iterator %d", iterator); + DeviceIterator it(iterator); + try { + reinterpret_cast(refCon)->ioChange(it); + } catch (...) { + secdebug("iokit", "ioChange callback threw an exception (ignored)"); + } +} + +void NotificationPort::ioDeviceNotification(void *refCon, io_service_t service, + natural_t messageType, void *messageArgument) +{ + secdebug("iokit", "dispatching NEW device notification iterator, service 0x%08X, msg: 0x%04X, arg: %p", + service, messageType, messageArgument); + + const char *msgstr = mach_error_string(messageType); + const char *msgtyp = mach_error_type(messageType); + if (msgstr && msgtyp) + secdebug("iokit", " msg: %s, typ: %s", msgstr, msgtyp); + + if (service!=io_service_t(-1)) + reinterpret_cast(refCon)->ioServiceChange(refCon, service, messageType, messageArgument); +} + +// +// Abstract NotificationPort::Receivers +// +NotificationPort::Receiver::~Receiver() +{ /* virtual */ } + + +// +// MachPortNotificationPorts +// +MachPortNotificationPort::MachPortNotificationPort() +{ + NoReplyHandler::port(NotificationPort::port()); +} + +MachPortNotificationPort::~MachPortNotificationPort() +{ +} + +boolean_t MachPortNotificationPort::handle(mach_msg_header_t *in) +{ + ::IODispatchCalloutFromMessage(NULL, in, mPortRef); + return TRUE; +} + + + +} // end namespace IOKit +} // end namespace Security