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