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