]> git.saurik.com Git - apple/security.git/blame - cdsa/cdsa_utilities/mach++.cpp
Security-30.1.tar.gz
[apple/security.git] / cdsa / cdsa_utilities / mach++.cpp
CommitLineData
bac41a7b
A
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
28namespace Security {
29namespace MachPlusPlus {
30
31
32Error::Error(kern_return_t err) : error(err)
33{
34}
35
36Error::~Error()
37{
38}
39
40CSSM_RETURN
41Error::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
52OSStatus
53Error::osStatus() const
54{
55 return cssmError();
56}
57
58void 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
80void Error::throwMe(kern_return_t err) { throw Error(err); }
81
82//
83// Port functions
84//
85mach_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//
96pid_t TaskPort::pid() const
97{
98 pid_t pid;
99 check(::pid_for_task(mPort, &pid));
100 return pid;
101}
102
103TaskPort 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//
114mach_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
121mach_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
131void Bootstrap::registerAs(mach_port_t port, const char *name) const
132{
133 check(::bootstrap_register(mPort, makeName(name), port));
134}
135
136mach_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
143mach_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
154Bootstrap 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//
165ReceivePort::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//
180ModuleNexus<Mutex> StBootstrap::critical;
181
182StBootstrap::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
190StBootstrap::~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//
200Message::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
207Message::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
214Message::~Message()
215{
216 if (mRelease)
217 delete[] mBuffer;
218}
219
220
221void 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
233void 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
246void 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
265void 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
284void 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