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 2007 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 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 #pragma ident "%Z%%M% %I% %E% SMI" 36 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <ctype.h> 40 #include <sys/types.h> 41 #include <string.h> 42 #include <syslog.h> 43 #include <sys/param.h> 44 #include <rpc/rpc.h> 45 #include <sys/stat.h> 46 #include <netconfig.h> 47 #include <netdir.h> 48 #include <sys/file.h> 49 #include <sys/time.h> 50 #include <sys/errno.h> 51 #include <rpcsvc/mount.h> 52 #include <sys/pathconf.h> 53 #include <sys/systeminfo.h> 54 #include <sys/utsname.h> 55 #include <signal.h> 56 #include <locale.h> 57 #include <unistd.h> 58 #include <errno.h> 59 #include <sys/socket.h> 60 #include <netinet/in.h> 61 #include <arpa/inet.h> 62 #include <netdb.h> 63 #include <thread.h> 64 #include <assert.h> 65 #include <priv_utils.h> 66 #include <nfs/auth.h> 67 #include <nfs/nfssys.h> 68 #include <nfs/nfs.h> 69 #include <nfs/nfs_sec.h> 70 #include <rpcsvc/daemon_utils.h> 71 #include <deflt.h> 72 #include "../../fslib.h" 73 #include <sharefs/share.h> 74 #include <sharefs/sharetab.h> 75 #include "../lib/sharetab.h" 76 #include "mountd.h" 77 78 struct sh_list *share_list; 79 80 rwlock_t sharetab_lock; /* lock to protect the cached sharetab */ 81 static mutex_t mnttab_lock; /* prevent concurrent mnttab readers */ 82 83 static struct share *find_lofsentry(char *, int *); 84 static void getclientsnames(SVCXPRT *, struct netbuf **, 85 struct nd_hostservlist **); 86 static int getclientsflavors_old(struct share *, struct netbuf *, 87 struct nd_hostservlist *, int *); 88 static int getclientsflavors_new(struct share *, struct netbuf *, 89 struct nd_hostservlist *, int *); 90 static int check_client_old(struct share *, struct netbuf *, 91 struct nd_hostservlist *, int); 92 static int check_client_new(struct share *, struct netbuf *, 93 struct nd_hostservlist *, int); 94 static int in_access_list(struct netbuf *, struct nd_hostservlist *, char *); 95 static void mnt(struct svc_req *, SVCXPRT *); 96 static void mnt_pathconf(struct svc_req *); 97 static void mount(struct svc_req *r); 98 static void sh_free(struct sh_list *); 99 static void umount(struct svc_req *); 100 static void umountall(struct svc_req *); 101 static int netmatch(struct netbuf *, char *); 102 static void sigexit(int); 103 static int newopts(char *); 104 105 static int verbose; 106 static int rejecting; 107 static int mount_vers_min = MOUNTVERS; 108 static int mount_vers_max = MOUNTVERS3; 109 110 thread_t nfsauth_thread; 111 112 /* ARGSUSED */ 113 static void * 114 nfsauth_svc(void *arg) 115 { 116 int doorfd = -1; 117 uint_t darg; 118 #ifdef DEBUG 119 int dfd; 120 #endif 121 122 if ((doorfd = door_create(nfsauth_func, NULL, 123 DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) { 124 syslog(LOG_ERR, "Unable to create door: %m\n"); 125 exit(10); 126 } 127 128 #ifdef DEBUG 129 /* 130 * Create a file system path for the door 131 */ 132 if ((dfd = open(MOUNTD_DOOR, O_RDWR|O_CREAT|O_TRUNC, 133 S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) == -1) { 134 syslog(LOG_ERR, "Unable to open %s: %m\n", MOUNTD_DOOR); 135 (void) close(doorfd); 136 exit(11); 137 } 138 139 /* 140 * Clean up any stale namespace associations 141 */ 142 (void) fdetach(MOUNTD_DOOR); 143 144 /* 145 * Register in namespace to pass to the kernel to door_ki_open 146 */ 147 if (fattach(doorfd, MOUNTD_DOOR) == -1) { 148 syslog(LOG_ERR, "Unable to fattach door: %m\n"); 149 (void) close(dfd); 150 (void) close(doorfd); 151 exit(12); 152 } 153 (void) close(dfd); 154 #endif 155 156 /* 157 * Must pass the doorfd down to the kernel. 158 */ 159 darg = doorfd; 160 (void) _nfssys(MOUNTD_ARGS, &darg); 161 162 /* 163 * Wait for incoming calls 164 */ 165 /*CONSTCOND*/ 166 for (;;) 167 (void) pause(); 168 169 /*NOTREACHED*/ 170 syslog(LOG_ERR, gettext("Door server exited")); 171 return (NULL); 172 } 173 174 int 175 main(int argc, char *argv[]) 176 { 177 int pid; 178 int c; 179 int rpc_svc_mode = RPC_SVC_MT_AUTO; 180 int maxthreads; 181 int maxrecsz = RPC_MAXDATASIZE; 182 bool_t exclbind = TRUE; 183 bool_t can_do_mlp; 184 long thr_flags = (THR_NEW_LWP|THR_DAEMON); 185 186 /* 187 * Mountd requires uid 0 for: 188 * /etc/rmtab updates (we could chown it to daemon) 189 * /etc/dfs/dfstab reading (it wants to lock out share which 190 * doesn't do any locking before first truncate; 191 * NFS share does; should use fcntl locking instead) 192 * Needed privileges: 193 * auditing 194 * nfs syscall 195 * file dac search (so it can stat all files) 196 * Optional privileges: 197 * MLP 198 */ 199 can_do_mlp = priv_ineffect(PRIV_NET_BINDMLP); 200 if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET, -1, -1, 201 PRIV_SYS_NFS, PRIV_PROC_AUDIT, PRIV_FILE_DAC_SEARCH, 202 can_do_mlp ? PRIV_NET_BINDMLP : NULL, NULL) == -1) { 203 (void) fprintf(stderr, 204 "%s must be run as with sufficient privileges\n", 205 argv[0]); 206 exit(1); 207 } 208 209 maxthreads = 0; 210 211 while ((c = getopt(argc, argv, "vrm:")) != EOF) { 212 switch (c) { 213 case 'v': 214 verbose++; 215 break; 216 case 'r': 217 rejecting = 1; 218 break; 219 case 'm': 220 maxthreads = atoi(optarg); 221 if (maxthreads < 1) { 222 (void) fprintf(stderr, 223 "%s: must specify positive maximum threads count, using default\n", 224 argv[0]); 225 maxthreads = 0; 226 } 227 break; 228 } 229 } 230 231 /* 232 * Read in the NFS version values from config file. 233 */ 234 if ((defopen(NFSADMIN)) == 0) { 235 char *defval; 236 int defvers; 237 238 if ((defval = defread("NFS_SERVER_VERSMIN=")) != NULL) { 239 errno = 0; 240 defvers = strtol(defval, (char **)NULL, 10); 241 if (errno == 0) { 242 mount_vers_min = defvers; 243 /* 244 * special because NFSv2 is 245 * supported by mount v1 & v2 246 */ 247 if (defvers == NFS_VERSION) 248 mount_vers_min = MOUNTVERS; 249 } 250 } 251 if ((defval = defread("NFS_SERVER_VERSMAX=")) != NULL) { 252 errno = 0; 253 defvers = strtol(defval, (char **)NULL, 10); 254 if (errno == 0) { 255 mount_vers_max = defvers; 256 } 257 } 258 259 /* close defaults file */ 260 defopen(NULL); 261 } 262 263 /* 264 * Sanity check versions, 265 * even though we may get versions > MOUNTVERS3, we still need 266 * to start nfsauth service, so continue on regardless of values. 267 */ 268 if (mount_vers_min > mount_vers_max) { 269 syslog(LOG_NOTICE, "NFS_SERVER_VERSMIN > NFS_SERVER_VERSMAX"); 270 mount_vers_max = mount_vers_min; 271 } 272 (void) setlocale(LC_ALL, ""); 273 (void) rwlock_init(&sharetab_lock, USYNC_THREAD, NULL); 274 (void) mutex_init(&mnttab_lock, USYNC_THREAD, NULL); 275 netgroup_init(); 276 277 #if !defined(TEXT_DOMAIN) 278 #define TEXT_DOMAIN "SYS_TEST" 279 #endif 280 (void) textdomain(TEXT_DOMAIN); 281 282 /* Don't drop core if the NFS module isn't loaded. */ 283 (void) signal(SIGSYS, SIG_IGN); 284 285 (void) signal(SIGHUP, sigexit); 286 (void) signal(SIGCLD, sigexit); 287 288 switch (fork()) { 289 case 0: /* child */ 290 break; 291 case -1: 292 perror("mountd: can't fork"); 293 exit(1); 294 default: /* parent */ 295 for (;;) 296 (void) pause(); 297 /* NOTREACHED */ 298 } 299 300 (void) signal(SIGHUP, SIG_DFL); 301 (void) signal(SIGCLD, SIG_DFL); 302 303 /* 304 * If we coredump it'll be in /core 305 */ 306 if (chdir("/") < 0) 307 syslog(LOG_ERR, "chdir /: %m"); 308 309 /* 310 * Close existing file descriptors, open "/dev/null" as 311 * standard input, output, and error, and detach from 312 * controlling terminal. 313 */ 314 closefrom(0); 315 (void) open("/dev/null", O_RDONLY); 316 (void) open("/dev/null", O_WRONLY); 317 (void) dup(1); 318 (void) setsid(); 319 320 openlog("mountd", LOG_PID, LOG_DAEMON); 321 322 /* 323 * establish our lock on the lock file and write our pid to it. 324 * exit if some other process holds the lock, or if there's any 325 * error in writing/locking the file. 326 */ 327 pid = _enter_daemon_lock(MOUNTD); 328 switch (pid) { 329 case 0: 330 break; 331 case -1: 332 syslog(LOG_ERR, "error locking for %s: %s", MOUNTD, 333 strerror(errno)); 334 exit(2); 335 default: 336 /* daemon was already running */ 337 exit(0); 338 } 339 340 audit_mountd_setup(); /* BSM */ 341 342 /* 343 * Tell RPC that we want automatic thread mode. 344 * A new thread will be spawned for each request. 345 */ 346 if (!rpc_control(RPC_SVC_MTMODE_SET, &rpc_svc_mode)) { 347 syslog(LOG_ERR, "unable to set automatic MT mode"); 348 exit(1); 349 } 350 351 /* 352 * Enable non-blocking mode and maximum record size checks for 353 * connection oriented transports. 354 */ 355 if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrecsz)) { 356 syslog(LOG_INFO, "unable to set RPC max record size"); 357 } 358 359 /* 360 * Prevent our non-priv udp and tcp ports bound w/wildcard addr 361 * from being hijacked by a bind to a more specific addr. 362 */ 363 if (!rpc_control(__RPC_SVC_EXCLBIND_SET, &exclbind)) { 364 syslog(LOG_INFO, "warning: unable to set udp/tcp EXCLBIND"); 365 } 366 367 /* 368 * If the -m argument was specified, then set the 369 * maximum number of threads to the value specified. 370 */ 371 if (maxthreads > 0 && !rpc_control(RPC_SVC_THRMAX_SET, &maxthreads)) { 372 syslog(LOG_ERR, "unable to set maxthreads"); 373 exit(1); 374 } 375 376 /* 377 * Make sure to unregister any previous versions in case the 378 * user is reconfiguring the server in interesting ways. 379 */ 380 svc_unreg(MOUNTPROG, MOUNTVERS); 381 svc_unreg(MOUNTPROG, MOUNTVERS_POSIX); 382 svc_unreg(MOUNTPROG, MOUNTVERS3); 383 384 /* 385 * Create the nfsauth thread with same signal disposition 386 * as the main thread. We need to create a separate thread 387 * since mountd() will be both an RPC server (for remote 388 * traffic) _and_ a doors server (for kernel upcalls). 389 */ 390 if (thr_create(NULL, 0, nfsauth_svc, 0, thr_flags, &nfsauth_thread)) { 391 syslog(LOG_ERR, gettext("Failed to create NFSAUTH svc thread")); 392 exit(2); 393 } 394 395 /* 396 * Create datagram and connection oriented services 397 */ 398 if (mount_vers_max >= MOUNTVERS) { 399 if (svc_create(mnt, MOUNTPROG, MOUNTVERS, "datagram_v") == 0) { 400 syslog(LOG_ERR, 401 "couldn't register datagram_v MOUNTVERS"); 402 exit(1); 403 } 404 if (svc_create(mnt, MOUNTPROG, MOUNTVERS, "circuit_v") == 0) { 405 syslog(LOG_ERR, 406 "couldn't register circuit_v MOUNTVERS"); 407 exit(1); 408 } 409 } 410 if (mount_vers_max >= MOUNTVERS_POSIX) { 411 if (svc_create(mnt, MOUNTPROG, MOUNTVERS_POSIX, 412 "datagram_v") == 0) { 413 syslog(LOG_ERR, 414 "couldn't register datagram_v MOUNTVERS_POSIX"); 415 exit(1); 416 } 417 if (svc_create(mnt, MOUNTPROG, MOUNTVERS_POSIX, 418 "circuit_v") == 0) { 419 syslog(LOG_ERR, 420 "couldn't register circuit_v MOUNTVERS_POSIX"); 421 exit(1); 422 } 423 } 424 425 if (mount_vers_max >= MOUNTVERS3) { 426 if (svc_create(mnt, MOUNTPROG, MOUNTVERS3, "datagram_v") == 0) { 427 syslog(LOG_ERR, 428 "couldn't register datagram_v MOUNTVERS3"); 429 exit(1); 430 } 431 if (svc_create(mnt, MOUNTPROG, MOUNTVERS3, "circuit_v") == 0) { 432 syslog(LOG_ERR, 433 "couldn't register circuit_v MOUNTVERS3"); 434 exit(1); 435 } 436 } 437 438 /* 439 * Start serving 440 */ 441 rmtab_load(); 442 (void) kill(getppid(), SIGHUP); 443 444 /* Get rid of the most dangerous basic privileges. */ 445 __fini_daemon_priv(PRIV_PROC_EXEC, PRIV_PROC_INFO, PRIV_PROC_SESSION, 446 (char *)NULL); 447 448 svc_run(); 449 syslog(LOG_ERR, "Error: svc_run shouldn't have returned"); 450 abort(); 451 /* NOTREACHED */ 452 return (0); 453 } 454 455 /* 456 * Server procedure switch routine 457 */ 458 void 459 mnt(struct svc_req *rqstp, SVCXPRT *transp) 460 { 461 switch (rqstp->rq_proc) { 462 case NULLPROC: 463 errno = 0; 464 if (!svc_sendreply(transp, xdr_void, (char *)0)) 465 log_cant_reply(transp); 466 return; 467 468 case MOUNTPROC_MNT: 469 mount(rqstp); 470 return; 471 472 case MOUNTPROC_DUMP: 473 mntlist_send(transp); 474 return; 475 476 case MOUNTPROC_UMNT: 477 umount(rqstp); 478 return; 479 480 case MOUNTPROC_UMNTALL: 481 umountall(rqstp); 482 return; 483 484 case MOUNTPROC_EXPORT: 485 case MOUNTPROC_EXPORTALL: 486 export(rqstp); 487 return; 488 489 case MOUNTPROC_PATHCONF: 490 if (rqstp->rq_vers == MOUNTVERS_POSIX) 491 mnt_pathconf(rqstp); 492 else 493 svcerr_noproc(transp); 494 return; 495 496 default: 497 svcerr_noproc(transp); 498 return; 499 } 500 } 501 502 /* Set up anonymous client */ 503 504 struct nd_hostservlist * 505 anon_client(char *host) 506 { 507 struct nd_hostservlist *anon_hsl; 508 struct nd_hostserv *anon_hs; 509 510 anon_hsl = malloc(sizeof (*anon_hsl)); 511 if (anon_hsl == NULL) 512 return (NULL); 513 514 anon_hs = malloc(sizeof (*anon_hs)); 515 if (anon_hs == NULL) { 516 free(anon_hsl); 517 return (NULL); 518 } 519 520 if (host == NULL) 521 anon_hs->h_host = strdup("(anon)"); 522 else 523 anon_hs->h_host = strdup(host); 524 525 if (anon_hs->h_host == NULL) { 526 free(anon_hs); 527 free(anon_hsl); 528 return (NULL); 529 } 530 anon_hs->h_serv = '\0'; 531 532 anon_hsl->h_cnt = 1; 533 anon_hsl->h_hostservs = anon_hs; 534 535 return (anon_hsl); 536 } 537 538 /* 539 * Get the client's hostname from the transport handle 540 * If the name is not available then return "(anon)". 541 */ 542 void 543 getclientsnames(SVCXPRT *transp, struct netbuf **nbuf, 544 struct nd_hostservlist **serv) 545 { 546 struct netconfig *nconf; 547 char tmp[MAXIPADDRLEN]; 548 char *host = NULL; 549 550 nconf = getnetconfigent(transp->xp_netid); 551 if (nconf == NULL) { 552 syslog(LOG_ERR, "%s: getnetconfigent failed", 553 transp->xp_netid); 554 *serv = anon_client(host); 555 return; 556 } 557 558 *nbuf = svc_getrpccaller(transp); 559 if (*nbuf == NULL) { 560 freenetconfigent(nconf); 561 *serv = anon_client(host); 562 return; 563 } 564 565 /* 566 * Use the this API instead of the netdir_getbyaddr() 567 * to avoid service lookup. 568 */ 569 if (__netdir_getbyaddr_nosrv(nconf, serv, *nbuf)) { 570 host = &tmp[0]; 571 if (strcmp(nconf->nc_protofmly, NC_INET) == 0) { 572 struct sockaddr_in *sa; 573 574 /* LINTED pointer alignment */ 575 sa = (struct sockaddr_in *)((*nbuf)->buf); 576 (void) inet_ntoa_r(sa->sin_addr, tmp); 577 *serv = anon_client(host); 578 freenetconfigent(nconf); 579 return; 580 } else if (strcmp(nconf->nc_protofmly, NC_INET6) == 0) { 581 struct sockaddr_in6 *sa; 582 583 /* LINTED pointer alignment */ 584 sa = (struct sockaddr_in6 *)((*nbuf)->buf); 585 (void) inet_ntop(AF_INET6, sa->sin6_addr.s6_addr, 586 tmp, INET6_ADDRSTRLEN); 587 *serv = anon_client(host); 588 freenetconfigent(nconf); 589 return; 590 } 591 freenetconfigent(nconf); 592 *serv = anon_client(host); 593 return; 594 } 595 freenetconfigent(nconf); 596 } 597 598 void 599 log_cant_reply(SVCXPRT *transp) 600 { 601 int saverrno; 602 struct nd_hostservlist *clnames = NULL; 603 register char *host; 604 struct netbuf *nb; 605 606 saverrno = errno; /* save error code */ 607 getclientsnames(transp, &nb, &clnames); 608 if (clnames == NULL) 609 return; 610 host = clnames->h_hostservs->h_host; 611 612 errno = saverrno; 613 if (errno == 0) 614 syslog(LOG_ERR, "couldn't send reply to %s", host); 615 else 616 syslog(LOG_ERR, "couldn't send reply to %s: %m", host); 617 618 netdir_free(clnames, ND_HOSTSERVLIST); 619 } 620 621 /* 622 * Answer pathconf questions for the mount point fs 623 */ 624 static void 625 mnt_pathconf(struct svc_req *rqstp) 626 { 627 SVCXPRT *transp; 628 struct pathcnf p; 629 char *path, rpath[MAXPATHLEN]; 630 struct stat st; 631 632 transp = rqstp->rq_xprt; 633 path = NULL; 634 (void) memset((caddr_t)&p, 0, sizeof (p)); 635 636 if (!svc_getargs(transp, xdr_dirpath, (caddr_t)&path)) { 637 svcerr_decode(transp); 638 return; 639 } 640 if (lstat(path, &st) < 0) { 641 _PC_SET(_PC_ERROR, p.pc_mask); 642 goto done; 643 } 644 /* 645 * Get a path without symbolic links. 646 */ 647 if (realpath(path, rpath) == NULL) { 648 syslog(LOG_DEBUG, 649 "mount request: realpath failed on %s: %m", 650 path); 651 _PC_SET(_PC_ERROR, p.pc_mask); 652 goto done; 653 } 654 (void) memset((caddr_t)&p, 0, sizeof (p)); 655 /* 656 * can't ask about devices over NFS 657 */ 658 _PC_SET(_PC_MAX_CANON, p.pc_mask); 659 _PC_SET(_PC_MAX_INPUT, p.pc_mask); 660 _PC_SET(_PC_PIPE_BUF, p.pc_mask); 661 _PC_SET(_PC_VDISABLE, p.pc_mask); 662 663 errno = 0; 664 p.pc_link_max = pathconf(rpath, _PC_LINK_MAX); 665 if (errno) 666 _PC_SET(_PC_LINK_MAX, p.pc_mask); 667 p.pc_name_max = pathconf(rpath, _PC_NAME_MAX); 668 if (errno) 669 _PC_SET(_PC_NAME_MAX, p.pc_mask); 670 p.pc_path_max = pathconf(rpath, _PC_PATH_MAX); 671 if (errno) 672 _PC_SET(_PC_PATH_MAX, p.pc_mask); 673 if (pathconf(rpath, _PC_NO_TRUNC) == 1) 674 _PC_SET(_PC_NO_TRUNC, p.pc_mask); 675 if (pathconf(rpath, _PC_CHOWN_RESTRICTED) == 1) 676 _PC_SET(_PC_CHOWN_RESTRICTED, p.pc_mask); 677 678 done: 679 errno = 0; 680 if (!svc_sendreply(transp, xdr_ppathcnf, (char *)&p)) 681 log_cant_reply(transp); 682 if (path != NULL) 683 svc_freeargs(transp, xdr_dirpath, (caddr_t)&path); 684 } 685 686 /* 687 * If the rootmount (export) option is specified, the all mount requests for 688 * subdirectories return EACCES. 689 */ 690 static int 691 checkrootmount(struct share *sh, char *rpath) 692 { 693 char *val; 694 695 if ((val = getshareopt(sh->sh_opts, SHOPT_NOSUB)) != NULL) { 696 free(val); 697 if (strcmp(sh->sh_path, rpath) != 0) 698 return (0); 699 else 700 return (1); 701 } else 702 return (1); 703 } 704 705 #define MAX_FLAVORS 128 706 707 /* 708 * Return only EACCES if client does not have access 709 * to this directory. 710 * "If the server exports only /a/b, an attempt to 711 * mount a/b/c will fail with ENOENT if the directory 712 * does not exist"... However, if the client 713 * does not have access to /a/b, an attacker can 714 * determine whether the directory exists. 715 * This routine checks either existence of the file or 716 * existence of the file name entry in the mount table. 717 * If the file exists and there is no file name entry, 718 * the error returned should be EACCES. 719 * If the file does not exist, it must be determined 720 * whether the client has access to a parent 721 * directory. If the client has access to a parent 722 * directory, the error returned should be ENOENT, 723 * otherwise EACCES. 724 */ 725 static int 726 mount_enoent_error(char *path, char *rpath, struct nd_hostservlist *clnames, 727 struct netbuf *nb, int *flavor_list) 728 { 729 char *checkpath, *dp; 730 struct share *sh = NULL; 731 int realpath_error = ENOENT, reply_error = EACCES, lofs_tried = 0; 732 int flavor_count; 733 734 checkpath = strdup(path); 735 if (checkpath == NULL) { 736 syslog(LOG_ERR, "mount_enoent: no memory"); 737 return (EACCES); 738 } 739 740 /* CONSTCOND */ 741 while (1) { 742 if (sh) { 743 sharefree(sh); 744 sh = NULL; 745 } 746 if ((sh = findentry(rpath)) == NULL && 747 (sh = find_lofsentry(rpath, &lofs_tried)) == NULL) { 748 /* 749 * There is no file name entry. 750 * If the file (with symbolic links resolved) exists, 751 * the error returned should be EACCES. 752 */ 753 if (realpath_error == 0) 754 break; 755 } else if (checkrootmount(sh, rpath) == 0) { 756 /* 757 * This is a "nosub" only export, in which case, 758 * mounting subdirectories isn't allowed. 759 * If the file (with symbolic links resolved) exists, 760 * the error returned should be EACCES. 761 */ 762 if (realpath_error == 0) 763 break; 764 } else { 765 /* 766 * Check permissions in mount table. 767 */ 768 if (newopts(sh->sh_opts)) 769 flavor_count = getclientsflavors_new(sh, nb, 770 clnames, flavor_list); 771 else 772 flavor_count = getclientsflavors_old(sh, nb, 773 clnames, flavor_list); 774 if (flavor_count != 0) { 775 /* 776 * Found entry in table and 777 * client has correct permissions. 778 */ 779 reply_error = ENOENT; 780 break; 781 } 782 } 783 /* 784 * Check all parent directories. 785 */ 786 dp = strrchr(checkpath, '/'); 787 if (dp == NULL) 788 break; 789 *dp = '\0'; 790 if (strlen(checkpath) == 0) 791 break; 792 /* 793 * Get the real path (no symbolic links in it) 794 */ 795 if (realpath(checkpath, rpath) == NULL) { 796 if (errno != ENOENT) 797 break; 798 } else { 799 realpath_error = 0; 800 } 801 } 802 803 if (sh) 804 sharefree(sh); 805 free(checkpath); 806 return (reply_error); 807 } 808 809 /* 810 * Check mount requests, add to mounted list if ok 811 */ 812 static void 813 mount(struct svc_req *rqstp) 814 { 815 SVCXPRT *transp; 816 int version, vers; 817 struct fhstatus fhs; 818 struct mountres3 mountres3; 819 char fh[FHSIZE3]; 820 int len = FHSIZE3; 821 char *path, rpath[MAXPATHLEN]; 822 struct share *sh = NULL; 823 struct nd_hostservlist *clnames = NULL; 824 char *host = NULL; 825 int error = 0, lofs_tried = 0; 826 int flavor_list[MAX_FLAVORS]; 827 int flavor_count; 828 struct netbuf *nb; 829 830 transp = rqstp->rq_xprt; 831 version = rqstp->rq_vers; 832 path = NULL; 833 834 if (!svc_getargs(transp, xdr_dirpath, (caddr_t)&path)) { 835 svcerr_decode(transp); 836 return; 837 } 838 839 getclientsnames(transp, &nb, &clnames); 840 if (clnames == NULL || nb == NULL) { 841 /* 842 * We failed to get a name for the client, even 'anon', 843 * probably because we ran out of memory. In this situation 844 * it doesn't make sense to allow the mount to succeed. 845 */ 846 error = EACCES; 847 goto reply; 848 } 849 host = clnames->h_hostservs[0].h_host; 850 851 /* 852 * If the version being used is less than the minimum version, 853 * the filehandle translation should not be provided to the 854 * client. 855 */ 856 if (rejecting || version < mount_vers_min) { 857 if (verbose) 858 syslog(LOG_NOTICE, "Rejected mount: %s for %s", 859 host, path); 860 error = EACCES; 861 goto reply; 862 } 863 864 /* 865 * Trusted Extension doesn't support older versions of nfs(v2, v3). 866 * To prevent circumventing TX label policy via using an older 867 * version of nfs client, reject the mount request and log an 868 * error. 869 */ 870 if (is_system_labeled()) { 871 syslog(LOG_ERR, 872 "mount rejected: Solaris TX only supports nfs4 clients"); 873 error = EACCES; 874 goto reply; 875 } 876 877 /* 878 * Get the real path (no symbolic links in it) 879 */ 880 if (realpath(path, rpath) == NULL) { 881 error = errno; 882 if (verbose) 883 syslog(LOG_ERR, 884 "mount request: realpath: %s: %m", path); 885 if (error == ENOENT) 886 error = mount_enoent_error(path, rpath, clnames, nb, 887 flavor_list); 888 goto reply; 889 } 890 891 if ((sh = findentry(rpath)) == NULL && 892 (sh = find_lofsentry(rpath, &lofs_tried)) == NULL) { 893 error = EACCES; 894 goto reply; 895 } 896 897 /* 898 * Check if this is a "nosub" only export, in which case, mounting 899 * subdirectories isn't allowed. Bug 1184573. 900 */ 901 if (checkrootmount(sh, rpath) == 0) { 902 error = EACCES; 903 goto reply; 904 } 905 906 if (newopts(sh->sh_opts)) 907 flavor_count = getclientsflavors_new(sh, nb, clnames, 908 flavor_list); 909 else 910 flavor_count = getclientsflavors_old(sh, nb, clnames, 911 flavor_list); 912 913 if (flavor_count == 0) { 914 error = EACCES; 915 goto reply; 916 } 917 918 /* 919 * Now get the filehandle. 920 * 921 * NFS V2 clients get a 32 byte filehandle. 922 * NFS V3 clients get a 32 or 64 byte filehandle, depending on 923 * the embedded FIDs. 924 */ 925 vers = (version == MOUNTVERS3) ? NFS_V3 : NFS_VERSION; 926 927 /* LINTED pointer alignment */ 928 while (nfs_getfh(rpath, vers, &len, fh) < 0) { 929 if (errno == EINVAL && 930 (sh = find_lofsentry(rpath, &lofs_tried)) != NULL) { 931 errno = 0; 932 continue; 933 } 934 error = errno == EINVAL ? EACCES : errno; 935 syslog(LOG_DEBUG, "mount request: getfh failed on %s: %m", 936 path); 937 break; 938 } 939 940 if (version == MOUNTVERS3) { 941 mountres3.mountres3_u.mountinfo.fhandle.fhandle3_len = len; 942 mountres3.mountres3_u.mountinfo.fhandle.fhandle3_val = fh; 943 } else { 944 bcopy(fh, &fhs.fhstatus_u.fhs_fhandle, NFS_FHSIZE); 945 } 946 947 reply: 948 switch (version) { 949 case MOUNTVERS: 950 case MOUNTVERS_POSIX: 951 if (error == EINVAL) 952 fhs.fhs_status = NFSERR_ACCES; 953 else if (error == EREMOTE) 954 fhs.fhs_status = NFSERR_REMOTE; 955 else 956 fhs.fhs_status = error; 957 if (!svc_sendreply(transp, xdr_fhstatus, (char *)&fhs)) 958 log_cant_reply(transp); 959 audit_mountd_mount(host, path, fhs.fhs_status); /* BSM */ 960 break; 961 962 case MOUNTVERS3: 963 if (!error) { 964 mountres3.mountres3_u.mountinfo.auth_flavors.auth_flavors_val = 965 flavor_list; 966 mountres3.mountres3_u.mountinfo.auth_flavors.auth_flavors_len = 967 flavor_count; 968 969 } else if (error == ENAMETOOLONG) 970 error = MNT3ERR_NAMETOOLONG; 971 972 mountres3.fhs_status = error; 973 if (!svc_sendreply(transp, xdr_mountres3, (char *)&mountres3)) 974 log_cant_reply(transp); 975 audit_mountd_mount(host, path, mountres3.fhs_status); /* BSM */ 976 977 break; 978 } 979 980 if (verbose) 981 syslog(LOG_NOTICE, "MOUNT: %s %s %s", 982 (host == NULL) ? "unknown host" : host, 983 error ? "denied" : "mounted", path); 984 985 if (path != NULL) 986 svc_freeargs(transp, xdr_dirpath, (caddr_t)&path); 987 988 if (!error) 989 mntlist_new(host, rpath); /* add entry to mount list */ 990 done: 991 if (sh) 992 sharefree(sh); 993 netdir_free(clnames, ND_HOSTSERVLIST); 994 } 995 996 struct share * 997 findentry(char *path) 998 { 999 struct share *sh = NULL; 1000 struct sh_list *shp; 1001 register char *p1, *p2; 1002 struct stat st1; 1003 struct stat64 st2; 1004 1005 check_sharetab(); 1006 1007 (void) rw_rdlock(&sharetab_lock); 1008 1009 for (shp = share_list; shp; shp = shp->shl_next) { 1010 sh = shp->shl_sh; 1011 for (p1 = sh->sh_path, p2 = path; *p1 == *p2; p1++, p2++) 1012 if (*p1 == '\0') 1013 goto done; /* exact match */ 1014 1015 /* 1016 * Now compare the pathnames for three cases: 1017 * 1018 * Parent: /export/foo (no trailing slash on parent) 1019 * Child: /export/foo/bar 1020 * 1021 * Parent: /export/foo/ (trailing slash on parent) 1022 * Child: /export/foo/bar 1023 * 1024 * Parent: /export/foo/ (no trailing slash on child) 1025 * Child: /export/foo 1026 * 1027 * Then compare the dev_t of the parent and child to 1028 * make sure that they're both in the same filesystem. 1029 */ 1030 if ((*p1 == '\0' && *p2 == '/') || 1031 (*p1 == '\0' && *(p1-1) == '/') || 1032 (*p2 == '\0' && *p1 == '/' && *(p1+1) == '\0')) { 1033 if (stat(sh->sh_path, &st1) < 0) { 1034 if (verbose) 1035 syslog(LOG_NOTICE, "%s: %m", p1); 1036 shp = NULL; 1037 goto done; 1038 } 1039 /* 1040 * Use stat64 on "path" since it might be larger 1041 * than 2 Gb and 32 bit stat would fail EOVERFLOW 1042 */ 1043 if (stat64(path, &st2) < 0) { 1044 if (verbose) 1045 syslog(LOG_NOTICE, "%s: %m", p2); 1046 shp = NULL; 1047 goto done; 1048 } 1049 if (st1.st_dev == st2.st_dev) 1050 goto done; 1051 } 1052 } 1053 done: 1054 sh = shp ? sharedup(sh) : NULL; 1055 1056 (void) rw_unlock(&sharetab_lock); 1057 1058 return (sh); 1059 } 1060 1061 1062 static int 1063 is_substring(char **mntp, char **path) 1064 { 1065 char *p1 = *mntp, *p2 = *path; 1066 1067 if (*p1 == '\0' && *p2 == '\0') /* exact match */ 1068 return (1); 1069 else if (*p1 == '\0' && *p2 == '/') 1070 return (1); 1071 else if (*p1 == '\0' && *(p1-1) == '/') { 1072 *path = --p2; /* we need the slash in p2 */ 1073 return (1); 1074 } else if (*p2 == '\0') { 1075 while (*p1 == '/') 1076 p1++; 1077 if (*p1 == '\0') /* exact match */ 1078 return (1); 1079 } 1080 return (0); 1081 } 1082 1083 /* 1084 * find_lofsentry() searches for the real path which this requested LOFS path 1085 * (rpath) shadows. If found, it will return the sharetab entry of 1086 * the real path that corresponds to the LOFS path. 1087 * We first search mnttab to see if the requested path is an automounted 1088 * path. If it is an automounted path, it will trigger the mount by stat()ing 1089 * the requested path. Note that it is important to check that this path is 1090 * actually an automounted path, otherwise we would stat() a path which may 1091 * turn out to be NFS and block indefinitely on a dead server. The automounter 1092 * times-out if the server is dead, so there's no risk of hanging this 1093 * thread waiting for stat(). 1094 * After the mount has been triggered (if necessary), we look for a 1095 * mountpoint of type LOFS (by searching /etc/mnttab again) which 1096 * is a substring of the rpath. If found, we construct a new path by 1097 * concatenating the mnt_special and the remaining of rpath, call findentry() 1098 * to make sure the 'real path' is shared. 1099 */ 1100 static struct share * 1101 find_lofsentry(char *rpath, int *done_flag) 1102 { 1103 struct stat r_stbuf; 1104 mntlist_t *ml, *mntl, *mntpnt = NULL; 1105 struct share *retcode = NULL; 1106 char tmp_path[MAXPATHLEN]; 1107 int mntpnt_len = 0, tmp; 1108 char *p1, *p2; 1109 1110 if ((*done_flag)++) 1111 return (retcode); 1112 1113 /* 1114 * While fsgetmntlist() uses lockf() to 1115 * lock the mnttab before reading it in, 1116 * the lock ignores threads in the same process. 1117 * Read in the mnttab with the protection of a mutex. 1118 */ 1119 (void) mutex_lock(&mnttab_lock); 1120 mntl = fsgetmntlist(); 1121 (void) mutex_unlock(&mnttab_lock); 1122 1123 /* 1124 * Obtain the mountpoint for the requested path. 1125 */ 1126 for (ml = mntl; ml; ml = ml->mntl_next) { 1127 for (p1 = ml->mntl_mnt->mnt_mountp, p2 = rpath; 1128 *p1 == *p2 && *p1; p1++, p2++); 1129 if (is_substring(&p1, &p2) && 1130 (tmp = strlen(ml->mntl_mnt->mnt_mountp)) >= mntpnt_len) { 1131 mntpnt = ml; 1132 mntpnt_len = tmp; 1133 } 1134 } 1135 1136 /* 1137 * If the path needs to be autoFS mounted, trigger the mount by 1138 * stat()ing it. This is determined by checking whether the 1139 * mountpoint we just found is of type autofs. 1140 */ 1141 if (mntpnt != NULL && 1142 strcmp(mntpnt->mntl_mnt->mnt_fstype, "autofs") == 0) { 1143 /* 1144 * The requested path is a substring of an autoFS filesystem. 1145 * Trigger the mount. 1146 */ 1147 if (stat(rpath, &r_stbuf) < 0) { 1148 if (verbose) 1149 syslog(LOG_NOTICE, "%s: %m", rpath); 1150 goto done; 1151 } 1152 if ((r_stbuf.st_mode & S_IFMT) == S_IFDIR) { 1153 /* 1154 * The requested path is a directory, stat(2) it 1155 * again with a trailing '.' to force the autoFS 1156 * module to trigger the mount of indirect 1157 * automount entries, such as /net/jurassic/. 1158 */ 1159 if (strlen(rpath) + 2 > MAXPATHLEN) { 1160 if (verbose) { 1161 syslog(LOG_NOTICE, 1162 "%s/.: exceeds MAXPATHLEN %d", 1163 rpath, MAXPATHLEN); 1164 } 1165 goto done; 1166 } 1167 (void) strcpy(tmp_path, rpath); 1168 (void) strcat(tmp_path, "/."); 1169 1170 if (stat(tmp_path, &r_stbuf) < 0) { 1171 if (verbose) 1172 syslog(LOG_NOTICE, "%s: %m", tmp_path); 1173 goto done; 1174 } 1175 } 1176 /* 1177 * The mount has been triggered, re-read mnttab to pick up 1178 * the changes made by autoFS. 1179 */ 1180 fsfreemntlist(mntl); 1181 (void) mutex_lock(&mnttab_lock); 1182 mntl = fsgetmntlist(); 1183 (void) mutex_unlock(&mnttab_lock); 1184 } 1185 1186 /* 1187 * The autoFS mountpoint has been triggered if necessary, 1188 * now search mnttab again to determine if the requested path 1189 * is an LOFS mount of a shared path. 1190 */ 1191 mntpnt_len = 0; 1192 for (ml = mntl; ml; ml = ml->mntl_next) { 1193 if (strcmp(ml->mntl_mnt->mnt_fstype, "lofs")) 1194 continue; 1195 1196 for (p1 = ml->mntl_mnt->mnt_mountp, p2 = rpath; 1197 *p1 == *p2 && *p1; p1++, p2++); 1198 1199 if (is_substring(&p1, &p2) && 1200 ((tmp = strlen(ml->mntl_mnt->mnt_mountp)) >= mntpnt_len)) { 1201 mntpnt_len = tmp; 1202 1203 if ((strlen(ml->mntl_mnt->mnt_special) + strlen(p2)) > 1204 MAXPATHLEN) { 1205 if (verbose) { 1206 syslog(LOG_NOTICE, "%s%s: exceeds %d", 1207 ml->mntl_mnt->mnt_special, p2, 1208 MAXPATHLEN); 1209 } 1210 if (retcode) 1211 sharefree(retcode); 1212 retcode = NULL; 1213 goto done; 1214 } 1215 1216 (void) strcpy(tmp_path, ml->mntl_mnt->mnt_special); 1217 (void) strcat(tmp_path, p2); 1218 if (retcode) 1219 sharefree(retcode); 1220 retcode = findentry(tmp_path); 1221 } 1222 } 1223 1224 if (retcode) { 1225 assert(strlen(tmp_path) > 0); 1226 (void) strcpy(rpath, tmp_path); 1227 } 1228 1229 done: 1230 fsfreemntlist(mntl); 1231 return (retcode); 1232 } 1233 1234 /* 1235 * Determine whether an access list grants rights to a particular host. 1236 * We match on aliases of the hostname as well as on the canonical name. 1237 * Names in the access list may be either hosts or netgroups; they're 1238 * not distinguished syntactically. We check for hosts first because 1239 * it's cheaper (just M*N strcmp()s), then try netgroups. 1240 */ 1241 int 1242 in_access_list(struct netbuf *nb, struct nd_hostservlist *clnames, 1243 char *access_list) /* N.B. we clobber this "input" parameter */ 1244 { 1245 int nentries; 1246 char *gr; 1247 char *lasts; 1248 char *host; 1249 int off; 1250 int i; 1251 int netgroup_match; 1252 int response; 1253 1254 /* 1255 * If no access list - then it's unrestricted 1256 */ 1257 if (access_list == NULL || *access_list == '\0') 1258 return (1); 1259 1260 nentries = 0; 1261 1262 for (gr = strtok_r(access_list, ":", &lasts); 1263 gr != NULL; gr = strtok_r(NULL, ":", &lasts)) { 1264 1265 /* 1266 * If the list name has a '-' prepended 1267 * then a match of the following name 1268 * implies failure instead of success. 1269 */ 1270 if (*gr == '-') { 1271 response = 0; 1272 gr++; 1273 } else 1274 response = 1; 1275 1276 /* 1277 * The following loops through all the 1278 * client's aliases. Usually it's just one name. 1279 */ 1280 for (i = 0; i < clnames->h_cnt; i++) { 1281 host = clnames->h_hostservs[i].h_host; 1282 1283 /* 1284 * If the list name begins with a dot then 1285 * do a domain name suffix comparison. 1286 * A single dot matches any name with no 1287 * suffix. 1288 */ 1289 if (*gr == '.') { 1290 if (*(gr + 1) == '\0') { /* single dot */ 1291 if (strchr(host, '.') == NULL) 1292 return (response); 1293 } else { 1294 off = strlen(host) - strlen(gr); 1295 if (off > 0 && 1296 strcasecmp(host + off, gr) == 0) { 1297 return (response); 1298 } 1299 } 1300 } else 1301 1302 /* 1303 * If the list name begins with an at 1304 * sign then do a network comparison. 1305 */ 1306 if (*gr == '@') { 1307 if (netmatch(nb, gr + 1)) 1308 return (response); 1309 } else 1310 1311 /* 1312 * Just do a hostname match 1313 */ 1314 if (strcasecmp(gr, host) == 0) { 1315 return (response); /* Matched a hostname */ 1316 } 1317 } 1318 1319 nentries++; 1320 } 1321 1322 netgroup_match = netgroup_check(clnames, access_list, nentries); 1323 1324 return (netgroup_match); 1325 } 1326 1327 1328 int 1329 netmatch(struct netbuf *nb, char *name) 1330 { 1331 uint_t claddr; 1332 struct netent n, *np; 1333 char *mp, *p; 1334 uint_t addr, mask; 1335 int i, bits; 1336 char buff[256]; 1337 1338 /* 1339 * Check if it's an IPv4 addr 1340 */ 1341 if (nb->len != sizeof (struct sockaddr_in)) 1342 return (0); 1343 1344 (void) memcpy(&claddr, 1345 /* LINTED pointer alignment */ 1346 &((struct sockaddr_in *)nb->buf)->sin_addr.s_addr, 1347 sizeof (struct in_addr)); 1348 claddr = ntohl(claddr); 1349 1350 mp = strchr(name, '/'); 1351 if (mp) 1352 *mp++ = '\0'; 1353 1354 if (isdigit(*name)) { 1355 /* 1356 * Convert a dotted IP address 1357 * to an IP address. The conversion 1358 * is not the same as that in inet_addr(). 1359 */ 1360 p = name; 1361 addr = 0; 1362 for (i = 0; i < 4; i++) { 1363 addr |= atoi(p) << ((3-i) * 8); 1364 p = strchr(p, '.'); 1365 if (p == NULL) 1366 break; 1367 p++; 1368 } 1369 } else { 1370 /* 1371 * Turn the netname into 1372 * an IP address. 1373 */ 1374 np = getnetbyname_r(name, &n, buff, sizeof (buff)); 1375 if (np == NULL) { 1376 syslog(LOG_DEBUG, "getnetbyname_r: %s: %m", name); 1377 return (0); 1378 } 1379 addr = np->n_net; 1380 } 1381 1382 /* 1383 * If the mask is specified explicitly then 1384 * use that value, e.g. 1385 * 1386 * @109.104.56/28 1387 * 1388 * otherwise assume a mask from the zero octets 1389 * in the least significant bits of the address, e.g. 1390 * 1391 * @109.104 or @109.104.0.0 1392 */ 1393 if (mp) { 1394 bits = atoi(mp); 1395 mask = bits ? ~0 << ((sizeof (struct in_addr) * NBBY) - bits) 1396 : 0; 1397 addr &= mask; 1398 } else { 1399 if ((addr & 0x00ffffff) == 0) 1400 mask = 0xff000000; 1401 else if ((addr & 0x0000ffff) == 0) 1402 mask = 0xffff0000; 1403 else if ((addr & 0x000000ff) == 0) 1404 mask = 0xffffff00; 1405 } 1406 1407 return ((claddr & mask) == addr); 1408 } 1409 1410 1411 static char *optlist[] = { 1412 #define OPT_RO 0 1413 SHOPT_RO, 1414 #define OPT_RW 1 1415 SHOPT_RW, 1416 #define OPT_ROOT 2 1417 SHOPT_ROOT, 1418 #define OPT_SECURE 3 1419 SHOPT_SECURE, 1420 #define OPT_ANON 4 1421 SHOPT_ANON, 1422 #define OPT_WINDOW 5 1423 SHOPT_WINDOW, 1424 #define OPT_NOSUID 6 1425 SHOPT_NOSUID, 1426 #define OPT_ACLOK 7 1427 SHOPT_ACLOK, 1428 #define OPT_SEC 8 1429 SHOPT_SEC, 1430 NULL 1431 }; 1432 1433 static int 1434 map_flavor(char *str) 1435 { 1436 seconfig_t sec; 1437 1438 if (nfs_getseconfig_byname(str, &sec)) 1439 return (-1); 1440 1441 return (sec.sc_nfsnum); 1442 } 1443 1444 /* 1445 * If the option string contains a "sec=" 1446 * option, then use new option syntax. 1447 */ 1448 static int 1449 newopts(char *opts) 1450 { 1451 char *head, *p, *val; 1452 1453 if (!opts || *opts == '\0') 1454 return (0); 1455 1456 head = strdup(opts); 1457 if (head == NULL) { 1458 syslog(LOG_ERR, "opts: no memory"); 1459 return (0); 1460 } 1461 1462 p = head; 1463 while (*p) { 1464 if (getsubopt(&p, optlist, &val) == OPT_SEC) { 1465 free(head); 1466 return (1); 1467 } 1468 } 1469 1470 free(head); 1471 return (0); 1472 } 1473 1474 /* 1475 * Given an export and the clients hostname(s) 1476 * determine the security flavors that this 1477 * client is permitted to use. 1478 * 1479 * This routine is called only for "old" syntax, i.e. 1480 * only one security flavor is allowed. So we need 1481 * to determine two things: the particular flavor, 1482 * and whether the client is allowed to use this 1483 * flavor, i.e. is in the access list. 1484 * 1485 * Note that if there is no access list, then the 1486 * default is that access is granted. 1487 */ 1488 static int 1489 getclientsflavors_old(struct share *sh, struct netbuf *nb, 1490 struct nd_hostservlist *clnames, int *flavors) 1491 { 1492 char *opts, *p, *val; 1493 int ok = 0; 1494 int defaultaccess = 1; 1495 1496 opts = strdup(sh->sh_opts); 1497 if (opts == NULL) { 1498 syslog(LOG_ERR, "getclientsflavors: no memory"); 1499 return (0); 1500 } 1501 1502 flavors[0] = AUTH_SYS; 1503 p = opts; 1504 1505 while (*p) { 1506 1507 switch (getsubopt(&p, optlist, &val)) { 1508 case OPT_SECURE: 1509 flavors[0] = AUTH_DES; 1510 break; 1511 1512 case OPT_RO: 1513 case OPT_RW: 1514 defaultaccess = 0; 1515 if (in_access_list(nb, clnames, val)) 1516 ok++; 1517 break; 1518 } 1519 } 1520 1521 free(opts); 1522 1523 return (defaultaccess || ok); 1524 } 1525 1526 /* 1527 * Given an export and the clients hostname(s) 1528 * determine the security flavors that this 1529 * client is permitted to use. 1530 * 1531 * This is somewhat more complicated than the "old" 1532 * routine because the options may contain multiple 1533 * security flavors (sec=) each with its own access 1534 * lists. So a client could be granted access based 1535 * on a number of security flavors. Note that the 1536 * type of access might not always be the same, the 1537 * client may get readonly access with one flavor 1538 * and readwrite with another, however the client 1539 * is not told this detail, it gets only the list 1540 * of flavors, and only if the client is using 1541 * version 3 of the mount protocol. 1542 */ 1543 static int 1544 getclientsflavors_new(struct share *sh, struct netbuf *nb, 1545 struct nd_hostservlist *clnames, int *flavors) 1546 { 1547 char *opts, *p, *val; 1548 char *lasts; 1549 char *f; 1550 int access_ok, count, c; 1551 1552 opts = strdup(sh->sh_opts); 1553 if (opts == NULL) { 1554 syslog(LOG_ERR, "getclientsflavors: no memory"); 1555 return (0); 1556 } 1557 1558 p = opts; 1559 count = c = 0; 1560 /* default access is rw */ 1561 access_ok = 1; 1562 1563 while (*p) { 1564 switch (getsubopt(&p, optlist, &val)) { 1565 case OPT_SEC: 1566 /* 1567 * Before a new sec=xxx option, check if we need 1568 * to move the c index back to the previous count. 1569 */ 1570 if (!access_ok) { 1571 c = count; 1572 } 1573 1574 /* get all the sec=f1[:f2] flavors */ 1575 while ((f = strtok_r(val, ":", &lasts)) 1576 != NULL) { 1577 flavors[c++] = map_flavor(f); 1578 val = NULL; 1579 } 1580 /* for a new sec=xxx option, default is rw access */ 1581 access_ok = 1; 1582 break; 1583 1584 case OPT_RO: 1585 case OPT_RW: 1586 if (in_access_list(nb, clnames, val)) { 1587 count = c; 1588 access_ok = 1; 1589 } else { 1590 access_ok = 0; 1591 } 1592 break; 1593 } 1594 } 1595 1596 if (!access_ok) { 1597 c = count; 1598 } 1599 free(opts); 1600 1601 return (c); 1602 } 1603 1604 /* 1605 * This is a tricky piece of code that parses the 1606 * share options looking for a match on the auth 1607 * flavor that the client is using. If it finds 1608 * a match, then the client is given ro, rw, or 1609 * no access depending whether it is in the access 1610 * list. There is a special case for "secure" 1611 * flavor. Other flavors are values of the new "sec=" option. 1612 */ 1613 int 1614 check_client(struct share *sh, struct netbuf *nb, 1615 struct nd_hostservlist *clnames, int flavor) 1616 { 1617 if (newopts(sh->sh_opts)) 1618 return (check_client_new(sh, nb, clnames, flavor)); 1619 else 1620 return (check_client_old(sh, nb, clnames, flavor)); 1621 } 1622 1623 static int 1624 check_client_old(struct share *sh, struct netbuf *nb, 1625 struct nd_hostservlist *clnames, int flavor) 1626 { 1627 char *opts, *p, *val; 1628 int match; /* Set when a flavor is matched */ 1629 int perm = 0; /* Set when "ro", "rw" or "root" is matched */ 1630 int list = 0; /* Set when "ro", "rw" is found */ 1631 int ro_val = 0; /* Set if ro option is 'ro=' */ 1632 int rw_val = 0; /* Set if rw option is 'rw=' */ 1633 1634 opts = strdup(sh->sh_opts); 1635 if (opts == NULL) { 1636 syslog(LOG_ERR, "check_client: no memory"); 1637 return (0); 1638 } 1639 1640 p = opts; 1641 match = AUTH_UNIX; 1642 1643 while (*p) { 1644 switch (getsubopt(&p, optlist, &val)) { 1645 1646 case OPT_SECURE: 1647 match = AUTH_DES; 1648 break; 1649 1650 case OPT_RO: 1651 list++; 1652 if (val) ro_val++; 1653 if (in_access_list(nb, clnames, val)) 1654 perm |= NFSAUTH_RO; 1655 break; 1656 1657 case OPT_RW: 1658 list++; 1659 if (val) rw_val++; 1660 if (in_access_list(nb, clnames, val)) 1661 perm |= NFSAUTH_RW; 1662 break; 1663 1664 case OPT_ROOT: 1665 /* 1666 * Check if the client is in 1667 * the root list. Only valid 1668 * for AUTH_SYS. 1669 */ 1670 if (flavor != AUTH_SYS) 1671 break; 1672 1673 if (val == NULL || *val == '\0') 1674 break; 1675 1676 if (in_access_list(nb, clnames, val)) 1677 perm |= NFSAUTH_ROOT; 1678 break; 1679 } 1680 } 1681 1682 free(opts); 1683 1684 if (flavor != match) 1685 return (NFSAUTH_DENIED); 1686 1687 if (list) { 1688 /* 1689 * If the client doesn't match an "ro" or "rw" 1690 * list then set no access. 1691 */ 1692 if ((perm & (NFSAUTH_RO | NFSAUTH_RW)) == 0) 1693 perm |= NFSAUTH_DENIED; 1694 } else { 1695 /* 1696 * The client matched a flavor entry that 1697 * has no explicit "rw" or "ro" determination. 1698 * Default it to "rw". 1699 */ 1700 perm |= NFSAUTH_RW; 1701 } 1702 1703 1704 /* 1705 * The client may show up in both ro= and rw= 1706 * lists. If so, then turn off the RO access 1707 * bit leaving RW access. 1708 */ 1709 if (perm & NFSAUTH_RO && perm & NFSAUTH_RW) { 1710 /* 1711 * Logically cover all permutations of rw=,ro=. 1712 * In the case where, rw,ro=<host> we would like 1713 * to remove RW access for the host. In all other cases 1714 * RW wins the precedence battle. 1715 */ 1716 if (!rw_val && ro_val) { 1717 perm &= ~(NFSAUTH_RW); 1718 } else { 1719 perm &= ~(NFSAUTH_RO); 1720 } 1721 } 1722 1723 return (perm); 1724 } 1725 1726 /* 1727 * Check if the client has access by using a flavor different from 1728 * the given "flavor". If "flavor" is not in the flavor list, 1729 * return TRUE to indicate that this "flavor" is a wrong sec. 1730 */ 1731 static bool_t 1732 is_wrongsec(struct share *sh, struct netbuf *nb, 1733 struct nd_hostservlist *clnames, int flavor) 1734 { 1735 int flavor_list[MAX_FLAVORS]; 1736 int flavor_count, i; 1737 1738 /* get the flavor list that the client has access with */ 1739 flavor_count = getclientsflavors_new(sh, nb, clnames, flavor_list); 1740 1741 if (flavor_count == 0) 1742 return (FALSE); 1743 1744 /* 1745 * Check if the given "flavor" is in the flavor_list. 1746 */ 1747 for (i = 0; i < flavor_count; i++) { 1748 if (flavor == flavor_list[i]) 1749 return (FALSE); 1750 } 1751 1752 /* 1753 * If "flavor" is not in the flavor_list, return TRUE to indicate 1754 * that the client should have access by using a security flavor 1755 * different from this "flavor". 1756 */ 1757 return (TRUE); 1758 } 1759 1760 /* 1761 * Given an export and the client's hostname, we 1762 * check the security options to see whether the 1763 * client is allowed to use the given security flavor. 1764 * 1765 * The strategy is to proceed through the options looking 1766 * for a flavor match, then pay attention to the ro, rw, 1767 * and root options. 1768 * 1769 * Note that an entry may list several flavors in a 1770 * single entry, e.g. 1771 * 1772 * sec=krb5,rw=clnt1:clnt2,ro,sec=sys,ro 1773 * 1774 */ 1775 1776 static int 1777 check_client_new(struct share *sh, struct netbuf *nb, 1778 struct nd_hostservlist *clnames, int flavor) 1779 { 1780 char *opts, *p, *val; 1781 char *lasts; 1782 char *f; 1783 int match = 0; /* Set when a flavor is matched */ 1784 int perm = 0; /* Set when "ro", "rw" or "root" is matched */ 1785 int list = 0; /* Set when "ro", "rw" is found */ 1786 int ro_val = 0; /* Set if ro option is 'ro=' */ 1787 int rw_val = 0; /* Set if rw option is 'rw=' */ 1788 1789 opts = strdup(sh->sh_opts); 1790 if (opts == NULL) { 1791 syslog(LOG_ERR, "check_client: no memory"); 1792 return (0); 1793 } 1794 1795 p = opts; 1796 1797 while (*p) { 1798 switch (getsubopt(&p, optlist, &val)) { 1799 1800 case OPT_SEC: 1801 if (match) 1802 goto done; 1803 1804 while ((f = strtok_r(val, ":", &lasts)) 1805 != NULL) { 1806 if (flavor == map_flavor(f)) { 1807 match = 1; 1808 break; 1809 } 1810 val = NULL; 1811 } 1812 break; 1813 1814 case OPT_RO: 1815 if (!match) 1816 break; 1817 1818 list++; 1819 if (val) ro_val++; 1820 if (in_access_list(nb, clnames, val)) 1821 perm |= NFSAUTH_RO; 1822 break; 1823 1824 case OPT_RW: 1825 if (!match) 1826 break; 1827 1828 list++; 1829 if (val) rw_val++; 1830 if (in_access_list(nb, clnames, val)) 1831 perm |= NFSAUTH_RW; 1832 break; 1833 1834 case OPT_ROOT: 1835 /* 1836 * Check if the client is in 1837 * the root list. Only valid 1838 * for AUTH_SYS. 1839 */ 1840 if (flavor != AUTH_SYS) 1841 break; 1842 1843 if (!match) 1844 break; 1845 1846 if (val == NULL || *val == '\0') 1847 break; 1848 1849 if (in_access_list(nb, clnames, val)) 1850 perm |= NFSAUTH_ROOT; 1851 break; 1852 } 1853 } 1854 1855 done: 1856 /* 1857 * If no match then set the perm accordingly 1858 */ 1859 if (!match) 1860 return (NFSAUTH_DENIED); 1861 1862 if (list) { 1863 /* 1864 * If the client doesn't match an "ro" or "rw" list then 1865 * check if it may have access by using a different flavor. 1866 * If so, return NFSAUTH_WRONGSEC. 1867 * If not, return NFSAUTH_DENIED. 1868 */ 1869 if ((perm & (NFSAUTH_RO | NFSAUTH_RW)) == 0) { 1870 if (is_wrongsec(sh, nb, clnames, flavor)) 1871 perm |= NFSAUTH_WRONGSEC; 1872 else 1873 perm |= NFSAUTH_DENIED; 1874 } 1875 } else { 1876 /* 1877 * The client matched a flavor entry that 1878 * has no explicit "rw" or "ro" determination. 1879 * Make sure it defaults to "rw". 1880 */ 1881 perm |= NFSAUTH_RW; 1882 } 1883 1884 /* 1885 * The client may show up in both ro= and rw= 1886 * lists. If so, then turn off the RO access 1887 * bit leaving RW access. 1888 */ 1889 if (perm & NFSAUTH_RO && perm & NFSAUTH_RW) { 1890 /* 1891 * Logically cover all permutations of rw=,ro=. 1892 * In the case where, rw,ro=<host> we would like 1893 * to remove RW access for the host. In all other cases 1894 * RW wins the precedence battle. 1895 */ 1896 if (!rw_val && ro_val) { 1897 perm &= ~(NFSAUTH_RW); 1898 } else { 1899 perm &= ~(NFSAUTH_RO); 1900 } 1901 } 1902 1903 free(opts); 1904 1905 return (perm); 1906 } 1907 1908 void 1909 check_sharetab() 1910 { 1911 FILE *f; 1912 struct stat st; 1913 static timestruc_t last_sharetab_time; 1914 timestruc_t prev_sharetab_time; 1915 struct share *sh; 1916 struct sh_list *shp, *shp_prev; 1917 int res, c = 0; 1918 1919 /* 1920 * read in /etc/dfs/sharetab if it has changed 1921 */ 1922 1923 if (stat(SHARETAB, &st) != 0) { 1924 syslog(LOG_ERR, "Cannot stat %s: %m", SHARETAB); 1925 return; 1926 } 1927 1928 if (st.st_mtim.tv_sec == last_sharetab_time.tv_sec && 1929 st.st_mtim.tv_nsec == last_sharetab_time.tv_nsec) { 1930 /* 1931 * No change. 1932 */ 1933 return; 1934 } 1935 1936 /* 1937 * Remember the mod time, then after getting the 1938 * write lock check again. If another thread 1939 * already did the update, then there's no 1940 * work to do. 1941 */ 1942 prev_sharetab_time = last_sharetab_time; 1943 1944 (void) rw_wrlock(&sharetab_lock); 1945 1946 if (prev_sharetab_time.tv_sec != last_sharetab_time.tv_sec || 1947 prev_sharetab_time.tv_nsec != last_sharetab_time.tv_nsec) { 1948 (void) rw_unlock(&sharetab_lock); 1949 return; 1950 } 1951 1952 /* 1953 * Note that since the sharetab is now in memory 1954 * and a snapshot is taken, we no longer have to 1955 * lock the file. 1956 */ 1957 f = fopen(SHARETAB, "r"); 1958 if (f == NULL) { 1959 syslog(LOG_ERR, "Cannot open %s: %m", SHARETAB); 1960 (void) rw_unlock(&sharetab_lock); 1961 return; 1962 } 1963 1964 /* 1965 * Once we are sure /etc/dfs/sharetab has been 1966 * modified, flush netgroup cache entries. 1967 */ 1968 netgrp_cache_flush(); 1969 1970 sh_free(share_list); /* free old list */ 1971 share_list = NULL; 1972 1973 while ((res = getshare(f, &sh)) > 0) { 1974 c++; 1975 if (strcmp(sh->sh_fstype, "nfs") != 0) 1976 continue; 1977 1978 shp = malloc(sizeof (*shp)); 1979 if (shp == NULL) 1980 goto alloc_failed; 1981 if (share_list == NULL) 1982 share_list = shp; 1983 else 1984 /* LINTED not used before set */ 1985 shp_prev->shl_next = shp; 1986 shp_prev = shp; 1987 shp->shl_next = NULL; 1988 shp->shl_sh = sharedup(sh); 1989 if (shp->shl_sh == NULL) 1990 goto alloc_failed; 1991 } 1992 if (res < 0) 1993 syslog(LOG_ERR, "%s: invalid at line %d\n", 1994 SHARETAB, c + 1); 1995 1996 if (stat(SHARETAB, &st) != 0) { 1997 syslog(LOG_ERR, "Cannot stat %s: %m", SHARETAB); 1998 (void) fclose(f); 1999 (void) rw_unlock(&sharetab_lock); 2000 return; 2001 } 2002 last_sharetab_time = st.st_mtim; 2003 (void) fclose(f); 2004 (void) rw_unlock(&sharetab_lock); 2005 return; 2006 2007 alloc_failed: 2008 syslog(LOG_ERR, "check_sharetab: no memory"); 2009 sh_free(share_list); 2010 share_list = NULL; 2011 (void) fclose(f); 2012 (void) rw_unlock(&sharetab_lock); 2013 } 2014 2015 static void 2016 sh_free(struct sh_list *shp) 2017 { 2018 register struct sh_list *next; 2019 2020 while (shp) { 2021 sharefree(shp->shl_sh); 2022 next = shp->shl_next; 2023 free(shp); 2024 shp = next; 2025 } 2026 } 2027 2028 2029 /* 2030 * Remove an entry from mounted list 2031 */ 2032 static void 2033 umount(struct svc_req *rqstp) 2034 { 2035 char *host, *path, *remove_path; 2036 char rpath[MAXPATHLEN]; 2037 struct nd_hostservlist *clnames = NULL; 2038 SVCXPRT *transp; 2039 struct netbuf *nb; 2040 2041 transp = rqstp->rq_xprt; 2042 path = NULL; 2043 if (!svc_getargs(transp, xdr_dirpath, (caddr_t)&path)) { 2044 svcerr_decode(transp); 2045 return; 2046 } 2047 errno = 0; 2048 if (!svc_sendreply(transp, xdr_void, (char *)NULL)) 2049 log_cant_reply(transp); 2050 2051 getclientsnames(transp, &nb, &clnames); 2052 if (clnames == NULL) { 2053 /* 2054 * Without the hostname we can't do audit or delete 2055 * this host from the mount entries. 2056 */ 2057 svc_freeargs(transp, xdr_dirpath, (caddr_t)&path); 2058 return; 2059 } 2060 host = clnames->h_hostservs[0].h_host; 2061 2062 if (verbose) 2063 syslog(LOG_NOTICE, "UNMOUNT: %s unmounted %s", host, path); 2064 2065 audit_mountd_umount(host, path); 2066 2067 remove_path = rpath; /* assume we will use the cannonical path */ 2068 if (realpath(path, rpath) == NULL) { 2069 if (verbose) 2070 syslog(LOG_WARNING, "UNMOUNT: realpath: %s: %m ", path); 2071 remove_path = path; /* use path provided instead */ 2072 } 2073 2074 mntlist_delete(host, remove_path); /* remove from mount list */ 2075 2076 svc_freeargs(transp, xdr_dirpath, (caddr_t)&path); 2077 netdir_free(clnames, ND_HOSTSERVLIST); 2078 } 2079 2080 /* 2081 * Remove all entries for one machine from mounted list 2082 */ 2083 static void 2084 umountall(struct svc_req *rqstp) 2085 { 2086 struct nd_hostservlist *clnames = NULL; 2087 SVCXPRT *transp; 2088 char *host; 2089 struct netbuf *nb; 2090 2091 transp = rqstp->rq_xprt; 2092 if (!svc_getargs(transp, xdr_void, NULL)) { 2093 svcerr_decode(transp); 2094 return; 2095 } 2096 /* 2097 * We assume that this call is asynchronous and made via rpcbind 2098 * callit routine. Therefore return control immediately. The error 2099 * causes rpcbind to remain silent, as opposed to every machine 2100 * on the net blasting the requester with a response. 2101 */ 2102 svcerr_systemerr(transp); 2103 getclientsnames(transp, &nb, &clnames); 2104 if (clnames == NULL) { 2105 /* Can't do anything without the name of the client */ 2106 return; 2107 } 2108 2109 host = clnames->h_hostservs[0].h_host; 2110 2111 /* 2112 * Remove all hosts entries from mount list 2113 */ 2114 mntlist_delete_all(host); 2115 2116 if (verbose) 2117 syslog(LOG_NOTICE, "UNMOUNTALL: from %s", host); 2118 2119 netdir_free(clnames, ND_HOSTSERVLIST); 2120 } 2121 2122 void * 2123 exmalloc(size_t size) 2124 { 2125 void *ret; 2126 2127 if ((ret = malloc(size)) == NULL) { 2128 syslog(LOG_ERR, "Out of memory"); 2129 exit(1); 2130 } 2131 return (ret); 2132 } 2133 2134 static void 2135 sigexit(int signum) 2136 { 2137 2138 if (signum == SIGHUP) 2139 _exit(0); 2140 _exit(1); 2141 } 2142