]> git.saurik.com Git - apple/system_cmds.git/blob - mach_init.tproj/rpc_services.c
6c08bbea95f9edebe3de1f320c9e8a3dad6afe9f
[apple/system_cmds.git] / mach_init.tproj / rpc_services.c
1 /*
2 * Copyright (c) 1999 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 #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
48 /* extern port_all_t backup_port; */
49
50 /*
51 * kern_return_t
52 * bootstrap_check_in(mach_port_t bootstrap_port,
53 * name_t service_name,
54 * mach_port_t *service_portp)
55 *
56 * Returns receive rights to service_port of service named by service_name.
57 *
58 * Errors: Returns appropriate kernel errors on rpc failure.
59 * Returns BOOTSTRAP_UNKNOWN_SERVICE, if service does not exist.
60 * Returns BOOTSTRAP_SERVICE_NOT_DECLARED, if service not declared
61 * in /etc/bootstrap.conf.
62 * Returns BOOTSTRAP_SERVICE_ACTIVE, if service has already been
63 * registered or checked-in.
64 */
65 kern_return_t
66 x_bootstrap_check_in(
67 mach_port_t bootstrap_port,
68 name_t service_name,
69 mach_port_t *service_portp)
70 {
71 kern_return_t result;
72 service_t *servicep;
73 server_t *serverp;
74 bootstrap_info_t *bootstrap;
75
76 bootstrap = lookup_bootstrap_by_port(bootstrap_port);
77 serverp = lookup_server_by_port(bootstrap_port);
78 if (serverp == NULL) {
79 debug("bootstrap_check_in service %s has no server",
80 service_name);
81 return BOOTSTRAP_NOT_PRIVILEGED;
82 }
83 servicep = lookup_service_by_name(bootstrap, service_name);
84 if (servicep == NULL || servicep->port == MACH_PORT_NULL) {
85 debug("bootstrap_check_in service %s unknown%s", service_name,
86 forward_ok ? " forwarding" : "");
87 result = BOOTSTRAP_UNKNOWN_SERVICE;
88 goto forward;
89 }
90 if (servicep->server != NULL && servicep->server != serverp) {
91 debug("bootstrap_check_in service %s not privileged",
92 service_name);
93 return BOOTSTRAP_NOT_PRIVILEGED;
94 }
95 if (servicep->servicetype == SELF || !canReceive(servicep->port)) {
96 ASSERT(servicep->isActive);
97 debug("bootstrap_check_in service %s already active",
98 service_name);
99 return BOOTSTRAP_SERVICE_ACTIVE;
100 }
101 log("Checkin service %s", service_name);
102 ASSERT(servicep->isActive == FALSE);
103 servicep->isActive = TRUE;
104 *service_portp = servicep->port;
105 info("Check-in port %d for service %s\n",
106 servicep->port, servicep->name);
107 return BOOTSTRAP_SUCCESS;
108 forward:
109 return forward_ok
110 ? bootstrap_check_in(inherited_bootstrap_port,
111 service_name,
112 service_portp)
113 : result;
114 }
115
116 /*
117 * kern_return_t
118 * bootstrap_register(mach_port_t bootstrap_port,
119 * name_t service_name,
120 * mach_port_t service_port)
121 *
122 * Registers send rights for the port service_port for the service named by
123 * service_name. Registering a declared service or registering a service for
124 * which bootstrap has receive rights via a port backup notification is
125 * allowed.
126 * The previous service port will be deallocated. Restarting services wishing
127 * to resume service for previous clients must first attempt to checkin to the
128 * service.
129 *
130 * Errors: Returns appropriate kernel errors on rpc failure.
131 * Returns BOOTSTRAP_NOT_PRIVILEGED, if request directed to
132 * unprivileged bootstrap port.
133 * Returns BOOTSTRAP_SERVICE_ACTIVE, if service has already been
134 * register or checked-in.
135 */
136 kern_return_t
137 x_bootstrap_register(
138 mach_port_t bootstrap_port,
139 name_t service_name,
140 mach_port_t service_port)
141 {
142 service_t *servicep;
143 server_t *serverp;
144 bootstrap_info_t *bootstrap;
145 mach_port_t old_port;
146
147 bootstrap = lookup_bootstrap_by_port(bootstrap_port);
148 ASSERT(canSend(service_port));
149 debug("Register attempt for service %s port %d",
150 service_name, service_port);
151
152 /*
153 * If this bootstrap port is for a server, or it's an unprivileged
154 * bootstrap can't register the port.
155 */
156 serverp = lookup_server_by_port(bootstrap_port);
157 servicep = lookup_service_by_name(bootstrap, service_name);
158 if (servicep && servicep->server && servicep->server != serverp)
159 return BOOTSTRAP_NOT_PRIVILEGED;
160
161 if (serverp)
162 bootstrap_port = bootstrap->bootstrap_port;
163 else if (bootstrap_port != bootstrap->bootstrap_port)
164 return BOOTSTRAP_NOT_PRIVILEGED;
165
166 if (servicep == NULL || servicep->bootstrap != bootstrap) {
167 servicep = new_service(bootstrap,
168 service_name,
169 service_port,
170 ACTIVE,
171 REGISTERED,
172 NULL_SERVER);
173 debug("Registered new service %s", service_name);
174 } else {
175 if (servicep->isActive) {
176 debug("Register: service %s already active, port %d",
177 servicep->name, servicep->port);
178 ASSERT(!canReceive(servicep->port));
179 return BOOTSTRAP_SERVICE_ACTIVE;
180 }
181 old_port = servicep->port;
182 servicep->port = service_port;
183 msg_destroy_port(old_port);
184 servicep->isActive = TRUE;
185 log("Re-registered inactive service %s", service_name);
186 }
187 debug("Registering port %d for service %s\n",
188 servicep->port,
189 servicep->name);
190 return BOOTSTRAP_SUCCESS;
191 }
192
193 /*
194 * kern_return_t
195 * bootstrap_look_up(mach_port_t bootstrap_port,
196 * name_t service_name,
197 * mach_port_t *service_portp)
198 *
199 * Returns send rights for the service port of the service named by
200 * service_name in *service_portp. Service is not guaranteed to be active.
201 *
202 * Errors: Returns appropriate kernel errors on rpc failure.
203 * Returns BOOTSTRAP_UNKNOWN_SERVICE, if service does not exist.
204 */
205 kern_return_t
206 x_bootstrap_look_up(
207 mach_port_t bootstrap_port,
208 name_t service_name,
209 mach_port_t *service_portp)
210 {
211 service_t *servicep;
212 bootstrap_info_t *bootstrap;
213
214 bootstrap = lookup_bootstrap_by_port(bootstrap_port);
215 servicep = lookup_service_by_name(bootstrap, service_name);
216 if (servicep == NULL || servicep->port == MACH_PORT_NULL) {
217 if (forward_ok) {
218 #if DEBUG
219 debug("bootstrap_look_up service %s forwarding",
220 service_name);
221 #endif DEBUG
222 return bootstrap_look_up(inherited_bootstrap_port,
223 service_name,
224 service_portp);
225 } else {
226 #if DEBUG
227 debug("bootstrap_look_up service %s unknown",
228 service_name);
229 #endif DEBUG
230 return BOOTSTRAP_UNKNOWN_SERVICE;
231 }
232 }
233 if (!canSend(servicep->port)) {
234 error("Mysterious loss of send rights on port %d, "
235 "deleting service %s",
236 servicep->port,
237 servicep->name);
238 delete_service(servicep);
239 return BOOTSTRAP_UNKNOWN_SERVICE;
240 }
241 *service_portp = servicep->port;
242 #if DEBUG
243 debug("Lookup returns port %d for service %s\n",
244 servicep->port,
245 servicep->name);
246 #endif DEBUG
247 return BOOTSTRAP_SUCCESS;
248 }
249
250 /*
251 * kern_return_t
252 * bootstrap_look_up_array(mach_port_t bootstrap_port,
253 * name_array_t service_names,
254 * int service_names_cnt,
255 * mach_port_array_t *service_ports,
256 * int *service_ports_cnt,
257 * boolean_t *all_services_known)
258 *
259 * Returns port send rights in corresponding entries of the array service_ports
260 * for all services named in the array service_names. Service_ports_cnt is
261 * returned and will always equal service_names_cnt (assuming service_names_cnt
262 * is greater than or equal to zero).
263 *
264 * Errors: Returns appropriate kernel errors on rpc failure.
265 * Returns BOOTSTRAP_NO_MEMORY, if server couldn't obtain memory
266 * for response.
267 * Unknown service names have the corresponding service
268 * port set to MACH_PORT_NULL.
269 * If all services are known, all_services_known is true on
270 * return,
271 * if any service is unknown, it's false.
272 */
273 kern_return_t
274 x_bootstrap_look_up_array(
275 mach_port_t bootstrap_port,
276 name_array_t service_names,
277 unsigned int service_names_cnt,
278 mach_port_array_t *service_portsp,
279 unsigned int *service_ports_cnt,
280 boolean_t *all_services_known)
281 {
282 unsigned int i;
283 static mach_port_t service_ports[BOOTSTRAP_MAX_LOOKUP_COUNT];
284
285 if (service_names_cnt > BOOTSTRAP_MAX_LOOKUP_COUNT)
286 return BOOTSTRAP_BAD_COUNT;
287 *service_ports_cnt = service_names_cnt;
288 *all_services_known = TRUE;
289 for (i = 0; i < service_names_cnt; i++) {
290 if ( x_bootstrap_look_up(bootstrap_port,
291 service_names[i],
292 &service_ports[i])
293 != BOOTSTRAP_SUCCESS)
294 {
295 *all_services_known = FALSE;
296 service_ports[i] = MACH_PORT_NULL;
297 }
298 }
299 #if DEBUG
300 debug("bootstrap_look_up_array returns %d ports", service_names_cnt);
301 #endif DEBUG
302 *service_portsp = service_ports;
303 return BOOTSTRAP_SUCCESS;
304 }
305
306 /*
307 * kern_return_t
308 * bootstrap_status(mach_port_t bootstrap_port,
309 * name_t service_name,
310 * boolean_t *service_active);
311 *
312 * Returns: service_active is true if service is available.
313 *
314 * Errors: Returns appropriate kernel errors on rpc failure.
315 * Returns BOOTSTRAP_UNKNOWN_SERVICE, if service does not exist.
316 */
317 kern_return_t
318 x_bootstrap_status(
319 mach_port_t bootstrap_port,
320 name_t service_name,
321 boolean_t *service_active)
322 {
323 service_t *servicep;
324 bootstrap_info_t *bootstrap;
325
326 bootstrap = lookup_bootstrap_by_port(bootstrap_port);
327 servicep = lookup_service_by_name(bootstrap, service_name);
328 if (servicep == NULL) {
329 if (forward_ok) {
330 debug("bootstrap_status forwarding status, server %s",
331 service_name);
332 return bootstrap_status(inherited_bootstrap_port,
333 service_name,
334 service_active);
335 } else {
336 #if DEBUG
337 debug("bootstrap_status service %s unknown",
338 service_name);
339 #endif DEBUG
340 return BOOTSTRAP_UNKNOWN_SERVICE;
341 }
342 }
343 *service_active = servicep->isActive;
344 #if DEBUG
345 debug("bootstrap_status server %s %sactive", service_name,
346 servicep->isActive ? "" : "in");
347 #endif DEBUG
348 return BOOTSTRAP_SUCCESS;
349 }
350
351 /*
352 * kern_return_t
353 * bootstrap_info(mach_port_t bootstrap_port,
354 * name_array_t *service_names,
355 * int *service_names_cnt,
356 * name_array_t *server_names,
357 * int *server_names_cnt,
358 * bool_array_t *service_actives,
359 * int *service_active_cnt);
360 *
361 * Returns bootstrap status for all known services.
362 *
363 * Errors: Returns appropriate kernel errors on rpc failure.
364 */
365 kern_return_t
366 x_bootstrap_info(
367 mach_port_t bootstrap_port,
368 name_array_t *service_namesp,
369 unsigned int *service_names_cnt,
370 name_array_t *server_namesp,
371 unsigned int *server_names_cnt,
372 bool_array_t *service_activesp,
373 unsigned int *service_actives_cnt)
374 {
375 kern_return_t result;
376 unsigned int i, cnt;
377 service_t *servicep;
378 server_t *serverp;
379 bootstrap_info_t *bootstrap;
380 name_array_t service_names;
381 name_array_t server_names;
382 bool_array_t service_actives;
383
384 bootstrap = lookup_bootstrap_by_port(bootstrap_port);
385
386 for ( cnt = i = 0, servicep = services.next
387 ; i < nservices
388 ; servicep = servicep->next, i++)
389 {
390 if (lookup_service_by_name(bootstrap, servicep->name) == servicep)
391 {
392 cnt++;
393 }
394 }
395 result = vm_allocate(mach_task_self(),
396 (vm_address_t *)&service_names,
397 cnt * sizeof(service_names[0]),
398 ANYWHERE);
399 if (result != KERN_SUCCESS)
400 return BOOTSTRAP_NO_MEMORY;
401
402 result = vm_allocate(mach_task_self(),
403 (vm_address_t *)&server_names,
404 cnt * sizeof(server_names[0]),
405 ANYWHERE);
406 if (result != KERN_SUCCESS) {
407 (void)vm_deallocate(mach_task_self(),
408 (vm_address_t)service_names,
409 cnt * sizeof(service_names[0]));
410 return BOOTSTRAP_NO_MEMORY;
411 }
412 result = vm_allocate(mach_task_self(),
413 (vm_address_t *)&service_actives,
414 cnt * sizeof(service_actives[0]),
415 ANYWHERE);
416 if (result != KERN_SUCCESS) {
417 (void)vm_deallocate(mach_task_self(),
418 (vm_address_t)service_names,
419 cnt * sizeof(service_names[0]));
420 (void)vm_deallocate(mach_task_self(),
421 (vm_address_t)server_names,
422 cnt * sizeof(server_names[0]));
423 return BOOTSTRAP_NO_MEMORY;
424 }
425
426 for ( i = 0, servicep = services.next
427 ; i < nservices
428 ; servicep = servicep->next)
429 {
430 if ( lookup_service_by_name(bootstrap, servicep->name)
431 != servicep)
432 continue;
433 strncpy(service_names[i],
434 servicep->name,
435 sizeof(service_names[0]));
436 service_names[i][sizeof(service_names[0]) - 1] = '\0';
437 if (servicep->server) {
438 serverp = servicep->server;
439 strncpy(server_names[i],
440 serverp->cmd,
441 sizeof(server_names[0]));
442 server_names[i][sizeof(server_names[0]) - 1] = '\0';
443 debug("bootstrap info service %s server %s %sactive",
444 servicep->name,
445 serverp->cmd, servicep->isActive ? "" : "in");
446 } else {
447 server_names[i][0] = '\0';
448 debug("bootstrap info service %s %sactive",
449 servicep->name, servicep->isActive ? "" : "in");
450 }
451 service_actives[i] = servicep->isActive;
452 i++;
453 }
454 *service_namesp = service_names;
455 *server_namesp = server_names;
456 *service_activesp = service_actives;
457 *service_names_cnt = *server_names_cnt =
458 *service_actives_cnt = cnt;
459
460 return BOOTSTRAP_SUCCESS;
461 }
462
463 /*
464 * kern_return_t
465 * bootstrap_subset(mach_port_t bootstrap_port,
466 * mach_port_t requestor_port,
467 * mach_port_t *subset_port);
468 *
469 * Returns a new port to use as a bootstrap port. This port behaves
470 * exactly like the previous bootstrap_port, except that ports dynamically
471 * registered via bootstrap_register() are available only to users of this
472 * specific subset_port. Lookups on the subset_port will return ports
473 * registered with this port specifically, and ports registered with
474 * ancestors of this subset_port. Duplications of services already
475 * registered with an ancestor port may be registered with the subset port
476 * are allowed. Services already advertised may then be effectively removed
477 * by registering MACH_PORT_NULL for the service.
478 * When it is detected that the requestor_port is destroied the subset
479 * port and all services advertized by it are destroied as well.
480 *
481 * Errors: Returns appropriate kernel errors on rpc failure.
482 */
483 kern_return_t
484 x_bootstrap_subset(
485 mach_port_t bootstrap_port,
486 mach_port_t requestor_port,
487 mach_port_t *subset_port)
488 {
489 kern_return_t result;
490 bootstrap_info_t *bootstrap;
491 bootstrap_info_t *subset;
492 mach_port_t new_bootstrap_port;
493
494 bootstrap = lookup_bootstrap_by_port(bootstrap_port);
495
496 result = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &new_bootstrap_port);
497 if (result != KERN_SUCCESS)
498 kern_fatal(result, "mach_port_allocate");
499 result = mach_port_insert_right(mach_task_self(), new_bootstrap_port, new_bootstrap_port, MACH_MSG_TYPE_MAKE_SEND);
500 if (result != KERN_SUCCESS)
501 kern_fatal(result, "failed to insert send right");
502
503 result = mach_port_move_member(mach_task_self(), new_bootstrap_port, bootstrap_port_set);
504 if (result != KERN_SUCCESS)
505 kern_fatal(result, "port_set_add");
506
507 subset = new_bootstrap(bootstrap, new_bootstrap_port, requestor_port);
508 *subset_port = new_bootstrap_port;
509 debug("bootstrap_subset new bootstrap %d", new_bootstrap_port);
510 return BOOTSTRAP_SUCCESS;
511 }
512
513 /*
514 * kern_return_t
515 * bootstrap_create_service(mach_port_t bootstrap_port,
516 * name_t service_name,
517 * mach_port_t *service_port)
518 *
519 * Creates a service named "service_name" and returns send rights to that
520 * port in "service_port." The port may later be checked in as if this
521 * port were configured in the bootstrap configuration file.
522 *
523 * Errors: Returns appropriate kernel errors on rpc failure.
524 * Returns BOOTSTRAP_NAME_IN_USE, if service already exists.
525 */
526 kern_return_t
527 x_bootstrap_create_service(
528 mach_port_t bootstrap_port,
529 name_t service_name,
530 mach_port_t *service_port)
531 {
532 service_t *servicep;
533 bootstrap_info_t *bootstrap;
534 kern_return_t result;
535 mach_port_t previous;
536
537 bootstrap = lookup_bootstrap_by_port(bootstrap_port);
538 ASSERT(bootstrap);
539 debug("Service creation attempt for service %s", service_name);
540
541 servicep = lookup_service_by_name(bootstrap, service_name);
542 if (servicep) {
543 debug("Service creation attempt for service %s failed, "
544 "service already exists", service_name);
545 return BOOTSTRAP_NAME_IN_USE;
546 }
547
548 result = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, service_port);
549 if (result != KERN_SUCCESS)
550 kern_fatal(result, "port_allocate");
551 result = mach_port_insert_right(mach_task_self(), *service_port, *service_port, MACH_MSG_TYPE_MAKE_SEND);
552 if (result != KERN_SUCCESS)
553 kern_fatal(result, "failed to insert send right");
554 #if notyet
555 result = port_set_backup(mach_task_self(), *service_port, backup_port,
556 &previous);
557 if (result != KERN_SUCCESS)
558 kern_fatal(result, "port_set_backup");
559 info("Declared port %d for service %s", *service_port,
560 service_name);
561 #endif /*notyet */
562
563 servicep = new_service(bootstrap,
564 service_name,
565 *service_port,
566 !ACTIVE,
567 DECLARED,
568 NULL_SERVER);
569
570 log("Created new service %s", service_name);
571
572 return BOOTSTRAP_SUCCESS;
573 }