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