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