]>
Commit | Line | Data |
---|---|---|
1815bff5 | 1 | /* |
b51d5b5f | 2 | * Copyright (c) 1999-2002 Apple Computer, Inc. All rights reserved. |
1815bff5 A |
3 | * |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
20e66415 A |
6 | * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights |
7 | * Reserved. This file contains Original Code and/or Modifications of | |
8 | * Original Code as defined in and that are subject to the Apple Public | |
9 | * Source License Version 1.0 (the 'License'). You may not use this file | |
10 | * except in compliance with the License. Please obtain a copy of the | |
11 | * License at http://www.apple.com/publicsource and read it before using | |
12 | * this file. | |
1815bff5 A |
13 | * |
14 | * The Original Code and all software distributed under the License are | |
15 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
16 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
17 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
20e66415 A |
18 | * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the |
19 | * License for the specific language governing rights and limitations | |
20 | * under the License." | |
1815bff5 A |
21 | * |
22 | * @APPLE_LICENSE_HEADER_END@ | |
23 | */ | |
24 | /* | |
25 | * bootstrap -- fundamental service initiator and port server | |
26 | * Mike DeMoney, NeXT, Inc. | |
27 | * Copyright, 1990. All rights reserved. | |
28 | * | |
29 | * rpc_services.c -- implementation of bootstrap rpc services | |
30 | */ | |
31 | ||
32 | #import <mach/mach.h> | |
33 | #import <string.h> | |
34 | ||
35 | #import "bootstrap_internal.h" | |
36 | #import "error_log.h" | |
37 | #import "lists.h" | |
38 | #import "bootstrap.h" | |
39 | ||
40 | #ifndef ASSERT | |
41 | #define ASSERT(p) | |
42 | #endif | |
43 | ||
44 | #ifndef NULL | |
45 | #define NULL ((void *)0) | |
46 | #endif NULL | |
47 | ||
b51d5b5f A |
48 | #define bsstatus(servicep) \ |
49 | (((servicep)->isActive) ? BOOTSTRAP_STATUS_ACTIVE : \ | |
50 | (((servicep)->server && (servicep)->server->servertype == DEMAND) ? \ | |
51 | BOOTSTRAP_STATUS_ON_DEMAND : BOOTSTRAP_STATUS_INACTIVE)) | |
52 | ||
1815bff5 A |
53 | /* extern port_all_t backup_port; */ |
54 | ||
b51d5b5f A |
55 | /* |
56 | * kern_return_t | |
57 | * bootstrap_create_server(mach_port_t bootstrap_port, | |
58 | * cmd_t server_cmd, | |
59 | * integer_t server_uid, | |
60 | * boolean_t on_demand, | |
61 | * mach_port_t *server_portp) | |
62 | * | |
63 | * Returns send rights to server_port of service. At this point, the | |
64 | * server appears active, so nothing will try to launch it. The server_port | |
65 | * can be used to delare services associated with this server by calling | |
66 | * bootstrap_create_service() and passing server_port as the bootstrap port. | |
67 | * | |
68 | * Errors: Returns appropriate kernel errors on rpc failure. | |
69 | * Returns BOOTSTRAP_NOT_PRIVILEGED, if bootstrap port invalid. | |
70 | */ | |
71 | kern_return_t | |
72 | x_bootstrap_create_server( | |
73 | mach_port_t bootstrap_port, | |
74 | cmd_t server_cmd, | |
75 | int server_uid, | |
76 | boolean_t on_demand, | |
77 | security_token_t sectoken, | |
78 | mach_port_t *server_portp) | |
79 | { | |
80 | server_t *serverp; | |
81 | bootstrap_info_t *bootstrap; | |
82 | ||
83 | bootstrap = lookup_bootstrap_by_port(bootstrap_port); | |
84 | debug("Server create attempt: \"%s\" bootstrap %x", | |
85 | server_cmd, bootstrap_port); | |
86 | ||
87 | /* No forwarding allowed for this call - security risk (we run as root) */ | |
88 | if (!bootstrap || !active_bootstrap(bootstrap)) { | |
89 | debug("Server create: \"%s\": invalid bootstrap %x", | |
90 | server_cmd, bootstrap_port); | |
91 | return BOOTSTRAP_NOT_PRIVILEGED; | |
92 | } | |
93 | ||
94 | /* only same uid (or root client) */ | |
95 | if (sectoken.val[0] && sectoken.val[0] != server_uid) { | |
96 | log("Server create: \"%s\": invalid security token (%d != %d)", | |
97 | server_cmd, sectoken.val[0], server_uid); | |
98 | return BOOTSTRAP_NOT_PRIVILEGED; | |
99 | } | |
100 | serverp = new_server( | |
101 | bootstrap, | |
102 | server_cmd, | |
103 | server_uid, | |
104 | (on_demand) ? DEMAND : RESTARTABLE); | |
105 | setup_server(serverp); | |
106 | ||
107 | info("New server %x in bootstrap %x: \"%s\"", | |
108 | serverp->port, bootstrap_port, server_cmd); | |
109 | *server_portp = serverp->port; | |
110 | return BOOTSTRAP_SUCCESS; | |
111 | } | |
112 | ||
113 | /* | |
114 | * kern_return_t | |
115 | * bootstrap_unprivileged(mach_port_t bootstrap_port, | |
116 | * mach_port_t *unpriv_port) | |
117 | * | |
118 | * Given a bootstrap port, return its unprivileged equivalent. If | |
119 | * the port is already unprivileged, another reference to the same | |
120 | * port is returned. | |
121 | * | |
122 | * This is most often used by servers, which are launched with their | |
123 | * bootstrap port set to the privileged port for the server, to get | |
124 | * an unprivileged version of the same port for use by its unprivileged | |
125 | * children (or any offspring that it does not want to count as part | |
126 | * of the "server" for mach_init registration and re-launch purposes). | |
127 | */ | |
128 | kern_return_t | |
129 | x_bootstrap_unprivileged( | |
130 | mach_port_t bootstrap_port, | |
131 | mach_port_t *unpriv_portp) | |
132 | { | |
133 | bootstrap_info_t *bootstrap; | |
134 | ||
135 | debug("Get unprivileged attempt for bootstrap %x", bootstrap_port); | |
136 | ||
137 | bootstrap = lookup_bootstrap_by_port(bootstrap_port); | |
138 | if (!bootstrap || !active_bootstrap(bootstrap)) { | |
139 | debug("Get unprivileged: invalid bootstrap %x", bootstrap_port); | |
140 | return BOOTSTRAP_NOT_PRIVILEGED; | |
141 | } | |
142 | ||
143 | *unpriv_portp = bootstrap->bootstrap_port; | |
144 | ||
145 | debug ("Get unpriv bootstrap %x returned for bootstrap %x", | |
146 | bootstrap->bootstrap_port, bootstrap_port); | |
147 | return BOOTSTRAP_SUCCESS; | |
148 | } | |
149 | ||
150 | ||
1815bff5 A |
151 | /* |
152 | * kern_return_t | |
153 | * bootstrap_check_in(mach_port_t bootstrap_port, | |
154 | * name_t service_name, | |
155 | * mach_port_t *service_portp) | |
156 | * | |
157 | * Returns receive rights to service_port of service named by service_name. | |
158 | * | |
159 | * Errors: Returns appropriate kernel errors on rpc failure. | |
160 | * Returns BOOTSTRAP_UNKNOWN_SERVICE, if service does not exist. | |
161 | * Returns BOOTSTRAP_SERVICE_NOT_DECLARED, if service not declared | |
162 | * in /etc/bootstrap.conf. | |
163 | * Returns BOOTSTRAP_SERVICE_ACTIVE, if service has already been | |
164 | * registered or checked-in. | |
165 | */ | |
166 | kern_return_t | |
167 | x_bootstrap_check_in( | |
168 | mach_port_t bootstrap_port, | |
169 | name_t service_name, | |
170 | mach_port_t *service_portp) | |
171 | { | |
172 | kern_return_t result; | |
b51d5b5f | 173 | mach_port_t previous; |
1815bff5 A |
174 | service_t *servicep; |
175 | server_t *serverp; | |
176 | bootstrap_info_t *bootstrap; | |
177 | ||
1815bff5 | 178 | serverp = lookup_server_by_port(bootstrap_port); |
b51d5b5f A |
179 | bootstrap = lookup_bootstrap_by_port(bootstrap_port); |
180 | debug("Service checkin attempt for service %s bootstrap %x", | |
181 | service_name, bootstrap_port); | |
182 | ||
1815bff5 A |
183 | servicep = lookup_service_by_name(bootstrap, service_name); |
184 | if (servicep == NULL || servicep->port == MACH_PORT_NULL) { | |
185 | debug("bootstrap_check_in service %s unknown%s", service_name, | |
186 | forward_ok ? " forwarding" : ""); | |
b51d5b5f A |
187 | return forward_ok ? |
188 | bootstrap_check_in( | |
189 | inherited_bootstrap_port, | |
190 | service_name, | |
191 | service_portp) : | |
192 | BOOTSTRAP_UNKNOWN_SERVICE; | |
1815bff5 A |
193 | } |
194 | if (servicep->server != NULL && servicep->server != serverp) { | |
195 | debug("bootstrap_check_in service %s not privileged", | |
196 | service_name); | |
197 | return BOOTSTRAP_NOT_PRIVILEGED; | |
198 | } | |
199 | if (servicep->servicetype == SELF || !canReceive(servicep->port)) { | |
200 | ASSERT(servicep->isActive); | |
201 | debug("bootstrap_check_in service %s already active", | |
202 | service_name); | |
203 | return BOOTSTRAP_SERVICE_ACTIVE; | |
204 | } | |
b51d5b5f A |
205 | debug("Checkin service %s for bootstrap %x", service_name, |
206 | bootstrap->bootstrap_port); | |
1815bff5 A |
207 | ASSERT(servicep->isActive == FALSE); |
208 | servicep->isActive = TRUE; | |
b51d5b5f A |
209 | |
210 | if (servicep->server != NULL_SERVER) { | |
211 | /* registered server - service needs backup */ | |
212 | serverp->activity++; | |
213 | serverp->active_services++; | |
214 | result = mach_port_request_notification( | |
215 | mach_task_self(), | |
216 | servicep->port, | |
217 | MACH_NOTIFY_PORT_DESTROYED, | |
218 | 0, | |
219 | backup_port, | |
220 | MACH_MSG_TYPE_MAKE_SEND_ONCE, | |
221 | &previous); | |
222 | if (result != KERN_SUCCESS) | |
223 | kern_fatal(result, "mach_port_request_notification"); | |
224 | } else { | |
225 | /* one time use/created service */ | |
226 | servicep->servicetype = REGISTERED; | |
227 | result = mach_port_request_notification( | |
228 | mach_task_self(), | |
229 | servicep->port, | |
230 | MACH_NOTIFY_DEAD_NAME, | |
231 | 0, | |
232 | notify_port, | |
233 | MACH_MSG_TYPE_MAKE_SEND_ONCE, | |
234 | &previous); | |
235 | if (result != KERN_SUCCESS) | |
236 | kern_fatal(result, "mach_port_request_notification"); | |
237 | else if (previous != MACH_PORT_NULL) { | |
238 | debug("deallocating old notification port (%x) for checked in service %x", | |
239 | previous, servicep->port); | |
240 | result = mach_port_deallocate( | |
241 | mach_task_self(), | |
242 | previous); | |
243 | if (result != KERN_SUCCESS) | |
244 | kern_fatal(result, "mach_port_deallocate"); | |
245 | } | |
246 | } | |
247 | ||
248 | info("Check-in service %x in bootstrap %x: %s", | |
249 | servicep->port, servicep->bootstrap->bootstrap_port, servicep->name); | |
250 | ||
1815bff5 | 251 | *service_portp = servicep->port; |
1815bff5 | 252 | return BOOTSTRAP_SUCCESS; |
1815bff5 A |
253 | } |
254 | ||
255 | /* | |
256 | * kern_return_t | |
257 | * bootstrap_register(mach_port_t bootstrap_port, | |
258 | * name_t service_name, | |
259 | * mach_port_t service_port) | |
260 | * | |
261 | * Registers send rights for the port service_port for the service named by | |
262 | * service_name. Registering a declared service or registering a service for | |
263 | * which bootstrap has receive rights via a port backup notification is | |
264 | * allowed. | |
265 | * The previous service port will be deallocated. Restarting services wishing | |
266 | * to resume service for previous clients must first attempt to checkin to the | |
267 | * service. | |
268 | * | |
269 | * Errors: Returns appropriate kernel errors on rpc failure. | |
270 | * Returns BOOTSTRAP_NOT_PRIVILEGED, if request directed to | |
271 | * unprivileged bootstrap port. | |
272 | * Returns BOOTSTRAP_SERVICE_ACTIVE, if service has already been | |
273 | * register or checked-in. | |
274 | */ | |
275 | kern_return_t | |
276 | x_bootstrap_register( | |
277 | mach_port_t bootstrap_port, | |
278 | name_t service_name, | |
279 | mach_port_t service_port) | |
280 | { | |
b51d5b5f | 281 | kern_return_t result; |
1815bff5 A |
282 | service_t *servicep; |
283 | server_t *serverp; | |
284 | bootstrap_info_t *bootstrap; | |
285 | mach_port_t old_port; | |
286 | ||
b51d5b5f | 287 | debug("Register attempt for service %s port %x", |
1815bff5 A |
288 | service_name, service_port); |
289 | ||
b51d5b5f A |
290 | /* |
291 | * Validate the bootstrap. | |
292 | */ | |
293 | bootstrap = lookup_bootstrap_by_port(bootstrap_port); | |
294 | if (!bootstrap || !active_bootstrap(bootstrap)) | |
295 | return BOOTSTRAP_NOT_PRIVILEGED; | |
296 | ||
1815bff5 A |
297 | /* |
298 | * If this bootstrap port is for a server, or it's an unprivileged | |
299 | * bootstrap can't register the port. | |
300 | */ | |
301 | serverp = lookup_server_by_port(bootstrap_port); | |
302 | servicep = lookup_service_by_name(bootstrap, service_name); | |
303 | if (servicep && servicep->server && servicep->server != serverp) | |
304 | return BOOTSTRAP_NOT_PRIVILEGED; | |
305 | ||
1815bff5 A |
306 | if (servicep == NULL || servicep->bootstrap != bootstrap) { |
307 | servicep = new_service(bootstrap, | |
308 | service_name, | |
309 | service_port, | |
310 | ACTIVE, | |
311 | REGISTERED, | |
312 | NULL_SERVER); | |
313 | debug("Registered new service %s", service_name); | |
314 | } else { | |
b51d5b5f A |
315 | if (servicep->isActive) { |
316 | debug("Register: service %s already active, port %x", | |
1815bff5 A |
317 | servicep->name, servicep->port); |
318 | ASSERT(!canReceive(servicep->port)); | |
319 | return BOOTSTRAP_SERVICE_ACTIVE; | |
320 | } | |
b51d5b5f A |
321 | old_port = servicep->port; |
322 | if (servicep->servicetype == DECLARED) { | |
323 | servicep->servicetype = REGISTERED; | |
324 | ||
325 | if (servicep->server) { | |
326 | ASSERT(servicep->server == serverp); | |
327 | ASSERT(active_server(serverp)); | |
328 | servicep->server = NULL_SERVER; | |
329 | serverp->activity++; | |
330 | } | |
331 | ||
332 | result = mach_port_mod_refs( | |
333 | mach_task_self(), | |
334 | old_port, | |
335 | MACH_PORT_RIGHT_RECEIVE, | |
336 | -1); | |
337 | if (result != KERN_SUCCESS) | |
338 | kern_fatal(result, "mach_port_mod_refs"); | |
339 | } | |
340 | result = mach_port_deallocate( | |
341 | mach_task_self(), | |
342 | old_port); | |
343 | if (result != KERN_SUCCESS) | |
344 | kern_fatal(result, "mach_port_mod_refs"); | |
345 | ||
1815bff5 | 346 | servicep->port = service_port; |
1815bff5 | 347 | servicep->isActive = TRUE; |
b51d5b5f A |
348 | debug("Re-registered inactive service %x bootstrap %x: %s", |
349 | servicep->port, servicep->bootstrap->bootstrap_port, service_name); | |
1815bff5 | 350 | } |
b51d5b5f A |
351 | |
352 | /* detect the new service port going dead */ | |
353 | result = mach_port_request_notification( | |
354 | mach_task_self(), | |
355 | service_port, | |
356 | MACH_NOTIFY_DEAD_NAME, | |
357 | 0, | |
358 | notify_port, | |
359 | MACH_MSG_TYPE_MAKE_SEND_ONCE, | |
360 | &old_port); | |
361 | if (result != KERN_SUCCESS) { | |
362 | debug("Can't request notification on service %x bootstrap %x: %s", | |
363 | service_port, servicep->bootstrap->bootstrap_port, "must be dead"); | |
364 | delete_service(servicep); | |
365 | return BOOTSTRAP_SUCCESS; | |
366 | } else if (old_port != MACH_PORT_NULL) { | |
367 | debug("deallocating old notification port (%x) for service %x", | |
368 | old_port, service_port); | |
369 | result = mach_port_deallocate( | |
370 | mach_task_self(), | |
371 | old_port); | |
372 | if (result != KERN_SUCCESS) | |
373 | kern_fatal(result, "mach_port_deallocate"); | |
374 | } | |
375 | info("Registered service %x bootstrap %x: %s", | |
376 | servicep->port, servicep->bootstrap->bootstrap_port, servicep->name); | |
1815bff5 A |
377 | return BOOTSTRAP_SUCCESS; |
378 | } | |
379 | ||
380 | /* | |
381 | * kern_return_t | |
382 | * bootstrap_look_up(mach_port_t bootstrap_port, | |
383 | * name_t service_name, | |
384 | * mach_port_t *service_portp) | |
385 | * | |
386 | * Returns send rights for the service port of the service named by | |
387 | * service_name in *service_portp. Service is not guaranteed to be active. | |
388 | * | |
389 | * Errors: Returns appropriate kernel errors on rpc failure. | |
390 | * Returns BOOTSTRAP_UNKNOWN_SERVICE, if service does not exist. | |
391 | */ | |
392 | kern_return_t | |
393 | x_bootstrap_look_up( | |
394 | mach_port_t bootstrap_port, | |
395 | name_t service_name, | |
396 | mach_port_t *service_portp) | |
397 | { | |
398 | service_t *servicep; | |
399 | bootstrap_info_t *bootstrap; | |
400 | ||
401 | bootstrap = lookup_bootstrap_by_port(bootstrap_port); | |
402 | servicep = lookup_service_by_name(bootstrap, service_name); | |
403 | if (servicep == NULL || servicep->port == MACH_PORT_NULL) { | |
404 | if (forward_ok) { | |
1815bff5 A |
405 | debug("bootstrap_look_up service %s forwarding", |
406 | service_name); | |
1815bff5 A |
407 | return bootstrap_look_up(inherited_bootstrap_port, |
408 | service_name, | |
409 | service_portp); | |
410 | } else { | |
1815bff5 A |
411 | debug("bootstrap_look_up service %s unknown", |
412 | service_name); | |
1815bff5 A |
413 | return BOOTSTRAP_UNKNOWN_SERVICE; |
414 | } | |
415 | } | |
1815bff5 | 416 | *service_portp = servicep->port; |
b51d5b5f | 417 | debug("Lookup returns port %x for service %s", |
1815bff5 A |
418 | servicep->port, |
419 | servicep->name); | |
1815bff5 A |
420 | return BOOTSTRAP_SUCCESS; |
421 | } | |
422 | ||
423 | /* | |
424 | * kern_return_t | |
425 | * bootstrap_look_up_array(mach_port_t bootstrap_port, | |
426 | * name_array_t service_names, | |
427 | * int service_names_cnt, | |
428 | * mach_port_array_t *service_ports, | |
429 | * int *service_ports_cnt, | |
430 | * boolean_t *all_services_known) | |
431 | * | |
432 | * Returns port send rights in corresponding entries of the array service_ports | |
433 | * for all services named in the array service_names. Service_ports_cnt is | |
434 | * returned and will always equal service_names_cnt (assuming service_names_cnt | |
435 | * is greater than or equal to zero). | |
436 | * | |
437 | * Errors: Returns appropriate kernel errors on rpc failure. | |
438 | * Returns BOOTSTRAP_NO_MEMORY, if server couldn't obtain memory | |
439 | * for response. | |
440 | * Unknown service names have the corresponding service | |
441 | * port set to MACH_PORT_NULL. | |
442 | * If all services are known, all_services_known is true on | |
443 | * return, | |
444 | * if any service is unknown, it's false. | |
445 | */ | |
446 | kern_return_t | |
447 | x_bootstrap_look_up_array( | |
448 | mach_port_t bootstrap_port, | |
449 | name_array_t service_names, | |
450 | unsigned int service_names_cnt, | |
451 | mach_port_array_t *service_portsp, | |
452 | unsigned int *service_ports_cnt, | |
453 | boolean_t *all_services_known) | |
454 | { | |
455 | unsigned int i; | |
456 | static mach_port_t service_ports[BOOTSTRAP_MAX_LOOKUP_COUNT]; | |
457 | ||
458 | if (service_names_cnt > BOOTSTRAP_MAX_LOOKUP_COUNT) | |
459 | return BOOTSTRAP_BAD_COUNT; | |
460 | *service_ports_cnt = service_names_cnt; | |
461 | *all_services_known = TRUE; | |
462 | for (i = 0; i < service_names_cnt; i++) { | |
463 | if ( x_bootstrap_look_up(bootstrap_port, | |
464 | service_names[i], | |
465 | &service_ports[i]) | |
466 | != BOOTSTRAP_SUCCESS) | |
467 | { | |
468 | *all_services_known = FALSE; | |
469 | service_ports[i] = MACH_PORT_NULL; | |
470 | } | |
471 | } | |
1815bff5 | 472 | debug("bootstrap_look_up_array returns %d ports", service_names_cnt); |
1815bff5 A |
473 | *service_portsp = service_ports; |
474 | return BOOTSTRAP_SUCCESS; | |
475 | } | |
476 | ||
b51d5b5f A |
477 | /* |
478 | * kern_return_t | |
479 | * bootstrap_parent(mach_port_t bootstrap_port, | |
480 | * mach_port_t *parent_port); | |
481 | * | |
482 | * Given a bootstrap subset port, return the parent bootstrap port. | |
483 | * If the specified bootstrap port is already the root subset, | |
484 | * MACH_PORT_NULL will be returned. | |
485 | * | |
486 | * Errors: | |
487 | * Returns BOOTSTRAP_NOT_PRIVILEGED if the caller is not running | |
488 | * with an effective user id of root (as determined by the security | |
489 | * token in the message trailer). | |
490 | */ | |
491 | kern_return_t | |
492 | x_bootstrap_parent( | |
493 | mach_port_t bootstrap_port, | |
494 | security_token_t sectoken, | |
495 | mach_port_t *parent_port) | |
496 | { | |
b51d5b5f A |
497 | bootstrap_info_t *bootstrap; |
498 | ||
499 | debug("Parent attempt for bootstrap %x", bootstrap_port); | |
500 | ||
501 | bootstrap = lookup_bootstrap_by_port(bootstrap_port); | |
502 | if (!bootstrap || !active_bootstrap(bootstrap)) { | |
503 | debug("Parent attempt for bootstrap %x: invalid bootstrap", | |
504 | bootstrap_port); | |
505 | return BOOTSTRAP_NOT_PRIVILEGED; | |
506 | } | |
507 | if (sectoken.val[0]) { | |
508 | log("Bootstrap parent for bootstrap %x: invalid security token (%d)", | |
509 | bootstrap_port, sectoken.val[0]); | |
510 | return BOOTSTRAP_NOT_PRIVILEGED; | |
511 | } | |
512 | debug("Returning bootstrap parent %x for bootstrap %x", | |
513 | bootstrap->parent->bootstrap_port, bootstrap_port); | |
514 | *parent_port = bootstrap->parent->bootstrap_port; | |
515 | return BOOTSTRAP_SUCCESS; | |
b51d5b5f A |
516 | } |
517 | ||
1815bff5 A |
518 | /* |
519 | * kern_return_t | |
520 | * bootstrap_status(mach_port_t bootstrap_port, | |
521 | * name_t service_name, | |
b51d5b5f | 522 | * bootstrap_status_t *service_active); |
1815bff5 | 523 | * |
b51d5b5f | 524 | * Returns: service_active indicates if service is available. |
1815bff5 A |
525 | * |
526 | * Errors: Returns appropriate kernel errors on rpc failure. | |
527 | * Returns BOOTSTRAP_UNKNOWN_SERVICE, if service does not exist. | |
528 | */ | |
529 | kern_return_t | |
530 | x_bootstrap_status( | |
b51d5b5f A |
531 | mach_port_t bootstrap_port, |
532 | name_t service_name, | |
533 | bootstrap_status_t *service_active) | |
1815bff5 A |
534 | { |
535 | service_t *servicep; | |
536 | bootstrap_info_t *bootstrap; | |
537 | ||
538 | bootstrap = lookup_bootstrap_by_port(bootstrap_port); | |
539 | servicep = lookup_service_by_name(bootstrap, service_name); | |
540 | if (servicep == NULL) { | |
541 | if (forward_ok) { | |
542 | debug("bootstrap_status forwarding status, server %s", | |
543 | service_name); | |
544 | return bootstrap_status(inherited_bootstrap_port, | |
545 | service_name, | |
546 | service_active); | |
547 | } else { | |
1815bff5 A |
548 | debug("bootstrap_status service %s unknown", |
549 | service_name); | |
1815bff5 A |
550 | return BOOTSTRAP_UNKNOWN_SERVICE; |
551 | } | |
552 | } | |
b51d5b5f A |
553 | *service_active = bsstatus(servicep); |
554 | ||
1815bff5 A |
555 | debug("bootstrap_status server %s %sactive", service_name, |
556 | servicep->isActive ? "" : "in"); | |
1815bff5 A |
557 | return BOOTSTRAP_SUCCESS; |
558 | } | |
559 | ||
560 | /* | |
561 | * kern_return_t | |
562 | * bootstrap_info(mach_port_t bootstrap_port, | |
563 | * name_array_t *service_names, | |
564 | * int *service_names_cnt, | |
565 | * name_array_t *server_names, | |
566 | * int *server_names_cnt, | |
b51d5b5f | 567 | * bootstrap_status_array_t *service_actives, |
1815bff5 A |
568 | * int *service_active_cnt); |
569 | * | |
570 | * Returns bootstrap status for all known services. | |
571 | * | |
572 | * Errors: Returns appropriate kernel errors on rpc failure. | |
573 | */ | |
574 | kern_return_t | |
575 | x_bootstrap_info( | |
b51d5b5f A |
576 | mach_port_t bootstrap_port, |
577 | name_array_t *service_namesp, | |
578 | unsigned int *service_names_cnt, | |
579 | name_array_t *server_namesp, | |
580 | unsigned int *server_names_cnt, | |
581 | bootstrap_status_array_t *service_activesp, | |
582 | unsigned int *service_actives_cnt) | |
1815bff5 A |
583 | { |
584 | kern_return_t result; | |
585 | unsigned int i, cnt; | |
586 | service_t *servicep; | |
587 | server_t *serverp; | |
588 | bootstrap_info_t *bootstrap; | |
589 | name_array_t service_names; | |
590 | name_array_t server_names; | |
b51d5b5f | 591 | bootstrap_status_array_t service_actives; |
1815bff5 A |
592 | |
593 | bootstrap = lookup_bootstrap_by_port(bootstrap_port); | |
594 | ||
595 | for ( cnt = i = 0, servicep = services.next | |
596 | ; i < nservices | |
597 | ; servicep = servicep->next, i++) | |
598 | { | |
599 | if (lookup_service_by_name(bootstrap, servicep->name) == servicep) | |
600 | { | |
601 | cnt++; | |
602 | } | |
603 | } | |
604 | result = vm_allocate(mach_task_self(), | |
605 | (vm_address_t *)&service_names, | |
606 | cnt * sizeof(service_names[0]), | |
607 | ANYWHERE); | |
608 | if (result != KERN_SUCCESS) | |
609 | return BOOTSTRAP_NO_MEMORY; | |
610 | ||
611 | result = vm_allocate(mach_task_self(), | |
612 | (vm_address_t *)&server_names, | |
613 | cnt * sizeof(server_names[0]), | |
614 | ANYWHERE); | |
615 | if (result != KERN_SUCCESS) { | |
616 | (void)vm_deallocate(mach_task_self(), | |
617 | (vm_address_t)service_names, | |
618 | cnt * sizeof(service_names[0])); | |
619 | return BOOTSTRAP_NO_MEMORY; | |
620 | } | |
621 | result = vm_allocate(mach_task_self(), | |
622 | (vm_address_t *)&service_actives, | |
623 | cnt * sizeof(service_actives[0]), | |
624 | ANYWHERE); | |
625 | if (result != KERN_SUCCESS) { | |
626 | (void)vm_deallocate(mach_task_self(), | |
627 | (vm_address_t)service_names, | |
628 | cnt * sizeof(service_names[0])); | |
629 | (void)vm_deallocate(mach_task_self(), | |
630 | (vm_address_t)server_names, | |
631 | cnt * sizeof(server_names[0])); | |
632 | return BOOTSTRAP_NO_MEMORY; | |
633 | } | |
634 | ||
635 | for ( i = 0, servicep = services.next | |
b51d5b5f | 636 | ; i < cnt |
1815bff5 A |
637 | ; servicep = servicep->next) |
638 | { | |
639 | if ( lookup_service_by_name(bootstrap, servicep->name) | |
640 | != servicep) | |
641 | continue; | |
642 | strncpy(service_names[i], | |
643 | servicep->name, | |
644 | sizeof(service_names[0])); | |
645 | service_names[i][sizeof(service_names[0]) - 1] = '\0'; | |
646 | if (servicep->server) { | |
647 | serverp = servicep->server; | |
648 | strncpy(server_names[i], | |
649 | serverp->cmd, | |
650 | sizeof(server_names[0])); | |
651 | server_names[i][sizeof(server_names[0]) - 1] = '\0'; | |
652 | debug("bootstrap info service %s server %s %sactive", | |
653 | servicep->name, | |
654 | serverp->cmd, servicep->isActive ? "" : "in"); | |
655 | } else { | |
656 | server_names[i][0] = '\0'; | |
657 | debug("bootstrap info service %s %sactive", | |
658 | servicep->name, servicep->isActive ? "" : "in"); | |
659 | } | |
b51d5b5f | 660 | service_actives[i] = bsstatus(servicep); |
1815bff5 A |
661 | i++; |
662 | } | |
663 | *service_namesp = service_names; | |
664 | *server_namesp = server_names; | |
665 | *service_activesp = service_actives; | |
666 | *service_names_cnt = *server_names_cnt = | |
667 | *service_actives_cnt = cnt; | |
668 | ||
669 | return BOOTSTRAP_SUCCESS; | |
670 | } | |
671 | ||
672 | /* | |
673 | * kern_return_t | |
674 | * bootstrap_subset(mach_port_t bootstrap_port, | |
675 | * mach_port_t requestor_port, | |
676 | * mach_port_t *subset_port); | |
677 | * | |
678 | * Returns a new port to use as a bootstrap port. This port behaves | |
679 | * exactly like the previous bootstrap_port, except that ports dynamically | |
680 | * registered via bootstrap_register() are available only to users of this | |
681 | * specific subset_port. Lookups on the subset_port will return ports | |
682 | * registered with this port specifically, and ports registered with | |
683 | * ancestors of this subset_port. Duplications of services already | |
684 | * registered with an ancestor port may be registered with the subset port | |
685 | * are allowed. Services already advertised may then be effectively removed | |
686 | * by registering MACH_PORT_NULL for the service. | |
687 | * When it is detected that the requestor_port is destroied the subset | |
688 | * port and all services advertized by it are destroied as well. | |
689 | * | |
690 | * Errors: Returns appropriate kernel errors on rpc failure. | |
691 | */ | |
692 | kern_return_t | |
693 | x_bootstrap_subset( | |
694 | mach_port_t bootstrap_port, | |
695 | mach_port_t requestor_port, | |
696 | mach_port_t *subset_port) | |
697 | { | |
698 | kern_return_t result; | |
699 | bootstrap_info_t *bootstrap; | |
700 | bootstrap_info_t *subset; | |
701 | mach_port_t new_bootstrap_port; | |
b51d5b5f A |
702 | mach_port_t previous; |
703 | ||
704 | debug("Subset create attempt: bootstrap %x, requestor: %x", | |
705 | bootstrap_port, requestor_port); | |
1815bff5 A |
706 | |
707 | bootstrap = lookup_bootstrap_by_port(bootstrap_port); | |
b51d5b5f A |
708 | if (!bootstrap || !active_bootstrap(bootstrap)) |
709 | return BOOTSTRAP_NOT_PRIVILEGED; | |
1815bff5 | 710 | |
b51d5b5f A |
711 | result = mach_port_allocate( |
712 | mach_task_self(), | |
713 | MACH_PORT_RIGHT_RECEIVE, | |
714 | &new_bootstrap_port); | |
1815bff5 A |
715 | if (result != KERN_SUCCESS) |
716 | kern_fatal(result, "mach_port_allocate"); | |
b51d5b5f A |
717 | |
718 | result = mach_port_insert_right( | |
719 | mach_task_self(), | |
720 | new_bootstrap_port, | |
721 | new_bootstrap_port, | |
722 | MACH_MSG_TYPE_MAKE_SEND); | |
1815bff5 A |
723 | if (result != KERN_SUCCESS) |
724 | kern_fatal(result, "failed to insert send right"); | |
725 | ||
b51d5b5f A |
726 | result = mach_port_insert_member( |
727 | mach_task_self(), | |
728 | new_bootstrap_port, | |
729 | bootstrap_port_set); | |
1815bff5 A |
730 | if (result != KERN_SUCCESS) |
731 | kern_fatal(result, "port_set_add"); | |
732 | ||
733 | subset = new_bootstrap(bootstrap, new_bootstrap_port, requestor_port); | |
b51d5b5f A |
734 | |
735 | result = mach_port_request_notification( | |
736 | mach_task_self(), | |
737 | requestor_port, | |
738 | MACH_NOTIFY_DEAD_NAME, | |
739 | 0, | |
740 | notify_port, | |
741 | MACH_MSG_TYPE_MAKE_SEND_ONCE, | |
742 | &previous); | |
743 | if (result != KERN_SUCCESS) { | |
744 | kern_error(result, "mach_port_request_notification"); | |
745 | mach_port_deallocate(mach_task_self(), requestor_port); | |
746 | subset->requestor_port = MACH_PORT_NULL; | |
747 | deactivate_bootstrap(subset); | |
748 | } else if (previous != MACH_PORT_NULL) { | |
749 | debug("deallocating old notification port (%x) for requestor %x", | |
750 | previous, requestor_port); | |
751 | result = mach_port_deallocate( | |
752 | mach_task_self(), | |
753 | previous); | |
754 | if (result != KERN_SUCCESS) | |
755 | kern_fatal(result, "mach_port_deallocate"); | |
756 | } | |
757 | ||
758 | info("Created bootstrap subset %x parent %x requestor %x", | |
759 | new_bootstrap_port, bootstrap_port, requestor_port); | |
1815bff5 | 760 | *subset_port = new_bootstrap_port; |
1815bff5 A |
761 | return BOOTSTRAP_SUCCESS; |
762 | } | |
763 | ||
764 | /* | |
765 | * kern_return_t | |
766 | * bootstrap_create_service(mach_port_t bootstrap_port, | |
767 | * name_t service_name, | |
768 | * mach_port_t *service_port) | |
769 | * | |
770 | * Creates a service named "service_name" and returns send rights to that | |
771 | * port in "service_port." The port may later be checked in as if this | |
772 | * port were configured in the bootstrap configuration file. | |
773 | * | |
774 | * Errors: Returns appropriate kernel errors on rpc failure. | |
775 | * Returns BOOTSTRAP_NAME_IN_USE, if service already exists. | |
776 | */ | |
777 | kern_return_t | |
778 | x_bootstrap_create_service( | |
779 | mach_port_t bootstrap_port, | |
780 | name_t service_name, | |
781 | mach_port_t *service_port) | |
782 | { | |
b51d5b5f | 783 | server_t *serverp; |
1815bff5 A |
784 | service_t *servicep; |
785 | bootstrap_info_t *bootstrap; | |
786 | kern_return_t result; | |
1815bff5 A |
787 | |
788 | bootstrap = lookup_bootstrap_by_port(bootstrap_port); | |
b51d5b5f A |
789 | if (!bootstrap || !active_bootstrap(bootstrap)) |
790 | return BOOTSTRAP_NOT_PRIVILEGED; | |
791 | ||
792 | debug("Service creation attempt for service %s bootstrap %x", | |
793 | service_name, bootstrap_port); | |
1815bff5 A |
794 | |
795 | servicep = lookup_service_by_name(bootstrap, service_name); | |
796 | if (servicep) { | |
797 | debug("Service creation attempt for service %s failed, " | |
798 | "service already exists", service_name); | |
799 | return BOOTSTRAP_NAME_IN_USE; | |
800 | } | |
801 | ||
b51d5b5f A |
802 | serverp = lookup_server_by_port(bootstrap_port); |
803 | ||
1815bff5 A |
804 | result = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, service_port); |
805 | if (result != KERN_SUCCESS) | |
806 | kern_fatal(result, "port_allocate"); | |
807 | result = mach_port_insert_right(mach_task_self(), *service_port, *service_port, MACH_MSG_TYPE_MAKE_SEND); | |
808 | if (result != KERN_SUCCESS) | |
809 | kern_fatal(result, "failed to insert send right"); | |
b51d5b5f A |
810 | |
811 | if (serverp) | |
812 | serverp->activity++; | |
1815bff5 A |
813 | |
814 | servicep = new_service(bootstrap, | |
815 | service_name, | |
816 | *service_port, | |
817 | !ACTIVE, | |
818 | DECLARED, | |
b51d5b5f | 819 | serverp); |
1815bff5 | 820 | |
b51d5b5f A |
821 | info("Created new service %x in bootstrap %x: %s", |
822 | servicep->port, bootstrap->bootstrap_port, service_name); | |
1815bff5 A |
823 | |
824 | return BOOTSTRAP_SUCCESS; | |
825 | } |