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