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