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