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