]> git.saurik.com Git - apple/system_cmds.git/blob - mach_init.tproj/bootstrap.c
81e49bc666d3ac2049251796fb8ae7ac65ebe106
[apple/system_cmds.git] / mach_init.tproj / bootstrap.c
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 * bootstrap.c -- implementation of bootstrap main service loop
30 */
31
32 /*
33 * Imports
34 */
35 #import <mach/mach.h>
36 #import <mach/boolean.h>
37 #import <mach/message.h>
38 #import <mach/notify.h>
39 #import <mach/mig_errors.h>
40 #include <mach/mach_traps.h>
41 #include <mach/mach_interface.h>
42 #include <mach/bootstrap.h>
43 #include <mach/host_info.h>
44 #include <mach/mach_host.h>
45 #include <mach/exception.h>
46
47 #import <sys/ioctl.h>
48 #import <sys/types.h>
49 #import <sys/time.h>
50 #import <sys/resource.h>
51 #import <sys/wait.h>
52 #import <pthread.h>
53 #import <string.h>
54 #import <ctype.h>
55 #import <stdio.h>
56 #import <libc.h>
57 #import <paths.h>
58 #import <pwd.h>
59
60 #include <bsm/audit.h>
61 #include <bsm/libbsm.h>
62
63 #import "bootstrap.h"
64
65 #import "bootstrap_internal.h"
66 #import "lists.h"
67 #import "error_log.h"
68
69 /* Mig should produce a declaration for this, but doesn't */
70 extern boolean_t bootstrap_server(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP);
71
72 /*
73 * Exports
74 */
75 const char *program_name; /* our name for error messages */
76
77 #ifndef INIT_PATH
78 #define INIT_PATH "/sbin/init" /* default init path */
79 #endif INIT_PATH
80
81 uid_t inherited_uid = 0;
82 auditinfo_t inherited_audit;
83 mach_port_t inherited_bootstrap_port = MACH_PORT_NULL;
84 boolean_t forward_ok = FALSE;
85 boolean_t shutdown_in_progress = FALSE;
86 boolean_t debugging = FALSE;
87 boolean_t register_self = FALSE;
88 boolean_t force_fork = FALSE;
89 const char *register_name;
90 task_t bootstrap_self;
91
92 #ifndef ASSERT
93 #define ASSERT(p)
94 #endif
95
96 /*
97 * Private macros
98 */
99 #define NELEM(x) (sizeof(x)/sizeof(x[0]))
100 #define END_OF(x) (&(x)[NELEM(x)])
101 #define streq(a,b) (strcmp(a,b) == 0)
102
103 /*
104 * Private declarations
105 */
106 static void wait_for_go(mach_port_t init_notify_port);
107 static void init_ports(void);
108 static void start_server(server_t *serverp);
109 static void unblock_init(mach_port_t init_notify_port, mach_port_t newBootstrap);
110 static void exec_server(server_t *serverp);
111 static char **argvize(const char *string);
112 static void *demand_loop(void *arg);
113 static void server_loop(void);
114 extern kern_return_t bootstrap_register
115 (
116 mach_port_t bootstrap_port,
117 name_t service_name,
118 mach_port_t service_port
119 );
120
121 /*
122 * Private ports we hold receive rights for. We also hold receive rights
123 * for all the privileged ports. Those are maintained in the server
124 * structs.
125 */
126 mach_port_t bootstrap_port_set;
127 mach_port_t demand_port_set;
128 pthread_t demand_thread;
129
130 mach_port_t notify_port;
131 mach_port_t backup_port;
132
133
134 static void
135 enablecoredumps(boolean_t enabled)
136 {
137 struct rlimit rlimit;
138
139 getrlimit(RLIMIT_CORE, &rlimit);
140 rlimit.rlim_cur = (enabled) ? rlimit.rlim_max : 0;
141 setrlimit(RLIMIT_CORE, &rlimit);
142 }
143
144 static void
145 toggle_debug(int signal)
146 {
147
148 debugging = (debugging) ? FALSE : TRUE;
149 enablecoredumps(debugging);
150 }
151
152 static mach_msg_return_t
153 inform_server_loop(
154 mach_port_name_t about,
155 mach_msg_option_t options)
156 {
157 mach_port_destroyed_notification_t not;
158 mach_msg_size_t size = sizeof(not) - sizeof(not.trailer);
159
160 not.not_header.msgh_id = DEMAND_REQUEST;
161 not.not_header.msgh_remote_port = backup_port;
162 not.not_header.msgh_local_port = MACH_PORT_NULL;
163 not.not_header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0);
164 not.not_header.msgh_size = size;
165 not.not_body.msgh_descriptor_count = 1;
166 not.not_port.type = MACH_MSG_PORT_DESCRIPTOR;
167 not.not_port.disposition = MACH_MSG_TYPE_PORT_NAME;
168 not.not_port.name = about;
169 return mach_msg(&not.not_header, MACH_SEND_MSG|options, size,
170 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
171 }
172
173 static void
174 notify_server_loop(mach_port_name_t about)
175 {
176 mach_msg_return_t result;
177
178 result = inform_server_loop(about, MACH_MSG_OPTION_NONE);
179 if (result != MACH_MSG_SUCCESS)
180 kern_error(result, "notify_server_loop: mach_msg()");
181 }
182
183 void start_shutdown(int signal)
184 {
185 shutdown_in_progress = TRUE;
186 (void) inform_server_loop(MACH_PORT_NULL, MACH_SEND_TIMEOUT);
187 }
188
189 int
190 main(int argc, char * argv[])
191 {
192 const char *argp;
193 char c;
194 kern_return_t result;
195 mach_port_t init_notify_port;
196 pthread_attr_t attr;
197 sigset_t mask;
198 int pid;
199
200 /*
201 * If we are pid one, we have to exec init. Before doing so, we'll
202 * fork a child, and that will become the true mach_init. But we have
203 * to be very careful about ports. They aren't inherited across fork,
204 * so we have to avoid storing port names in memory before the fork that
205 * might not be valid after.
206 */
207 pid = getpid();
208 if (pid == 1)
209 {
210 result = mach_port_allocate(
211 mach_task_self(),
212 MACH_PORT_RIGHT_RECEIVE,
213 &init_notify_port);
214 if (result != KERN_SUCCESS)
215 kern_fatal(result, "mach_port_allocate");
216
217 result = mach_port_insert_right(
218 mach_task_self(),
219 init_notify_port,
220 init_notify_port,
221 MACH_MSG_TYPE_MAKE_SEND);
222 if (result != KERN_SUCCESS)
223 kern_fatal(result, "mach_port_insert_right");
224
225 result = task_set_bootstrap_port(
226 mach_task_self(),
227 init_notify_port);
228 if (result != KERN_SUCCESS)
229 kern_fatal(result, "task_set_bootstrap_port");
230
231 pid = fork();
232
233 if (pid < 0)
234 unix_fatal("fork");
235
236 else if (pid != 0) { /* PARENT - will become init when ready */
237 int fd;
238
239 /*
240 * Wait for mach_init ot give us a real bootstrap port
241 */
242 wait_for_go(init_notify_port);
243
244 close(0);
245 close(1);
246 close(2);
247 fd = open("/dev/tty", O_RDONLY);
248 if (fd >= 0) {
249 ioctl(fd, TIOCNOTTY, 0);
250 close(fd);
251 }
252
253 /* pass our arguments on to init */
254 argv[0] = INIT_PATH;
255 execv(argv[0], argv);
256 exit(1); /* will likely trigger a panic */
257
258 }
259
260 /*
261 * Child - will continue along as mach_init. Save off
262 * the init_notify_port and put back a NULL bootstrap
263 * port for ourselves.
264 */
265 init_notify_port = bootstrap_port;
266 bootstrap_port = MACH_PORT_NULL;
267 (void)task_set_bootstrap_port(
268 mach_task_self(),
269 bootstrap_port);
270 if (result != KERN_SUCCESS)
271 kern_fatal(result, "task_get_bootstrap_port");
272
273 close(0);
274 open("/dev/null", O_RDONLY, 0);
275 close(1);
276 open("/dev/null", O_WRONLY, 0);
277 close(2);
278 open("/dev/null", O_WRONLY, 0);
279
280 } else
281 init_notify_port = MACH_PORT_NULL;
282
283 /* Initialize error handling */
284 program_name = rindex(*argv, '/');
285 if (program_name)
286 program_name++;
287 else
288 program_name = *argv;
289 argv++; argc--;
290
291 /* Parse command line args */
292 while (argc > 0 && **argv == '-') {
293 argp = *argv++ + 1; argc--;
294 while (*argp) {
295 switch (c = *argp++) {
296 case 'd':
297 debugging = TRUE;
298 break;
299 case 'D':
300 debugging = FALSE;
301 break;
302 case 'F':
303 if (init_notify_port != MACH_PORT_NULL)
304 force_fork = TRUE;
305 break;
306 case 'r':
307 register_self = forward_ok = TRUE;
308 if (argc > 0) {
309 register_name = *argv++; argc--;
310 } else
311 fatal("-r requires name");
312 break;
313 case '-':
314 default:
315 break;
316 }
317 }
318 }
319
320 /*
321 * If we must fork, do it now before we get Mach ports in use
322 */
323 if (force_fork) {
324 pid = fork();
325 if (pid < 0)
326 unix_fatal("fork");
327 else if (pid != 0) /* PARENT: just exit */
328 exit(0);
329 }
330
331 /*
332 * This task will become the bootstrap task, initialize the ports.
333 */
334 bootstrap_self = mach_task_self();
335 inherited_uid = getuid();
336 getaudit(&inherited_audit);
337 init_lists();
338 init_ports();
339
340 if (init_notify_port != MACH_PORT_NULL) {
341 /* send init a real bootstrap port to use */
342 unblock_init(init_notify_port, bootstraps.bootstrap_port);
343
344 result = mach_port_deallocate(
345 bootstrap_self,
346 init_notify_port);
347 if (result != KERN_SUCCESS)
348 kern_fatal(result, "mach_port_deallocate");
349
350 forward_ok = FALSE;
351 inherited_bootstrap_port = MACH_PORT_NULL;
352
353 } else {
354 /* get inherited bootstrap port */
355 result = task_get_bootstrap_port(
356 bootstrap_self,
357 &inherited_bootstrap_port);
358 if (result != KERN_SUCCESS)
359 kern_fatal(result, "task_get_bootstrap_port");
360
361 /* We set this explicitly as we start each child */
362 task_set_bootstrap_port(bootstrap_self, MACH_PORT_NULL);
363 if (inherited_bootstrap_port == MACH_PORT_NULL)
364 forward_ok = FALSE;
365
366 /* register "self" port with anscestor */
367 if (register_self && forward_ok) {
368 result = bootstrap_register(
369 inherited_bootstrap_port,
370 (char *)register_name,
371 bootstraps.bootstrap_port);
372 if (result != KERN_SUCCESS)
373 kern_fatal(result, "register self");
374 }
375 }
376
377 pthread_attr_init (&attr);
378 pthread_attr_setdetachstate ( &attr, PTHREAD_CREATE_DETACHED );
379 result = pthread_create(
380 &demand_thread,
381 &attr,
382 demand_loop,
383 NULL);
384 if (result) {
385 unix_error("pthread_create()");
386 exit(1);
387 }
388
389 /* block all but SIGHUP and SIGTERM */
390 sigfillset(&mask);
391 sigdelset(&mask, SIGHUP);
392 signal(SIGHUP, toggle_debug);
393 sigdelset(&mask, SIGTERM);
394 signal(SIGTERM, start_shutdown);
395 (void) sigprocmask(SIG_SETMASK, &mask, (sigset_t *)NULL);
396
397 /*
398 * Construct a very basic environment - as much as if we
399 * were actually forked from init (instead of the other
400 * way around):
401 *
402 * Set up the PATH to be approriate for the root user.
403 * Create an initial session.
404 * Establish an initial user.
405 * Disbale core dumps.
406 */
407 setsid();
408 setlogin("root");
409 enablecoredumps(debugging);
410 setenv("PATH", _PATH_STDPATH, 1);
411
412 init_errlog(pid == 0); /* are we a daemon? */
413 notice("Started with uid=%d audit-uid=%d%s%s%s",
414 inherited_uid,
415 inherited_audit.ai_auid,
416 (register_self) ? " registered-as=" : "",
417 (register_self) ? register_name : "",
418 (debugging) ? " in debug-mode" : "");
419
420 /* Process bootstrap service requests */
421 server_loop(); /* Should never return */
422 exit(1);
423 }
424
425 static void
426 wait_for_go(mach_port_t init_notify_port)
427 {
428 struct {
429 mach_msg_header_t hdr;
430 mach_msg_trailer_t trailer;
431 } init_go_msg;
432 kern_return_t result;
433
434 /*
435 * For now, we just blindly wait until we receive a message or
436 * timeout. We don't expect any notifications, and if we get one,
437 * it probably means something dire has happened; so we might as
438 * well give a shot at letting init run.
439 */
440 result = mach_msg(
441 &init_go_msg.hdr, MACH_RCV_MSG,
442 0, sizeof(init_go_msg), init_notify_port,
443 MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
444 if (result != KERN_SUCCESS) {
445 kern_error(result, "mach_msg(receive) failed in wait_for_go");
446 }
447 bootstrap_port = init_go_msg.hdr.msgh_remote_port;
448 result = task_set_bootstrap_port(
449 mach_task_self(),
450 bootstrap_port);
451 if (result != KERN_SUCCESS) {
452 kern_error(result, "task_get_bootstrap_port()");
453 }
454 }
455
456
457 static void
458 unblock_init(mach_port_t init_notify_port,
459 mach_port_t newBootstrap)
460 {
461 mach_msg_header_t init_go_msg;
462 kern_return_t result;
463
464 /*
465 * Proc 1 is blocked in a msg_receive on its notify port, this lets
466 * it continue, and we hand off its new bootstrap port
467 */
468 init_go_msg.msgh_remote_port = init_notify_port;
469 init_go_msg.msgh_local_port = newBootstrap;
470 init_go_msg.msgh_bits = MACH_MSGH_BITS(
471 MACH_MSG_TYPE_COPY_SEND,
472 MACH_MSG_TYPE_MAKE_SEND);
473 init_go_msg.msgh_size = sizeof(init_go_msg);
474 result = mach_msg_send(&init_go_msg);
475 if (result != KERN_SUCCESS)
476 kern_fatal(result, "unblock_init mach_msg_send() failed");
477 debug("sent go message");
478 }
479
480
481 static void
482 init_ports(void)
483 {
484 kern_return_t result;
485
486 /*
487 * This task will become the bootstrap task.
488 */
489 /* Create port set that server loop listens to */
490 result = mach_port_allocate(
491 bootstrap_self,
492 MACH_PORT_RIGHT_PORT_SET,
493 &bootstrap_port_set);
494 if (result != KERN_SUCCESS)
495 kern_fatal(result, "port_set_allocate");
496
497 /* Create demand port set that second thread listens to */
498 result = mach_port_allocate(
499 bootstrap_self,
500 MACH_PORT_RIGHT_PORT_SET,
501 &demand_port_set);
502 if (result != KERN_SUCCESS)
503 kern_fatal(result, "port_set_allocate");
504
505 /* Create notify port and add to server port set */
506 result = mach_port_allocate(
507 bootstrap_self,
508 MACH_PORT_RIGHT_RECEIVE,
509 &notify_port);
510 if (result != KERN_SUCCESS)
511 kern_fatal(result, "mach_port_allocate");
512
513 result = mach_port_move_member(
514 bootstrap_self,
515 notify_port,
516 bootstrap_port_set);
517 if (result != KERN_SUCCESS)
518 kern_fatal(result, "mach_port_move_member");
519
520 /* Create backup port and add to server port set */
521 result = mach_port_allocate(
522 bootstrap_self,
523 MACH_PORT_RIGHT_RECEIVE,
524 &backup_port);
525 if (result != KERN_SUCCESS)
526 kern_fatal(result, "mach_port_allocate");
527
528 result = mach_port_move_member(
529 bootstrap_self,
530 backup_port,
531 bootstrap_port_set);
532 if (result != KERN_SUCCESS)
533 kern_fatal(result, "mach_port_move_member");
534
535 /* Create "self" port and add to server port set */
536 result = mach_port_allocate(
537 bootstrap_self,
538 MACH_PORT_RIGHT_RECEIVE,
539 &bootstraps.bootstrap_port);
540 if (result != KERN_SUCCESS)
541 kern_fatal(result, "mach_port_allocate");
542 result = mach_port_insert_right(
543 bootstrap_self,
544 bootstraps.bootstrap_port,
545 bootstraps.bootstrap_port,
546 MACH_MSG_TYPE_MAKE_SEND);
547 if (result != KERN_SUCCESS)
548 kern_fatal(result, "mach_port_insert_right");
549
550 /* keep the root bootstrap port "active" */
551 bootstraps.requestor_port = bootstraps.bootstrap_port;
552
553 result = mach_port_move_member(
554 bootstrap_self,
555 bootstraps.bootstrap_port,
556 bootstrap_port_set);
557 if (result != KERN_SUCCESS)
558 kern_fatal(result, "mach_port_move_member");
559 }
560
561 boolean_t
562 active_bootstrap(bootstrap_info_t *bootstrap)
563 {
564 return (bootstrap->requestor_port != MACH_PORT_NULL);
565 }
566
567 boolean_t
568 useless_server(server_t *serverp)
569 {
570 return ( !active_bootstrap(serverp->bootstrap) ||
571 !lookup_service_by_server(serverp) ||
572 !serverp->activity);
573 }
574
575 boolean_t
576 active_server(server_t *serverp)
577 {
578 return ( serverp->port ||
579 serverp->task_port || serverp->active_services);
580 }
581
582 static void
583 reap_server(server_t *serverp)
584 {
585 kern_return_t result;
586 pid_t presult;
587 int wstatus;
588
589 /*
590 * Reap our children.
591 */
592 presult = waitpid(serverp->pid, &wstatus, WNOHANG);
593 if (presult != serverp->pid) {
594 unix_error("waitpid: cmd = %s", serverp->cmd);
595 } else if (wstatus) {
596 notice("Server %x in bootstrap %x uid %d: \"%s\": %s %d [pid %d]",
597 serverp->port, serverp->bootstrap->bootstrap_port,
598 serverp->uid, serverp->cmd,
599 ((WIFEXITED(wstatus)) ?
600 "exited with non-zero status" :
601 "exited as a result of signal"),
602 ((WIFEXITED(wstatus)) ? WEXITSTATUS(wstatus) : WTERMSIG(wstatus)),
603 serverp->pid);
604 }
605 serverp->pid = 0;
606
607 /*
608 * Release the server task port reference, if we ever
609 * got it in the first place.
610 */
611 if (serverp->task_port != MACH_PORT_NULL) {
612 result = mach_port_deallocate(
613 mach_task_self(),
614 serverp->task_port);
615 if (result != KERN_SUCCESS)
616 kern_error(result, "mach_port_deallocate");
617 serverp->task_port = MACH_PORT_NULL;
618 }
619 }
620
621 static void
622 demand_server(server_t *serverp)
623 {
624 service_t *servicep;
625 kern_return_t result;
626
627 /*
628 * For on-demand servers, make sure that the service ports are
629 * back in on-demand portset. Active service ports should come
630 * back through a PORT_DESTROYED notification. We only have to
631 * worry about the inactive ports that may have been previously
632 * pulled from the set but never checked-in by the server.
633 */
634
635 for ( servicep = FIRST(services)
636 ; !IS_END(servicep, services)
637 ; servicep = NEXT(servicep))
638 {
639 if (serverp == servicep->server && !servicep->isActive) {
640 result = mach_port_move_member(
641 mach_task_self(),
642 servicep->port,
643 demand_port_set);
644 if (result != KERN_SUCCESS)
645 kern_fatal(result, "mach_port_move_member");
646 }
647 }
648 }
649
650 static
651 void dispatch_server(server_t *serverp)
652 {
653 if (!active_server(serverp)) {
654 if (useless_server(serverp))
655 delete_server(serverp);
656 else if (serverp->servertype == RESTARTABLE)
657 start_server(serverp);
658 else if (serverp->servertype == DEMAND)
659 demand_server(serverp);
660 }
661 }
662
663 void
664 setup_server(server_t *serverp)
665 {
666 kern_return_t result;
667 mach_port_t old_port;
668
669 /* Allocate privileged port for requests from service */
670 result = mach_port_allocate(mach_task_self(),
671 MACH_PORT_RIGHT_RECEIVE ,
672 &serverp->port);
673 info("Allocating port %x for server %s", serverp->port, serverp->cmd);
674 if (result != KERN_SUCCESS)
675 kern_fatal(result, "port_allocate");
676
677 /* Request no-senders notification so we can tell when server dies */
678 result = mach_port_request_notification(mach_task_self(),
679 serverp->port,
680 MACH_NOTIFY_NO_SENDERS,
681 1,
682 serverp->port,
683 MACH_MSG_TYPE_MAKE_SEND_ONCE,
684 &old_port);
685 if (result != KERN_SUCCESS)
686 kern_fatal(result, "mach_port_request_notification");
687
688 /* Add privileged server port to bootstrap port set */
689 result = mach_port_move_member(mach_task_self(),
690 serverp->port,
691 bootstrap_port_set);
692 if (result != KERN_SUCCESS)
693 kern_fatal(result, "mach_port_move_member");
694 }
695
696 static void
697 start_server(server_t *serverp)
698 {
699 kern_return_t result;
700 mach_port_t old_port;
701 int pid;
702
703 /*
704 * Do what's appropriate to get bootstrap port setup in server task
705 */
706 switch (serverp->servertype) {
707
708 case MACHINIT:
709 break;
710
711 case SERVER:
712 case DEMAND:
713 case RESTARTABLE:
714 if (!serverp->port)
715 setup_server(serverp);
716
717 serverp->activity = 0;
718
719 /* Insert a send right */
720 result = mach_port_insert_right(mach_task_self(),
721 serverp->port,
722 serverp->port,
723 MACH_MSG_TYPE_MAKE_SEND);
724 if (result != KERN_SUCCESS)
725 kern_fatal(result, "mach_port_insert_right");
726
727 /* Give trusted service a unique bootstrap port */
728 result = task_set_bootstrap_port(mach_task_self(),
729 serverp->port);
730 if (result != KERN_SUCCESS)
731 kern_fatal(result, "task_set_bootstrap_port");
732
733 result = mach_port_deallocate(mach_task_self(),
734 serverp->port);
735 if (result != KERN_SUCCESS)
736 kern_fatal(result, "mach_port_deallocate");
737
738 pid = fork();
739 if (pid < 0) {
740 unix_error("fork");
741 } else if (pid == 0) { /* CHILD */
742 exec_server(serverp);
743 exit(1);
744 } else { /* PARENT */
745
746 result = task_set_bootstrap_port(
747 mach_task_self(),
748 MACH_PORT_NULL);
749 if (result != KERN_SUCCESS)
750 kern_fatal(result, "task_set_bootstrap_port");
751
752 info("Launched server %x in bootstrap %x uid %d: \"%s\": [pid %d]",
753 serverp->port, serverp->bootstrap->bootstrap_port,
754 serverp->uid, serverp->cmd, pid);
755 serverp->pid = pid;
756 result = task_for_pid(
757 mach_task_self(),
758 pid,
759 &serverp->task_port);
760 if (result != KERN_SUCCESS) {
761 kern_error(result, "getting server task port");
762 reap_server(serverp);
763 dispatch_server(serverp);
764 break;
765 }
766
767 /* Request dead name notification to tell when task dies */
768 result = mach_port_request_notification(
769 mach_task_self(),
770 serverp->task_port,
771 MACH_NOTIFY_DEAD_NAME,
772 0,
773 notify_port,
774 MACH_MSG_TYPE_MAKE_SEND_ONCE,
775 &old_port);
776 if (result != KERN_SUCCESS) {
777 kern_error(result, "mach_port_request_notification");
778 reap_server(serverp);
779 dispatch_server(serverp);
780 }
781 }
782 break;
783 }
784 }
785
786 static void
787 exec_server(server_t *serverp)
788 {
789 char **argv;
790 sigset_t mask;
791
792 /*
793 * Setup environment for server, someday this should be Mach stuff
794 * rather than Unix crud
795 */
796 argv = argvize(serverp->cmd);
797 close_errlog();
798
799 /*
800 * Set up the audit state for the user (if necessesary).
801 */
802 if (inherited_uid == 0 &&
803 (serverp->auinfo.ai_auid != inherited_uid ||
804 serverp->auinfo.ai_asid != inherited_audit.ai_asid)) {
805 struct passwd *pwd = NULL;
806
807 pwd = getpwuid(serverp->auinfo.ai_auid);
808 if (pwd == NULL) {
809 unix_fatal("Disabled server %x bootstrap %x: \"%s\": getpwuid(%d) failed",
810 serverp->port, serverp->bootstrap->bootstrap_port,
811 serverp->cmd, serverp->auinfo.ai_auid);
812
813 } else if (au_user_mask(pwd->pw_name, &serverp->auinfo.ai_mask) != 0) {
814 unix_fatal("Disabled server %x bootstrap %x: \"%s\": au_user_mask(%s) failed",
815 serverp->port, serverp->bootstrap->bootstrap_port,
816 serverp->cmd, pwd->pw_name);
817 } else if (setaudit(&serverp->auinfo) != 0)
818 unix_fatal("Disabled server %x bootstrap %x: \"%s\": setaudit()",
819 serverp->port, serverp->bootstrap->bootstrap_port,
820 serverp->cmd);
821 }
822
823 if (serverp->uid != inherited_uid)
824 if (setuid(serverp->uid) < 0)
825 unix_fatal("Disabled server %x bootstrap %x: \"%s\": setuid(%d)",
826 serverp->port, serverp->bootstrap->bootstrap_port,
827 serverp->cmd, serverp->uid);
828
829 if (setsid() < 0) {
830 /*
831 * We can't keep this from happening, but we shouldn't start
832 * the server not as a process group leader. So, just fake like
833 * there was real activity, and exit the child. If needed,
834 * we'll re-launch it under another pid.
835 */
836 serverp->activity = 1;
837 unix_fatal("Temporary failure server %x bootstrap %x: \"%s\": setsid()",
838 serverp->port, serverp->bootstrap->bootstrap_port,
839 serverp->cmd);
840 }
841
842 sigemptyset(&mask);
843 (void) sigprocmask(SIG_SETMASK, &mask, (sigset_t *)NULL);
844
845 execv(argv[0], argv);
846 unix_fatal("Disabled server %x bootstrap %x: \"%s\": exec()",
847 serverp->port,
848 serverp->bootstrap->bootstrap_port,
849 serverp->cmd);
850 }
851
852 static char **
853 argvize(const char *string)
854 {
855 static char *argv[100], args[1000];
856 const char *cp;
857 char *argp, term;
858 int nargs;
859
860 /*
861 * Convert a command line into an argv for execv
862 */
863 nargs = 0;
864 argp = args;
865
866 for (cp = string; *cp;) {
867 while (isspace(*cp))
868 cp++;
869 term = (*cp == '"') ? *cp++ : '\0';
870 if (nargs < NELEM(argv))
871 argv[nargs++] = argp;
872 while (*cp && (term ? *cp != term : !isspace(*cp))
873 && argp < END_OF(args)) {
874 if (*cp == '\\')
875 cp++;
876 *argp++ = *cp;
877 if (*cp)
878 cp++;
879 }
880 *argp++ = '\0';
881 }
882 argv[nargs] = NULL;
883 return argv;
884 }
885
886 static void *
887 demand_loop(void *arg)
888 {
889 mach_msg_empty_rcv_t dummy;
890 kern_return_t dresult;
891
892
893 for(;;) {
894 mach_port_name_array_t members;
895 mach_msg_type_number_t membersCnt;
896 mach_port_status_t status;
897 mach_msg_type_number_t statusCnt;
898 int i;
899
900 /*
901 * Receive indication of message on demand service
902 * ports without actually receiving the message (we'll
903 * let the actual server do that.
904 */
905 dresult = mach_msg(
906 &dummy.header,
907 MACH_RCV_MSG|MACH_RCV_LARGE,
908 0,
909 0,
910 demand_port_set,
911 0,
912 MACH_PORT_NULL);
913 if (dresult != MACH_RCV_TOO_LARGE) {
914 kern_error(dresult, "demand_loop: mach_msg()");
915 continue;
916 }
917
918 /*
919 * If we are shutting down, there is no use processing
920 * any more of these messages.
921 */
922 if (shutdown_in_progress == TRUE)
923 return arg;
924
925 /*
926 * Some port(s) now have messages on them, find out
927 * which ones (there is no indication of which port
928 * triggered in the MACH_RCV_TOO_LARGE indication).
929 */
930 dresult = mach_port_get_set_status(
931 mach_task_self(),
932 demand_port_set,
933 &members,
934 &membersCnt);
935 if (dresult != KERN_SUCCESS) {
936 kern_error(dresult, "demand_loop: mach_port_get_set_status()");
937 continue;
938 }
939
940 for (i = 0; i < membersCnt; i++) {
941 statusCnt = MACH_PORT_RECEIVE_STATUS_COUNT;
942 dresult = mach_port_get_attributes(
943 mach_task_self(),
944 members[i],
945 MACH_PORT_RECEIVE_STATUS,
946 (mach_port_info_t)&status,
947 &statusCnt);
948 if (dresult != KERN_SUCCESS) {
949 kern_error(dresult, "demand_loop: mach_port_get_attributes()");
950 continue;
951 }
952
953 /*
954 * For each port with messages, take it out of the
955 * demand service portset, and inform the main thread
956 * that it might have to start the server responsible
957 * for it.
958 */
959 if (status.mps_msgcount) {
960 dresult = mach_port_move_member(
961 mach_task_self(),
962 members[i],
963 MACH_PORT_NULL);
964 if (dresult != KERN_SUCCESS) {
965 kern_error(dresult, "demand_loop: mach_port_move_member()");
966 continue;
967 }
968 notify_server_loop(members[i]);
969 }
970 }
971
972 dresult = vm_deallocate(
973 mach_task_self(),
974 (vm_address_t) members,
975 (vm_size_t) membersCnt * sizeof(mach_port_name_t));
976 if (dresult != KERN_SUCCESS) {
977 kern_error(dresult, "demand_loop: vm_deallocate()");
978 continue;
979 }
980 }
981 return NULL;
982 }
983
984 /*
985 * server_demux -- processes requests off our service port
986 * Also handles notifications
987 */
988
989 static boolean_t
990 server_demux(
991 mach_msg_header_t *Request,
992 mach_msg_header_t *Reply)
993 {
994 bootstrap_info_t *bootstrap;
995 service_t *servicep;
996 server_t *serverp;
997 kern_return_t result;
998 mig_reply_error_t *reply;
999
1000 debug("received message on port %x\n", Request->msgh_local_port);
1001
1002 /*
1003 * Do minimal cleanup and then exit.
1004 */
1005 if (shutdown_in_progress == TRUE) {
1006 notice("Shutting down. Deactivating root bootstrap (%x) ...",
1007 bootstraps.bootstrap_port);
1008 deactivate_bootstrap(&bootstraps);
1009 notice("Done.");
1010 exit(0);
1011 }
1012
1013 reply = (mig_reply_error_t *)Reply;
1014
1015 /*
1016 * Pick off notification messages
1017 */
1018 if (Request->msgh_local_port == notify_port) {
1019 mach_port_name_t np;
1020
1021 memset(reply, 0, sizeof(*reply));
1022 switch (Request->msgh_id) {
1023 case MACH_NOTIFY_DEAD_NAME:
1024 np = ((mach_dead_name_notification_t *)Request)->not_port;
1025 debug("Notified dead name %x", np);
1026
1027 if (np == inherited_bootstrap_port) {
1028 inherited_bootstrap_port = MACH_PORT_NULL;
1029 forward_ok = FALSE;
1030 }
1031
1032 /*
1033 * Check to see if a subset requestor port was deleted.
1034 */
1035 while (bootstrap = lookup_bootstrap_by_req_port(np)) {
1036 debug("Received dead name notification for bootstrap subset %x requestor port %x",
1037 bootstrap->bootstrap_port, bootstrap->requestor_port);
1038 mach_port_deallocate(
1039 mach_task_self(),
1040 bootstrap->requestor_port);
1041 bootstrap->requestor_port = MACH_PORT_NULL;
1042 deactivate_bootstrap(bootstrap);
1043 }
1044
1045 /*
1046 * Check to see if a defined service has gone
1047 * away.
1048 */
1049 while (servicep = lookup_service_by_port(np)) {
1050 /*
1051 * Port gone, registered service died.
1052 */
1053 debug("Received dead name notification for service %s "
1054 "on bootstrap port %x\n",
1055 servicep->name, servicep->bootstrap);
1056 debug("Service %s failed - deallocate", servicep->name);
1057 delete_service(servicep);
1058 }
1059
1060 /*
1061 * Check to see if a launched server task has gone
1062 * away.
1063 */
1064 if (serverp = lookup_server_by_task_port(np)) {
1065 /*
1066 * Port gone, server died.
1067 */
1068 debug("Received task death notification for server %s ",
1069 serverp->cmd);
1070 reap_server(serverp);
1071 dispatch_server(serverp);
1072 }
1073
1074 mach_port_deallocate(mach_task_self(), np);
1075 reply->RetCode = KERN_SUCCESS;
1076 break;
1077
1078 case MACH_NOTIFY_PORT_DELETED:
1079 np = ((mach_port_deleted_notification_t *)Request)->not_port;
1080 debug("port deleted notification on 0x%x\n", np);
1081 reply->RetCode = KERN_SUCCESS;
1082 break;
1083
1084 case MACH_NOTIFY_SEND_ONCE:
1085 debug("notification send-once right went unused\n");
1086 reply->RetCode = KERN_SUCCESS;
1087 break;
1088
1089 default:
1090 error("Unexpected notification: %d", Request->msgh_id);
1091 reply->RetCode = KERN_FAILURE;
1092 break;
1093 }
1094 }
1095
1096 else if (Request->msgh_local_port == backup_port) {
1097 mach_port_name_t np;
1098
1099 memset(reply, 0, sizeof(*reply));
1100
1101 np = ((mach_port_destroyed_notification_t *)Request)->not_port.name;
1102 servicep = lookup_service_by_port(np);
1103 if (servicep != NULL) {
1104 server_t *serverp = servicep->server;
1105
1106 switch (Request->msgh_id) {
1107
1108 case MACH_NOTIFY_PORT_DESTROYED:
1109 /*
1110 * Port sent back to us, server died.
1111 */
1112 debug("Received destroyed notification for service %s",
1113 servicep->name);
1114 debug("Service %x bootstrap %x backed up: %s",
1115 servicep->port, servicep->bootstrap->bootstrap_port,
1116 servicep->name);
1117 ASSERT(canReceive(servicep->port));
1118 servicep->isActive = FALSE;
1119 serverp->active_services--;
1120 dispatch_server(serverp);
1121 reply->RetCode = KERN_SUCCESS;
1122 break;
1123
1124 case DEMAND_REQUEST:
1125 /* message reflected over from demand start thread */
1126 if (!active_server(serverp))
1127 start_server(serverp);
1128 reply->RetCode = KERN_SUCCESS;
1129 break;
1130
1131 default:
1132 debug("Mysterious backup_port notification %d", Request->msgh_id);
1133 reply->RetCode = KERN_FAILURE;
1134 break;
1135 }
1136 } else {
1137 debug("Backup_port notification - previously deleted service");
1138 reply->RetCode = KERN_FAILURE;
1139 }
1140 }
1141
1142 else if (Request->msgh_id == MACH_NOTIFY_NO_SENDERS) {
1143 mach_port_t ns = Request->msgh_local_port;
1144
1145 if ((serverp = lookup_server_by_port(ns)) != NULL_SERVER) {
1146 /*
1147 * A server we launched has released his bootstrap
1148 * port send right. We won't re-launch him unless
1149 * his services came back to roost. But we need to
1150 * destroy the bootstrap port for fear of leaking.
1151 */
1152 debug("server %s dropped server port", serverp->cmd);
1153 serverp->port = MACH_PORT_NULL;
1154 dispatch_server(serverp);
1155 } else if (bootstrap = lookup_bootstrap_by_port(ns)) {
1156 /*
1157 * The last direct user of a deactivated bootstrap went away.
1158 * We can finally free it.
1159 */
1160 debug("Deallocating bootstrap %x: no more clients", ns);
1161 bootstrap->bootstrap_port = MACH_PORT_NULL;
1162 deallocate_bootstrap(bootstrap);
1163 }
1164
1165 result = mach_port_mod_refs(
1166 mach_task_self(),
1167 ns,
1168 MACH_PORT_RIGHT_RECEIVE,
1169 -1);
1170 if (result != KERN_SUCCESS)
1171 kern_fatal(result, "mach_port_mod_refs");
1172
1173 memset(reply, 0, sizeof(*reply));
1174 reply->RetCode = KERN_SUCCESS;
1175 }
1176
1177 else { /* must be a service request */
1178 debug("Handled request.");
1179 return bootstrap_server(Request, Reply);
1180 }
1181 return TRUE;
1182 }
1183
1184 /*
1185 * server_loop -- pick requests off our service port and process them
1186 * Also handles notifications
1187 */
1188 #define bootstrapMaxRequestSize 1024
1189 #define bootstrapMaxReplySize 1024
1190
1191 static void
1192 server_loop(void)
1193 {
1194 mach_msg_return_t mresult;
1195
1196 for (;;) {
1197 mresult = mach_msg_server(
1198 server_demux,
1199 bootstrapMaxRequestSize,
1200 bootstrap_port_set,
1201 MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_SENDER)|
1202 MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0));
1203 if (mresult != MACH_MSG_SUCCESS)
1204 kern_error(mresult, "mach_msg_server");
1205 }
1206 }
1207
1208 boolean_t
1209 canReceive(mach_port_t port)
1210 {
1211 mach_port_type_t p_type;
1212 kern_return_t result;
1213
1214 result = mach_port_type(mach_task_self(), port, &p_type);
1215 if (result != KERN_SUCCESS) {
1216 kern_error(result, "port_type");
1217 return FALSE;
1218 }
1219 return ((p_type & MACH_PORT_TYPE_RECEIVE) != 0);
1220 }
1221
1222
1223 boolean_t
1224 canSend(mach_port_t port)
1225 {
1226 mach_port_type_t p_type;
1227 kern_return_t result;
1228
1229 result = mach_port_type(mach_task_self(), port, &p_type);
1230 if (result != KERN_SUCCESS) {
1231 kern_error(result, "port_type");
1232 return FALSE;
1233 }
1234 return ((p_type & MACH_PORT_TYPE_PORT_RIGHTS) != 0);
1235 }