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