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