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