1/* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22/* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27/* 28 * Portions Copyright 2007-2013 Apple Inc. 29 */ 30 31#pragma ident "@(#)autod_main.c 1.69 05/06/08 SMI" 32 33#include <stdio.h> 34#include <stdlib.h> 35#include <unistd.h> 36#include <signal.h> 37#include <fcntl.h> 38#include <sys/types.h> 39#include <sys/stat.h> 40#include <sys/ioctl.h> 41#include <stdarg.h> 42#include <sys/resource.h> 43#include <syslog.h> 44#include <errno.h> 45#include <string.h> 46#include <pthread.h> 47#include <locale.h> 48#include <vproc.h> 49#include <assert.h> 50#include <mach/mach.h> 51#include <servers/bootstrap.h> 52 53#include "automount.h" 54#include "automountd.h" 55#include "autofs_protServer.h" 56#include <arpa/inet.h> 57#include "deflt.h" 58#include <strings.h> 59#include "sysctl_fsid.h" 60 61#define MAXVAL(a, b) ((a) > (b) ? (a) : (b)) 62#define AUTOFS_MAX_MSG_SIZE \ 63 MAXVAL(sizeof (union __RequestUnion__autofs_subsystem), \ 64 sizeof (union __ReplyUnion__autofs_subsystem)) 65 66static void usage(void); 67static void *automount_thread(void *); 68static void new_worker_thread(void); 69static void compute_new_timeout(struct timespec *); 70static void *shutdown_thread(void *); 71static void *timeout_thread(void *); 72static void *wait_for_flush_indication_thread(void *); 73static int do_mount_subtrigger(autofs_pathname, autofs_pathname, 74 autofs_pathname, autofs_opts, autofs_pathname, autofs_pathname, 75 autofs_component, uint32_t, uint32_t, int32_t, fsid_t *, boolean_t *); 76 77/* 78 * XXX - this limit is the same as Solaris, although we don't have the 79 * System V binary compatibility problem that limits their standard 80 * I/O library to a maximum of 256 FILE *'s. (Now why that affects 81 * their automounter is another question....) 82 */ 83#define MAXTHREADS 64 84#define SHUTDOWN_TIMEOUT 2 /* timeout gets set to this after TERM signal */ 85#define TIMEOUT RDDIR_CACHE_TIME /* Hang around if caches might be valid */ 86#define APPLE_PREFIX "com.apple." /* Bootstrap name prefix */ 87#define MAXLABEL 256 /* Max bootstrap name */ 88 89static pthread_mutex_t numthreads_lock; 90static pthread_cond_t numthreads_cv; 91static int numthreads; 92static pthread_attr_t attr; /* To create detached threads */ 93static vproc_transaction_t vproc_transaction; 94static time_t timeout = TIMEOUT; /* Seconds to wait before exiting */ 95static int bye = 0; /* Force clean shutdown flag. */ 96 97static sigset_t waitset; /* Signals that we wait for */ 98static sigset_t contset; /* Signals that we don't exit from */ 99 100static mach_port_t service_port_receive_right; 101 102static int autofs_fd; 103 104#define RESOURCE_FACTOR 8 105 106struct autodir *dir_head; 107struct autodir *dir_tail; 108 109time_t timenow; 110int verbose = 0; 111int trace = 0; 112int automountd_nobrowse = 0; 113int automountd_nosuid = TRUE; 114char *automountd_defopts = NULL; 115 116/* 117 * This daemon is to be started by launchd, as such it follows the following 118 * launchd rules: 119 * We don't: 120 * call daemon(3) 121 * call fork and having the parent process exit 122 * change uids or gids. 123 * set up the current working directory or chroot. 124 * set the session id 125 * change stdio to /dev/null. 126 * call setrusage(2) 127 * call setpriority(2) 128 * Ignore SIGTERM. 129 * We are launched on demand 130 * and we catch SIGTERM and use vproc_transactions to exit cleanly. 131 * 132 * In practice daemonizing in the classic unix sense would probably be ok 133 * since we get invoked by traffic on a task_special_port, but we will play 134 * by the rules; it's even easier, to boot. 135 */ 136 137 138int 139main(argc, argv) 140 int argc; 141 char *argv[]; 142 143{ 144 int c, error; 145 kern_return_t ret; 146 pthread_t thread, timeout_thr, shutdown_thr; 147 char *defval; 148 int defflags; 149 char bname[MAXLABEL] = { APPLE_PREFIX }; 150 char *myname; 151 152 /* 153 * If launchd is redirecting these two files they'll be block- 154 * buffered, as they'll be pipes, or some other such non-tty, 155 * sending data to launchd. Probably not what you want. 156 */ 157 setlinebuf(stdout); 158 setlinebuf(stderr); 159 160 /* Figure out our bootstrap name based on what we are called. */ 161 162 myname = strrchr(argv[0], '/'); 163 myname = myname ? myname + 1 : argv[0]; 164 strlcat(bname, myname, sizeof(bname)); 165 166 /* 167 * Read in the values from config file first before we check 168 * commandline options so the options override the file. 169 */ 170 if ((defopen(AUTOFSADMIN)) == 0) { 171 if ((defval = defread("AUTOMOUNTD_VERBOSE=")) != NULL) { 172 if (strncasecmp("true", defval, 4) == 0) 173 verbose = TRUE; 174 else 175 verbose = FALSE; 176 } 177 if ((defval = defread("AUTOMOUNTD_NOBROWSE=")) != NULL) { 178 if (strncasecmp("true", defval, 4) == 0) 179 automountd_nobrowse = TRUE; 180 else 181 automountd_nobrowse = FALSE; 182 } 183 if ((defval = defread("AUTOMOUNTD_TRACE=")) != NULL) { 184 errno = 0; 185 trace = (int)strtol(defval, (char **)NULL, 10); 186 if (errno != 0) 187 trace = 0; 188 } 189 if ((defval = defread("AUTOMOUNTD_ENV=")) != NULL) { 190 (void) putenv(strdup(defval)); 191 defflags = defcntl(DC_GETFLAGS, 0); 192 TURNON(defflags, DC_NOREWIND); 193 defflags = defcntl(DC_SETFLAGS, defflags); 194 while ((defval = defread("AUTOMOUNTD_ENV=")) != NULL) 195 (void) putenv(strdup(defval)); 196 (void) defcntl(DC_SETFLAGS, defflags); 197 } 198 if ((defval = defread("AUTOMOUNTD_MNTOPTS=")) != NULL 199 && *defval != '\0') { 200 automountd_defopts = strdup(defval); 201 if (automountd_defopts == NULL) { 202 syslog(LOG_ERR, "Memory allocation failed: %m"); 203 exit(2); 204 } 205 } 206 if ((defval = defread("AUTOMOUNTD_NOSUID=")) != NULL) { 207 if (strncasecmp("true", defval, 4) == 0) 208 automountd_nosuid = TRUE; 209 else 210 automountd_nosuid = FALSE; 211 } 212 213 /* close defaults file */ 214 defopen(NULL); 215 } 216 217 while ((c = getopt(argc, argv, "vnTo:D:")) != EOF) { 218 switch (c) { 219 case 'v': 220 verbose++; 221 break; 222 case 'n': 223 automountd_nobrowse++; 224 break; 225 case 'T': 226 trace++; 227 break; 228 case 'o': 229 if (automountd_defopts != NULL) 230 free(automountd_defopts); 231 automountd_defopts = strdup(optarg); 232 break; 233 case 'D': 234 (void) putenv(optarg); 235 break; 236 default: 237 usage(); 238 } 239 } 240 241 openlog(myname, LOG_PID, LOG_DAEMON); 242 (void) setlocale(LC_ALL, ""); 243 244 if (trace > 0) 245 trace_prt(1, "%s running", myname); 246 247 /* 248 * This is platform-dependent; for now, we just say 249 * "macintosh" - I guess we could do something to 250 * distinguish x86 from PowerPC. 251 */ 252 if (getenv("ARCH") == NULL) 253 (void) putenv("ARCH=macintosh"); 254 if (getenv("CPU") == NULL) { 255#if defined(__ppc__) 256 (void) putenv("CPU=powerpc"); 257#elif defined(__i386__) || defined(__x86_64__) 258 /* 259 * At least on Solaris, "CPU" appears to be the 260 * narrowest ISA the machine supports, with 261 * "NATISA" being the widest, so "CPU" is "i386" 262 * even on x86-64. 263 */ 264 (void) putenv("CPU=i386"); 265#else 266#error "can't determine processor type"); 267#endif 268 } 269 270 /* 271 * We catch 272 * 273 * SIGINT - if we get one, we just drive on; 274 * SIGHUP - if we get one, we log a message 275 * so the user knows that it doesn't 276 * do anything useful, and drive on; 277 * SIGTERM - we quit. 278 */ 279 sigemptyset(&waitset); 280 sigaddset(&waitset, SIGINT); 281 sigaddset(&waitset, SIGHUP); 282 contset = waitset; 283 sigaddset(&waitset, SIGTERM); 284 pthread_sigmask(SIG_BLOCK, &waitset, NULL); 285 286 /* 287 * We create most threads as detached threads, so any Mach 288 * resources they have are reclaimed when they terminate. 289 */ 290 (void) pthread_attr_init(&attr); 291 (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 292 293 (void) pthread_mutex_init(&numthreads_lock, NULL); 294 (void) pthread_cond_init(&numthreads_cv, NULL); 295 (void) pthread_rwlock_init(&cache_lock, NULL); 296 (void) pthread_rwlock_init(&rddir_cache_lock, NULL); 297 298 /* 299 * initialize the name services, use NULL arguments to ensure 300 * we don't initialize the stack of files used in file service 301 * 302 * XXX - do we need to do something equivalent here? 303 */ 304#if 0 305 (void) ns_setup(NULL, NULL); 306#endif 307 308 /* 309 * Attempt to open the autofs device to establish ourselves 310 * as an automounter; 311 * 312 * We hold it open as long as we're running; if we exit, 313 * that'll close it, so autofs will forget that we were 314 * the automounter. 315 * 316 * This device also delivers notifications that we should 317 * flush our caches. 318 */ 319 autofs_fd = open("/dev/" AUTOFS_DEVICE, O_RDONLY); 320 if (autofs_fd == -1) { 321 syslog(LOG_ERR, "Can't open /dev/autofs: %s", 322 strerror(errno)); 323 exit(2); 324 } 325 326 /* 327 * Check in with launchd to get the receive right. 328 * N.B. Since we're using a task special port, if launchd 329 * does not have the receive right we can't get it. 330 * And since we should always be started by launchd 331 * this should always succeed. 332 */ 333 ret = bootstrap_check_in(bootstrap_port, bname, &service_port_receive_right); 334 if (ret != BOOTSTRAP_SUCCESS) { 335 syslog(LOG_ERR, "Could not get receive right for %s: %s (%d)\n", 336 bname, bootstrap_strerror(ret), ret); 337 exit(EXIT_FAILURE); 338 } 339 340 /* Create signal handling thread */ 341 error = pthread_create(&shutdown_thr, &attr, shutdown_thread, NULL); 342 if (error) { 343 syslog(LOG_ERR, "unable to create shutdown thread: %s", strerror(error)); 344 exit(EXIT_FAILURE); 345 } 346 347 /* Create time out thread */ 348 error = pthread_create(&timeout_thr, NULL, timeout_thread, NULL); 349 if (error) { 350 syslog(LOG_ERR, "unable to create time out thread: %s", strerror(error)); 351 exit(EXIT_FAILURE); 352 } 353 354 /* 355 * Create cache_cleanup thread 356 */ 357 error = pthread_create(&thread, &attr, cache_cleanup, NULL); 358 if (error) { 359 syslog(LOG_ERR, "unable to create cache_cleanup thread: %s", 360 strerror(error)); 361 exit(1); 362 } 363 364 /* 365 * Create wait-for-cache-flush-indication thread. 366 */ 367 error = pthread_create(&thread, &attr, wait_for_flush_indication_thread, 368 NULL); 369 if (error) { 370 syslog(LOG_ERR, "unable to create wait-for-flush-indication thread: %s", 371 strerror(error)); 372 exit(1); 373 } 374 375 /* 376 * Start a worker thread to listen for a message. 377 * Then just spin. 378 * 379 * This is a bit ugly. If there were a version of mach_msg_server() 380 * that spun off a thread before calling the dispatch routine, 381 * and had that thread handle the message, we could have this 382 * thread run that routine, with workers created as messages arrive. 383 */ 384 new_worker_thread(); 385 386 /* Wait for time out */ 387 pthread_join(timeout_thr, NULL); 388 389 pthread_attr_destroy(&attr); 390 391 /* 392 * Wake up the "wait for flush indication" thread. 393 */ 394 if (ioctl(autofs_fd, AUTOFS_NOTIFYCHANGE, 0) == -1) 395 pr_msg("AUTOFS_NOTIFYCHANGE failed: %m"); 396 397 if (trace > 0) 398 trace_prt(1, "%s exited", myname); 399 400 return (EXIT_SUCCESS); 401} 402 403static void 404usage(void) 405{ 406 (void) fprintf(stderr, "Usage: automountd\n" 407 "\t[-o opts]\t\t(default mount options)\n" 408 "\t[-T]\t\t(trace requests)\n" 409 "\t[-v]\t\t(verbose error msgs)\n" 410 "\t[-D n=s]\t(define env variable)\n"); 411 exit(1); 412 /* NOTREACHED */ 413} 414 415/* 416 * Receive one message and process it. 417 */ 418static void * 419automount_thread(__unused void *arg) 420{ 421 kern_return_t ret; 422 423 pthread_setname_np("upcall receiver"); 424 ret = mach_msg_server_once(autofs_server, AUTOFS_MAX_MSG_SIZE, 425 service_port_receive_right, 426 MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_SENDER) | MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0)); 427 if (ret != KERN_SUCCESS) { 428 syslog(LOG_ERR, "automounter mach_msg_server_once failed: %s", 429 mach_error_string(ret)); 430 } 431 return NULL; 432} 433 434/* 435 * Wait until we have fewer than the maximum number of worker threads, 436 * and then create one running automount_thread(). 437 * 438 * Called by the dispatch routines just before processing a message, 439 * so we're listening for messages even while processing a message, 440 * as long as we aren't out of threads. 441 */ 442static void 443new_worker_thread(void) 444{ 445 pthread_t thread; 446 int error; 447 448 (void) pthread_mutex_lock(&numthreads_lock); 449 while (bye == 0 && numthreads >= MAXTHREADS) 450 (void) pthread_cond_wait(&numthreads_cv, &numthreads_lock); 451 if (bye) 452 goto out; 453 numthreads++; 454 error = pthread_create(&thread, &attr, automount_thread, NULL); 455 if (error) { 456 syslog(LOG_ERR, "unable to create worker thread: %s", 457 strerror(error)); 458 numthreads--; 459 } 460 if (numthreads == 2) 461 vproc_transaction = vproc_transaction_begin(NULL); 462out: 463 (void) pthread_mutex_unlock(&numthreads_lock); 464} 465 466/* 467 * This worker thread is terminating; reduce the count of worker threads, 468 * and, if it's dropped below the maximum, wake up anybody waiting for 469 * it to drop below the maximum. 470 * 471 * Called by the dispatch routines just before returning. 472 */ 473static void 474end_worker_thread(void) 475{ 476 (void) pthread_mutex_lock(&numthreads_lock); 477 numthreads--; 478 if (numthreads == 1) 479 vproc_transaction_end(NULL, vproc_transaction); 480 if (numthreads < MAXTHREADS) 481 pthread_cond_signal(&numthreads_cv); 482 (void) pthread_mutex_unlock(&numthreads_lock); 483} 484 485/* 486 * Thread that handles signals for us and will tell the timeout thread to 487 * shut us down if we get a signal that we don't continue for. We set a global 488 * variable bye and the timeout value to SHUTDOWN_TIMEOUT and wake every 489 * body up. Threads blocked in new_worker_thread will see bye is set and exit. 490 * We set timeout to SHUTDOWN_TIMEOUT for the timeout thread, so that threads 491 * executing dispatch routines have an opportunity to finish. 492 * 493 * If there are no worker threads running, as indicated by vproc_transaction 494 * then launchd will signal with SIGKILL instead of SIGTERM so we'll exit 495 * immediately rather than wait for the shutdown timeout. 496 */ 497static void* 498shutdown_thread(__unused void *arg) 499{ 500 int sig; 501 502 pthread_setname_np("shutdown"); 503 do { 504 sigwait(&waitset, &sig); 505 switch (sig) { 506 case SIGHUP: 507 /* 508 * The old automounter supported a SIGHUP 509 * to allow it to resynchronize internal 510 * state with the /etc/mnttab. 511 * This is no longer relevant, but we 512 * need to catch the signal and warn 513 * the user. 514 */ 515 516 syslog(LOG_ERR, "SIGHUP received: ignored"); 517 break; 518 } 519 } while (sigismember(&contset, sig)); 520 521 pthread_mutex_lock(&numthreads_lock); 522 bye = 1; 523 /* 524 * Wait a little bit for dispatch threads to complete. 525 */ 526 timeout = SHUTDOWN_TIMEOUT; 527 /* 528 * Force the timeout_thread and all the rest to to wake up and exit. 529 */ 530 pthread_cond_broadcast(&numthreads_cv); 531 pthread_mutex_unlock(&numthreads_lock); 532 533 return (NULL); 534} 535 536static void 537compute_new_timeout(struct timespec *new) 538{ 539 struct timeval current; 540 541 gettimeofday(¤t, NULL); 542 new->tv_sec = current.tv_sec + timeout; 543 new->tv_nsec = 1000 * current.tv_usec; 544} 545 546static void* 547timeout_thread(__unused void *arg) 548{ 549 int rv = 0; 550 struct timespec exittime; 551 552 pthread_setname_np("timeout"); 553 (void) pthread_mutex_lock(&numthreads_lock); 554 555 /* 556 * Wait until the timer given to pthread_cond_timedwait() 557 * expires (which causes it to return ETIMEDOUT rather 558 * than 0) and we have no worker threads running, or 559 * until bye was set to 1 by the shutdown thread (telling 560 * us to terminate) and the timer expires (we shut down 561 * after SHUTDOWN_TIMEOUT in that case). 562 */ 563 while ((rv == 0 || numthreads > 1) && bye < 2) { 564 compute_new_timeout(&exittime); 565 /* 566 * If the shutdown thread has told us to exit (bye == 1), 567 * then increment bye so that we will exit after 568 * SHUTDOWN_TIMEOUT. 569 */ 570 if (bye) 571 bye++; 572 rv = pthread_cond_timedwait(&numthreads_cv, 573 &numthreads_lock, &exittime); 574 } 575 576 (void) pthread_mutex_unlock(&numthreads_lock); 577 578 return (NULL); 579} 580 581static void * 582wait_for_flush_indication_thread(__unused void *arg) 583{ 584 /* 585 * This thread waits for an indication that we should flush 586 * our caches. It quits if bye >= 1, meaning we're shutting 587 * down. 588 */ 589 pthread_setname_np("wait for flush indication"); 590 for (;;) { 591 /* 592 * Check whether we're shutting down. 593 */ 594 pthread_mutex_lock(&numthreads_lock); 595 if (bye >= 1) { 596 pthread_mutex_unlock(&numthreads_lock); 597 break; 598 } 599 pthread_mutex_unlock(&numthreads_lock); 600 601 if (ioctl(autofs_fd, AUTOFS_WAITFORFLUSH, 0) == -1) { 602 if (errno != EINTR) { 603 syslog(LOG_ERR, 604 "AUTOFS_WAITFORFLUSH failed: %s", 605 strerror(errno)); 606 } 607 } else 608 flush_caches(); 609 } 610 return (NULL); 611} 612 613kern_return_t 614autofs_readdir(__unused mach_port_t server, autofs_pathname rda_map, 615 int64_t rda_offset, uint32_t rda_count, int *status, int64_t *rddir_offset, 616 boolean_t *rddir_eof, byte_buffer *rddir_entries, 617 mach_msg_type_number_t *rddir_entriesCnt, security_token_t token) 618{ 619 new_worker_thread(); 620 621 pthread_setname_np("readdir worker"); 622 623 /* 624 * Reject this if the sender wasn't root 625 * (all messages from the kernel will be from root). 626 */ 627 if (token.val[0] != 0) { 628 *status = EPERM; 629 end_worker_thread(); 630 return KERN_SUCCESS; 631 } 632 633 if (trace > 0) 634 trace_prt(1, "READDIR REQUEST : %s @ %llu\n", rda_map, rda_offset); 635 636 *status = do_readdir(rda_map, rda_offset, rda_count, rddir_offset, 637 rddir_eof, rddir_entries, rddir_entriesCnt); 638 639 if (trace > 0) 640 trace_prt(1, "READDIR REPLY : status=%d\n", *status); 641 642 end_worker_thread(); 643 644 return KERN_SUCCESS; 645} 646 647kern_return_t 648autofs_readsubdir(__unused mach_port_t server, autofs_pathname rda_map, 649 autofs_component rda_name, mach_msg_type_number_t rda_nameCnt, 650 autofs_pathname rda_subdir, autofs_opts rda_mntopts, 651 uint32_t rda_parentino, int64_t rda_offset, uint32_t rda_count, 652 int *status, int64_t *rddir_offset, boolean_t *rddir_eof, 653 byte_buffer *rddir_entries, mach_msg_type_number_t *rddir_entriesCnt, 654 security_token_t token) 655{ 656 char *key; 657 658 new_worker_thread(); 659 660 /* 661 * Reject this if the sender wasn't root 662 * (all messages from the kernel will be from root). 663 */ 664 if (token.val[0] != 0) { 665 *status = EPERM; 666 end_worker_thread(); 667 return KERN_SUCCESS; 668 } 669 670 /* 671 * The name component is a counted string; make a 672 * null-terminated string out of it. 673 */ 674 if (rda_nameCnt < 1 || rda_nameCnt > MAXNAMLEN) { 675 *status = ENOENT; 676 end_worker_thread(); 677 return KERN_SUCCESS; 678 } 679 key = malloc(rda_nameCnt + 1); 680 if (key == NULL) { 681 *status = ENOMEM; 682 end_worker_thread(); 683 return KERN_SUCCESS; 684 } 685 memcpy(key, rda_name, rda_nameCnt); 686 key[rda_nameCnt] = '\0'; 687 688 if (trace > 0) 689 trace_prt(1, "READSUBDIR REQUEST : name=%s[%s] map=%s @ %llu\n", 690 key, rda_subdir, rda_map, rda_offset); 691 692 *status = do_readsubdir(rda_map, key, rda_subdir, rda_mntopts, 693 rda_parentino, rda_offset, rda_count, rddir_offset, rddir_eof, 694 rddir_entries, rddir_entriesCnt); 695 free(key); 696 697 if (trace > 0) 698 trace_prt(1, "READSUBDIR REPLY : status=%d\n", *status); 699 700 end_worker_thread(); 701 702 return KERN_SUCCESS; 703} 704 705kern_return_t 706autofs_unmount(__unused mach_port_t server, fsid_t mntpnt_fsid, 707 autofs_pathname mntresource, autofs_pathname mntpnt, 708 autofs_component fstype, autofs_opts mntopts, int *status, 709 security_token_t token) 710{ 711 new_worker_thread(); 712 713 pthread_setname_np("unmount worker"); 714 715 /* 716 * Reject this if the sender wasn't root 717 * (all messages from the kernel will be from root). 718 */ 719 if (token.val[0] != 0) { 720 *status = EPERM; 721 end_worker_thread(); 722 return KERN_SUCCESS; 723 } 724 725 if (trace > 0) { 726 trace_prt(1, "UNMOUNT REQUEST: resource=%s fstype=%s mntpnt=%s mntopts=%s\n", 727 mntresource, fstype, mntpnt, mntopts); 728 } 729 730 *status = do_unmount1(mntpnt_fsid, mntresource, mntpnt, fstype, 731 mntopts); 732 733 if (trace > 0) 734 trace_prt(1, "UNMOUNT REPLY: status=%d\n", *status); 735 736 end_worker_thread(); 737 738 return KERN_SUCCESS; 739} 740 741kern_return_t 742autofs_lookup(__unused mach_port_t server, autofs_pathname map, 743 autofs_pathname path, autofs_component name, mach_msg_type_number_t nameCnt, 744 autofs_pathname subdir, autofs_opts opts, boolean_t isdirect, 745 uint32_t sendereuid, int *err, int *node_type, boolean_t *lu_verbose, 746 security_token_t token) 747{ 748 char *key; 749 750 new_worker_thread(); 751 752 pthread_setname_np("lookup worker"); 753 754 /* 755 * Reject this if the sender wasn't root 756 * (all messages from the kernel will be from root). 757 */ 758 if (token.val[0] != 0) { 759 *err = EPERM; 760 *node_type = 0; 761 *lu_verbose = 0; 762 end_worker_thread(); 763 return KERN_SUCCESS; 764 } 765 766 /* 767 * The name component is a counted string; make a 768 * null-terminated string out of it. 769 */ 770 if (nameCnt < 1 || nameCnt > MAXNAMLEN) { 771 *err = ENOENT; 772 *node_type = 0; 773 *lu_verbose = 0; 774 end_worker_thread(); 775 return KERN_SUCCESS; 776 } 777 key = malloc(nameCnt + 1); 778 if (key == NULL) { 779 *err = ENOMEM; 780 *node_type = 0; 781 *lu_verbose = 0; 782 end_worker_thread(); 783 return KERN_SUCCESS; 784 } 785 memcpy(key, name, nameCnt); 786 key[nameCnt] = '\0'; 787 788 if (trace > 0) { 789 trace_prt(1, "LOOKUP REQUEST: name=%s[%s] map=%s opts=%s path=%s direct=%d uid=%u\n", 790 key, subdir, map, opts, path, isdirect, sendereuid); 791 } 792 793 *err = do_lookup1(map, key, subdir, opts, isdirect, sendereuid, 794 node_type); 795 *lu_verbose = verbose; 796 free(key); 797 798 if (trace > 0) 799 trace_prt(1, "LOOKUP REPLY : status=%d\n", *err); 800 801 end_worker_thread(); 802 803 return KERN_SUCCESS; 804} 805 806kern_return_t 807autofs_mount(__unused mach_port_t server, autofs_pathname map, 808 autofs_pathname path, autofs_component name, mach_msg_type_number_t nameCnt, 809 autofs_pathname subdir, autofs_opts opts, boolean_t isdirect, 810 boolean_t issubtrigger, fsid_t mntpnt_fsid, uint32_t sendereuid, 811 int32_t asid, int *mr_type, fsid_t *fsidp, uint32_t *retflags, 812 byte_buffer *actions, mach_msg_type_number_t *actionsCnt, int *err, 813 boolean_t *mr_verbose, security_token_t token) 814{ 815 char *key; 816 int status; 817 static time_t prevmsg = 0; 818 819 new_worker_thread(); 820 821 pthread_setname_np("mount worker"); 822 823 *retflags = 0; /* what we call sets retflags as needed */ 824 825 /* 826 * Reject this if the sender wasn't root 827 * (all messages from the kernel will be from root). 828 */ 829 if (token.val[0] != 0) { 830 *mr_type = AUTOFS_DONE; 831 *err = EPERM; 832 *mr_verbose = 0; 833 end_worker_thread(); 834 return KERN_SUCCESS; 835 } 836 837 /* 838 * The name component is a counted string; make a 839 * null-terminated string out of it. 840 */ 841 if (nameCnt < 1 || nameCnt > MAXNAMLEN) { 842 *mr_type = AUTOFS_DONE; 843 *err = ENOENT; 844 *mr_verbose = 0; 845 end_worker_thread(); 846 return KERN_SUCCESS; 847 } 848 key = malloc(nameCnt + 1); 849 if (key == NULL) { 850 *mr_type = AUTOFS_DONE; 851 *err = ENOMEM; 852 *mr_verbose = 0; 853 end_worker_thread(); 854 return KERN_SUCCESS; 855 } 856 memcpy(key, name, nameCnt); 857 key[nameCnt] = '\0'; 858 859 if (trace > 0) { 860 trace_prt(1, "MOUNT REQUEST: name=%s [%s] map=%s opts=%s path=%s direct=%d\n", 861 key, subdir, map, opts, path, isdirect); 862 } 863 864 status = do_mount1(map, key, subdir, opts, path, isdirect, 865 issubtrigger, mntpnt_fsid, sendereuid, asid, fsidp, 866 retflags, actions, actionsCnt); 867 868 if (status == 0 && *actionsCnt != 0) 869 *mr_type = AUTOFS_ACTION; 870 else 871 *mr_type = AUTOFS_DONE; 872 873 *err = status; 874 *mr_verbose = verbose; 875 876 if (trace > 0) { 877 switch (*mr_type) { 878 case AUTOFS_ACTION: 879 trace_prt(1, "MOUNT REPLY : status=%d, AUTOFS_ACTION\n", status); 880 break; 881 case AUTOFS_DONE: 882 trace_prt(1, "MOUNT REPLY : status=%d, AUTOFS_DONE\n", status); 883 break; 884 default: 885 trace_prt(1, "MOUNT REPLY : status=%d, UNKNOWN\n", status); 886 } 887 } 888 889 /* 890 * Report a failed mount. 891 * Failed mounts can come in bursts of dozens of 892 * these messages - so limit to one in 5 sec interval. 893 */ 894 if (status && prevmsg < time((time_t) NULL)) { 895 prevmsg = time((time_t) NULL) + 5; 896 if (isdirect) { 897 /* direct mount */ 898 syslog(LOG_ERR, "mount of %s%s failed: %s", path, 899 issubtrigger ? "" : subdir, strerror(status)); 900 } else { 901 /* indirect mount */ 902 syslog(LOG_ERR, 903 "mount of %s/%s%s failed: %s", path, key, 904 issubtrigger ? "" : subdir, strerror(status)); 905 } 906 } 907 free(key); 908 909 end_worker_thread(); 910 911 return KERN_SUCCESS; 912} 913 914kern_return_t 915autofs_mount_subtrigger(__unused mach_port_t server, 916 autofs_pathname mntpt, autofs_pathname submntpt, 917 autofs_pathname path, autofs_opts opts, 918 autofs_pathname map, autofs_pathname subdir, 919 autofs_component key, uint32_t flags, uint32_t mntflags, 920 int32_t direct, fsid_t *fsidp, boolean_t *top_level, int *err, 921 security_token_t token) 922{ 923 new_worker_thread(); 924 925 pthread_setname_np("mount-subtrigger worker"); 926 927 /* 928 * Reject this if the sender wasn't root 929 * (all messages from the kernel will be from root). 930 */ 931 if (token.val[0] != 0) { 932 *err = EPERM; 933 end_worker_thread(); 934 return KERN_SUCCESS; 935 } 936 937 *err = do_mount_subtrigger(mntpt, submntpt, path, opts, map, subdir, 938 key, flags, mntflags, direct, fsidp, top_level); 939 940 if (*err) 941 syslog(LOG_ERR, "subtrigger mount on %s failed: %s", mntpt, 942 strerror(*err)); 943 944 end_worker_thread(); 945 946 return KERN_SUCCESS; 947} 948 949static int 950do_mount_subtrigger(autofs_pathname mntpt, autofs_pathname submntpt, 951 autofs_pathname path, autofs_opts opts, 952 autofs_pathname map, autofs_pathname subdir, 953 autofs_component key, uint32_t flags, uint32_t mntflags, 954 int32_t direct, fsid_t *fsidp, boolean_t *top_level) 955{ 956 struct stat statb; 957 struct autofs_args mnt_args; 958 struct statfs buf; 959 int err; 960 961 /* 962 * Check whether this is a symlink; Solaris does this entirely 963 * in the kernel, and looks up the trigger mount point with 964 * a no-follow lookup, but we can't do that, so we have to 965 * check this ourselves. 966 * 967 * (We don't want to be tricked by sneaky servers into mounting 968 * a trigger on top of, for example, "/etc".) 969 * 970 * XXX - will this still happen? These mounts will only be 971 * done as a result of a planted trigger; will vfs_addtrigger(), 972 * which takes a relative path as an argument and won't cross 973 * mount points, handle that? Should vfs_addtrigger() not follow 974 * symlinks? Or is it sufficient that it won't leave the file 975 * system that was just mounted? 976 */ 977 if (lstat(mntpt, &statb) == 0) { 978 if (S_ISLNK(statb.st_mode)) { 979 syslog(LOG_ERR, "%s symbolic link: not a valid mountpoint - mount failed", 980 mntpt); 981 return (ENOENT); 982 } 983 } 984 985 mnt_args.version = AUTOFS_ARGSVERSION; 986 mnt_args.path = path; 987 mnt_args.opts = opts; 988 mnt_args.map = map; 989 mnt_args.subdir = subdir; 990 mnt_args.key = key; 991 mnt_args.mntflags = mntflags; 992 mnt_args.direct = direct; 993 mnt_args.mount_type = MOUNT_TYPE_SUBTRIGGER; /* special trigger submount */ 994 /* 995 * XXX - subtriggers are always direct maps, right? 996 */ 997 if (direct) 998 mnt_args.node_type = NT_TRIGGER; 999 else 1000 mnt_args.node_type = 0; /* not a trigger */ 1001 1002 if (mount(MNTTYPE_AUTOFS, mntpt, flags|MNT_AUTOMOUNTED|MNT_DONTBROWSE, 1003 &mnt_args) == -1) 1004 return (errno); 1005 /* 1006 * XXX - what if somebody unmounts the mount out from under us? 1007 */ 1008 if (statfs(mntpt, &buf) == -1) { 1009 err = errno; 1010 /* 1011 * XXX - if the unmount fails, we're screwed - we can't 1012 * succeed, and we can't undo the mount. 1013 * It "shouldn't happen", though - but it could, if, 1014 * for example, we're mounting on a soft-mounted NFS 1015 * mount and it times out. 1016 */ 1017 unmount(mntpt, MNT_FORCE); 1018 return (err); 1019 } 1020 *fsidp = buf.f_fsid; 1021 *top_level = (strcmp(submntpt, ".") == 0); 1022 return (0); 1023} 1024 1025kern_return_t 1026autofs_mount_url(__unused mach_port_t server, autofs_pathname url, 1027 autofs_pathname mountpoint, autofs_opts opts, fsid_t mntpnt_fsid, 1028 uint32_t sendereuid, int32_t asid, fsid_t *fsidp, 1029 uint32_t *retflags, int *err, security_token_t token) 1030{ 1031 int status; 1032 1033 new_worker_thread(); 1034 1035 pthread_setname_np("mount-url worker"); 1036 1037 *retflags = 0; /* what we call sets retflags as needed */ 1038 1039 /* 1040 * Reject this if the sender wasn't root 1041 * (all messages from the kernel will be from root). 1042 */ 1043 if (token.val[0] != 0) { 1044 *err = EPERM; 1045 end_worker_thread(); 1046 return KERN_SUCCESS; 1047 } 1048 1049 if (trace > 0) { 1050 trace_prt(1, "MOUNT_URL REQUEST: url=%s mountpoint=%s\n", url, mountpoint); 1051 } 1052 1053 status = mount_generic(url, "url", opts, 0, mountpoint, FALSE, 1054 TRUE, mntpnt_fsid, sendereuid, asid, fsidp, retflags); 1055 1056 *err = status; 1057 1058 if (trace > 0) { 1059 trace_prt(1, "MOUNT_URL REPLY : status=%d\n", status); 1060 } 1061 1062 if (status && verbose) 1063 syslog(LOG_ERR, "mount of %s on %s failed", url, mountpoint); 1064 1065 end_worker_thread(); 1066 1067 return KERN_SUCCESS; 1068} 1069 1070#define SMBREMOUNTSERVER_PATH "/System/Library/Extensions/autofs.kext/Contents/Resources/smbremountserver" 1071 1072kern_return_t 1073autofs_smb_remount_server(__unused mach_port_t server, byte_buffer blob, 1074 mach_msg_type_number_t blobCnt, au_asid_t asid, 1075 security_token_t token) 1076{ 1077 int pipefds[2]; 1078 int child_pid; 1079 int res; 1080 uint32_t byte_count; 1081 ssize_t bytes_written; 1082 int stat_loc; 1083 1084 new_worker_thread(); 1085 1086 pthread_setname_np("smb-remount-server worker"); 1087 1088 /* 1089 * Reject this if the sender wasn't root 1090 * (all messages from the kernel will be from root). 1091 */ 1092 if (token.val[0] != 0) { 1093 end_worker_thread(); 1094 return KERN_SUCCESS; 1095 } 1096 1097 if (trace > 0) { 1098 trace_prt(1, "SMB_REMOUNT_SERVER REQUEST:\n"); 1099 } 1100 1101 /* 1102 * This is a bit ugly; we have to do the SMBRemountServer() 1103 * call in a subprocess, for reasons listed in the comment 1104 * in smbremountserver.c. 1105 */ 1106 1107 /* 1108 * Set up a pipe over which we send the blob to the subprocess. 1109 */ 1110 if (pipe(pipefds) == -1) { 1111 syslog(LOG_ERR, "Can't create pipe to smbremountserver: %m"); 1112 goto done; 1113 } 1114 1115 1116 switch ((child_pid = fork())) { 1117 case -1: 1118 /* 1119 * Fork failure. Close the pipe, 1120 * log an error, and quit. 1121 */ 1122 close(pipefds[0]); 1123 close(pipefds[1]); 1124 syslog(LOG_ERR, "Cannot fork: %m"); 1125 break; 1126 1127 case 0: 1128 /* 1129 * Child. 1130 * 1131 * We make the read side of the pipe our standard 1132 * input. 1133 * 1134 * We leave the rest of our environment as it is; we assume 1135 * that launchd has made the right thing happen for us, 1136 * and that this is also the right thing for the processes 1137 * we run. 1138 * 1139 * Join the passed in audit session so we will have access to credentials 1140 */ 1141 if (join_session(asid)) 1142 _exit(EPERM); 1143 1144 if (dup2(pipefds[0], 0) == -1) { 1145 res = errno; 1146 syslog(LOG_ERR, "Cannot dup2: %m"); 1147 _exit(res); 1148 } 1149 close(pipefds[0]); 1150 close(pipefds[1]); 1151 (void) execl(SMBREMOUNTSERVER_PATH, SMBREMOUNTSERVER_PATH, 1152 NULL); 1153 res = errno; 1154 syslog(LOG_ERR, "exec %s: %m", SMBREMOUNTSERVER_PATH); 1155 _exit(res); 1156 1157 default: 1158 /* 1159 * Parent. 1160 * 1161 * Close the read side of the pipe. 1162 */ 1163 close(pipefds[0]); 1164 1165 /* 1166 * Send the size of the blob down the pipe, in host 1167 * byte order. 1168 */ 1169 byte_count = blobCnt; 1170 bytes_written = write(pipefds[1], &byte_count, 1171 sizeof byte_count); 1172 if (bytes_written == -1) { 1173 syslog(LOG_ERR, "Write of byte count to pipe failed: %m"); 1174 close(pipefds[1]); 1175 goto done; 1176 } 1177 if ((size_t)bytes_written != sizeof byte_count) { 1178 syslog(LOG_ERR, "Write of byte count to pipe wrote only %zd of %zu bytes", 1179 bytes_written, sizeof byte_count); 1180 close(pipefds[1]); 1181 goto done; 1182 } 1183 1184 /* 1185 * Send the blob itself. 1186 */ 1187 bytes_written = write(pipefds[1], blob, byte_count); 1188 if (bytes_written == -1) { 1189 syslog(LOG_ERR, "Write of blob to pipe failed: %m"); 1190 close(pipefds[1]); 1191 goto done; 1192 } 1193 if (bytes_written != (ssize_t)byte_count) { 1194 syslog(LOG_ERR, "Write of blob to pipe wrote only %zd of %u bytes", 1195 bytes_written, byte_count); 1196 close(pipefds[1]); 1197 goto done; 1198 } 1199 1200 /* 1201 * Close the pipe, so the subprocess knows there's nothing 1202 * more to read. 1203 */ 1204 close(pipefds[1]); 1205 1206 /* 1207 * Now wait for the child to finish. 1208 */ 1209 while (waitpid(child_pid, &stat_loc, WUNTRACED) < 0) { 1210 if (errno == EINTR) 1211 continue; 1212 syslog(LOG_ERR, "waitpid %d failed - error %d", child_pid, errno); 1213 goto done; 1214 } 1215 1216 if (WIFSIGNALED(stat_loc)) { 1217 syslog(LOG_ERR, "SMBRemountServer subprocess terminated with %s", 1218 strsignal(WTERMSIG(stat_loc))); 1219 } else if (WIFSTOPPED(stat_loc)) { 1220 syslog(LOG_ERR, "SMBRemountServer subprocess stopped with %s", 1221 strsignal(WSTOPSIG(stat_loc))); 1222 } else if (!WIFEXITED(stat_loc)) { 1223 syslog(LOG_ERR, "SMBRemountServer subprocess got unknown status 0x%08x", 1224 stat_loc); 1225 } 1226 break; 1227 } 1228 1229done: 1230 1231 if (trace > 0) { 1232 trace_prt(1, "SMB_REMOUNT_SERVER REPLY\n"); 1233 } 1234 1235 end_worker_thread(); 1236 1237 return KERN_SUCCESS; 1238} 1239 1240/* 1241 * Used for reporting messages from code 1242 * shared with automount command. 1243 * Calls vsyslog to log the message. 1244 * 1245 * Print an error. 1246 * Works like printf (fmt string and variable args) 1247 * except that it will subsititute an error message 1248 * for a "%m" string (like syslog). 1249 */ 1250void 1251pr_msg(const char *fmt, ...) 1252{ 1253 va_list ap; 1254 1255#if 0 1256 fmt = gettext(fmt); 1257#endif 1258 1259 va_start(ap, fmt); 1260 (void) vsyslog(LOG_ERR, fmt, ap); 1261 va_end(ap); 1262} 1263