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