]>
Commit | Line | Data |
---|---|---|
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 | ||
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 |