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