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