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