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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 * 21 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. 22 * Copyright 2014 Nexenta Systems, Inc. All rights reserved. 23 */ 24 25 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 26 /* All Rights Reserved */ 27 28 /* 29 * Portions of this source code were derived from Berkeley 4.3 BSD 30 * under license from the Regents of the University of California. 31 */ 32 33 #include <stdio.h> 34 #include <stdio_ext.h> 35 #include <stdlib.h> 36 #include <ctype.h> 37 #include <sys/types.h> 38 #include <string.h> 39 #include <syslog.h> 40 #include <sys/param.h> 41 #include <rpc/rpc.h> 42 #include <sys/stat.h> 43 #include <netconfig.h> 44 #include <netdir.h> 45 #include <sys/file.h> 46 #include <sys/time.h> 47 #include <sys/errno.h> 48 #include <rpcsvc/mount.h> 49 #include <sys/pathconf.h> 50 #include <sys/systeminfo.h> 51 #include <sys/utsname.h> 52 #include <sys/wait.h> 53 #include <sys/resource.h> 54 #include <signal.h> 55 #include <locale.h> 56 #include <unistd.h> 57 #include <errno.h> 58 #include <sys/socket.h> 59 #include <netinet/in.h> 60 #include <arpa/inet.h> 61 #include <netdb.h> 62 #include <thread.h> 63 #include <assert.h> 64 #include <priv_utils.h> 65 #include <nfs/auth.h> 66 #include <nfs/nfssys.h> 67 #include <nfs/nfs.h> 68 #include <nfs/nfs_sec.h> 69 #include <rpcsvc/daemon_utils.h> 70 #include <deflt.h> 71 #include "../../fslib.h" 72 #include <sharefs/share.h> 73 #include <sharefs/sharetab.h> 74 #include "../lib/sharetab.h" 75 #include "mountd.h" 76 #include <tsol/label.h> 77 #include <sys/tsol/label_macro.h> 78 #include <libtsnet.h> 79 #include <sys/sdt.h> 80 #include <libscf.h> 81 #include <limits.h> 82 #include <sys/nvpair.h> 83 #include <attr.h> 84 #include "smfcfg.h" 85 86 extern int daemonize_init(void); 87 extern void daemonize_fini(int fd); 88 89 struct sh_list *share_list; 90 91 rwlock_t sharetab_lock; /* lock to protect the cached sharetab */ 92 static mutex_t mnttab_lock; /* prevent concurrent mnttab readers */ 93 94 static mutex_t logging_queue_lock; 95 static cond_t logging_queue_cv; 96 97 static share_t *find_lofsentry(char *, int *); 98 static int getclientsnames_lazy(char *, struct netbuf **, 99 struct nd_hostservlist **); 100 static int getclientsnames(SVCXPRT *, struct netbuf **, 101 struct nd_hostservlist **); 102 static int getclientsflavors_old(share_t *, SVCXPRT *, struct netbuf **, 103 struct nd_hostservlist **, int *); 104 static int getclientsflavors_new(share_t *, SVCXPRT *, struct netbuf **, 105 struct nd_hostservlist **, int *); 106 static int check_client_old(share_t *, SVCXPRT *, struct netbuf **, 107 struct nd_hostservlist **, int); 108 static int check_client_new(share_t *, SVCXPRT *, struct netbuf **, 109 struct nd_hostservlist **, int); 110 static void mnt(struct svc_req *, SVCXPRT *); 111 static void mnt_pathconf(struct svc_req *); 112 static int mount(struct svc_req *r); 113 static void sh_free(struct sh_list *); 114 static void umount(struct svc_req *); 115 static void umountall(struct svc_req *); 116 static void sigexit(int); 117 static int newopts(char *); 118 static tsol_tpent_t *get_client_template(struct sockaddr *); 119 120 static int verbose; 121 static int rejecting; 122 static int mount_vers_min = MOUNTVERS; 123 static int mount_vers_max = MOUNTVERS3; 124 125 /* Needs to be accessed by nfscmd.c */ 126 int in_access_list(SVCXPRT *, struct netbuf **, 127 struct nd_hostservlist **, char *); 128 129 extern void nfscmd_func(void *, char *, size_t, door_desc_t *, uint_t); 130 131 thread_t nfsauth_thread; 132 thread_t cmd_thread; 133 thread_t logging_thread; 134 135 typedef struct logging_data { 136 char *ld_host; 137 char *ld_path; 138 char *ld_rpath; 139 int ld_status; 140 char *ld_netid; 141 struct netbuf *ld_nb; 142 struct logging_data *ld_next; 143 } logging_data; 144 145 static logging_data *logging_head = NULL; 146 static logging_data *logging_tail = NULL; 147 148 /* ARGSUSED */ 149 static void * 150 nfsauth_svc(void *arg) 151 { 152 int doorfd = -1; 153 uint_t darg; 154 #ifdef DEBUG 155 int dfd; 156 #endif 157 158 if ((doorfd = door_create(nfsauth_func, NULL, 159 DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) { 160 syslog(LOG_ERR, "Unable to create door: %m\n"); 161 exit(10); 162 } 163 164 #ifdef DEBUG 165 /* 166 * Create a file system path for the door 167 */ 168 if ((dfd = open(MOUNTD_DOOR, O_RDWR|O_CREAT|O_TRUNC, 169 S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) == -1) { 170 syslog(LOG_ERR, "Unable to open %s: %m\n", MOUNTD_DOOR); 171 (void) close(doorfd); 172 exit(11); 173 } 174 175 /* 176 * Clean up any stale namespace associations 177 */ 178 (void) fdetach(MOUNTD_DOOR); 179 180 /* 181 * Register in namespace to pass to the kernel to door_ki_open 182 */ 183 if (fattach(doorfd, MOUNTD_DOOR) == -1) { 184 syslog(LOG_ERR, "Unable to fattach door: %m\n"); 185 (void) close(dfd); 186 (void) close(doorfd); 187 exit(12); 188 } 189 (void) close(dfd); 190 #endif 191 192 /* 193 * Must pass the doorfd down to the kernel. 194 */ 195 darg = doorfd; 196 (void) _nfssys(MOUNTD_ARGS, &darg); 197 198 /* 199 * Wait for incoming calls 200 */ 201 /*CONSTCOND*/ 202 for (;;) 203 (void) pause(); 204 205 /*NOTREACHED*/ 206 syslog(LOG_ERR, gettext("Door server exited")); 207 return (NULL); 208 } 209 210 /* 211 * NFS command service thread code for setup and handling of the 212 * nfs_cmd requests for character set conversion and other future 213 * events. 214 */ 215 216 static void * 217 cmd_svc(void *arg) 218 { 219 int doorfd = -1; 220 uint_t darg; 221 222 if ((doorfd = door_create(nfscmd_func, NULL, 223 DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) { 224 syslog(LOG_ERR, "Unable to create cmd door: %m\n"); 225 exit(10); 226 } 227 228 /* 229 * Must pass the doorfd down to the kernel. 230 */ 231 darg = doorfd; 232 (void) _nfssys(NFSCMD_ARGS, &darg); 233 234 /* 235 * Wait for incoming calls 236 */ 237 /*CONSTCOND*/ 238 for (;;) 239 (void) pause(); 240 241 /*NOTREACHED*/ 242 syslog(LOG_ERR, gettext("Cmd door server exited")); 243 return (NULL); 244 } 245 246 static void 247 free_logging_data(logging_data *lq) 248 { 249 if (lq != NULL) { 250 free(lq->ld_host); 251 free(lq->ld_netid); 252 253 if (lq->ld_nb != NULL) { 254 free(lq->ld_nb->buf); 255 free(lq->ld_nb); 256 } 257 258 free(lq->ld_path); 259 free(lq->ld_rpath); 260 261 free(lq); 262 } 263 } 264 265 static logging_data * 266 remove_head_of_queue(void) 267 { 268 logging_data *lq; 269 270 /* 271 * Pull it off the queue. 272 */ 273 lq = logging_head; 274 if (lq) { 275 logging_head = lq->ld_next; 276 277 /* 278 * Drained it. 279 */ 280 if (logging_head == NULL) { 281 logging_tail = NULL; 282 } 283 } 284 285 return (lq); 286 } 287 288 static void 289 do_logging_queue(logging_data *lq) 290 { 291 int cleared = 0; 292 char *host; 293 294 struct nd_hostservlist *clnames; 295 296 while (lq) { 297 if (lq->ld_host == NULL) { 298 DTRACE_PROBE(mountd, name_by_lazy); 299 if (getclientsnames_lazy(lq->ld_netid, 300 &lq->ld_nb, &clnames) != 0) 301 host = NULL; 302 else 303 host = clnames->h_hostservs[0].h_host; 304 } else 305 host = lq->ld_host; 306 307 audit_mountd_mount(host, lq->ld_path, lq->ld_status); /* BSM */ 308 309 /* add entry to mount list */ 310 if (lq->ld_rpath) 311 mntlist_new(host, lq->ld_rpath); 312 313 if (lq->ld_host != host) 314 netdir_free(clnames, ND_HOSTSERVLIST); 315 316 free_logging_data(lq); 317 cleared++; 318 319 (void) mutex_lock(&logging_queue_lock); 320 lq = remove_head_of_queue(); 321 (void) mutex_unlock(&logging_queue_lock); 322 } 323 324 DTRACE_PROBE1(mountd, logging_cleared, cleared); 325 } 326 327 static void * 328 logging_svc(void *arg) 329 { 330 logging_data *lq; 331 332 for (;;) { 333 (void) mutex_lock(&logging_queue_lock); 334 while (logging_head == NULL) { 335 (void) cond_wait(&logging_queue_cv, 336 &logging_queue_lock); 337 } 338 339 lq = remove_head_of_queue(); 340 (void) mutex_unlock(&logging_queue_lock); 341 342 do_logging_queue(lq); 343 } 344 345 /*NOTREACHED*/ 346 syslog(LOG_ERR, gettext("Logging server exited")); 347 return (NULL); 348 } 349 350 static int 351 convert_int(int *val, char *str) 352 { 353 long lval; 354 355 if (str == NULL || !isdigit(*str)) 356 return (-1); 357 358 lval = strtol(str, &str, 10); 359 if (*str != '\0' || lval > INT_MAX) 360 return (-2); 361 362 *val = (int)lval; 363 return (0); 364 } 365 366 int 367 main(int argc, char *argv[]) 368 { 369 int pid; 370 int c; 371 int rpc_svc_fdunlim = 1; 372 int rpc_svc_mode = RPC_SVC_MT_AUTO; 373 int maxrecsz = RPC_MAXDATASIZE; 374 bool_t exclbind = TRUE; 375 bool_t can_do_mlp; 376 long thr_flags = (THR_NEW_LWP|THR_DAEMON); 377 char defval[4]; 378 int defvers, ret, bufsz; 379 struct rlimit rl; 380 int listen_backlog = 0; 381 int max_threads = 0; 382 int tmp; 383 384 int pipe_fd = -1; 385 386 /* 387 * Mountd requires uid 0 for: 388 * /etc/rmtab updates (we could chown it to daemon) 389 * /etc/dfs/dfstab reading (it wants to lock out share which 390 * doesn't do any locking before first truncate; 391 * NFS share does; should use fcntl locking instead) 392 * Needed privileges: 393 * auditing 394 * nfs syscall 395 * file dac search (so it can stat all files) 396 * Optional privileges: 397 * MLP 398 */ 399 can_do_mlp = priv_ineffect(PRIV_NET_BINDMLP); 400 if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET, -1, -1, 401 PRIV_SYS_NFS, PRIV_PROC_AUDIT, PRIV_FILE_DAC_SEARCH, 402 can_do_mlp ? PRIV_NET_BINDMLP : NULL, NULL) == -1) { 403 (void) fprintf(stderr, 404 "%s: must be run with sufficient privileges\n", 405 argv[0]); 406 exit(1); 407 } 408 409 if (getrlimit(RLIMIT_NOFILE, &rl) != 0) { 410 syslog(LOG_ERR, "getrlimit failed"); 411 } else { 412 rl.rlim_cur = rl.rlim_max; 413 if (setrlimit(RLIMIT_NOFILE, &rl) != 0) 414 syslog(LOG_ERR, "setrlimit failed"); 415 } 416 417 (void) enable_extended_FILE_stdio(-1, -1); 418 419 ret = nfs_smf_get_iprop("mountd_max_threads", &max_threads, 420 DEFAULT_INSTANCE, SCF_TYPE_INTEGER, NFSD); 421 if (ret != SA_OK) { 422 syslog(LOG_ERR, "Reading of mountd_max_threads from SMF " 423 "failed, using default value"); 424 } 425 426 while ((c = getopt(argc, argv, "vrm:")) != EOF) { 427 switch (c) { 428 case 'v': 429 verbose++; 430 break; 431 case 'r': 432 rejecting = 1; 433 break; 434 case 'm': 435 if (convert_int(&tmp, optarg) != 0 || tmp < 1) { 436 (void) fprintf(stderr, "%s: invalid " 437 "max_threads option, using defaults\n", 438 argv[0]); 439 break; 440 } 441 max_threads = tmp; 442 break; 443 default: 444 fprintf(stderr, "usage: mountd [-v] [-r]\n"); 445 exit(1); 446 } 447 } 448 449 /* 450 * Read in the NFS version values from config file. 451 */ 452 bufsz = 4; 453 ret = nfs_smf_get_prop("server_versmin", defval, DEFAULT_INSTANCE, 454 SCF_TYPE_INTEGER, NFSD, &bufsz); 455 if (ret == SA_OK) { 456 errno = 0; 457 defvers = strtol(defval, (char **)NULL, 10); 458 if (errno == 0) { 459 mount_vers_min = defvers; 460 /* 461 * special because NFSv2 is 462 * supported by mount v1 & v2 463 */ 464 if (defvers == NFS_VERSION) 465 mount_vers_min = MOUNTVERS; 466 } 467 } 468 469 bufsz = 4; 470 ret = nfs_smf_get_prop("server_versmax", defval, DEFAULT_INSTANCE, 471 SCF_TYPE_INTEGER, NFSD, &bufsz); 472 if (ret == SA_OK) { 473 errno = 0; 474 defvers = strtol(defval, (char **)NULL, 10); 475 if (errno == 0) { 476 mount_vers_max = defvers; 477 } 478 } 479 480 ret = nfs_smf_get_iprop("mountd_listen_backlog", &listen_backlog, 481 DEFAULT_INSTANCE, SCF_TYPE_INTEGER, NFSD); 482 if (ret != SA_OK) { 483 syslog(LOG_ERR, "Reading of mountd_listen_backlog from SMF " 484 "failed, using default value"); 485 } 486 487 /* 488 * Sanity check versions, 489 * even though we may get versions > MOUNTVERS3, we still need 490 * to start nfsauth service, so continue on regardless of values. 491 */ 492 if (mount_vers_min > mount_vers_max) { 493 fprintf(stderr, "server_versmin > server_versmax\n"); 494 mount_vers_max = mount_vers_min; 495 } 496 (void) setlocale(LC_ALL, ""); 497 (void) rwlock_init(&sharetab_lock, USYNC_THREAD, NULL); 498 (void) mutex_init(&mnttab_lock, USYNC_THREAD, NULL); 499 (void) mutex_init(&logging_queue_lock, USYNC_THREAD, NULL); 500 (void) cond_init(&logging_queue_cv, USYNC_THREAD, NULL); 501 502 netgroup_init(); 503 504 #if !defined(TEXT_DOMAIN) 505 #define TEXT_DOMAIN "SYS_TEST" 506 #endif 507 (void) textdomain(TEXT_DOMAIN); 508 509 /* Don't drop core if the NFS module isn't loaded. */ 510 (void) signal(SIGSYS, SIG_IGN); 511 512 pipe_fd = daemonize_init(); 513 514 /* 515 * If we coredump it'll be in /core 516 */ 517 if (chdir("/") < 0) 518 fprintf(stderr, "chdir /: %s\n", strerror(errno)); 519 520 openlog("mountd", LOG_PID, LOG_DAEMON); 521 522 /* 523 * establish our lock on the lock file and write our pid to it. 524 * exit if some other process holds the lock, or if there's any 525 * error in writing/locking the file. 526 */ 527 pid = _enter_daemon_lock(MOUNTD); 528 switch (pid) { 529 case 0: 530 break; 531 case -1: 532 fprintf(stderr, "error locking for %s: %s\n", MOUNTD, 533 strerror(errno)); 534 exit(2); 535 default: 536 /* daemon was already running */ 537 exit(0); 538 } 539 540 audit_mountd_setup(); /* BSM */ 541 542 /* 543 * Set number of file descriptors to unlimited 544 */ 545 if (!rpc_control(RPC_SVC_USE_POLLFD, &rpc_svc_fdunlim)) { 546 syslog(LOG_INFO, "unable to set number of FDs to unlimited"); 547 } 548 549 /* 550 * Tell RPC that we want automatic thread mode. 551 * A new thread will be spawned for each request. 552 */ 553 if (!rpc_control(RPC_SVC_MTMODE_SET, &rpc_svc_mode)) { 554 fprintf(stderr, "unable to set automatic MT mode\n"); 555 exit(1); 556 } 557 558 /* 559 * Enable non-blocking mode and maximum record size checks for 560 * connection oriented transports. 561 */ 562 if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrecsz)) { 563 fprintf(stderr, "unable to set RPC max record size\n"); 564 } 565 566 /* 567 * Prevent our non-priv udp and tcp ports bound w/wildcard addr 568 * from being hijacked by a bind to a more specific addr. 569 */ 570 if (!rpc_control(__RPC_SVC_EXCLBIND_SET, &exclbind)) { 571 fprintf(stderr, "warning: unable to set udp/tcp EXCLBIND\n"); 572 } 573 574 /* 575 * Set the maximum number of outstanding connection 576 * indications (listen backlog) to the value specified. 577 */ 578 if (listen_backlog > 0 && !rpc_control(__RPC_SVC_LSTNBKLOG_SET, 579 &listen_backlog)) { 580 fprintf(stderr, "unable to set listen backlog\n"); 581 exit(1); 582 } 583 584 /* 585 * If max_threads was specified, then set the 586 * maximum number of threads to the value specified. 587 */ 588 if (max_threads > 0 && !rpc_control(RPC_SVC_THRMAX_SET, &max_threads)) { 589 fprintf(stderr, "unable to set max_threads\n"); 590 exit(1); 591 } 592 593 /* 594 * Make sure to unregister any previous versions in case the 595 * user is reconfiguring the server in interesting ways. 596 */ 597 svc_unreg(MOUNTPROG, MOUNTVERS); 598 svc_unreg(MOUNTPROG, MOUNTVERS_POSIX); 599 svc_unreg(MOUNTPROG, MOUNTVERS3); 600 601 /* 602 * Create the nfsauth thread with same signal disposition 603 * as the main thread. We need to create a separate thread 604 * since mountd() will be both an RPC server (for remote 605 * traffic) _and_ a doors server (for kernel upcalls). 606 */ 607 if (thr_create(NULL, 0, nfsauth_svc, 0, thr_flags, &nfsauth_thread)) { 608 fprintf(stderr, 609 gettext("Failed to create NFSAUTH svc thread\n")); 610 exit(2); 611 } 612 613 /* 614 * Create the cmd service thread with same signal disposition 615 * as the main thread. We need to create a separate thread 616 * since mountd() will be both an RPC server (for remote 617 * traffic) _and_ a doors server (for kernel upcalls). 618 */ 619 if (thr_create(NULL, 0, cmd_svc, 0, thr_flags, &cmd_thread)) { 620 syslog(LOG_ERR, gettext("Failed to create CMD svc thread")); 621 exit(2); 622 } 623 624 /* 625 * Create an additional thread to service the rmtab and 626 * audit_mountd_mount logging for mount requests. Use the same 627 * signal disposition as the main thread. We create 628 * a separate thread to allow the mount request threads to 629 * clear as soon as possible. 630 */ 631 if (thr_create(NULL, 0, logging_svc, 0, thr_flags, &logging_thread)) { 632 syslog(LOG_ERR, gettext("Failed to create LOGGING svc thread")); 633 exit(2); 634 } 635 636 /* 637 * Create datagram and connection oriented services 638 */ 639 if (mount_vers_max >= MOUNTVERS) { 640 if (svc_create(mnt, MOUNTPROG, MOUNTVERS, "datagram_v") == 0) { 641 fprintf(stderr, 642 "couldn't register datagram_v MOUNTVERS\n"); 643 exit(1); 644 } 645 if (svc_create(mnt, MOUNTPROG, MOUNTVERS, "circuit_v") == 0) { 646 fprintf(stderr, 647 "couldn't register circuit_v MOUNTVERS\n"); 648 exit(1); 649 } 650 } 651 652 if (mount_vers_max >= MOUNTVERS_POSIX) { 653 if (svc_create(mnt, MOUNTPROG, MOUNTVERS_POSIX, 654 "datagram_v") == 0) { 655 fprintf(stderr, 656 "couldn't register datagram_v MOUNTVERS_POSIX\n"); 657 exit(1); 658 } 659 if (svc_create(mnt, MOUNTPROG, MOUNTVERS_POSIX, 660 "circuit_v") == 0) { 661 fprintf(stderr, 662 "couldn't register circuit_v MOUNTVERS_POSIX\n"); 663 exit(1); 664 } 665 } 666 667 if (mount_vers_max >= MOUNTVERS3) { 668 if (svc_create(mnt, MOUNTPROG, MOUNTVERS3, "datagram_v") == 0) { 669 fprintf(stderr, 670 "couldn't register datagram_v MOUNTVERS3\n"); 671 exit(1); 672 } 673 if (svc_create(mnt, MOUNTPROG, MOUNTVERS3, "circuit_v") == 0) { 674 fprintf(stderr, 675 "couldn't register circuit_v MOUNTVERS3\n"); 676 exit(1); 677 } 678 } 679 680 /* 681 * Start serving 682 */ 683 rmtab_load(); 684 685 daemonize_fini(pipe_fd); 686 687 /* Get rid of the most dangerous basic privileges. */ 688 __fini_daemon_priv(PRIV_PROC_EXEC, PRIV_PROC_INFO, PRIV_PROC_SESSION, 689 (char *)NULL); 690 691 svc_run(); 692 syslog(LOG_ERR, "Error: svc_run shouldn't have returned"); 693 abort(); 694 695 /* NOTREACHED */ 696 return (0); 697 } 698 699 /* 700 * Server procedure switch routine 701 */ 702 void 703 mnt(struct svc_req *rqstp, SVCXPRT *transp) 704 { 705 switch (rqstp->rq_proc) { 706 case NULLPROC: 707 errno = 0; 708 if (!svc_sendreply(transp, xdr_void, (char *)0)) 709 log_cant_reply(transp); 710 return; 711 712 case MOUNTPROC_MNT: 713 (void) mount(rqstp); 714 return; 715 716 case MOUNTPROC_DUMP: 717 mntlist_send(transp); 718 return; 719 720 case MOUNTPROC_UMNT: 721 umount(rqstp); 722 return; 723 724 case MOUNTPROC_UMNTALL: 725 umountall(rqstp); 726 return; 727 728 case MOUNTPROC_EXPORT: 729 case MOUNTPROC_EXPORTALL: 730 export(rqstp); 731 return; 732 733 case MOUNTPROC_PATHCONF: 734 if (rqstp->rq_vers == MOUNTVERS_POSIX) 735 mnt_pathconf(rqstp); 736 else 737 svcerr_noproc(transp); 738 return; 739 740 default: 741 svcerr_noproc(transp); 742 return; 743 } 744 } 745 746 /* Set up anonymous client */ 747 748 struct nd_hostservlist * 749 anon_client(char *host) 750 { 751 struct nd_hostservlist *anon_hsl; 752 struct nd_hostserv *anon_hs; 753 754 anon_hsl = malloc(sizeof (*anon_hsl)); 755 if (anon_hsl == NULL) 756 return (NULL); 757 758 anon_hs = malloc(sizeof (*anon_hs)); 759 if (anon_hs == NULL) { 760 free(anon_hsl); 761 return (NULL); 762 } 763 764 if (host == NULL) 765 anon_hs->h_host = strdup("(anon)"); 766 else 767 anon_hs->h_host = strdup(host); 768 769 if (anon_hs->h_host == NULL) { 770 free(anon_hs); 771 free(anon_hsl); 772 return (NULL); 773 } 774 anon_hs->h_serv = '\0'; 775 776 anon_hsl->h_cnt = 1; 777 anon_hsl->h_hostservs = anon_hs; 778 779 return (anon_hsl); 780 } 781 782 static int 783 getclientsnames_common(struct netconfig *nconf, struct netbuf **nbuf, 784 struct nd_hostservlist **serv) 785 { 786 char host[MAXIPADDRLEN]; 787 788 assert(*nbuf != NULL); 789 790 /* 791 * Use the this API instead of the netdir_getbyaddr() 792 * to avoid service lookup. 793 */ 794 if (__netdir_getbyaddr_nosrv(nconf, serv, *nbuf) != 0) { 795 if (strcmp(nconf->nc_protofmly, NC_INET) == 0) { 796 struct sockaddr_in *sa; 797 798 /* LINTED pointer alignment */ 799 sa = (struct sockaddr_in *)((*nbuf)->buf); 800 (void) inet_ntoa_r(sa->sin_addr, host); 801 } else if (strcmp(nconf->nc_protofmly, NC_INET6) == 0) { 802 struct sockaddr_in6 *sa; 803 804 /* LINTED pointer alignment */ 805 sa = (struct sockaddr_in6 *)((*nbuf)->buf); 806 (void) inet_ntop(AF_INET6, sa->sin6_addr.s6_addr, 807 host, INET6_ADDRSTRLEN); 808 } else { 809 syslog(LOG_ERR, gettext( 810 "Client's address is neither IPv4 nor IPv6")); 811 return (EINVAL); 812 } 813 814 *serv = anon_client(host); 815 if (*serv == NULL) 816 return (ENOMEM); 817 } 818 819 assert(*serv != NULL); 820 return (0); 821 } 822 823 /* 824 * Get the client's hostname from the copy of the 825 * relevant transport handle parts. 826 * If the name is not available then return "(anon)". 827 */ 828 static int 829 getclientsnames_lazy(char *netid, struct netbuf **nbuf, 830 struct nd_hostservlist **serv) 831 { 832 struct netconfig *nconf; 833 int rc; 834 835 nconf = getnetconfigent(netid); 836 if (nconf == NULL) { 837 syslog(LOG_ERR, "%s: getnetconfigent failed", netid); 838 *serv = anon_client(NULL); 839 if (*serv == NULL) 840 return (ENOMEM); 841 return (0); 842 } 843 844 rc = getclientsnames_common(nconf, nbuf, serv); 845 freenetconfigent(nconf); 846 return (rc); 847 } 848 849 /* 850 * Get the client's hostname from the transport handle. 851 * If the name is not available then return "(anon)". 852 */ 853 int 854 getclientsnames(SVCXPRT *transp, struct netbuf **nbuf, 855 struct nd_hostservlist **serv) 856 { 857 struct netconfig *nconf; 858 int rc; 859 860 nconf = getnetconfigent(transp->xp_netid); 861 if (nconf == NULL) { 862 syslog(LOG_ERR, "%s: getnetconfigent failed", 863 transp->xp_netid); 864 *serv = anon_client(NULL); 865 if (*serv == NULL) 866 return (ENOMEM); 867 return (0); 868 } 869 870 *nbuf = svc_getrpccaller(transp); 871 if (*nbuf == NULL) { 872 freenetconfigent(nconf); 873 *serv = anon_client(NULL); 874 if (*serv == NULL) 875 return (ENOMEM); 876 return (0); 877 } 878 879 rc = getclientsnames_common(nconf, nbuf, serv); 880 freenetconfigent(nconf); 881 return (rc); 882 } 883 884 void 885 log_cant_reply(SVCXPRT *transp) 886 { 887 int saverrno; 888 struct nd_hostservlist *clnames = NULL; 889 register char *host; 890 struct netbuf *nb; 891 892 saverrno = errno; /* save error code */ 893 if (getclientsnames(transp, &nb, &clnames) != 0) 894 return; 895 host = clnames->h_hostservs->h_host; 896 897 errno = saverrno; 898 if (errno == 0) 899 syslog(LOG_ERR, "couldn't send reply to %s", host); 900 else 901 syslog(LOG_ERR, "couldn't send reply to %s: %m", host); 902 903 netdir_free(clnames, ND_HOSTSERVLIST); 904 } 905 906 /* 907 * Answer pathconf questions for the mount point fs 908 */ 909 static void 910 mnt_pathconf(struct svc_req *rqstp) 911 { 912 SVCXPRT *transp; 913 struct pathcnf p; 914 char *path, rpath[MAXPATHLEN]; 915 struct stat st; 916 917 transp = rqstp->rq_xprt; 918 path = NULL; 919 (void) memset((caddr_t)&p, 0, sizeof (p)); 920 921 if (!svc_getargs(transp, xdr_dirpath, (caddr_t)&path)) { 922 svcerr_decode(transp); 923 return; 924 } 925 if (lstat(path, &st) < 0) { 926 _PC_SET(_PC_ERROR, p.pc_mask); 927 goto done; 928 } 929 /* 930 * Get a path without symbolic links. 931 */ 932 if (realpath(path, rpath) == NULL) { 933 syslog(LOG_DEBUG, 934 "mount request: realpath failed on %s: %m", 935 path); 936 _PC_SET(_PC_ERROR, p.pc_mask); 937 goto done; 938 } 939 (void) memset((caddr_t)&p, 0, sizeof (p)); 940 /* 941 * can't ask about devices over NFS 942 */ 943 _PC_SET(_PC_MAX_CANON, p.pc_mask); 944 _PC_SET(_PC_MAX_INPUT, p.pc_mask); 945 _PC_SET(_PC_PIPE_BUF, p.pc_mask); 946 _PC_SET(_PC_VDISABLE, p.pc_mask); 947 948 errno = 0; 949 p.pc_link_max = pathconf(rpath, _PC_LINK_MAX); 950 if (errno) 951 _PC_SET(_PC_LINK_MAX, p.pc_mask); 952 p.pc_name_max = pathconf(rpath, _PC_NAME_MAX); 953 if (errno) 954 _PC_SET(_PC_NAME_MAX, p.pc_mask); 955 p.pc_path_max = pathconf(rpath, _PC_PATH_MAX); 956 if (errno) 957 _PC_SET(_PC_PATH_MAX, p.pc_mask); 958 if (pathconf(rpath, _PC_NO_TRUNC) == 1) 959 _PC_SET(_PC_NO_TRUNC, p.pc_mask); 960 if (pathconf(rpath, _PC_CHOWN_RESTRICTED) == 1) 961 _PC_SET(_PC_CHOWN_RESTRICTED, p.pc_mask); 962 963 done: 964 errno = 0; 965 if (!svc_sendreply(transp, xdr_ppathcnf, (char *)&p)) 966 log_cant_reply(transp); 967 if (path != NULL) 968 svc_freeargs(transp, xdr_dirpath, (caddr_t)&path); 969 } 970 971 /* 972 * If the rootmount (export) option is specified, the all mount requests for 973 * subdirectories return EACCES. 974 */ 975 static int 976 checkrootmount(share_t *sh, char *rpath) 977 { 978 char *val; 979 980 if ((val = getshareopt(sh->sh_opts, SHOPT_NOSUB)) != NULL) { 981 free(val); 982 if (strcmp(sh->sh_path, rpath) != 0) 983 return (0); 984 else 985 return (1); 986 } else 987 return (1); 988 } 989 990 #define MAX_FLAVORS 128 991 992 /* 993 * Return only EACCES if client does not have access 994 * to this directory. 995 * "If the server exports only /a/b, an attempt to 996 * mount a/b/c will fail with ENOENT if the directory 997 * does not exist"... However, if the client 998 * does not have access to /a/b, an attacker can 999 * determine whether the directory exists. 1000 * This routine checks either existence of the file or 1001 * existence of the file name entry in the mount table. 1002 * If the file exists and there is no file name entry, 1003 * the error returned should be EACCES. 1004 * If the file does not exist, it must be determined 1005 * whether the client has access to a parent 1006 * directory. If the client has access to a parent 1007 * directory, the error returned should be ENOENT, 1008 * otherwise EACCES. 1009 */ 1010 static int 1011 mount_enoent_error(SVCXPRT *transp, char *path, char *rpath, 1012 struct nd_hostservlist **clnames, struct netbuf **nb, int *flavor_list) 1013 { 1014 char *checkpath, *dp; 1015 share_t *sh = NULL; 1016 int realpath_error = ENOENT, reply_error = EACCES, lofs_tried = 0; 1017 int flavor_count; 1018 1019 checkpath = strdup(path); 1020 if (checkpath == NULL) { 1021 syslog(LOG_ERR, "mount_enoent: no memory"); 1022 return (EACCES); 1023 } 1024 1025 /* CONSTCOND */ 1026 while (1) { 1027 if (sh) { 1028 sharefree(sh); 1029 sh = NULL; 1030 } 1031 1032 if ((sh = findentry(rpath)) == NULL && 1033 (sh = find_lofsentry(rpath, &lofs_tried)) == NULL) { 1034 /* 1035 * There is no file name entry. 1036 * If the file (with symbolic links resolved) exists, 1037 * the error returned should be EACCES. 1038 */ 1039 if (realpath_error == 0) 1040 break; 1041 } else if (checkrootmount(sh, rpath) == 0) { 1042 /* 1043 * This is a "nosub" only export, in which case, 1044 * mounting subdirectories isn't allowed. 1045 * If the file (with symbolic links resolved) exists, 1046 * the error returned should be EACCES. 1047 */ 1048 if (realpath_error == 0) 1049 break; 1050 } else { 1051 /* 1052 * Check permissions in mount table. 1053 */ 1054 if (newopts(sh->sh_opts)) 1055 flavor_count = getclientsflavors_new(sh, 1056 transp, nb, clnames, flavor_list); 1057 else 1058 flavor_count = getclientsflavors_old(sh, 1059 transp, nb, clnames, flavor_list); 1060 if (flavor_count != 0) { 1061 /* 1062 * Found entry in table and 1063 * client has correct permissions. 1064 */ 1065 reply_error = ENOENT; 1066 break; 1067 } 1068 } 1069 1070 /* 1071 * Check all parent directories. 1072 */ 1073 dp = strrchr(checkpath, '/'); 1074 if (dp == NULL) 1075 break; 1076 *dp = '\0'; 1077 if (strlen(checkpath) == 0) 1078 break; 1079 /* 1080 * Get the real path (no symbolic links in it) 1081 */ 1082 if (realpath(checkpath, rpath) == NULL) { 1083 if (errno != ENOENT) 1084 break; 1085 } else { 1086 realpath_error = 0; 1087 } 1088 } 1089 1090 if (sh) 1091 sharefree(sh); 1092 free(checkpath); 1093 return (reply_error); 1094 } 1095 1096 /* 1097 * We need to inform the caller whether or not we were 1098 * able to add a node to the queue. If we are not, then 1099 * it is up to the caller to go ahead and log the data. 1100 */ 1101 static int 1102 enqueue_logging_data(char *host, SVCXPRT *transp, char *path, 1103 char *rpath, int status, int error) 1104 { 1105 logging_data *lq; 1106 struct netbuf *nb; 1107 1108 lq = (logging_data *)calloc(1, sizeof (logging_data)); 1109 if (lq == NULL) 1110 goto cleanup; 1111 1112 /* 1113 * We might not yet have the host... 1114 */ 1115 if (host) { 1116 DTRACE_PROBE1(mountd, log_host, host); 1117 lq->ld_host = strdup(host); 1118 if (lq->ld_host == NULL) 1119 goto cleanup; 1120 } else { 1121 DTRACE_PROBE(mountd, log_no_host); 1122 1123 lq->ld_netid = strdup(transp->xp_netid); 1124 if (lq->ld_netid == NULL) 1125 goto cleanup; 1126 1127 lq->ld_nb = calloc(1, sizeof (struct netbuf)); 1128 if (lq->ld_nb == NULL) 1129 goto cleanup; 1130 1131 nb = svc_getrpccaller(transp); 1132 if (nb == NULL) { 1133 DTRACE_PROBE(mountd, e__nb__enqueue); 1134 goto cleanup; 1135 } 1136 1137 DTRACE_PROBE(mountd, nb_set_enqueue); 1138 1139 lq->ld_nb->maxlen = nb->maxlen; 1140 lq->ld_nb->len = nb->len; 1141 1142 lq->ld_nb->buf = malloc(lq->ld_nb->len); 1143 if (lq->ld_nb->buf == NULL) 1144 goto cleanup; 1145 1146 bcopy(nb->buf, lq->ld_nb->buf, lq->ld_nb->len); 1147 } 1148 1149 lq->ld_path = strdup(path); 1150 if (lq->ld_path == NULL) 1151 goto cleanup; 1152 1153 if (!error) { 1154 lq->ld_rpath = strdup(rpath); 1155 if (lq->ld_rpath == NULL) 1156 goto cleanup; 1157 } 1158 1159 lq->ld_status = status; 1160 1161 /* 1162 * Add to the tail of the logging queue. 1163 */ 1164 (void) mutex_lock(&logging_queue_lock); 1165 if (logging_tail == NULL) { 1166 logging_tail = logging_head = lq; 1167 } else { 1168 logging_tail->ld_next = lq; 1169 logging_tail = lq; 1170 } 1171 (void) cond_signal(&logging_queue_cv); 1172 (void) mutex_unlock(&logging_queue_lock); 1173 1174 return (TRUE); 1175 1176 cleanup: 1177 1178 free_logging_data(lq); 1179 1180 return (FALSE); 1181 } 1182 1183 /* 1184 * Check mount requests, add to mounted list if ok 1185 */ 1186 static int 1187 mount(struct svc_req *rqstp) 1188 { 1189 SVCXPRT *transp; 1190 int version, vers; 1191 struct fhstatus fhs; 1192 struct mountres3 mountres3; 1193 char fh[FHSIZE3]; 1194 int len = FHSIZE3; 1195 char *path, rpath[MAXPATHLEN]; 1196 share_t *sh = NULL; 1197 struct nd_hostservlist *clnames = NULL; 1198 char *host = NULL; 1199 int error = 0, lofs_tried = 0, enqueued; 1200 int flavor_list[MAX_FLAVORS]; 1201 int flavor_count; 1202 struct netbuf *nb = NULL; 1203 ucred_t *uc = NULL; 1204 1205 int audit_status; 1206 1207 transp = rqstp->rq_xprt; 1208 version = rqstp->rq_vers; 1209 path = NULL; 1210 1211 if (!svc_getargs(transp, xdr_dirpath, (caddr_t)&path)) { 1212 svcerr_decode(transp); 1213 return (EACCES); 1214 } 1215 1216 /* 1217 * Put off getting the name for the client until we 1218 * need it. This is a performance gain. If we are logging, 1219 * then we don't care about performance and might as well 1220 * get the host name now in case we need to spit out an 1221 * error message. 1222 */ 1223 if (verbose) { 1224 DTRACE_PROBE(mountd, name_by_verbose); 1225 if (getclientsnames(transp, &nb, &clnames) != 0) { 1226 /* 1227 * We failed to get a name for the client, even 1228 * 'anon', probably because we ran out of memory. 1229 * In this situation it doesn't make sense to 1230 * allow the mount to succeed. 1231 */ 1232 error = EACCES; 1233 goto reply; 1234 } 1235 host = clnames->h_hostservs[0].h_host; 1236 } 1237 1238 /* 1239 * If the version being used is less than the minimum version, 1240 * the filehandle translation should not be provided to the 1241 * client. 1242 */ 1243 if (rejecting || version < mount_vers_min) { 1244 if (verbose) 1245 syslog(LOG_NOTICE, "Rejected mount: %s for %s", 1246 host, path); 1247 error = EACCES; 1248 goto reply; 1249 } 1250 1251 /* 1252 * Trusted Extension doesn't support nfsv2. nfsv2 client 1253 * uses MOUNT protocol v1 and v2. To prevent circumventing 1254 * TX label policy via using nfsv2 client, reject a mount 1255 * request with version less than 3 and log an error. 1256 */ 1257 if (is_system_labeled()) { 1258 if (version < 3) { 1259 if (verbose) 1260 syslog(LOG_ERR, 1261 "Rejected mount: TX doesn't support NFSv2"); 1262 error = EACCES; 1263 goto reply; 1264 } 1265 } 1266 1267 /* 1268 * Get the real path (no symbolic links in it) 1269 */ 1270 if (realpath(path, rpath) == NULL) { 1271 error = errno; 1272 if (verbose) 1273 syslog(LOG_ERR, 1274 "mount request: realpath: %s: %m", path); 1275 if (error == ENOENT) 1276 error = mount_enoent_error(transp, path, rpath, 1277 &clnames, &nb, flavor_list); 1278 goto reply; 1279 } 1280 1281 if ((sh = findentry(rpath)) == NULL && 1282 (sh = find_lofsentry(rpath, &lofs_tried)) == NULL) { 1283 error = EACCES; 1284 goto reply; 1285 } 1286 1287 /* 1288 * Check if this is a "nosub" only export, in which case, mounting 1289 * subdirectories isn't allowed. Bug 1184573. 1290 */ 1291 if (checkrootmount(sh, rpath) == 0) { 1292 error = EACCES; 1293 goto reply; 1294 } 1295 1296 if (newopts(sh->sh_opts)) 1297 flavor_count = getclientsflavors_new(sh, transp, &nb, &clnames, 1298 flavor_list); 1299 else 1300 flavor_count = getclientsflavors_old(sh, transp, &nb, &clnames, 1301 flavor_list); 1302 1303 if (clnames) 1304 host = clnames->h_hostservs[0].h_host; 1305 1306 if (flavor_count == 0) { 1307 error = EACCES; 1308 goto reply; 1309 } 1310 1311 /* 1312 * Check MAC policy here. The server side policy should be 1313 * consistent with client side mount policy, i.e. 1314 * - we disallow an admin_low unlabeled client to mount 1315 * - we disallow mount from a lower labeled client. 1316 */ 1317 if (is_system_labeled()) { 1318 m_label_t *clabel = NULL; 1319 m_label_t *slabel = NULL; 1320 m_label_t admin_low; 1321 1322 if (svc_getcallerucred(rqstp->rq_xprt, &uc) != 0) { 1323 syslog(LOG_ERR, 1324 "mount request: Failed to get caller's ucred : %m"); 1325 error = EACCES; 1326 goto reply; 1327 } 1328 if ((clabel = ucred_getlabel(uc)) == NULL) { 1329 syslog(LOG_ERR, 1330 "mount request: can't get client label from ucred"); 1331 error = EACCES; 1332 goto reply; 1333 } 1334 1335 bsllow(&admin_low); 1336 if (blequal(&admin_low, clabel)) { 1337 struct sockaddr *ca; 1338 tsol_tpent_t *tp; 1339 1340 ca = (struct sockaddr *)(void *)svc_getrpccaller( 1341 rqstp->rq_xprt)->buf; 1342 if (ca == NULL) { 1343 error = EACCES; 1344 goto reply; 1345 } 1346 /* 1347 * get trusted network template associated 1348 * with the client. 1349 */ 1350 tp = get_client_template(ca); 1351 if (tp == NULL || tp->host_type != SUN_CIPSO) { 1352 if (tp != NULL) 1353 tsol_freetpent(tp); 1354 error = EACCES; 1355 goto reply; 1356 } 1357 tsol_freetpent(tp); 1358 } else { 1359 if ((slabel = m_label_alloc(MAC_LABEL)) == NULL) { 1360 error = EACCES; 1361 goto reply; 1362 } 1363 1364 if (getlabel(rpath, slabel) != 0) { 1365 m_label_free(slabel); 1366 error = EACCES; 1367 goto reply; 1368 } 1369 1370 if (!bldominates(clabel, slabel)) { 1371 m_label_free(slabel); 1372 error = EACCES; 1373 goto reply; 1374 } 1375 m_label_free(slabel); 1376 } 1377 } 1378 1379 /* 1380 * Now get the filehandle. 1381 * 1382 * NFS V2 clients get a 32 byte filehandle. 1383 * NFS V3 clients get a 32 or 64 byte filehandle, depending on 1384 * the embedded FIDs. 1385 */ 1386 vers = (version == MOUNTVERS3) ? NFS_V3 : NFS_VERSION; 1387 1388 /* LINTED pointer alignment */ 1389 while (nfs_getfh(rpath, vers, &len, fh) < 0) { 1390 if (errno == EINVAL && 1391 (sh = find_lofsentry(rpath, &lofs_tried)) != NULL) { 1392 errno = 0; 1393 continue; 1394 } 1395 error = errno == EINVAL ? EACCES : errno; 1396 syslog(LOG_DEBUG, "mount request: getfh failed on %s: %m", 1397 path); 1398 break; 1399 } 1400 1401 if (version == MOUNTVERS3) { 1402 mountres3.mountres3_u.mountinfo.fhandle.fhandle3_len = len; 1403 mountres3.mountres3_u.mountinfo.fhandle.fhandle3_val = fh; 1404 } else { 1405 bcopy(fh, &fhs.fhstatus_u.fhs_fhandle, NFS_FHSIZE); 1406 } 1407 1408 reply: 1409 if (uc != NULL) 1410 ucred_free(uc); 1411 1412 switch (version) { 1413 case MOUNTVERS: 1414 case MOUNTVERS_POSIX: 1415 if (error == EINVAL) 1416 fhs.fhs_status = NFSERR_ACCES; 1417 else if (error == EREMOTE) 1418 fhs.fhs_status = NFSERR_REMOTE; 1419 else 1420 fhs.fhs_status = error; 1421 1422 if (!svc_sendreply(transp, xdr_fhstatus, (char *)&fhs)) 1423 log_cant_reply(transp); 1424 1425 audit_status = fhs.fhs_status; 1426 break; 1427 1428 case MOUNTVERS3: 1429 if (!error) { 1430 mountres3.mountres3_u.mountinfo.auth_flavors.auth_flavors_val = 1431 flavor_list; 1432 mountres3.mountres3_u.mountinfo.auth_flavors.auth_flavors_len = 1433 flavor_count; 1434 1435 } else if (error == ENAMETOOLONG) 1436 error = MNT3ERR_NAMETOOLONG; 1437 1438 mountres3.fhs_status = error; 1439 if (!svc_sendreply(transp, xdr_mountres3, (char *)&mountres3)) 1440 log_cant_reply(transp); 1441 1442 audit_status = mountres3.fhs_status; 1443 break; 1444 } 1445 1446 if (verbose) 1447 syslog(LOG_NOTICE, "MOUNT: %s %s %s", 1448 (host == NULL) ? "unknown host" : host, 1449 error ? "denied" : "mounted", path); 1450 1451 /* 1452 * If we can not create a queue entry, go ahead and do it 1453 * in the context of this thread. 1454 */ 1455 enqueued = enqueue_logging_data(host, transp, path, rpath, 1456 audit_status, error); 1457 if (enqueued == FALSE) { 1458 if (host == NULL) { 1459 DTRACE_PROBE(mountd, name_by_in_thread); 1460 if (getclientsnames(transp, &nb, &clnames) == 0) 1461 host = clnames->h_hostservs[0].h_host; 1462 } 1463 1464 DTRACE_PROBE(mountd, logged_in_thread); 1465 audit_mountd_mount(host, path, audit_status); /* BSM */ 1466 if (!error) 1467 mntlist_new(host, rpath); /* add entry to mount list */ 1468 } 1469 1470 if (path != NULL) 1471 svc_freeargs(transp, xdr_dirpath, (caddr_t)&path); 1472 1473 done: 1474 if (sh) 1475 sharefree(sh); 1476 netdir_free(clnames, ND_HOSTSERVLIST); 1477 1478 return (error); 1479 } 1480 1481 /* 1482 * Determine whether two paths are within the same file system. 1483 * Returns nonzero (true) if paths are the same, zero (false) if 1484 * they are different. If an error occurs, return false. 1485 * 1486 * Use the actual FSID if it's available (via getattrat()); otherwise, 1487 * fall back on st_dev. 1488 * 1489 * With ZFS snapshots, st_dev differs from the regular file system 1490 * versus the snapshot. But the fsid is the same throughout. Thus 1491 * the fsid is a better test. 1492 */ 1493 static int 1494 same_file_system(const char *path1, const char *path2) 1495 { 1496 uint64_t fsid1, fsid2; 1497 struct stat64 st1, st2; 1498 nvlist_t *nvl1 = NULL; 1499 nvlist_t *nvl2 = NULL; 1500 1501 if ((getattrat(AT_FDCWD, XATTR_VIEW_READONLY, path1, &nvl1) == 0) && 1502 (getattrat(AT_FDCWD, XATTR_VIEW_READONLY, path2, &nvl2) == 0) && 1503 (nvlist_lookup_uint64(nvl1, A_FSID, &fsid1) == 0) && 1504 (nvlist_lookup_uint64(nvl2, A_FSID, &fsid2) == 0)) { 1505 nvlist_free(nvl1); 1506 nvlist_free(nvl2); 1507 /* 1508 * We have found fsid's for both paths. 1509 */ 1510 1511 if (fsid1 == fsid2) 1512 return (B_TRUE); 1513 1514 return (B_FALSE); 1515 } 1516 1517 if (nvl1 != NULL) 1518 nvlist_free(nvl1); 1519 if (nvl2 != NULL) 1520 nvlist_free(nvl2); 1521 1522 /* 1523 * We were unable to find fsid's for at least one of the paths. 1524 * fall back on st_dev. 1525 */ 1526 1527 if (stat64(path1, &st1) < 0) { 1528 syslog(LOG_NOTICE, "%s: %m", path1); 1529 return (B_FALSE); 1530 } 1531 if (stat64(path2, &st2) < 0) { 1532 syslog(LOG_NOTICE, "%s: %m", path2); 1533 return (B_FALSE); 1534 } 1535 1536 if (st1.st_dev == st2.st_dev) 1537 return (B_TRUE); 1538 1539 return (B_FALSE); 1540 } 1541 1542 share_t * 1543 findentry(char *path) 1544 { 1545 share_t *sh = NULL; 1546 struct sh_list *shp; 1547 register char *p1, *p2; 1548 1549 check_sharetab(); 1550 1551 (void) rw_rdlock(&sharetab_lock); 1552 1553 for (shp = share_list; shp; shp = shp->shl_next) { 1554 sh = shp->shl_sh; 1555 for (p1 = sh->sh_path, p2 = path; *p1 == *p2; p1++, p2++) 1556 if (*p1 == '\0') 1557 goto done; /* exact match */ 1558 1559 /* 1560 * Now compare the pathnames for three cases: 1561 * 1562 * Parent: /export/foo (no trailing slash on parent) 1563 * Child: /export/foo/bar 1564 * 1565 * Parent: /export/foo/ (trailing slash on parent) 1566 * Child: /export/foo/bar 1567 * 1568 * Parent: /export/foo/ (no trailing slash on child) 1569 * Child: /export/foo 1570 */ 1571 if ((*p1 == '\0' && *p2 == '/') || 1572 (*p1 == '\0' && *(p1-1) == '/') || 1573 (*p2 == '\0' && *p1 == '/' && *(p1+1) == '\0')) { 1574 /* 1575 * We have a subdirectory. Test whether the 1576 * subdirectory is in the same file system. 1577 */ 1578 if (same_file_system(path, sh->sh_path)) 1579 goto done; 1580 } 1581 } 1582 done: 1583 sh = shp ? sharedup(sh) : NULL; 1584 1585 (void) rw_unlock(&sharetab_lock); 1586 1587 return (sh); 1588 } 1589 1590 1591 static int 1592 is_substring(char **mntp, char **path) 1593 { 1594 char *p1 = *mntp, *p2 = *path; 1595 1596 if (*p1 == '\0' && *p2 == '\0') /* exact match */ 1597 return (1); 1598 else if (*p1 == '\0' && *p2 == '/') 1599 return (1); 1600 else if (*p1 == '\0' && *(p1-1) == '/') { 1601 *path = --p2; /* we need the slash in p2 */ 1602 return (1); 1603 } else if (*p2 == '\0') { 1604 while (*p1 == '/') 1605 p1++; 1606 if (*p1 == '\0') /* exact match */ 1607 return (1); 1608 } 1609 return (0); 1610 } 1611 1612 /* 1613 * find_lofsentry() searches for the real path which this requested LOFS path 1614 * (rpath) shadows. If found, it will return the sharetab entry of 1615 * the real path that corresponds to the LOFS path. 1616 * We first search mnttab to see if the requested path is an automounted 1617 * path. If it is an automounted path, it will trigger the mount by stat()ing 1618 * the requested path. Note that it is important to check that this path is 1619 * actually an automounted path, otherwise we would stat() a path which may 1620 * turn out to be NFS and block indefinitely on a dead server. The automounter 1621 * times-out if the server is dead, so there's no risk of hanging this 1622 * thread waiting for stat(). 1623 * After the mount has been triggered (if necessary), we look for a 1624 * mountpoint of type LOFS (by searching /etc/mnttab again) which 1625 * is a substring of the rpath. If found, we construct a new path by 1626 * concatenating the mnt_special and the remaining of rpath, call findentry() 1627 * to make sure the 'real path' is shared. 1628 */ 1629 static share_t * 1630 find_lofsentry(char *rpath, int *done_flag) 1631 { 1632 struct stat r_stbuf; 1633 mntlist_t *ml, *mntl, *mntpnt = NULL; 1634 share_t *retcode = NULL; 1635 char tmp_path[MAXPATHLEN]; 1636 int mntpnt_len = 0, tmp; 1637 char *p1, *p2; 1638 1639 if ((*done_flag)++) 1640 return (retcode); 1641 1642 /* 1643 * While fsgetmntlist() uses lockf() to 1644 * lock the mnttab before reading it in, 1645 * the lock ignores threads in the same process. 1646 * Read in the mnttab with the protection of a mutex. 1647 */ 1648 (void) mutex_lock(&mnttab_lock); 1649 mntl = fsgetmntlist(); 1650 (void) mutex_unlock(&mnttab_lock); 1651 1652 /* 1653 * Obtain the mountpoint for the requested path. 1654 */ 1655 for (ml = mntl; ml; ml = ml->mntl_next) { 1656 for (p1 = ml->mntl_mnt->mnt_mountp, p2 = rpath; 1657 *p1 == *p2 && *p1; p1++, p2++) 1658 ; 1659 if (is_substring(&p1, &p2) && 1660 (tmp = strlen(ml->mntl_mnt->mnt_mountp)) >= mntpnt_len) { 1661 mntpnt = ml; 1662 mntpnt_len = tmp; 1663 } 1664 } 1665 1666 /* 1667 * If the path needs to be autoFS mounted, trigger the mount by 1668 * stat()ing it. This is determined by checking whether the 1669 * mountpoint we just found is of type autofs. 1670 */ 1671 if (mntpnt != NULL && 1672 strcmp(mntpnt->mntl_mnt->mnt_fstype, "autofs") == 0) { 1673 /* 1674 * The requested path is a substring of an autoFS filesystem. 1675 * Trigger the mount. 1676 */ 1677 if (stat(rpath, &r_stbuf) < 0) { 1678 if (verbose) 1679 syslog(LOG_NOTICE, "%s: %m", rpath); 1680 goto done; 1681 } 1682 if ((r_stbuf.st_mode & S_IFMT) == S_IFDIR) { 1683 /* 1684 * The requested path is a directory, stat(2) it 1685 * again with a trailing '.' to force the autoFS 1686 * module to trigger the mount of indirect 1687 * automount entries, such as /net/jurassic/. 1688 */ 1689 if (strlen(rpath) + 2 > MAXPATHLEN) { 1690 if (verbose) { 1691 syslog(LOG_NOTICE, 1692 "%s/.: exceeds MAXPATHLEN %d", 1693 rpath, MAXPATHLEN); 1694 } 1695 goto done; 1696 } 1697 (void) strcpy(tmp_path, rpath); 1698 (void) strcat(tmp_path, "/."); 1699 1700 if (stat(tmp_path, &r_stbuf) < 0) { 1701 if (verbose) 1702 syslog(LOG_NOTICE, "%s: %m", tmp_path); 1703 goto done; 1704 } 1705 } 1706 1707 /* 1708 * The mount has been triggered, re-read mnttab to pick up 1709 * the changes made by autoFS. 1710 */ 1711 fsfreemntlist(mntl); 1712 (void) mutex_lock(&mnttab_lock); 1713 mntl = fsgetmntlist(); 1714 (void) mutex_unlock(&mnttab_lock); 1715 } 1716 1717 /* 1718 * The autoFS mountpoint has been triggered if necessary, 1719 * now search mnttab again to determine if the requested path 1720 * is an LOFS mount of a shared path. 1721 */ 1722 mntpnt_len = 0; 1723 for (ml = mntl; ml; ml = ml->mntl_next) { 1724 if (strcmp(ml->mntl_mnt->mnt_fstype, "lofs")) 1725 continue; 1726 1727 for (p1 = ml->mntl_mnt->mnt_mountp, p2 = rpath; 1728 *p1 == *p2 && *p1; p1++, p2++) 1729 ; 1730 1731 if (is_substring(&p1, &p2) && 1732 ((tmp = strlen(ml->mntl_mnt->mnt_mountp)) >= mntpnt_len)) { 1733 mntpnt_len = tmp; 1734 1735 if ((strlen(ml->mntl_mnt->mnt_special) + strlen(p2)) > 1736 MAXPATHLEN) { 1737 if (verbose) { 1738 syslog(LOG_NOTICE, "%s%s: exceeds %d", 1739 ml->mntl_mnt->mnt_special, p2, 1740 MAXPATHLEN); 1741 } 1742 if (retcode) 1743 sharefree(retcode); 1744 retcode = NULL; 1745 goto done; 1746 } 1747 1748 (void) strcpy(tmp_path, ml->mntl_mnt->mnt_special); 1749 (void) strcat(tmp_path, p2); 1750 if (retcode) 1751 sharefree(retcode); 1752 retcode = findentry(tmp_path); 1753 } 1754 } 1755 1756 if (retcode) { 1757 assert(strlen(tmp_path) > 0); 1758 (void) strcpy(rpath, tmp_path); 1759 } 1760 1761 done: 1762 fsfreemntlist(mntl); 1763 return (retcode); 1764 } 1765 1766 /* 1767 * Determine whether an access list grants rights to a particular host. 1768 * We match on aliases of the hostname as well as on the canonical name. 1769 * Names in the access list may be either hosts or netgroups; they're 1770 * not distinguished syntactically. We check for hosts first because 1771 * it's cheaper, then try netgroups. 1772 * 1773 * If pnb and pclnames are NULL, it means that we have to use transp 1774 * to resolve client IP address to hostname. If they aren't NULL 1775 * then transp argument won't be used and can be NULL. 1776 */ 1777 int 1778 in_access_list(SVCXPRT *transp, struct netbuf **pnb, 1779 struct nd_hostservlist **pclnames, 1780 char *access_list) /* N.B. we clobber this "input" parameter */ 1781 { 1782 char addr[INET_ADDRSTRLEN]; 1783 char buff[256]; 1784 int nentries = 0; 1785 char *cstr = access_list; 1786 char *gr = access_list; 1787 char *host; 1788 int off; 1789 int i; 1790 int response; 1791 int sbr = 0; 1792 struct nd_hostservlist *clnames; 1793 struct netent n, *np; 1794 1795 /* If no access list - then it's unrestricted */ 1796 if (access_list == NULL || *access_list == '\0') 1797 return (1); 1798 1799 assert(transp != NULL || (*pnb != NULL && *pclnames != NULL)); 1800 1801 /* Get client address if it wasn't provided */ 1802 if (*pnb == NULL) 1803 /* Don't grant access if client address isn't known */ 1804 if ((*pnb = svc_getrpccaller(transp)) == NULL) 1805 return (0); 1806 1807 /* Try to lookup client hostname if it wasn't provided */ 1808 if (*pclnames == NULL) 1809 getclientsnames(transp, pnb, pclnames); 1810 clnames = *pclnames; 1811 1812 for (;;) { 1813 if ((cstr = strpbrk(cstr, "[]:")) != NULL) { 1814 switch (*cstr) { 1815 case '[': 1816 case ']': 1817 sbr = !sbr; 1818 cstr++; 1819 continue; 1820 case ':': 1821 if (sbr) { 1822 cstr++; 1823 continue; 1824 } 1825 *cstr = '\0'; 1826 } 1827 } 1828 1829 /* 1830 * If the list name has a '-' prepended then a match of 1831 * the following name implies failure instead of success. 1832 */ 1833 if (*gr == '-') { 1834 response = 0; 1835 gr++; 1836 } else { 1837 response = 1; 1838 } 1839 1840 /* 1841 * First check if we have '@' entry, as it doesn't 1842 * require client hostname. 1843 */ 1844 if (*gr == '@') { 1845 gr++; 1846 1847 /* Netname support */ 1848 if (!isdigit(*gr) && *gr != '[') { 1849 if ((np = getnetbyname_r(gr, &n, buff, 1850 sizeof (buff))) != NULL && 1851 np->n_net != 0) { 1852 while ((np->n_net & 0xFF000000u) == 0) 1853 np->n_net <<= 8; 1854 np->n_net = htonl(np->n_net); 1855 if (inet_ntop(AF_INET, &np->n_net, addr, 1856 INET_ADDRSTRLEN) == NULL) 1857 break; 1858 if (inet_matchaddr((*pnb)->buf, addr)) 1859 return (response); 1860 } 1861 } else { 1862 if (inet_matchaddr((*pnb)->buf, gr)) 1863 return (response); 1864 } 1865 1866 if (cstr == NULL) 1867 break; 1868 1869 gr = ++cstr; 1870 1871 continue; 1872 } 1873 1874 /* 1875 * No other checks can be performed if client address 1876 * can't be resolved. 1877 */ 1878 if (clnames == NULL) { 1879 if (cstr == NULL) 1880 break; 1881 1882 gr = ++cstr; 1883 1884 continue; 1885 } 1886 1887 /* Otherwise loop through all client hostname aliases */ 1888 for (i = 0; i < clnames->h_cnt; i++) { 1889 host = clnames->h_hostservs[i].h_host; 1890 1891 /* 1892 * If the list name begins with a dot then 1893 * do a domain name suffix comparison. 1894 * A single dot matches any name with no 1895 * suffix. 1896 */ 1897 if (*gr == '.') { 1898 if (*(gr + 1) == '\0') { /* single dot */ 1899 if (strchr(host, '.') == NULL) 1900 return (response); 1901 } else { 1902 off = strlen(host) - strlen(gr); 1903 if (off > 0 && 1904 strcasecmp(host + off, gr) == 0) { 1905 return (response); 1906 } 1907 } 1908 } else { 1909 /* Just do a hostname match */ 1910 if (strcasecmp(gr, host) == 0) 1911 return (response); 1912 } 1913 } 1914 1915 nentries++; 1916 1917 if (cstr == NULL) 1918 break; 1919 1920 gr = ++cstr; 1921 } 1922 1923 if (clnames == NULL) 1924 return (0); 1925 1926 return (netgroup_check(clnames, access_list, nentries)); 1927 } 1928 1929 1930 static char *optlist[] = { 1931 #define OPT_RO 0 1932 SHOPT_RO, 1933 #define OPT_RW 1 1934 SHOPT_RW, 1935 #define OPT_ROOT 2 1936 SHOPT_ROOT, 1937 #define OPT_SECURE 3 1938 SHOPT_SECURE, 1939 #define OPT_ANON 4 1940 SHOPT_ANON, 1941 #define OPT_WINDOW 5 1942 SHOPT_WINDOW, 1943 #define OPT_NOSUID 6 1944 SHOPT_NOSUID, 1945 #define OPT_ACLOK 7 1946 SHOPT_ACLOK, 1947 #define OPT_SEC 8 1948 SHOPT_SEC, 1949 #define OPT_NONE 9 1950 SHOPT_NONE, 1951 NULL 1952 }; 1953 1954 static int 1955 map_flavor(char *str) 1956 { 1957 seconfig_t sec; 1958 1959 if (nfs_getseconfig_byname(str, &sec)) 1960 return (-1); 1961 1962 return (sec.sc_nfsnum); 1963 } 1964 1965 /* 1966 * If the option string contains a "sec=" 1967 * option, then use new option syntax. 1968 */ 1969 static int 1970 newopts(char *opts) 1971 { 1972 char *head, *p, *val; 1973 1974 if (!opts || *opts == '\0') 1975 return (0); 1976 1977 head = strdup(opts); 1978 if (head == NULL) { 1979 syslog(LOG_ERR, "opts: no memory"); 1980 return (0); 1981 } 1982 1983 p = head; 1984 while (*p) { 1985 if (getsubopt(&p, optlist, &val) == OPT_SEC) { 1986 free(head); 1987 return (1); 1988 } 1989 } 1990 1991 free(head); 1992 return (0); 1993 } 1994 1995 /* 1996 * Given an export and the clients hostname(s) 1997 * determine the security flavors that this 1998 * client is permitted to use. 1999 * 2000 * This routine is called only for "old" syntax, i.e. 2001 * only one security flavor is allowed. So we need 2002 * to determine two things: the particular flavor, 2003 * and whether the client is allowed to use this 2004 * flavor, i.e. is in the access list. 2005 * 2006 * Note that if there is no access list, then the 2007 * default is that access is granted. 2008 */ 2009 static int 2010 getclientsflavors_old(share_t *sh, SVCXPRT *transp, struct netbuf **nb, 2011 struct nd_hostservlist **clnames, int *flavors) 2012 { 2013 char *opts, *p, *val; 2014 boolean_t ok = B_FALSE; 2015 int defaultaccess = 1; 2016 boolean_t reject = B_FALSE; 2017 2018 opts = strdup(sh->sh_opts); 2019 if (opts == NULL) { 2020 syslog(LOG_ERR, "getclientsflavors: no memory"); 2021 return (0); 2022 } 2023 2024 flavors[0] = AUTH_SYS; 2025 p = opts; 2026 2027 while (*p) { 2028 2029 switch (getsubopt(&p, optlist, &val)) { 2030 case OPT_SECURE: 2031 flavors[0] = AUTH_DES; 2032 break; 2033 2034 case OPT_RO: 2035 case OPT_RW: 2036 defaultaccess = 0; 2037 if (in_access_list(transp, nb, clnames, val)) 2038 ok++; 2039 break; 2040 2041 case OPT_NONE: 2042 defaultaccess = 0; 2043 if (in_access_list(transp, nb, clnames, val)) 2044 reject = B_TRUE; 2045 } 2046 } 2047 2048 free(opts); 2049 2050 /* none takes precedence over everything else */ 2051 if (reject) 2052 ok = B_TRUE; 2053 2054 return (defaultaccess || ok); 2055 } 2056 2057 /* 2058 * Given an export and the clients hostname(s) 2059 * determine the security flavors that this 2060 * client is permitted to use. 2061 * 2062 * This is somewhat more complicated than the "old" 2063 * routine because the options may contain multiple 2064 * security flavors (sec=) each with its own access 2065 * lists. So a client could be granted access based 2066 * on a number of security flavors. Note that the 2067 * type of access might not always be the same, the 2068 * client may get readonly access with one flavor 2069 * and readwrite with another, however the client 2070 * is not told this detail, it gets only the list 2071 * of flavors, and only if the client is using 2072 * version 3 of the mount protocol. 2073 */ 2074 static int 2075 getclientsflavors_new(share_t *sh, SVCXPRT *transp, struct netbuf **nb, 2076 struct nd_hostservlist **clnames, int *flavors) 2077 { 2078 char *opts, *p, *val; 2079 char *lasts; 2080 char *f; 2081 boolean_t access_ok; 2082 int count, c; 2083 boolean_t reject = B_FALSE; 2084 2085 opts = strdup(sh->sh_opts); 2086 if (opts == NULL) { 2087 syslog(LOG_ERR, "getclientsflavors: no memory"); 2088 return (0); 2089 } 2090 2091 p = opts; 2092 count = c = 0; 2093 /* default access is rw */ 2094 access_ok = B_TRUE; 2095 2096 while (*p) { 2097 switch (getsubopt(&p, optlist, &val)) { 2098 case OPT_SEC: 2099 /* 2100 * Before a new sec=xxx option, check if we need 2101 * to move the c index back to the previous count. 2102 */ 2103 if (!access_ok) { 2104 c = count; 2105 } 2106 2107 /* get all the sec=f1[:f2] flavors */ 2108 while ((f = strtok_r(val, ":", &lasts)) 2109 != NULL) { 2110 flavors[c++] = map_flavor(f); 2111 val = NULL; 2112 } 2113 2114 /* for a new sec=xxx option, default is rw access */ 2115 access_ok = B_TRUE; 2116 break; 2117 2118 case OPT_RO: 2119 case OPT_RW: 2120 if (in_access_list(transp, nb, clnames, val)) { 2121 count = c; 2122 access_ok = B_TRUE; 2123 } else { 2124 access_ok = B_FALSE; 2125 } 2126 break; 2127 2128 case OPT_NONE: 2129 if (in_access_list(transp, nb, clnames, val)) 2130 reject = B_TRUE; /* none overides rw/ro */ 2131 break; 2132 } 2133 } 2134 2135 if (reject) 2136 access_ok = B_FALSE; 2137 2138 if (!access_ok) 2139 c = count; 2140 2141 free(opts); 2142 2143 return (c); 2144 } 2145 2146 /* 2147 * This is a tricky piece of code that parses the 2148 * share options looking for a match on the auth 2149 * flavor that the client is using. If it finds 2150 * a match, then the client is given ro, rw, or 2151 * no access depending whether it is in the access 2152 * list. There is a special case for "secure" 2153 * flavor. Other flavors are values of the new "sec=" option. 2154 */ 2155 int 2156 check_client(share_t *sh, struct netbuf *nb, 2157 struct nd_hostservlist *clnames, int flavor) 2158 { 2159 if (newopts(sh->sh_opts)) 2160 return (check_client_new(sh, NULL, &nb, &clnames, flavor)); 2161 else 2162 return (check_client_old(sh, NULL, &nb, &clnames, flavor)); 2163 } 2164 2165 static int 2166 check_client_old(share_t *sh, SVCXPRT *transp, struct netbuf **nb, 2167 struct nd_hostservlist **clnames, int flavor) 2168 { 2169 char *opts, *p, *val; 2170 int match; /* Set when a flavor is matched */ 2171 int perm = 0; /* Set when "ro", "rw" or "root" is matched */ 2172 int list = 0; /* Set when "ro", "rw" is found */ 2173 int ro_val = 0; /* Set if ro option is 'ro=' */ 2174 int rw_val = 0; /* Set if rw option is 'rw=' */ 2175 boolean_t reject = B_FALSE; /* if none= contains the host */ 2176 2177 opts = strdup(sh->sh_opts); 2178 if (opts == NULL) { 2179 syslog(LOG_ERR, "check_client: no memory"); 2180 return (0); 2181 } 2182 2183 p = opts; 2184 match = AUTH_UNIX; 2185 2186 while (*p) { 2187 switch (getsubopt(&p, optlist, &val)) { 2188 2189 case OPT_SECURE: 2190 match = AUTH_DES; 2191 break; 2192 2193 case OPT_RO: 2194 list++; 2195 if (val) ro_val++; 2196 if (in_access_list(transp, nb, clnames, val)) 2197 perm |= NFSAUTH_RO; 2198 break; 2199 2200 case OPT_RW: 2201 list++; 2202 if (val) rw_val++; 2203 if (in_access_list(transp, nb, clnames, val)) 2204 perm |= NFSAUTH_RW; 2205 break; 2206 2207 case OPT_ROOT: 2208 /* 2209 * Check if the client is in 2210 * the root list. Only valid 2211 * for AUTH_SYS. 2212 */ 2213 if (flavor != AUTH_SYS) 2214 break; 2215 2216 if (val == NULL || *val == '\0') 2217 break; 2218 2219 if (in_access_list(transp, nb, clnames, val)) 2220 perm |= NFSAUTH_ROOT; 2221 break; 2222 2223 case OPT_NONE: 2224 /* 2225 * Check if the client should have no access 2226 * to this share at all. This option behaves 2227 * more like "root" than either "rw" or "ro". 2228 */ 2229 if (in_access_list(transp, nb, clnames, val)) 2230 reject = B_TRUE; 2231 break; 2232 } 2233 } 2234 2235 free(opts); 2236 2237 if (flavor != match || reject) 2238 return (NFSAUTH_DENIED); 2239 2240 if (list) { 2241 /* 2242 * If the client doesn't match an "ro" or "rw" 2243 * list then set no access. 2244 */ 2245 if ((perm & (NFSAUTH_RO | NFSAUTH_RW)) == 0) 2246 perm |= NFSAUTH_DENIED; 2247 } else { 2248 /* 2249 * The client matched a flavor entry that 2250 * has no explicit "rw" or "ro" determination. 2251 * Default it to "rw". 2252 */ 2253 perm |= NFSAUTH_RW; 2254 } 2255 2256 2257 /* 2258 * The client may show up in both ro= and rw= 2259 * lists. If so, then turn off the RO access 2260 * bit leaving RW access. 2261 */ 2262 if (perm & NFSAUTH_RO && perm & NFSAUTH_RW) { 2263 /* 2264 * Logically cover all permutations of rw=,ro=. 2265 * In the case where, rw,ro=<host> we would like 2266 * to remove RW access for the host. In all other cases 2267 * RW wins the precedence battle. 2268 */ 2269 if (!rw_val && ro_val) { 2270 perm &= ~(NFSAUTH_RW); 2271 } else { 2272 perm &= ~(NFSAUTH_RO); 2273 } 2274 } 2275 2276 return (perm); 2277 } 2278 2279 /* 2280 * Check if the client has access by using a flavor different from 2281 * the given "flavor". If "flavor" is not in the flavor list, 2282 * return TRUE to indicate that this "flavor" is a wrong sec. 2283 */ 2284 static bool_t 2285 is_wrongsec(share_t *sh, SVCXPRT *transp, struct netbuf **nb, 2286 struct nd_hostservlist **clnames, int flavor) 2287 { 2288 int flavor_list[MAX_FLAVORS]; 2289 int flavor_count, i; 2290 2291 /* get the flavor list that the client has access with */ 2292 flavor_count = getclientsflavors_new(sh, transp, nb, 2293 clnames, flavor_list); 2294 2295 if (flavor_count == 0) 2296 return (FALSE); 2297 2298 /* 2299 * Check if the given "flavor" is in the flavor_list. 2300 */ 2301 for (i = 0; i < flavor_count; i++) { 2302 if (flavor == flavor_list[i]) 2303 return (FALSE); 2304 } 2305 2306 /* 2307 * If "flavor" is not in the flavor_list, return TRUE to indicate 2308 * that the client should have access by using a security flavor 2309 * different from this "flavor". 2310 */ 2311 return (TRUE); 2312 } 2313 2314 /* 2315 * Given an export and the client's hostname, we 2316 * check the security options to see whether the 2317 * client is allowed to use the given security flavor. 2318 * 2319 * The strategy is to proceed through the options looking 2320 * for a flavor match, then pay attention to the ro, rw, 2321 * and root options. 2322 * 2323 * Note that an entry may list several flavors in a 2324 * single entry, e.g. 2325 * 2326 * sec=krb5,rw=clnt1:clnt2,ro,sec=sys,ro 2327 * 2328 */ 2329 2330 static int 2331 check_client_new(share_t *sh, SVCXPRT *transp, struct netbuf **nb, 2332 struct nd_hostservlist **clnames, int flavor) 2333 { 2334 char *opts, *p, *val; 2335 char *lasts; 2336 char *f; 2337 int match = 0; /* Set when a flavor is matched */ 2338 int perm = 0; /* Set when "ro", "rw" or "root" is matched */ 2339 int list = 0; /* Set when "ro", "rw" is found */ 2340 int ro_val = 0; /* Set if ro option is 'ro=' */ 2341 int rw_val = 0; /* Set if rw option is 'rw=' */ 2342 boolean_t reject; 2343 2344 opts = strdup(sh->sh_opts); 2345 if (opts == NULL) { 2346 syslog(LOG_ERR, "check_client: no memory"); 2347 return (0); 2348 } 2349 2350 p = opts; 2351 2352 while (*p) { 2353 switch (getsubopt(&p, optlist, &val)) { 2354 2355 case OPT_SEC: 2356 if (match) 2357 goto done; 2358 2359 while ((f = strtok_r(val, ":", &lasts)) 2360 != NULL) { 2361 if (flavor == map_flavor(f)) { 2362 match = 1; 2363 break; 2364 } 2365 val = NULL; 2366 } 2367 break; 2368 2369 case OPT_RO: 2370 if (!match) 2371 break; 2372 2373 list++; 2374 if (val) ro_val++; 2375 if (in_access_list(transp, nb, clnames, val)) 2376 perm |= NFSAUTH_RO; 2377 break; 2378 2379 case OPT_RW: 2380 if (!match) 2381 break; 2382 2383 list++; 2384 if (val) rw_val++; 2385 if (in_access_list(transp, nb, clnames, val)) 2386 perm |= NFSAUTH_RW; 2387 break; 2388 2389 case OPT_ROOT: 2390 /* 2391 * Check if the client is in 2392 * the root list. Only valid 2393 * for AUTH_SYS. 2394 */ 2395 if (flavor != AUTH_SYS) 2396 break; 2397 2398 if (!match) 2399 break; 2400 2401 if (val == NULL || *val == '\0') 2402 break; 2403 2404 if (in_access_list(transp, nb, clnames, val)) 2405 perm |= NFSAUTH_ROOT; 2406 break; 2407 2408 case OPT_NONE: 2409 /* 2410 * Check if the client should have no access 2411 * to this share at all. This option behaves 2412 * more like "root" than either "rw" or "ro". 2413 */ 2414 if (in_access_list(transp, nb, clnames, val)) 2415 perm |= NFSAUTH_DENIED; 2416 break; 2417 } 2418 } 2419 2420 done: 2421 /* 2422 * If no match then set the perm accordingly 2423 */ 2424 if (!match || perm & NFSAUTH_DENIED) 2425 return (NFSAUTH_DENIED); 2426 2427 if (list) { 2428 /* 2429 * If the client doesn't match an "ro" or "rw" list then 2430 * check if it may have access by using a different flavor. 2431 * If so, return NFSAUTH_WRONGSEC. 2432 * If not, return NFSAUTH_DENIED. 2433 */ 2434 if ((perm & (NFSAUTH_RO | NFSAUTH_RW)) == 0) { 2435 if (is_wrongsec(sh, transp, nb, clnames, flavor)) 2436 perm |= NFSAUTH_WRONGSEC; 2437 else 2438 perm |= NFSAUTH_DENIED; 2439 } 2440 } else { 2441 /* 2442 * The client matched a flavor entry that 2443 * has no explicit "rw" or "ro" determination. 2444 * Make sure it defaults to "rw". 2445 */ 2446 perm |= NFSAUTH_RW; 2447 } 2448 2449 /* 2450 * The client may show up in both ro= and rw= 2451 * lists. If so, then turn off the RO access 2452 * bit leaving RW access. 2453 */ 2454 if (perm & NFSAUTH_RO && perm & NFSAUTH_RW) { 2455 /* 2456 * Logically cover all permutations of rw=,ro=. 2457 * In the case where, rw,ro=<host> we would like 2458 * to remove RW access for the host. In all other cases 2459 * RW wins the precedence battle. 2460 */ 2461 if (!rw_val && ro_val) { 2462 perm &= ~(NFSAUTH_RW); 2463 } else { 2464 perm &= ~(NFSAUTH_RO); 2465 } 2466 } 2467 2468 free(opts); 2469 2470 return (perm); 2471 } 2472 2473 void 2474 check_sharetab() 2475 { 2476 FILE *f; 2477 struct stat st; 2478 static timestruc_t last_sharetab_time; 2479 timestruc_t prev_sharetab_time; 2480 share_t *sh; 2481 struct sh_list *shp, *shp_prev; 2482 int res, c = 0; 2483 2484 /* 2485 * read in /etc/dfs/sharetab if it has changed 2486 */ 2487 if (stat(SHARETAB, &st) != 0) { 2488 syslog(LOG_ERR, "Cannot stat %s: %m", SHARETAB); 2489 return; 2490 } 2491 2492 if (st.st_mtim.tv_sec == last_sharetab_time.tv_sec && 2493 st.st_mtim.tv_nsec == last_sharetab_time.tv_nsec) { 2494 /* 2495 * No change. 2496 */ 2497 return; 2498 } 2499 2500 /* 2501 * Remember the mod time, then after getting the 2502 * write lock check again. If another thread 2503 * already did the update, then there's no 2504 * work to do. 2505 */ 2506 prev_sharetab_time = last_sharetab_time; 2507 2508 (void) rw_wrlock(&sharetab_lock); 2509 2510 if (prev_sharetab_time.tv_sec != last_sharetab_time.tv_sec || 2511 prev_sharetab_time.tv_nsec != last_sharetab_time.tv_nsec) { 2512 (void) rw_unlock(&sharetab_lock); 2513 return; 2514 } 2515 2516 /* 2517 * Note that since the sharetab is now in memory 2518 * and a snapshot is taken, we no longer have to 2519 * lock the file. 2520 */ 2521 f = fopen(SHARETAB, "r"); 2522 if (f == NULL) { 2523 syslog(LOG_ERR, "Cannot open %s: %m", SHARETAB); 2524 (void) rw_unlock(&sharetab_lock); 2525 return; 2526 } 2527 2528 /* 2529 * Once we are sure /etc/dfs/sharetab has been 2530 * modified, flush netgroup cache entries. 2531 */ 2532 netgrp_cache_flush(); 2533 2534 sh_free(share_list); /* free old list */ 2535 share_list = NULL; 2536 2537 while ((res = getshare(f, &sh)) > 0) { 2538 c++; 2539 if (strcmp(sh->sh_fstype, "nfs") != 0) 2540 continue; 2541 2542 shp = malloc(sizeof (*shp)); 2543 if (shp == NULL) 2544 goto alloc_failed; 2545 if (share_list == NULL) 2546 share_list = shp; 2547 else 2548 /* LINTED not used before set */ 2549 shp_prev->shl_next = shp; 2550 shp_prev = shp; 2551 shp->shl_next = NULL; 2552 shp->shl_sh = sharedup(sh); 2553 if (shp->shl_sh == NULL) 2554 goto alloc_failed; 2555 } 2556 2557 if (res < 0) 2558 syslog(LOG_ERR, "%s: invalid at line %d\n", 2559 SHARETAB, c + 1); 2560 2561 if (stat(SHARETAB, &st) != 0) { 2562 syslog(LOG_ERR, "Cannot stat %s: %m", SHARETAB); 2563 (void) fclose(f); 2564 (void) rw_unlock(&sharetab_lock); 2565 return; 2566 } 2567 2568 last_sharetab_time = st.st_mtim; 2569 (void) fclose(f); 2570 (void) rw_unlock(&sharetab_lock); 2571 2572 return; 2573 2574 alloc_failed: 2575 2576 syslog(LOG_ERR, "check_sharetab: no memory"); 2577 sh_free(share_list); 2578 share_list = NULL; 2579 (void) fclose(f); 2580 (void) rw_unlock(&sharetab_lock); 2581 } 2582 2583 static void 2584 sh_free(struct sh_list *shp) 2585 { 2586 register struct sh_list *next; 2587 2588 while (shp) { 2589 sharefree(shp->shl_sh); 2590 next = shp->shl_next; 2591 free(shp); 2592 shp = next; 2593 } 2594 } 2595 2596 2597 /* 2598 * Remove an entry from mounted list 2599 */ 2600 static void 2601 umount(struct svc_req *rqstp) 2602 { 2603 char *host, *path, *remove_path; 2604 char rpath[MAXPATHLEN]; 2605 struct nd_hostservlist *clnames = NULL; 2606 SVCXPRT *transp; 2607 struct netbuf *nb; 2608 2609 transp = rqstp->rq_xprt; 2610 path = NULL; 2611 if (!svc_getargs(transp, xdr_dirpath, (caddr_t)&path)) { 2612 svcerr_decode(transp); 2613 return; 2614 } 2615 errno = 0; 2616 if (!svc_sendreply(transp, xdr_void, (char *)NULL)) 2617 log_cant_reply(transp); 2618 2619 if (getclientsnames(transp, &nb, &clnames) != 0) { 2620 /* 2621 * Without the hostname we can't do audit or delete 2622 * this host from the mount entries. 2623 */ 2624 svc_freeargs(transp, xdr_dirpath, (caddr_t)&path); 2625 return; 2626 } 2627 host = clnames->h_hostservs[0].h_host; 2628 2629 if (verbose) 2630 syslog(LOG_NOTICE, "UNMOUNT: %s unmounted %s", host, path); 2631 2632 audit_mountd_umount(host, path); 2633 2634 remove_path = rpath; /* assume we will use the cannonical path */ 2635 if (realpath(path, rpath) == NULL) { 2636 if (verbose) 2637 syslog(LOG_WARNING, "UNMOUNT: realpath: %s: %m ", path); 2638 remove_path = path; /* use path provided instead */ 2639 } 2640 2641 mntlist_delete(host, remove_path); /* remove from mount list */ 2642 2643 svc_freeargs(transp, xdr_dirpath, (caddr_t)&path); 2644 netdir_free(clnames, ND_HOSTSERVLIST); 2645 } 2646 2647 /* 2648 * Remove all entries for one machine from mounted list 2649 */ 2650 static void 2651 umountall(struct svc_req *rqstp) 2652 { 2653 struct nd_hostservlist *clnames = NULL; 2654 SVCXPRT *transp; 2655 char *host; 2656 struct netbuf *nb; 2657 2658 transp = rqstp->rq_xprt; 2659 if (!svc_getargs(transp, xdr_void, NULL)) { 2660 svcerr_decode(transp); 2661 return; 2662 } 2663 /* 2664 * We assume that this call is asynchronous and made via rpcbind 2665 * callit routine. Therefore return control immediately. The error 2666 * causes rpcbind to remain silent, as opposed to every machine 2667 * on the net blasting the requester with a response. 2668 */ 2669 svcerr_systemerr(transp); 2670 if (getclientsnames(transp, &nb, &clnames) != 0) { 2671 /* Can't do anything without the name of the client */ 2672 return; 2673 } 2674 2675 host = clnames->h_hostservs[0].h_host; 2676 2677 /* 2678 * Remove all hosts entries from mount list 2679 */ 2680 mntlist_delete_all(host); 2681 2682 if (verbose) 2683 syslog(LOG_NOTICE, "UNMOUNTALL: from %s", host); 2684 2685 netdir_free(clnames, ND_HOSTSERVLIST); 2686 } 2687 2688 void * 2689 exmalloc(size_t size) 2690 { 2691 void *ret; 2692 2693 if ((ret = malloc(size)) == NULL) { 2694 syslog(LOG_ERR, "Out of memory"); 2695 exit(1); 2696 } 2697 return (ret); 2698 } 2699 2700 static void 2701 sigexit(int signum) 2702 { 2703 2704 if (signum == SIGHUP) 2705 _exit(0); 2706 _exit(1); 2707 } 2708 2709 static tsol_tpent_t * 2710 get_client_template(struct sockaddr *sock) 2711 { 2712 in_addr_t v4client; 2713 in6_addr_t v6client; 2714 char v4_addr[INET_ADDRSTRLEN]; 2715 char v6_addr[INET6_ADDRSTRLEN]; 2716 tsol_rhent_t *rh; 2717 tsol_tpent_t *tp; 2718 2719 switch (sock->sa_family) { 2720 case AF_INET: 2721 v4client = ((struct sockaddr_in *)(void *)sock)-> 2722 sin_addr.s_addr; 2723 if (inet_ntop(AF_INET, &v4client, v4_addr, INET_ADDRSTRLEN) == 2724 NULL) 2725 return (NULL); 2726 rh = tsol_getrhbyaddr(v4_addr, sizeof (v4_addr), AF_INET); 2727 if (rh == NULL) 2728 return (NULL); 2729 tp = tsol_gettpbyname(rh->rh_template); 2730 tsol_freerhent(rh); 2731 return (tp); 2732 break; 2733 case AF_INET6: 2734 v6client = ((struct sockaddr_in6 *)(void *)sock)->sin6_addr; 2735 if (inet_ntop(AF_INET6, &v6client, v6_addr, INET6_ADDRSTRLEN) == 2736 NULL) 2737 return (NULL); 2738 rh = tsol_getrhbyaddr(v6_addr, sizeof (v6_addr), AF_INET6); 2739 if (rh == NULL) 2740 return (NULL); 2741 tp = tsol_gettpbyname(rh->rh_template); 2742 tsol_freerhent(rh); 2743 return (tp); 2744 break; 2745 default: 2746 return (NULL); 2747 } 2748 } 2749