]> git.saurik.com Git - apple/system_cmds.git/blame - mach_init.tproj/bootstrap.c
system_cmds-279.6.1.tar.gz
[apple/system_cmds.git] / mach_init.tproj / bootstrap.c
CommitLineData
1815bff5 1/*
733af6d0 2 * Copyright (c) 1999-2004 Apple Computer, Inc. All rights reserved.
1815bff5
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
d904471c
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,
d904471c
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 * 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>
b51d5b5f 48#import <sys/types.h>
20e66415
A
49#import <sys/time.h>
50#import <sys/resource.h>
b51d5b5f
A
51#import <sys/wait.h>
52#import <pthread.h>
1815bff5
A
53#import <string.h>
54#import <ctype.h>
55#import <stdio.h>
56#import <libc.h>
20e66415 57#import <paths.h>
733af6d0
A
58#import <pwd.h>
59
60#include <bsm/audit.h>
61#include <bsm/libbsm.h>
1815bff5 62
b51d5b5f 63#import "bootstrap.h"
1815bff5
A
64
65#import "bootstrap_internal.h"
66#import "lists.h"
67#import "error_log.h"
1815bff5
A
68
69/* Mig should produce a declaration for this, but doesn't */
70extern boolean_t bootstrap_server(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP);
71
72/*
73 * Exports
74 */
75const char *program_name; /* our name for error messages */
76
b51d5b5f
A
77#ifndef INIT_PATH
78#define INIT_PATH "/sbin/init" /* default init path */
79#endif INIT_PATH
1815bff5 80
733af6d0
A
81uid_t inherited_uid = 0;
82auditinfo_t inherited_audit;
1815bff5
A
83mach_port_t inherited_bootstrap_port = MACH_PORT_NULL;
84boolean_t forward_ok = FALSE;
b51d5b5f 85boolean_t shutdown_in_progress = FALSE;
1815bff5
A
86boolean_t debugging = FALSE;
87boolean_t register_self = FALSE;
b51d5b5f
A
88boolean_t force_fork = FALSE;
89const char *register_name;
90task_t bootstrap_self;
1815bff5
A
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 */
1815bff5
A
106static void wait_for_go(mach_port_t init_notify_port);
107static void init_ports(void);
108static void start_server(server_t *serverp);
b51d5b5f 109static void unblock_init(mach_port_t init_notify_port, mach_port_t newBootstrap);
1815bff5
A
110static void exec_server(server_t *serverp);
111static char **argvize(const char *string);
b51d5b5f 112static void *demand_loop(void *arg);
1815bff5 113static void server_loop(void);
b51d5b5f
A
114extern kern_return_t bootstrap_register
115(
116 mach_port_t bootstrap_port,
117 name_t service_name,
118 mach_port_t service_port
119);
1815bff5
A
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 */
126mach_port_t bootstrap_port_set;
b51d5b5f
A
127mach_port_t demand_port_set;
128pthread_t demand_thread;
129
1815bff5 130mach_port_t notify_port;
b51d5b5f 131mach_port_t backup_port;
1815bff5 132
20e66415 133
b51d5b5f 134static void
20e66415
A
135enablecoredumps(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
144static void
145toggle_debug(int signal)
146{
147
148 debugging = (debugging) ? FALSE : TRUE;
149 enablecoredumps(debugging);
150}
151
152static mach_msg_return_t
153inform_server_loop(
154 mach_port_name_t about,
155 mach_msg_option_t options)
b51d5b5f
A
156{
157 mach_port_destroyed_notification_t not;
20e66415 158 mach_msg_size_t size = sizeof(not) - sizeof(not.trailer);
b51d5b5f
A
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);
20e66415 164 not.not_header.msgh_size = size;
b51d5b5f
A
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;
20e66415
A
169 return mach_msg(&not.not_header, MACH_SEND_MSG|options, size,
170 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
b51d5b5f 171}
1815bff5 172
20e66415
A
173static void
174notify_server_loop(mach_port_name_t about)
1815bff5 175{
20e66415 176 mach_msg_return_t result;
1815bff5 177
20e66415
A
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()");
b51d5b5f
A
181}
182
183void start_shutdown(int signal)
184{
b51d5b5f 185 shutdown_in_progress = TRUE;
20e66415 186 (void) inform_server_loop(MACH_PORT_NULL, MACH_SEND_TIMEOUT);
b51d5b5f
A
187}
188
189int
190main(int argc, char * argv[])
1815bff5
A
191{
192 const char *argp;
193 char c;
1815bff5 194 kern_return_t result;
b51d5b5f
A
195 mach_port_t init_notify_port;
196 pthread_attr_t attr;
197 sigset_t mask;
1815bff5 198 int pid;
b51d5b5f
A
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 {
b51d5b5f
A
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);
b51d5b5f
A
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 }
20e66415
A
259
260 /*
c3a08f59
A
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.
20e66415 264 */
c3a08f59
A
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");
733af6d0
A
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
b51d5b5f
A
280 } else
281 init_notify_port = MACH_PORT_NULL;
1815bff5
A
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
1815bff5
A
291 /* Parse command line args */
292 while (argc > 0 && **argv == '-') {
1815bff5
A
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':
c3a08f59
A
303 if (init_notify_port != MACH_PORT_NULL)
304 force_fork = TRUE;
1815bff5 305 break;
1815bff5
A
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;
b51d5b5f 313 case '-':
1815bff5 314 default:
1815bff5
A
315 break;
316 }
317 }
1815bff5
A
318 }
319
1815bff5 320 /*
b51d5b5f 321 * If we must fork, do it now before we get Mach ports in use
1815bff5 322 */
b51d5b5f 323 if (force_fork) {
1815bff5
A
324 pid = fork();
325 if (pid < 0)
326 unix_fatal("fork");
b51d5b5f
A
327 else if (pid != 0) /* PARENT: just exit */
328 exit(0);
329 }
330
b51d5b5f 331 /*
c3a08f59 332 * This task will become the bootstrap task, initialize the ports.
b51d5b5f
A
333 */
334 bootstrap_self = mach_task_self();
335 inherited_uid = getuid();
733af6d0 336 getaudit(&inherited_audit);
c3a08f59 337 init_lists();
b51d5b5f 338 init_ports();
1815bff5 339
b51d5b5f 340 if (init_notify_port != MACH_PORT_NULL) {
c3a08f59 341 /* send init a real bootstrap port to use */
b51d5b5f
A
342 unblock_init(init_notify_port, bootstraps.bootstrap_port);
343
b51d5b5f
A
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 {
b51d5b5f
A
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);
1815bff5 372 if (result != KERN_SUCCESS)
b51d5b5f 373 kern_fatal(result, "register self");
1815bff5 374 }
1815bff5 375 }
1815bff5 376
b51d5b5f
A
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()");
1815bff5
A
386 exit(1);
387 }
1815bff5 388
c3a08f59
A
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? */
733af6d0 413 notice("Started with uid=%d audit-uid=%d%s%s%s",
c3a08f59 414 inherited_uid,
733af6d0 415 inherited_audit.ai_auid,
c3a08f59
A
416 (register_self) ? " registered-as=" : "",
417 (register_self) ? register_name : "",
418 (debugging) ? " in debug-mode" : "");
419
b51d5b5f
A
420 /* Process bootstrap service requests */
421 server_loop(); /* Should never return */
422 exit(1);
1815bff5
A
423}
424
425static void
426wait_for_go(mach_port_t init_notify_port)
427{
b51d5b5f 428 struct {
1815bff5
A
429 mach_msg_header_t hdr;
430 mach_msg_trailer_t trailer;
b51d5b5f 431 } init_go_msg;
1815bff5
A
432 kern_return_t result;
433
b51d5b5f 434 /*
1815bff5
A
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 */
b51d5b5f
A
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 }
c3a08f59 447 bootstrap_port = init_go_msg.hdr.msgh_remote_port;
b51d5b5f
A
448 result = task_set_bootstrap_port(
449 mach_task_self(),
c3a08f59 450 bootstrap_port);
b51d5b5f
A
451 if (result != KERN_SUCCESS) {
452 kern_error(result, "task_get_bootstrap_port()");
453 }
1815bff5
A
454}
455
b51d5b5f
A
456
457static void
458unblock_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
1815bff5
A
481static void
482init_ports(void)
483{
484 kern_return_t result;
1815bff5
A
485
486 /*
487 * This task will become the bootstrap task.
488 */
b51d5b5f
A
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);
1815bff5 494 if (result != KERN_SUCCESS)
b51d5b5f 495 kern_fatal(result, "port_set_allocate");
1815bff5 496
b51d5b5f
A
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);
1815bff5
A
502 if (result != KERN_SUCCESS)
503 kern_fatal(result, "port_set_allocate");
b51d5b5f 504
1815bff5 505 /* Create notify port and add to server port set */
b51d5b5f
A
506 result = mach_port_allocate(
507 bootstrap_self,
508 MACH_PORT_RIGHT_RECEIVE,
509 &notify_port);
1815bff5
A
510 if (result != KERN_SUCCESS)
511 kern_fatal(result, "mach_port_allocate");
512
b51d5b5f 513 result = mach_port_move_member(
1815bff5 514 bootstrap_self,
1815bff5 515 notify_port,
b51d5b5f
A
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);
1815bff5 525 if (result != KERN_SUCCESS)
b51d5b5f 526 kern_fatal(result, "mach_port_allocate");
1815bff5 527
b51d5b5f
A
528 result = mach_port_move_member(
529 bootstrap_self,
530 backup_port,
531 bootstrap_port_set);
1815bff5
A
532 if (result != KERN_SUCCESS)
533 kern_fatal(result, "mach_port_move_member");
534
535 /* Create "self" port and add to server port set */
b51d5b5f
A
536 result = mach_port_allocate(
537 bootstrap_self,
538 MACH_PORT_RIGHT_RECEIVE,
539 &bootstraps.bootstrap_port);
1815bff5
A
540 if (result != KERN_SUCCESS)
541 kern_fatal(result, "mach_port_allocate");
b51d5b5f
A
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);
1815bff5
A
557 if (result != KERN_SUCCESS)
558 kern_fatal(result, "mach_port_move_member");
1815bff5
A
559}
560
b51d5b5f
A
561boolean_t
562active_bootstrap(bootstrap_info_t *bootstrap)
563{
564 return (bootstrap->requestor_port != MACH_PORT_NULL);
565}
566
567boolean_t
568useless_server(server_t *serverp)
569{
570 return ( !active_bootstrap(serverp->bootstrap) ||
571 !lookup_service_by_server(serverp) ||
572 !serverp->activity);
573}
574
575boolean_t
576active_server(server_t *serverp)
577{
20e66415 578 return ( serverp->port ||
b51d5b5f
A
579 serverp->task_port || serverp->active_services);
580}
581
1815bff5 582static void
b51d5b5f
A
583reap_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) {
c3a08f59 596 notice("Server %x in bootstrap %x uid %d: \"%s\": %s %d [pid %d]",
b51d5b5f
A
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
621static void
622demand_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
650static
651void 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
663void
664setup_server(server_t *serverp)
1815bff5
A
665{
666 kern_return_t result;
667 mach_port_t old_port;
1815bff5 668
1815bff5 669 /* Allocate privileged port for requests from service */
b51d5b5f
A
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);
1815bff5
A
674 if (result != KERN_SUCCESS)
675 kern_fatal(result, "port_allocate");
676
b51d5b5f
A
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
1815bff5
A
688 /* Add privileged server port to bootstrap port set */
689 result = mach_port_move_member(mach_task_self(),
b51d5b5f
A
690 serverp->port,
691 bootstrap_port_set);
1815bff5
A
692 if (result != KERN_SUCCESS)
693 kern_fatal(result, "mach_port_move_member");
b51d5b5f
A
694}
695
696static void
697start_server(server_t *serverp)
698{
699 kern_return_t result;
700 mach_port_t old_port;
701 int pid;
1815bff5
A
702
703 /*
704 * Do what's appropriate to get bootstrap port setup in server task
705 */
706 switch (serverp->servertype) {
1815bff5
A
707
708 case MACHINIT:
709 break;
710
711 case SERVER:
b51d5b5f 712 case DEMAND:
1815bff5 713 case RESTARTABLE:
b51d5b5f 714 if (!serverp->port)
b51d5b5f
A
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
1815bff5 727 /* Give trusted service a unique bootstrap port */
b51d5b5f
A
728 result = task_set_bootstrap_port(mach_task_self(),
729 serverp->port);
1815bff5
A
730 if (result != KERN_SUCCESS)
731 kern_fatal(result, "task_set_bootstrap_port");
732
b51d5b5f
A
733 result = mach_port_deallocate(mach_task_self(),
734 serverp->port);
735 if (result != KERN_SUCCESS)
736 kern_fatal(result, "mach_port_deallocate");
737
1815bff5 738 pid = fork();
b51d5b5f 739 if (pid < 0) {
1815bff5 740 unix_error("fork");
b51d5b5f 741 } else if (pid == 0) { /* CHILD */
1815bff5
A
742 exec_server(serverp);
743 exit(1);
744 } else { /* PARENT */
b51d5b5f
A
745
746 result = task_set_bootstrap_port(
747 mach_task_self(),
748 MACH_PORT_NULL);
1815bff5
A
749 if (result != KERN_SUCCESS)
750 kern_fatal(result, "task_set_bootstrap_port");
751
b51d5b5f
A
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 }
1815bff5
A
781 }
782 break;
783 }
784}
785
1815bff5
A
786static void
787exec_server(server_t *serverp)
788{
b51d5b5f
A
789 char **argv;
790 sigset_t mask;
791
1815bff5
A
792 /*
793 * Setup environment for server, someday this should be Mach stuff
794 * rather than Unix crud
795 */
1815bff5 796 argv = argvize(serverp->cmd);
1815bff5
A
797 close_errlog();
798
733af6d0
A
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
b51d5b5f
A
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);
1815bff5
A
840 }
841
b51d5b5f
A
842 sigemptyset(&mask);
843 (void) sigprocmask(SIG_SETMASK, &mask, (sigset_t *)NULL);
1815bff5 844
b51d5b5f
A
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);
1815bff5
A
850}
851
852static char **
853argvize(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
b51d5b5f
A
886static void *
887demand_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
1815bff5 984/*
b51d5b5f 985 * server_demux -- processes requests off our service port
1815bff5
A
986 * Also handles notifications
987 */
1815bff5 988
b51d5b5f
A
989static boolean_t
990server_demux(
991 mach_msg_header_t *Request,
992 mach_msg_header_t *Reply)
1815bff5
A
993{
994 bootstrap_info_t *bootstrap;
995 service_t *servicep;
996 server_t *serverp;
997 kern_return_t result;
b51d5b5f 998 mig_reply_error_t *reply;
1815bff5 999
b51d5b5f 1000 debug("received message on port %x\n", Request->msgh_local_port);
1815bff5 1001
b51d5b5f
A
1002 /*
1003 * Do minimal cleanup and then exit.
1004 */
1005 if (shutdown_in_progress == TRUE) {
c3a08f59 1006 notice("Shutting down. Deactivating root bootstrap (%x) ...",
b51d5b5f
A
1007 bootstraps.bootstrap_port);
1008 deactivate_bootstrap(&bootstraps);
c3a08f59 1009 notice("Done.");
b51d5b5f
A
1010 exit(0);
1011 }
1012
1013 reply = (mig_reply_error_t *)Reply;
1815bff5
A
1014
1015 /*
1016 * Pick off notification messages
1017 */
b51d5b5f
A
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 }
1815bff5 1031
b51d5b5f
A
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 }
1815bff5 1044
b51d5b5f
A
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 }
1815bff5 1059
1815bff5 1060 /*
b51d5b5f
A
1061 * Check to see if a launched server task has gone
1062 * away.
1815bff5 1063 */
b51d5b5f
A
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;
1815bff5 1093 }
1815bff5 1094 }
1815bff5 1095
b51d5b5f
A
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;
1815bff5 1123
b51d5b5f
A
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 }
1815bff5 1136 } else {
b51d5b5f
A
1137 debug("Backup_port notification - previously deleted service");
1138 reply->RetCode = KERN_FAILURE;
1815bff5 1139 }
b51d5b5f
A
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);
1815bff5 1163 }
b51d5b5f
A
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);
1815bff5 1180 }
b51d5b5f 1181 return TRUE;
1815bff5
A
1182}
1183
1184/*
b51d5b5f
A
1185 * server_loop -- pick requests off our service port and process them
1186 * Also handles notifications
1815bff5 1187 */
b51d5b5f
A
1188#define bootstrapMaxRequestSize 1024
1189#define bootstrapMaxReplySize 1024
1190
1191static void
1192server_loop(void)
1815bff5 1193{
b51d5b5f
A
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 }
1815bff5
A
1206}
1207
1208boolean_t
1209canReceive(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
1223boolean_t
1224canSend(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}