]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_utilities/lib/iodevices.cpp
Security-57337.20.44.tar.gz
[apple/security.git] / OSX / libsecurity_utilities / lib / iodevices.cpp
1 /*
2 * Copyright (c) 2004-2007,2011 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
24
25 //
26 // iodevices - code for finding and tracking devices via IOKit
27 //
28 #include "iodevices.h"
29 #include <security_utilities/cfutilities.h>
30 #include <IOKit/IOMessage.h>
31 #include <IOKit/usb/IOUSBLib.h>
32
33 using namespace MachPlusPlus;
34
35
36 namespace Security {
37 namespace IOKit {
38
39
40 //
41 // Master Ports.
42 // Note that multiple MasterPort objects may refer to the same Mach port.
43 //
44 MasterPort::MasterPort()
45 {
46 Error::check(::IOMasterPort(MACH_PORT_NULL, &port()));
47 }
48
49
50 //
51 // IOKit Devices (a small subset of functionality)
52 //
53 Device::~Device()
54 {
55 ::IOObjectRelease(mService);
56 }
57
58 string Device::name() const
59 {
60 io_name_t tName;
61 Error::check(::IORegistryEntryGetName(mService, tName));
62 return tName;
63 }
64
65 string Device::name(const char *plane) const
66 {
67 io_name_t tName;
68 Error::check(::IORegistryEntryGetNameInPlane(mService, plane, tName));
69 return tName;
70 }
71
72 string Device::path(const char *plane) const
73 {
74 io_string_t tPath;
75 Error::check(::IORegistryEntryGetPath(mService, plane, tPath));
76 return tPath;
77 }
78
79 CFDictionaryRef Device::properties() const
80 {
81 CFMutableDictionaryRef dict;
82 Error::check(::IORegistryEntryCreateCFProperties(mService, &dict, NULL, 0));
83 return dict;
84 }
85
86 CFTypeRef Device::property(const char *name) const
87 {
88 return ::IORegistryEntryCreateCFProperty(mService, CFTempString(name), NULL, 0);
89 }
90
91
92 //
93 // DeviceIterators
94 //
95 DeviceIterator::~DeviceIterator()
96 {
97 // drain the iterator to avoid port leakage
98 while (Device dev = (*this)())
99 ;
100 }
101
102
103 io_service_t DeviceIterator::operator () ()
104 {
105 io_service_t dev = ::IOIteratorNext(mIterator);
106 mAtEnd = !dev;
107 return dev;
108 }
109
110
111 //
112 // DeviceMatches
113 //
114 DeviceMatch::DeviceMatch()
115 : CFRef<CFMutableDictionaryRef>(makeCFMutableDictionary())
116 {
117 CFError::check(*this);
118 }
119
120 DeviceMatch::DeviceMatch(const char *cls)
121 : CFRef<CFMutableDictionaryRef>(::IOServiceMatching(cls))
122 {
123 CFError::check(*this);
124 }
125
126 DeviceMatch::DeviceMatch(const char *cls, const char *name, uint32_t value, ...)
127 : CFRef<CFMutableDictionaryRef>(::IOServiceMatching(cls))
128 {
129 CFError::check(*this);
130
131 va_list args;
132 va_start(args, value);
133 while (name) {
134 add(name, value);
135 name = va_arg(args, const char *);
136 if (!name)
137 break;
138 value = va_arg(args, uint32_t);
139 }
140 }
141
142 void DeviceMatch::add(const char *name, uint32_t value)
143 {
144 CFRef<CFNumberRef> number = CFNumberCreate(NULL, kCFNumberSInt32Type, &value);
145 CFDictionarySetValue(*this, CFTempString(name), number);
146 }
147
148
149 //
150 // NotificationPorts
151 //
152 NotificationPort::NotificationPort()
153 {
154 CFError::check(mPortRef = ::IONotificationPortCreate(MasterPort()));
155 }
156
157 NotificationPort::NotificationPort(const MasterPort &master)
158 {
159 CFError::check(mPortRef = ::IONotificationPortCreate(master));
160 }
161
162 NotificationPort::~NotificationPort()
163 {
164 ::IONotificationPortDestroy(mPortRef);
165 }
166
167
168 mach_port_t NotificationPort::port() const
169 {
170 mach_port_t p = ::IONotificationPortGetMachPort(mPortRef);
171 CFError::check(p);
172 return p;
173 }
174
175 CFRunLoopSourceRef NotificationPort::source() const
176 {
177 CFRunLoopSourceRef rls = ::IONotificationPortGetRunLoopSource(mPortRef);
178 CFError::check(rls);
179 return rls;
180 }
181
182
183 void NotificationPort::add(const DeviceMatch &match, Receiver &receiver, const char *type)
184 {
185 io_iterator_t iterator;
186 CFRetain(match); // compensate for IOSAMN not retaining its argument
187 Error::check(::IOServiceAddMatchingNotification(mPortRef, type,
188 match,
189 ioNotify, &receiver,
190 &iterator));
191
192 // run initial iterator to process existing devices
193 secdebug("iokit", "dispatching initial device match iterator %d", iterator);
194 DeviceIterator it(iterator);
195 receiver.ioChange(it);
196 }
197
198 void NotificationPort::addInterestNotification(Receiver &receiver, io_service_t service,
199 const io_name_t interestType)
200 {
201 io_iterator_t iterator;
202 mach_port_t pp = NotificationPort::port();
203
204 secdebug("iokit", "NotificationPort::addInterest - type: %s [port: %p (0x%08X), service: 0x%08X]",
205 interestType, mPortRef, pp, service);
206
207 // We cannot throw if we get an error here since we will receive notifications
208 // from each plane, and not all planes have the necessary information to be
209 // able to add an interest notification
210 kern_return_t kr = ::IOServiceAddInterestNotification(mPortRef,
211 service, interestType, ioDeviceNotification, &receiver, &iterator);
212 const char *msgstr = mach_error_string(kr);
213 const char *msgtyp = mach_error_type(kr);
214 if (msgstr && msgtyp)
215 secdebug("iokit", " msg: %s, typ: %s", msgstr, msgtyp);
216 }
217
218 void NotificationPort::ioNotify(void *refCon, io_iterator_t iterator)
219 {
220 secdebug("iokit", "dispatching new device match iterator %d", iterator);
221 DeviceIterator it(iterator);
222 try {
223 reinterpret_cast<Receiver *>(refCon)->ioChange(it);
224 } catch (...) {
225 secdebug("iokit", "ioChange callback threw an exception (ignored)");
226 }
227 }
228
229 void NotificationPort::ioDeviceNotification(void *refCon, io_service_t service,
230 natural_t messageType, void *messageArgument)
231 {
232 secdebug("iokit", "dispatching NEW device notification iterator, service 0x%08X, msg: 0x%04X, arg: %p",
233 service, messageType, messageArgument);
234
235 const char *msgstr = mach_error_string(messageType);
236 const char *msgtyp = mach_error_type(messageType);
237 if (msgstr && msgtyp)
238 secdebug("iokit", " msg: %s, typ: %s", msgstr, msgtyp);
239
240 if (service!=io_service_t(-1))
241 reinterpret_cast<Receiver *>(refCon)->ioServiceChange(refCon, service, messageType, messageArgument);
242 }
243
244 //
245 // Abstract NotificationPort::Receivers
246 //
247 NotificationPort::Receiver::~Receiver()
248 { /* virtual */ }
249
250
251 //
252 // MachPortNotificationPorts
253 //
254 MachPortNotificationPort::MachPortNotificationPort()
255 {
256 NoReplyHandler::port(NotificationPort::port());
257 }
258
259 MachPortNotificationPort::~MachPortNotificationPort()
260 {
261 }
262
263 boolean_t MachPortNotificationPort::handle(mach_msg_header_t *in)
264 {
265 ::IODispatchCalloutFromMessage(NULL, in, mPortRef);
266 return TRUE;
267 }
268
269
270
271 } // end namespace IOKit
272 } // end namespace Security