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