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