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