]> git.saurik.com Git - apple/security.git/blob - cdsa/cdsa_utilities/mach++.cpp
Security-28.tar.gz
[apple/security.git] / cdsa / cdsa_utilities / mach++.cpp
1 /*
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
3 *
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
8 * using this file.
9 *
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
16 */
17
18
19 //
20 // mach++ - C++ bindings for useful Mach primitives
21 //
22 #include "mach++.h"
23 #include <mach/mach_error.h>
24 #include <stdio.h> // debug
25 #include <Security/debugging.h>
26 #include <servers/bootstrap_defs.h> // debug
27
28 namespace Security {
29 namespace MachPlusPlus {
30
31
32 Error::Error(kern_return_t err) : error(err)
33 {
34 }
35
36 Error::~Error()
37 {
38 }
39
40 CSSM_RETURN
41 Error::cssmError() const
42 {
43 switch (error) {
44 case BOOTSTRAP_UNKNOWN_SERVICE:
45 case MIG_SERVER_DIED:
46 return CSSM_ERRCODE_SERVICE_NOT_AVAILABLE;
47 default:
48 return CSSM_ERRCODE_INTERNAL_ERROR;
49 }
50 }
51
52 OSStatus
53 Error::osStatus() const
54 {
55 return cssmError();
56 }
57
58 void Error::check(kern_return_t status)
59 {
60 if (status != KERN_SUCCESS) {
61 #if !defined(NDEBUG)
62 // issue a diagnostic log for any discovered mach-level error
63 switch (status) {
64 case BOOTSTRAP_UNKNOWN_SERVICE:
65 debug("error", "mach error: BOOTSTRAP_UNKNOWN_SERVICE"); break;
66 case BOOTSTRAP_NAME_IN_USE:
67 debug("error", "mach error: BOOTSTRAP_NAME_IN_USE"); break;
68 case BOOTSTRAP_NOT_PRIVILEGED:
69 debug("error", "mach error: BOOTSTRAP_NOT_PRIVILEGED"); break;
70 case BOOTSTRAP_SERVICE_ACTIVE:
71 debug("error", "mach error: BOOTSTRAP_SERVICE_ACTIVE"); break;
72 default:
73 debug("error", "mach error: %s (%d)", mach_error_string(status), status); break;
74 }
75 #endif NDEBUG
76 Error::throwMe(status);
77 }
78 }
79
80 void Error::throwMe(kern_return_t err) { throw Error(err); }
81
82 //
83 // Port functions
84 //
85 mach_port_urefs_t Port::getRefs(mach_port_right_t right)
86 {
87 mach_port_urefs_t count;
88 check(::mach_port_get_refs(self(), mPort, right, &count));
89 return count;
90 }
91
92
93 //
94 // Task port features
95 //
96 pid_t TaskPort::pid() const
97 {
98 pid_t pid;
99 check(::pid_for_task(mPort, &pid));
100 return pid;
101 }
102
103 TaskPort TaskPort::forPid(pid_t pid)
104 {
105 TaskPort taskPort;
106 check(::task_for_pid(self(), pid, &taskPort.port()));
107 return taskPort;
108 }
109
110
111 //
112 // Bootstrap port management
113 //
114 mach_port_t Bootstrap::checkIn(const char *name) const
115 {
116 mach_port_t port;
117 check(::bootstrap_check_in(mPort, makeName(name), &port));
118 return port;
119 }
120
121 mach_port_t Bootstrap::checkInOptional(const char *name) const
122 {
123 mach_port_t port;
124 kern_return_t err = ::bootstrap_check_in(mPort, makeName(name), &port);
125 if (err == BOOTSTRAP_UNKNOWN_SERVICE || err == BOOTSTRAP_NOT_PRIVILEGED)
126 return 0;
127 check(err);
128 return port;
129 }
130
131 void Bootstrap::registerAs(mach_port_t port, const char *name) const
132 {
133 check(::bootstrap_register(mPort, makeName(name), port));
134 }
135
136 mach_port_t Bootstrap::lookup(const char *name) const
137 {
138 mach_port_t port;
139 check(::bootstrap_look_up(mPort, makeName(name), &port));
140 return port;
141 }
142
143 mach_port_t Bootstrap::lookupOptional(const char *name) const
144 {
145 mach_port_t port;
146 kern_return_t err = ::bootstrap_look_up(mPort, makeName(name), &port);
147 if (err == BOOTSTRAP_UNKNOWN_SERVICE)
148 return 0;
149 check(err);
150 return port;
151 }
152
153
154 Bootstrap Bootstrap::subset(Port requestor)
155 {
156 mach_port_t sub;
157 check(::bootstrap_subset(mPort, requestor, &sub));
158 return sub;
159 }
160
161
162 //
163 // ReceivePorts
164 //
165 ReceivePort::ReceivePort(const char *name, const Bootstrap &bootstrap)
166 {
167 mPort = bootstrap.checkInOptional(name);
168 if (!mPort)
169 {
170 allocate();
171 insertRight(MACH_MSG_TYPE_MAKE_SEND);
172 bootstrap.registerAs(mPort, name);
173 }
174 }
175
176
177 //
178 // Stack-based bootstrap switcher
179 //
180 ModuleNexus<Mutex> StBootstrap::critical;
181
182 StBootstrap::StBootstrap(const Bootstrap &newBoot, const TaskPort &task)
183 : mTask(task), locker(critical())
184 {
185 mOldBoot = Bootstrap();
186 mTask.bootstrap(newBoot);
187 debug("StBoot", "bootstrap for %d switched to %d", mTask.port(), newBoot.port());
188 }
189
190 StBootstrap::~StBootstrap()
191 {
192 mTask.bootstrap(mOldBoot);
193 debug("StBoot", "bootstrap for %d returned to %d", mTask.port(), mOldBoot.port());
194 }
195
196
197 //
198 // Mach message buffers
199 //
200 Message::Message(void *buffer, size_t size)
201 : mBuffer(reinterpret_cast<mig_reply_error_t *>(buffer)),
202 mSize(size), mRelease(false)
203 {
204 assert(size >= sizeof(mach_msg_header_t));
205 }
206
207 Message::Message(size_t size)
208 {
209 mSize = size + MAX_TRAILER_SIZE;
210 mBuffer = (mig_reply_error_t *)new char[mSize];
211 mRelease = true;
212 }
213
214 Message::~Message()
215 {
216 if (mRelease)
217 delete[] mBuffer;
218 }
219
220
221 void Message::send(mach_msg_option_t options,
222 mach_msg_timeout_t timeout,
223 mach_port_name_t notify)
224 {
225 check(mach_msg_overwrite_trap(*this,
226 options | MACH_SEND_MSG,
227 length(),
228 0, MACH_PORT_NULL,
229 timeout, notify,
230 NULL, 0));
231 }
232
233 void Message::receive(mach_port_t receivePort,
234 mach_msg_option_t options,
235 mach_msg_timeout_t timeout,
236 mach_port_name_t notify)
237 {
238 check(mach_msg_overwrite_trap(*this,
239 options | MACH_RCV_MSG,
240 length(),
241 mSize, receivePort,
242 timeout, notify,
243 NULL, 0));
244 }
245
246 void Message::sendReceive(mach_port_t receivePort,
247 mach_msg_option_t options,
248 mach_msg_timeout_t timeout,
249 mach_port_name_t notify)
250 {
251 check(mach_msg_overwrite_trap(*this,
252 options | MACH_SEND_MSG | MACH_RCV_MSG,
253 length(),
254 mSize, receivePort,
255 timeout, notify,
256 NULL, 0));
257 }
258
259
260 //
261 // Debug dumping of ports etc.
262 //
263 #if defined(DEBUGDUMP)
264
265 void Port::dump(const char *descr)
266 {
267 fprintf(stderr, "[%s(%d)", descr ? descr : "port", mPort);
268 mach_port_type_t type;
269 kern_return_t err = mach_port_type(self(), mPort, &type);
270 if (err != KERN_SUCCESS) {
271 fprintf(stderr, " !%s", mach_error_string(err));
272 } else {
273 if (type & MACH_PORT_TYPE_SEND) fprintf(stderr, " send(%d)", getRefs(MACH_PORT_RIGHT_SEND));
274 if (type & MACH_PORT_TYPE_RECEIVE) fprintf(stderr, " rcv");
275 if (type & MACH_PORT_TYPE_SEND_ONCE) fprintf(stderr, " once");
276 if (type & MACH_PORT_TYPE_PORT_SET) fprintf(stderr, " set");
277 if (type & MACH_PORT_TYPE_DEAD_NAME) fprintf(stderr, " dead");
278 if (type & MACH_PORT_TYPE_DNREQUEST) fprintf(stderr, " dnreq");
279 }
280 fprintf(stderr, "]\n");
281 }
282
283
284 void Bootstrap::dump()
285 {
286 name_array_t services, servers;
287 bool_array_t active;
288 mach_msg_type_number_t nServices, nServers, nActive;
289 check(bootstrap_info(mPort, &services, &nServices,
290 &servers, &nServers, &active, &nActive));
291 fprintf(stderr, "[port %d] %d services\n", mPort, nServices);
292 for (mach_msg_type_number_t n = 0; n < nServices; n++)
293 fprintf(stderr, "%s\n", services[n]);
294 }
295
296 #endif //DEBUGDUMP
297
298
299 } // end namespace MachPlusPlus
300 } // end namespace Security