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