1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 27 /* All Rights Reserved */ 28 29 /* 30 * Portions of this source code were derived from Berkeley 4.3 BSD 31 * under license from the Regents of the University of California. 32 */ 33 34 #pragma ident "%Z%%M% %I% %E% SMI" 35 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <ctype.h> 39 #include <sys/types.h> 40 #include <string.h> 41 #include <syslog.h> 42 #include <sys/param.h> 43 #include <rpc/rpc.h> 44 #include <sys/stat.h> 45 #include <netconfig.h> 46 #include <netdir.h> 47 #include <sys/file.h> 48 #include <sys/time.h> 49 #include <sys/errno.h> 50 #include <rpcsvc/mount.h> 51 #include <sys/pathconf.h> 52 #include <sys/systeminfo.h> 53 #include <sys/utsname.h> 54 #include <signal.h> 55 #include <locale.h> 56 #include <unistd.h> 57 #include <errno.h> 58 #include <sys/socket.h> 59 #include <netinet/in.h> 60 #include <arpa/inet.h> 61 #include <netdb.h> 62 #include <thread.h> 63 #include <assert.h> 64 #include <priv_utils.h> 65 #include <rpcsvc/nfsauth_prot.h> 66 #include <nfs/nfs.h> 67 #include <nfs/nfs_sec.h> 68 #include <rpcsvc/daemon_utils.h> 69 #include <deflt.h> 70 #include "../../fslib.h" 71 #include "../lib/sharetab.h" 72 #include "mountd.h" 73 74 struct sh_list *share_list; 75 76 rwlock_t sharetab_lock; /* lock to protect the cached sharetab */ 77 static mutex_t mnttab_lock; /* prevent concurrent mnttab readers */ 78 79 static struct share *find_lofsentry(char *, int *); 80 static void getclientsnames(SVCXPRT *, struct netbuf **, 81 struct nd_hostservlist **); 82 static int getclientsflavors_old(struct share *, struct netbuf *, 83 struct nd_hostservlist *, int *); 84 static int getclientsflavors_new(struct share *, struct netbuf *, 85 struct nd_hostservlist *, int *); 86 static int check_client_old(struct share *, struct netbuf *, 87 struct nd_hostservlist *, int); 88 static int check_client_new(struct share *, struct netbuf *, 89 struct nd_hostservlist *, int); 90 static int in_access_list(struct netbuf *, struct nd_hostservlist *, char *); 91 static void mnt(struct svc_req *, SVCXPRT *); 92 static void mnt_pathconf(struct svc_req *); 93 static void mount(struct svc_req *r); 94 static void sh_free(struct sh_list *); 95 static void umount(struct svc_req *); 96 static void umountall(struct svc_req *); 97 static int netmatch(struct netbuf *, char *); 98 static void sigexit(int); 99 static int newopts(char *); 100 101 static int verbose; 102 static int rejecting; 103 static int mount_vers_min = MOUNTVERS; 104 static int mount_vers_max = MOUNTVERS3; 105 106 int 107 main(int argc, char *argv[]) 108 { 109 int pid; 110 int c; 111 int rpc_svc_mode = RPC_SVC_MT_AUTO; 112 int maxthreads; 113 int maxrecsz = RPC_MAXDATASIZE; 114 bool_t exclbind = TRUE; 115 116 /* 117 * Mountd requires uid 0 for: 118 * /etc/rmtab updates (we could chown it to daemon) 119 * /etc/dfs/dfstab reading (it wants to lock out share which 120 * doesn't do any locking before first truncate; 121 * NFS share does; should use fcntl locking instead) 122 * Needed privileges: 123 * auditing 124 * nfs syscall 125 * file dac search (so it can stat all files) 126 */ 127 if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET, -1, -1, 128 PRIV_SYS_NFS, PRIV_PROC_AUDIT, PRIV_FILE_DAC_SEARCH, 129 (char *)NULL) == -1) { 130 (void) fprintf(stderr, 131 "%s must be run as with sufficient privileges\n", 132 argv[0]); 133 exit(1); 134 } 135 136 maxthreads = 0; 137 138 while ((c = getopt(argc, argv, "vrm:")) != EOF) { 139 switch (c) { 140 case 'v': 141 verbose++; 142 break; 143 case 'r': 144 rejecting = 1; 145 break; 146 case 'm': 147 maxthreads = atoi(optarg); 148 if (maxthreads < 1) { 149 (void) fprintf(stderr, 150 "%s: must specify positive maximum threads count, using default\n", 151 argv[0]); 152 maxthreads = 0; 153 } 154 break; 155 } 156 } 157 158 /* 159 * Read in the NFS version values from config file. 160 */ 161 if ((defopen(NFSADMIN)) == 0) { 162 char *defval; 163 int defvers; 164 165 if ((defval = defread("NFS_SERVER_VERSMIN=")) != NULL) { 166 errno = 0; 167 defvers = strtol(defval, (char **)NULL, 10); 168 if (errno == 0) { 169 mount_vers_min = defvers; 170 /* 171 * special because NFSv2 is 172 * supported by mount v1 & v2 173 */ 174 if (defvers == NFS_VERSION) 175 mount_vers_min = MOUNTVERS; 176 } 177 } 178 if ((defval = defread("NFS_SERVER_VERSMAX=")) != NULL) { 179 errno = 0; 180 defvers = strtol(defval, (char **)NULL, 10); 181 if (errno == 0) { 182 mount_vers_max = defvers; 183 } 184 } 185 186 /* close defaults file */ 187 defopen(NULL); 188 } 189 190 /* 191 * Sanity check versions, 192 * even though we may get versions > MOUNTVERS3, we still need 193 * to start nfsauth service, so continue on regardless of values. 194 */ 195 if (mount_vers_min > mount_vers_max) { 196 syslog(LOG_NOTICE, "NFS_SERVER_VERSMIN > NFS_SERVER_VERSMAX"); 197 mount_vers_max = mount_vers_min; 198 } 199 (void) setlocale(LC_ALL, ""); 200 (void) rwlock_init(&sharetab_lock, USYNC_THREAD, NULL); 201 (void) mutex_init(&mnttab_lock, USYNC_THREAD, NULL); 202 netgroup_init(); 203 204 #if !defined(TEXT_DOMAIN) 205 #define TEXT_DOMAIN "SYS_TEST" 206 #endif 207 (void) textdomain(TEXT_DOMAIN); 208 209 /* Don't drop core if the NFS module isn't loaded. */ 210 (void) signal(SIGSYS, SIG_IGN); 211 212 (void) signal(SIGHUP, sigexit); 213 (void) signal(SIGCLD, sigexit); 214 215 switch (fork()) { 216 case 0: /* child */ 217 break; 218 case -1: 219 perror("mountd: can't fork"); 220 exit(1); 221 default: /* parent */ 222 for (;;) 223 (void) pause(); 224 /* NOTREACHED */ 225 } 226 227 (void) signal(SIGHUP, SIG_DFL); 228 (void) signal(SIGCLD, SIG_DFL); 229 230 /* 231 * If we coredump it'll be in /core 232 */ 233 if (chdir("/") < 0) 234 syslog(LOG_ERR, "chdir /: %m"); 235 236 /* 237 * Close existing file descriptors, open "/dev/null" as 238 * standard input, output, and error, and detach from 239 * controlling terminal. 240 */ 241 closefrom(0); 242 (void) open("/dev/null", O_RDONLY); 243 (void) open("/dev/null", O_WRONLY); 244 (void) dup(1); 245 (void) setsid(); 246 247 openlog("mountd", LOG_PID, LOG_DAEMON); 248 249 /* 250 * establish our lock on the lock file and write our pid to it. 251 * exit if some other process holds the lock, or if there's any 252 * error in writing/locking the file. 253 */ 254 pid = _enter_daemon_lock(MOUNTD); 255 switch (pid) { 256 case 0: 257 break; 258 case -1: 259 syslog(LOG_ERR, "error locking for %s: %s", MOUNTD, 260 strerror(errno)); 261 exit(2); 262 default: 263 /* daemon was already running */ 264 exit(0); 265 } 266 267 audit_mountd_setup(); /* BSM */ 268 269 /* 270 * Tell RPC that we want automatic thread mode. 271 * A new thread will be spawned for each request. 272 */ 273 if (!rpc_control(RPC_SVC_MTMODE_SET, &rpc_svc_mode)) { 274 syslog(LOG_ERR, "unable to set automatic MT mode"); 275 exit(1); 276 } 277 278 /* 279 * Enable non-blocking mode and maximum record size checks for 280 * connection oriented transports. 281 */ 282 if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrecsz)) { 283 syslog(LOG_INFO, "unable to set RPC max record size"); 284 } 285 286 /* 287 * Prevent our non-priv udp and tcp ports bound w/wildcard addr 288 * from being hijacked by a bind to a more specific addr. 289 */ 290 if (!rpc_control(__RPC_SVC_EXCLBIND_SET, &exclbind)) { 291 syslog(LOG_INFO, "warning: unable to set udp/tcp EXCLBIND"); 292 } 293 294 /* 295 * If the -m argument was specified, then set the 296 * maximum number of threads to the value specified. 297 */ 298 if (maxthreads > 0 && !rpc_control(RPC_SVC_THRMAX_SET, &maxthreads)) { 299 syslog(LOG_ERR, "unable to set maxthreads"); 300 exit(1); 301 } 302 303 /* 304 * Make sure to unregister any previous versions in case the 305 * user is reconfiguring the server in interesting ways. 306 */ 307 svc_unreg(NFSAUTH_PROG, NFSAUTH_VERS); 308 svc_unreg(MOUNTPROG, MOUNTVERS); 309 svc_unreg(MOUNTPROG, MOUNTVERS_POSIX); 310 svc_unreg(MOUNTPROG, MOUNTVERS3); 311 312 /* 313 * Create Authentication Service 314 */ 315 if (svc_create_local_service(nfsauth_prog, 316 NFSAUTH_PROG, NFSAUTH_VERS, "netpath", "nfsauth") == 0) { 317 syslog(LOG_ERR, "unable to create nfsauth service"); 318 exit(1); 319 } 320 321 /* 322 * Create datagram and connection oriented services 323 */ 324 if (mount_vers_max >= MOUNTVERS) { 325 if (svc_create(mnt, MOUNTPROG, MOUNTVERS, "datagram_v") == 0) { 326 syslog(LOG_ERR, 327 "couldn't register datagram_v MOUNTVERS"); 328 exit(1); 329 } 330 if (svc_create(mnt, MOUNTPROG, MOUNTVERS, "circuit_v") == 0) { 331 syslog(LOG_ERR, 332 "couldn't register circuit_v MOUNTVERS"); 333 exit(1); 334 } 335 } 336 if (mount_vers_max >= MOUNTVERS_POSIX) { 337 if (svc_create(mnt, MOUNTPROG, MOUNTVERS_POSIX, 338 "datagram_v") == 0) { 339 syslog(LOG_ERR, 340 "couldn't register datagram_v MOUNTVERS_POSIX"); 341 exit(1); 342 } 343 if (svc_create(mnt, MOUNTPROG, MOUNTVERS_POSIX, 344 "circuit_v") == 0) { 345 syslog(LOG_ERR, 346 "couldn't register circuit_v MOUNTVERS_POSIX"); 347 exit(1); 348 } 349 } 350 351 if (mount_vers_max >= MOUNTVERS3) { 352 if (svc_create(mnt, MOUNTPROG, MOUNTVERS3, "datagram_v") == 0) { 353 syslog(LOG_ERR, 354 "couldn't register datagram_v MOUNTVERS3"); 355 exit(1); 356 } 357 if (svc_create(mnt, MOUNTPROG, MOUNTVERS3, "circuit_v") == 0) { 358 syslog(LOG_ERR, 359 "couldn't register circuit_v MOUNTVERS3"); 360 exit(1); 361 } 362 } 363 364 /* 365 * Start serving 366 */ 367 rmtab_load(); 368 (void) kill(getppid(), SIGHUP); 369 370 /* Get rid of the most dangerous basic privileges. */ 371 __fini_daemon_priv(PRIV_PROC_EXEC, PRIV_PROC_INFO, PRIV_PROC_SESSION, 372 (char *)NULL); 373 374 svc_run(); 375 syslog(LOG_ERR, "Error: svc_run shouldn't have returned"); 376 abort(); 377 /* NOTREACHED */ 378 return (0); 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, vers; 743 struct fhstatus fhs; 744 struct mountres3 mountres3; 745 char fh[FHSIZE3]; 746 int len = 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 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 * NFS V2 clients get a 32 byte filehandle. 835 * NFS V3 clients get a 32 or 64 byte filehandle, depending on 836 * the embedded FIDs. 837 */ 838 vers = (version == MOUNTVERS3) ? NFS_V3 : NFS_VERSION; 839 840 /* LINTED pointer alignment */ 841 while (nfs_getfh(rpath, vers, &len, fh) < 0) { 842 if (errno == EINVAL && 843 (sh = find_lofsentry(rpath, &lofs_tried)) != NULL) { 844 errno = 0; 845 continue; 846 } 847 error = errno == EINVAL ? EACCES : errno; 848 syslog(LOG_DEBUG, "mount request: getfh failed on %s: %m", 849 path); 850 break; 851 } 852 853 if (version == MOUNTVERS3) { 854 mountres3.mountres3_u.mountinfo.fhandle.fhandle3_len = len; 855 mountres3.mountres3_u.mountinfo.fhandle.fhandle3_val = fh; 856 } else { 857 bcopy(fh, &fhs.fhstatus_u.fhs_fhandle, NFS_FHSIZE); 858 } 859 860 reply: 861 switch (version) { 862 case MOUNTVERS: 863 case MOUNTVERS_POSIX: 864 if (error == EINVAL) 865 fhs.fhs_status = NFSERR_ACCES; 866 else if (error == EREMOTE) 867 fhs.fhs_status = NFSERR_REMOTE; 868 else 869 fhs.fhs_status = error; 870 if (!svc_sendreply(transp, xdr_fhstatus, (char *)&fhs)) 871 log_cant_reply(transp); 872 audit_mountd_mount(host, path, fhs.fhs_status); /* BSM */ 873 break; 874 875 case MOUNTVERS3: 876 if (!error) { 877 mountres3.mountres3_u.mountinfo.auth_flavors.auth_flavors_val = 878 flavor_list; 879 mountres3.mountres3_u.mountinfo.auth_flavors.auth_flavors_len = 880 flavor_count; 881 882 } else if (error == ENAMETOOLONG) 883 error = MNT3ERR_NAMETOOLONG; 884 885 mountres3.fhs_status = error; 886 if (!svc_sendreply(transp, xdr_mountres3, (char *)&mountres3)) 887 log_cant_reply(transp); 888 audit_mountd_mount(host, path, mountres3.fhs_status); /* BSM */ 889 890 break; 891 } 892 893 if (verbose) 894 syslog(LOG_NOTICE, "MOUNT: %s %s %s", 895 (host == NULL) ? "unknown host" : host, 896 error ? "denied" : "mounted", path); 897 898 if (path != NULL) 899 svc_freeargs(transp, xdr_dirpath, (caddr_t)&path); 900 901 if (!error) 902 mntlist_new(host, rpath); /* add entry to mount list */ 903 done: 904 if (sh) 905 sharefree(sh); 906 netdir_free(clnames, ND_HOSTSERVLIST); 907 } 908 909 struct share * 910 findentry(char *path) 911 { 912 struct share *sh = NULL; 913 struct sh_list *shp; 914 register char *p1, *p2; 915 struct stat st1; 916 struct stat64 st2; 917 918 check_sharetab(); 919 920 (void) rw_rdlock(&sharetab_lock); 921 922 for (shp = share_list; shp; shp = shp->shl_next) { 923 sh = shp->shl_sh; 924 for (p1 = sh->sh_path, p2 = path; *p1 == *p2; p1++, p2++) 925 if (*p1 == '\0') 926 goto done; /* exact match */ 927 928 /* 929 * Now compare the pathnames for three cases: 930 * 931 * Parent: /export/foo (no trailing slash on parent) 932 * Child: /export/foo/bar 933 * 934 * Parent: /export/foo/ (trailing slash on parent) 935 * Child: /export/foo/bar 936 * 937 * Parent: /export/foo/ (no trailing slash on child) 938 * Child: /export/foo 939 * 940 * Then compare the dev_t of the parent and child to 941 * make sure that they're both in the same filesystem. 942 */ 943 if ((*p1 == '\0' && *p2 == '/') || 944 (*p1 == '\0' && *(p1-1) == '/') || 945 (*p2 == '\0' && *p1 == '/' && *(p1+1) == '\0')) { 946 if (stat(sh->sh_path, &st1) < 0) { 947 if (verbose) 948 syslog(LOG_NOTICE, "%s: %m", p1); 949 shp = NULL; 950 goto done; 951 } 952 /* 953 * Use stat64 on "path" since it might be larger 954 * than 2 Gb and 32 bit stat would fail EOVERFLOW 955 */ 956 if (stat64(path, &st2) < 0) { 957 if (verbose) 958 syslog(LOG_NOTICE, "%s: %m", p2); 959 shp = NULL; 960 goto done; 961 } 962 if (st1.st_dev == st2.st_dev) 963 goto done; 964 } 965 } 966 done: 967 sh = shp ? sharedup(sh) : NULL; 968 969 (void) rw_unlock(&sharetab_lock); 970 971 return (sh); 972 } 973 974 975 static int 976 is_substring(char **mntp, char **path) 977 { 978 char *p1 = *mntp, *p2 = *path; 979 980 if (*p1 == '\0' && *p2 == '\0') /* exact match */ 981 return (1); 982 else if (*p1 == '\0' && *p2 == '/') 983 return (1); 984 else if (*p1 == '\0' && *(p1-1) == '/') { 985 *path = --p2; /* we need the slash in p2 */ 986 return (1); 987 } else if (*p2 == '\0') { 988 while (*p1 == '/') 989 p1++; 990 if (*p1 == '\0') /* exact match */ 991 return (1); 992 } 993 return (0); 994 } 995 996 /* 997 * find_lofsentry() searches for the real path which this requested LOFS path 998 * (rpath) shadows. If found, it will return the sharetab entry of 999 * the real path that corresponds to the LOFS path. 1000 * We first search mnttab to see if the requested path is an automounted 1001 * path. If it is an automounted path, it will trigger the mount by stat()ing 1002 * the requested path. Note that it is important to check that this path is 1003 * actually an automounted path, otherwise we would stat() a path which may 1004 * turn out to be NFS and block indefinitely on a dead server. The automounter 1005 * times-out if the server is dead, so there's no risk of hanging this 1006 * thread waiting for stat(). 1007 * After the mount has been triggered (if necessary), we look for a 1008 * mountpoint of type LOFS (by searching /etc/mnttab again) which 1009 * is a substring of the rpath. If found, we construct a new path by 1010 * concatenating the mnt_special and the remaining of rpath, call findentry() 1011 * to make sure the 'real path' is shared. 1012 */ 1013 static struct share * 1014 find_lofsentry(char *rpath, int *done_flag) 1015 { 1016 struct stat r_stbuf; 1017 mntlist_t *ml, *mntl, *mntpnt = NULL; 1018 struct share *retcode = NULL; 1019 char tmp_path[MAXPATHLEN]; 1020 int mntpnt_len = 0, tmp; 1021 char *p1, *p2; 1022 1023 if ((*done_flag)++) 1024 return (retcode); 1025 1026 /* 1027 * While fsgetmntlist() uses lockf() to 1028 * lock the mnttab before reading it in, 1029 * the lock ignores threads in the same process. 1030 * Read in the mnttab with the protection of a mutex. 1031 */ 1032 (void) mutex_lock(&mnttab_lock); 1033 mntl = fsgetmntlist(); 1034 (void) mutex_unlock(&mnttab_lock); 1035 1036 /* 1037 * Obtain the mountpoint for the requested path. 1038 */ 1039 for (ml = mntl; ml; ml = ml->mntl_next) { 1040 for (p1 = ml->mntl_mnt->mnt_mountp, p2 = rpath; 1041 *p1 == *p2 && *p1; p1++, p2++); 1042 if (is_substring(&p1, &p2) && 1043 (tmp = strlen(ml->mntl_mnt->mnt_mountp)) >= mntpnt_len) { 1044 mntpnt = ml; 1045 mntpnt_len = tmp; 1046 } 1047 } 1048 1049 /* 1050 * If the path needs to be autoFS mounted, trigger the mount by 1051 * stat()ing it. This is determined by checking whether the 1052 * mountpoint we just found is of type autofs. 1053 */ 1054 if (mntpnt != NULL && 1055 strcmp(mntpnt->mntl_mnt->mnt_fstype, "autofs") == 0) { 1056 /* 1057 * The requested path is a substring of an autoFS filesystem. 1058 * Trigger the mount. 1059 */ 1060 if (stat(rpath, &r_stbuf) < 0) { 1061 if (verbose) 1062 syslog(LOG_NOTICE, "%s: %m", rpath); 1063 goto done; 1064 } 1065 if ((r_stbuf.st_mode & S_IFMT) == S_IFDIR) { 1066 /* 1067 * The requested path is a directory, stat(2) it 1068 * again with a trailing '.' to force the autoFS 1069 * module to trigger the mount of indirect 1070 * automount entries, such as /net/jurassic/. 1071 */ 1072 if (strlen(rpath) + 2 > MAXPATHLEN) { 1073 if (verbose) { 1074 syslog(LOG_NOTICE, 1075 "%s/.: exceeds MAXPATHLEN %d", 1076 rpath, MAXPATHLEN); 1077 } 1078 goto done; 1079 } 1080 (void) strcpy(tmp_path, rpath); 1081 (void) strcat(tmp_path, "/."); 1082 1083 if (stat(tmp_path, &r_stbuf) < 0) { 1084 if (verbose) 1085 syslog(LOG_NOTICE, "%s: %m", tmp_path); 1086 goto done; 1087 } 1088 } 1089 /* 1090 * The mount has been triggered, re-read mnttab to pick up 1091 * the changes made by autoFS. 1092 */ 1093 fsfreemntlist(mntl); 1094 (void) mutex_lock(&mnttab_lock); 1095 mntl = fsgetmntlist(); 1096 (void) mutex_unlock(&mnttab_lock); 1097 } 1098 1099 /* 1100 * The autoFS mountpoint has been triggered if necessary, 1101 * now search mnttab again to determine if the requested path 1102 * is an LOFS mount of a shared path. 1103 */ 1104 mntpnt_len = 0; 1105 for (ml = mntl; ml; ml = ml->mntl_next) { 1106 if (strcmp(ml->mntl_mnt->mnt_fstype, "lofs")) 1107 continue; 1108 1109 for (p1 = ml->mntl_mnt->mnt_mountp, p2 = rpath; 1110 *p1 == *p2 && *p1; p1++, p2++); 1111 1112 if (is_substring(&p1, &p2) && 1113 ((tmp = strlen(ml->mntl_mnt->mnt_mountp)) >= mntpnt_len)) { 1114 mntpnt_len = tmp; 1115 1116 if ((strlen(ml->mntl_mnt->mnt_special) + strlen(p2)) > 1117 MAXPATHLEN) { 1118 if (verbose) { 1119 syslog(LOG_NOTICE, "%s%s: exceeds %d", 1120 ml->mntl_mnt->mnt_special, p2, 1121 MAXPATHLEN); 1122 } 1123 if (retcode) 1124 sharefree(retcode); 1125 retcode = NULL; 1126 goto done; 1127 } 1128 1129 (void) strcpy(tmp_path, ml->mntl_mnt->mnt_special); 1130 (void) strcat(tmp_path, p2); 1131 if (retcode) 1132 sharefree(retcode); 1133 retcode = findentry(tmp_path); 1134 } 1135 } 1136 1137 if (retcode) { 1138 assert(strlen(tmp_path) > 0); 1139 (void) strcpy(rpath, tmp_path); 1140 } 1141 1142 done: 1143 fsfreemntlist(mntl); 1144 return (retcode); 1145 } 1146 1147 /* 1148 * Determine whether an access list grants rights to a particular host. 1149 * We match on aliases of the hostname as well as on the canonical name. 1150 * Names in the access list may be either hosts or netgroups; they're 1151 * not distinguished syntactically. We check for hosts first because 1152 * it's cheaper (just M*N strcmp()s), then try netgroups. 1153 */ 1154 int 1155 in_access_list(struct netbuf *nb, struct nd_hostservlist *clnames, 1156 char *access_list) /* N.B. we clobber this "input" parameter */ 1157 { 1158 int nentries; 1159 char *gr; 1160 char *lasts; 1161 char *host; 1162 int off; 1163 int i; 1164 int netgroup_match; 1165 int response; 1166 1167 /* 1168 * If no access list - then it's unrestricted 1169 */ 1170 if (access_list == NULL || *access_list == '\0') 1171 return (1); 1172 1173 nentries = 0; 1174 1175 for (gr = strtok_r(access_list, ":", &lasts); 1176 gr != NULL; gr = strtok_r(NULL, ":", &lasts)) { 1177 1178 /* 1179 * If the list name has a '-' prepended 1180 * then a match of the following name 1181 * implies failure instead of success. 1182 */ 1183 if (*gr == '-') { 1184 response = 0; 1185 gr++; 1186 } else 1187 response = 1; 1188 1189 /* 1190 * The following loops through all the 1191 * client's aliases. Usually it's just one name. 1192 */ 1193 for (i = 0; i < clnames->h_cnt; i++) { 1194 host = clnames->h_hostservs[i].h_host; 1195 1196 /* 1197 * If the list name begins with a dot then 1198 * do a domain name suffix comparison. 1199 * A single dot matches any name with no 1200 * suffix. 1201 */ 1202 if (*gr == '.') { 1203 if (*(gr + 1) == '\0') { /* single dot */ 1204 if (strchr(host, '.') == NULL) 1205 return (response); 1206 } else { 1207 off = strlen(host) - strlen(gr); 1208 if (off > 0 && 1209 strcasecmp(host + off, gr) == 0) { 1210 return (response); 1211 } 1212 } 1213 } else 1214 1215 /* 1216 * If the list name begins with an at 1217 * sign then do a network comparison. 1218 */ 1219 if (*gr == '@') { 1220 if (netmatch(nb, gr + 1)) 1221 return (response); 1222 } else 1223 1224 /* 1225 * Just do a hostname match 1226 */ 1227 if (strcasecmp(gr, host) == 0) { 1228 return (response); /* Matched a hostname */ 1229 } 1230 } 1231 1232 nentries++; 1233 } 1234 1235 netgroup_match = netgroup_check(clnames, access_list, nentries); 1236 1237 return (netgroup_match); 1238 } 1239 1240 1241 int 1242 netmatch(struct netbuf *nb, char *name) 1243 { 1244 uint_t claddr; 1245 struct netent n, *np; 1246 char *mp, *p; 1247 uint_t addr, mask; 1248 int i, bits; 1249 char buff[256]; 1250 1251 /* 1252 * Check if it's an IPv4 addr 1253 */ 1254 if (nb->len != sizeof (struct sockaddr_in)) 1255 return (0); 1256 1257 (void) memcpy(&claddr, 1258 /* LINTED pointer alignment */ 1259 &((struct sockaddr_in *)nb->buf)->sin_addr.s_addr, 1260 sizeof (struct in_addr)); 1261 claddr = ntohl(claddr); 1262 1263 mp = strchr(name, '/'); 1264 if (mp) 1265 *mp++ = '\0'; 1266 1267 if (isdigit(*name)) { 1268 /* 1269 * Convert a dotted IP address 1270 * to an IP address. The conversion 1271 * is not the same as that in inet_addr(). 1272 */ 1273 p = name; 1274 addr = 0; 1275 for (i = 0; i < 4; i++) { 1276 addr |= atoi(p) << ((3-i) * 8); 1277 p = strchr(p, '.'); 1278 if (p == NULL) 1279 break; 1280 p++; 1281 } 1282 } else { 1283 /* 1284 * Turn the netname into 1285 * an IP address. 1286 */ 1287 np = getnetbyname_r(name, &n, buff, sizeof (buff)); 1288 if (np == NULL) { 1289 syslog(LOG_DEBUG, "getnetbyname_r: %s: %m", name); 1290 return (0); 1291 } 1292 addr = np->n_net; 1293 } 1294 1295 /* 1296 * If the mask is specified explicitly then 1297 * use that value, e.g. 1298 * 1299 * @109.104.56/28 1300 * 1301 * otherwise assume a mask from the zero octets 1302 * in the least significant bits of the address, e.g. 1303 * 1304 * @109.104 or @109.104.0.0 1305 */ 1306 if (mp) { 1307 bits = atoi(mp); 1308 mask = bits ? ~0 << ((sizeof (struct in_addr) * NBBY) - bits) 1309 : 0; 1310 addr &= mask; 1311 } else { 1312 if ((addr & 0x00ffffff) == 0) 1313 mask = 0xff000000; 1314 else if ((addr & 0x0000ffff) == 0) 1315 mask = 0xffff0000; 1316 else if ((addr & 0x000000ff) == 0) 1317 mask = 0xffffff00; 1318 } 1319 1320 return ((claddr & mask) == addr); 1321 } 1322 1323 1324 static char *optlist[] = { 1325 #define OPT_RO 0 1326 SHOPT_RO, 1327 #define OPT_RW 1 1328 SHOPT_RW, 1329 #define OPT_ROOT 2 1330 SHOPT_ROOT, 1331 #define OPT_SECURE 3 1332 SHOPT_SECURE, 1333 #define OPT_ANON 4 1334 SHOPT_ANON, 1335 #define OPT_WINDOW 5 1336 SHOPT_WINDOW, 1337 #define OPT_NOSUID 6 1338 SHOPT_NOSUID, 1339 #define OPT_ACLOK 7 1340 SHOPT_ACLOK, 1341 #define OPT_SEC 8 1342 SHOPT_SEC, 1343 NULL 1344 }; 1345 1346 static int 1347 map_flavor(char *str) 1348 { 1349 seconfig_t sec; 1350 1351 if (nfs_getseconfig_byname(str, &sec)) 1352 return (-1); 1353 1354 return (sec.sc_nfsnum); 1355 } 1356 1357 /* 1358 * If the option string contains a "sec=" 1359 * option, then use new option syntax. 1360 */ 1361 static int 1362 newopts(char *opts) 1363 { 1364 char *head, *p, *val; 1365 1366 if (!opts || *opts == '\0') 1367 return (0); 1368 1369 head = strdup(opts); 1370 if (head == NULL) { 1371 syslog(LOG_ERR, "opts: no memory"); 1372 return (0); 1373 } 1374 1375 p = head; 1376 while (*p) { 1377 if (getsubopt(&p, optlist, &val) == OPT_SEC) { 1378 free(head); 1379 return (1); 1380 } 1381 } 1382 1383 free(head); 1384 return (0); 1385 } 1386 1387 /* 1388 * Given an export and the clients hostname(s) 1389 * determine the security flavors that this 1390 * client is permitted to use. 1391 * 1392 * This routine is called only for "old" syntax, i.e. 1393 * only one security flavor is allowed. So we need 1394 * to determine two things: the particular flavor, 1395 * and whether the client is allowed to use this 1396 * flavor, i.e. is in the access list. 1397 * 1398 * Note that if there is no access list, then the 1399 * default is that access is granted. 1400 */ 1401 static int 1402 getclientsflavors_old(struct share *sh, struct netbuf *nb, 1403 struct nd_hostservlist *clnames, int *flavors) 1404 { 1405 char *opts, *p, *val; 1406 int ok = 0; 1407 int defaultaccess = 1; 1408 1409 opts = strdup(sh->sh_opts); 1410 if (opts == NULL) { 1411 syslog(LOG_ERR, "getclientsflavors: no memory"); 1412 return (0); 1413 } 1414 1415 flavors[0] = AUTH_SYS; 1416 p = opts; 1417 1418 while (*p) { 1419 1420 switch (getsubopt(&p, optlist, &val)) { 1421 case OPT_SECURE: 1422 flavors[0] = AUTH_DES; 1423 break; 1424 1425 case OPT_RO: 1426 case OPT_RW: 1427 defaultaccess = 0; 1428 if (in_access_list(nb, clnames, val)) 1429 ok++; 1430 break; 1431 } 1432 } 1433 1434 free(opts); 1435 1436 return (defaultaccess || ok); 1437 } 1438 1439 /* 1440 * Given an export and the clients hostname(s) 1441 * determine the security flavors that this 1442 * client is permitted to use. 1443 * 1444 * This is somewhat more complicated than the "old" 1445 * routine because the options may contain multiple 1446 * security flavors (sec=) each with its own access 1447 * lists. So a client could be granted access based 1448 * on a number of security flavors. Note that the 1449 * type of access might not always be the same, the 1450 * client may get readonly access with one flavor 1451 * and readwrite with another, however the client 1452 * is not told this detail, it gets only the list 1453 * of flavors, and only if the client is using 1454 * version 3 of the mount protocol. 1455 */ 1456 static int 1457 getclientsflavors_new(struct share *sh, struct netbuf *nb, 1458 struct nd_hostservlist *clnames, int *flavors) 1459 { 1460 char *opts, *p, *val; 1461 char *lasts; 1462 char *f; 1463 int access_ok, count, c; 1464 1465 opts = strdup(sh->sh_opts); 1466 if (opts == NULL) { 1467 syslog(LOG_ERR, "getclientsflavors: no memory"); 1468 return (0); 1469 } 1470 1471 p = opts; 1472 count = c = 0; 1473 /* default access is rw */ 1474 access_ok = 1; 1475 1476 while (*p) { 1477 switch (getsubopt(&p, optlist, &val)) { 1478 case OPT_SEC: 1479 /* 1480 * Before a new sec=xxx option, check if we need 1481 * to move the c index back to the previous count. 1482 */ 1483 if (!access_ok) { 1484 c = count; 1485 } 1486 1487 /* get all the sec=f1[:f2] flavors */ 1488 while ((f = strtok_r(val, ":", &lasts)) 1489 != NULL) { 1490 flavors[c++] = map_flavor(f); 1491 val = NULL; 1492 } 1493 /* for a new sec=xxx option, default is rw access */ 1494 access_ok = 1; 1495 break; 1496 1497 case OPT_RO: 1498 case OPT_RW: 1499 if (in_access_list(nb, clnames, val)) { 1500 count = c; 1501 access_ok = 1; 1502 } else { 1503 access_ok = 0; 1504 } 1505 break; 1506 } 1507 } 1508 1509 if (!access_ok) { 1510 c = count; 1511 } 1512 free(opts); 1513 1514 return (c); 1515 } 1516 1517 /* 1518 * This is a tricky piece of code that parses the 1519 * share options looking for a match on the auth 1520 * flavor that the client is using. If it finds 1521 * a match, then the client is given ro, rw, or 1522 * no access depending whether it is in the access 1523 * list. There is a special case for "secure" 1524 * flavor. Other flavors are values of the new "sec=" option. 1525 */ 1526 int 1527 check_client(struct share *sh, struct netbuf *nb, 1528 struct nd_hostservlist *clnames, int flavor) 1529 { 1530 if (newopts(sh->sh_opts)) 1531 return (check_client_new(sh, nb, clnames, flavor)); 1532 else 1533 return (check_client_old(sh, nb, clnames, flavor)); 1534 } 1535 1536 static int 1537 check_client_old(struct share *sh, struct netbuf *nb, 1538 struct nd_hostservlist *clnames, int flavor) 1539 { 1540 char *opts, *p, *val; 1541 int match; /* Set when a flavor is matched */ 1542 int perm = 0; /* Set when "ro", "rw" or "root" is matched */ 1543 int list = 0; /* Set when "ro", "rw" is found */ 1544 int ro_val = 0; /* Set if ro option is 'ro=' */ 1545 int rw_val = 0; /* Set if rw option is 'rw=' */ 1546 1547 opts = strdup(sh->sh_opts); 1548 if (opts == NULL) { 1549 syslog(LOG_ERR, "check_client: no memory"); 1550 return (0); 1551 } 1552 1553 p = opts; 1554 match = AUTH_UNIX; 1555 1556 while (*p) { 1557 switch (getsubopt(&p, optlist, &val)) { 1558 1559 case OPT_SECURE: 1560 match = AUTH_DES; 1561 break; 1562 1563 case OPT_RO: 1564 list++; 1565 if (val) ro_val++; 1566 if (in_access_list(nb, clnames, val)) 1567 perm |= NFSAUTH_RO; 1568 break; 1569 1570 case OPT_RW: 1571 list++; 1572 if (val) rw_val++; 1573 if (in_access_list(nb, clnames, val)) 1574 perm |= NFSAUTH_RW; 1575 break; 1576 1577 case OPT_ROOT: 1578 /* 1579 * Check if the client is in 1580 * the root list. Only valid 1581 * for AUTH_SYS. 1582 */ 1583 if (flavor != AUTH_SYS) 1584 break; 1585 1586 if (val == NULL || *val == '\0') 1587 break; 1588 1589 if (in_access_list(nb, clnames, val)) 1590 perm |= NFSAUTH_ROOT; 1591 break; 1592 } 1593 } 1594 1595 free(opts); 1596 1597 if (flavor != match) 1598 return (NFSAUTH_DENIED); 1599 1600 if (list) { 1601 /* 1602 * If the client doesn't match an "ro" or "rw" 1603 * list then set no access. 1604 */ 1605 if ((perm & (NFSAUTH_RO | NFSAUTH_RW)) == 0) 1606 perm |= NFSAUTH_DENIED; 1607 } else { 1608 /* 1609 * The client matched a flavor entry that 1610 * has no explicit "rw" or "ro" determination. 1611 * Default it to "rw". 1612 */ 1613 perm |= NFSAUTH_RW; 1614 } 1615 1616 1617 /* 1618 * The client may show up in both ro= and rw= 1619 * lists. If so, then turn off the RO access 1620 * bit leaving RW access. 1621 */ 1622 if (perm & NFSAUTH_RO && perm & NFSAUTH_RW) { 1623 /* 1624 * Logically cover all permutations of rw=,ro=. 1625 * In the case where, rw,ro=<host> we would like 1626 * to remove RW access for the host. In all other cases 1627 * RW wins the precedence battle. 1628 */ 1629 if (!rw_val && ro_val) { 1630 perm &= ~(NFSAUTH_RW); 1631 } else { 1632 perm &= ~(NFSAUTH_RO); 1633 } 1634 } 1635 1636 return (perm); 1637 } 1638 1639 /* 1640 * Check if the client has access by using a flavor different from 1641 * the given "flavor". If "flavor" is not in the flavor list, 1642 * return TRUE to indicate that this "flavor" is a wrong sec. 1643 */ 1644 static bool_t 1645 is_wrongsec(struct share *sh, struct netbuf *nb, 1646 struct nd_hostservlist *clnames, int flavor) 1647 { 1648 int flavor_list[MAX_FLAVORS]; 1649 int flavor_count, i; 1650 1651 /* get the flavor list that the client has access with */ 1652 flavor_count = getclientsflavors_new(sh, nb, clnames, flavor_list); 1653 1654 if (flavor_count == 0) 1655 return (FALSE); 1656 1657 /* 1658 * Check if the given "flavor" is in the flavor_list. 1659 */ 1660 for (i = 0; i < flavor_count; i++) { 1661 if (flavor == flavor_list[i]) 1662 return (FALSE); 1663 } 1664 1665 /* 1666 * If "flavor" is not in the flavor_list, return TRUE to indicate 1667 * that the client should have access by using a security flavor 1668 * different from this "flavor". 1669 */ 1670 return (TRUE); 1671 } 1672 1673 /* 1674 * Given an export and the client's hostname, we 1675 * check the security options to see whether the 1676 * client is allowed to use the given security flavor. 1677 * 1678 * The strategy is to proceed through the options looking 1679 * for a flavor match, then pay attention to the ro, rw, 1680 * and root options. 1681 * 1682 * Note that an entry may list several flavors in a 1683 * single entry, e.g. 1684 * 1685 * sec=krb5,rw=clnt1:clnt2,ro,sec=sys,ro 1686 * 1687 */ 1688 1689 static int 1690 check_client_new(struct share *sh, struct netbuf *nb, 1691 struct nd_hostservlist *clnames, int flavor) 1692 { 1693 char *opts, *p, *val; 1694 char *lasts; 1695 char *f; 1696 int match = 0; /* Set when a flavor is matched */ 1697 int perm = 0; /* Set when "ro", "rw" or "root" is matched */ 1698 int list = 0; /* Set when "ro", "rw" is found */ 1699 int ro_val = 0; /* Set if ro option is 'ro=' */ 1700 int rw_val = 0; /* Set if rw option is 'rw=' */ 1701 1702 opts = strdup(sh->sh_opts); 1703 if (opts == NULL) { 1704 syslog(LOG_ERR, "check_client: no memory"); 1705 return (0); 1706 } 1707 1708 p = opts; 1709 1710 while (*p) { 1711 switch (getsubopt(&p, optlist, &val)) { 1712 1713 case OPT_SEC: 1714 if (match) 1715 goto done; 1716 1717 while ((f = strtok_r(val, ":", &lasts)) 1718 != NULL) { 1719 if (flavor == map_flavor(f)) { 1720 match = 1; 1721 break; 1722 } 1723 val = NULL; 1724 } 1725 break; 1726 1727 case OPT_RO: 1728 if (!match) 1729 break; 1730 1731 list++; 1732 if (val) ro_val++; 1733 if (in_access_list(nb, clnames, val)) 1734 perm |= NFSAUTH_RO; 1735 break; 1736 1737 case OPT_RW: 1738 if (!match) 1739 break; 1740 1741 list++; 1742 if (val) rw_val++; 1743 if (in_access_list(nb, clnames, val)) 1744 perm |= NFSAUTH_RW; 1745 break; 1746 1747 case OPT_ROOT: 1748 /* 1749 * Check if the client is in 1750 * the root list. Only valid 1751 * for AUTH_SYS. 1752 */ 1753 if (flavor != AUTH_SYS) 1754 break; 1755 1756 if (!match) 1757 break; 1758 1759 if (val == NULL || *val == '\0') 1760 break; 1761 1762 if (in_access_list(nb, clnames, val)) 1763 perm |= NFSAUTH_ROOT; 1764 break; 1765 } 1766 } 1767 1768 done: 1769 /* 1770 * If no match then set the perm accordingly 1771 */ 1772 if (!match) 1773 return (NFSAUTH_DENIED); 1774 1775 if (list) { 1776 /* 1777 * If the client doesn't match an "ro" or "rw" list then 1778 * check if it may have access by using a different flavor. 1779 * If so, return NFSAUTH_WRONGSEC. 1780 * If not, return NFSAUTH_DENIED. 1781 */ 1782 if ((perm & (NFSAUTH_RO | NFSAUTH_RW)) == 0) { 1783 if (is_wrongsec(sh, nb, clnames, flavor)) 1784 perm |= NFSAUTH_WRONGSEC; 1785 else 1786 perm |= NFSAUTH_DENIED; 1787 } 1788 } else { 1789 /* 1790 * The client matched a flavor entry that 1791 * has no explicit "rw" or "ro" determination. 1792 * Make sure it defaults to "rw". 1793 */ 1794 perm |= NFSAUTH_RW; 1795 } 1796 1797 /* 1798 * The client may show up in both ro= and rw= 1799 * lists. If so, then turn off the RO access 1800 * bit leaving RW access. 1801 */ 1802 if (perm & NFSAUTH_RO && perm & NFSAUTH_RW) { 1803 /* 1804 * Logically cover all permutations of rw=,ro=. 1805 * In the case where, rw,ro=<host> we would like 1806 * to remove RW access for the host. In all other cases 1807 * RW wins the precedence battle. 1808 */ 1809 if (!rw_val && ro_val) { 1810 perm &= ~(NFSAUTH_RW); 1811 } else { 1812 perm &= ~(NFSAUTH_RO); 1813 } 1814 } 1815 1816 free(opts); 1817 1818 return (perm); 1819 } 1820 1821 void 1822 check_sharetab() 1823 { 1824 FILE *f; 1825 struct stat st; 1826 static timestruc_t last_sharetab_time; 1827 timestruc_t prev_sharetab_time; 1828 struct share *sh; 1829 struct sh_list *shp, *shp_prev; 1830 int res, c = 0; 1831 1832 /* 1833 * read in /etc/dfs/sharetab if it has changed 1834 */ 1835 1836 if (stat(SHARETAB, &st) != 0) { 1837 syslog(LOG_ERR, "Cannot stat %s: %m", SHARETAB); 1838 return; 1839 } 1840 1841 if (st.st_mtim.tv_sec == last_sharetab_time.tv_sec && 1842 st.st_mtim.tv_nsec == last_sharetab_time.tv_nsec) { 1843 /* 1844 * No change. 1845 */ 1846 return; 1847 } 1848 1849 /* 1850 * Remember the mod time, then after getting the 1851 * write lock check again. If another thread 1852 * already did the update, then there's no 1853 * work to do. 1854 */ 1855 prev_sharetab_time = last_sharetab_time; 1856 1857 (void) rw_wrlock(&sharetab_lock); 1858 1859 if (prev_sharetab_time.tv_sec != last_sharetab_time.tv_sec || 1860 prev_sharetab_time.tv_nsec != last_sharetab_time.tv_nsec) { 1861 (void) rw_unlock(&sharetab_lock); 1862 return; 1863 } 1864 1865 f = fopen(SHARETAB, "r+"); 1866 if (f == NULL) { 1867 syslog(LOG_ERR, "Cannot open %s: %m", SHARETAB); 1868 (void) rw_unlock(&sharetab_lock); 1869 return; 1870 } 1871 1872 /* 1873 * Lock the file so that unshare can't 1874 * truncate it while we're reading 1875 */ 1876 if (lockf(fileno(f), F_LOCK, 0L) < 0) { 1877 syslog(LOG_ERR, "Cannot lock %s: %m", SHARETAB); 1878 (void) rw_unlock(&sharetab_lock); 1879 (void) fclose(f); 1880 return; 1881 } 1882 1883 /* 1884 * Once we are sure /etc/dfs/sharetab has been 1885 * modified, flush netgroup cache entries. 1886 */ 1887 netgrp_cache_flush(); 1888 1889 sh_free(share_list); /* free old list */ 1890 share_list = NULL; 1891 1892 while ((res = getshare(f, &sh)) > 0) { 1893 c++; 1894 if (strcmp(sh->sh_fstype, "nfs") != 0) 1895 continue; 1896 1897 shp = malloc(sizeof (*shp)); 1898 if (shp == NULL) 1899 goto alloc_failed; 1900 if (share_list == NULL) 1901 share_list = shp; 1902 else 1903 /* LINTED not used before set */ 1904 shp_prev->shl_next = shp; 1905 shp_prev = shp; 1906 shp->shl_next = NULL; 1907 shp->shl_sh = sharedup(sh); 1908 if (shp->shl_sh == NULL) 1909 goto alloc_failed; 1910 } 1911 if (res < 0) 1912 syslog(LOG_ERR, "%s: invalid at line %d\n", 1913 SHARETAB, c + 1); 1914 1915 if (stat(SHARETAB, &st) != 0) { 1916 syslog(LOG_ERR, "Cannot stat %s: %m", SHARETAB); 1917 (void) rw_unlock(&sharetab_lock); 1918 return; 1919 } 1920 last_sharetab_time = st.st_mtim; 1921 (void) fclose(f); 1922 (void) rw_unlock(&sharetab_lock); 1923 return; 1924 1925 alloc_failed: 1926 syslog(LOG_ERR, "check_sharetab: no memory"); 1927 sh_free(share_list); 1928 share_list = NULL; 1929 (void) fclose(f); 1930 (void) rw_unlock(&sharetab_lock); 1931 } 1932 1933 static void 1934 sh_free(struct sh_list *shp) 1935 { 1936 register struct sh_list *next; 1937 1938 while (shp) { 1939 sharefree(shp->shl_sh); 1940 next = shp->shl_next; 1941 free(shp); 1942 shp = next; 1943 } 1944 } 1945 1946 1947 /* 1948 * Remove an entry from mounted list 1949 */ 1950 static void 1951 umount(struct svc_req *rqstp) 1952 { 1953 char *host, *path, *remove_path; 1954 char rpath[MAXPATHLEN]; 1955 struct nd_hostservlist *clnames = NULL; 1956 SVCXPRT *transp; 1957 struct netbuf *nb; 1958 1959 transp = rqstp->rq_xprt; 1960 path = NULL; 1961 if (!svc_getargs(transp, xdr_dirpath, (caddr_t)&path)) { 1962 svcerr_decode(transp); 1963 return; 1964 } 1965 errno = 0; 1966 if (!svc_sendreply(transp, xdr_void, (char *)NULL)) 1967 log_cant_reply(transp); 1968 1969 getclientsnames(transp, &nb, &clnames); 1970 if (clnames == NULL) { 1971 /* 1972 * Without the hostname we can't do audit or delete 1973 * this host from the mount entries. 1974 */ 1975 svc_freeargs(transp, xdr_dirpath, (caddr_t)&path); 1976 return; 1977 } 1978 host = clnames->h_hostservs[0].h_host; 1979 1980 if (verbose) 1981 syslog(LOG_NOTICE, "UNMOUNT: %s unmounted %s", host, path); 1982 1983 audit_mountd_umount(host, path); 1984 1985 remove_path = rpath; /* assume we will use the cannonical path */ 1986 if (realpath(path, rpath) == NULL) { 1987 if (verbose) 1988 syslog(LOG_WARNING, "UNMOUNT: realpath: %s: %m ", path); 1989 remove_path = path; /* use path provided instead */ 1990 } 1991 1992 mntlist_delete(host, remove_path); /* remove from mount list */ 1993 1994 svc_freeargs(transp, xdr_dirpath, (caddr_t)&path); 1995 netdir_free(clnames, ND_HOSTSERVLIST); 1996 } 1997 1998 /* 1999 * Remove all entries for one machine from mounted list 2000 */ 2001 static void 2002 umountall(struct svc_req *rqstp) 2003 { 2004 struct nd_hostservlist *clnames = NULL; 2005 SVCXPRT *transp; 2006 char *host; 2007 struct netbuf *nb; 2008 2009 transp = rqstp->rq_xprt; 2010 if (!svc_getargs(transp, xdr_void, NULL)) { 2011 svcerr_decode(transp); 2012 return; 2013 } 2014 /* 2015 * We assume that this call is asynchronous and made via rpcbind 2016 * callit routine. Therefore return control immediately. The error 2017 * causes rpcbind to remain silent, as opposed to every machine 2018 * on the net blasting the requester with a response. 2019 */ 2020 svcerr_systemerr(transp); 2021 getclientsnames(transp, &nb, &clnames); 2022 if (clnames == NULL) { 2023 /* Can't do anything without the name of the client */ 2024 return; 2025 } 2026 2027 host = clnames->h_hostservs[0].h_host; 2028 2029 /* 2030 * Remove all hosts entries from mount list 2031 */ 2032 mntlist_delete_all(host); 2033 2034 if (verbose) 2035 syslog(LOG_NOTICE, "UNMOUNTALL: from %s", host); 2036 2037 netdir_free(clnames, ND_HOSTSERVLIST); 2038 } 2039 2040 void * 2041 exmalloc(size_t size) 2042 { 2043 void *ret; 2044 2045 if ((ret = malloc(size)) == NULL) { 2046 syslog(LOG_ERR, "Out of memory"); 2047 exit(1); 2048 } 2049 return (ret); 2050 } 2051 2052 static void 2053 sigexit(int signum) 2054 { 2055 2056 if (signum == SIGHUP) 2057 _exit(0); 2058 _exit(1); 2059 } 2060