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