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