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