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