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