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