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