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