]> git.saurik.com Git - apple/system_cmds.git/blame - mach_init.tproj/rpc_services.c
system_cmds-258.tar.gz
[apple/system_cmds.git] / mach_init.tproj / rpc_services.c
CommitLineData
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 */
71kern_return_t
72x_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 */
128kern_return_t
129x_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 */
166kern_return_t
167x_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 */
275kern_return_t
276x_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 */
392kern_return_t
393x_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 */
446kern_return_t
447x_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 */
491kern_return_t
492x_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 */
529kern_return_t
530x_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 */
574kern_return_t
575x_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 */
692kern_return_t
693x_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 */
777kern_return_t
778x_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}