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 & IN_CLASSA_HOST) == 0) 1511 mask = IN_CLASSA_NET; 1512 else if ((addr & IN_CLASSB_HOST) == 0) 1513 mask = IN_CLASSB_NET; 1514 else if ((addr & IN_CLASSC_HOST) == 0) 1515 mask = IN_CLASSC_NET; 1516 else 1517 mask = IN_CLASSE_NET; 1518 } 1519 1520 return ((claddr & mask) == addr); 1521 } 1522 1523 1524 static char *optlist[] = { 1525 #define OPT_RO 0 1526 SHOPT_RO, 1527 #define OPT_RW 1 1528 SHOPT_RW, 1529 #define OPT_ROOT 2 1530 SHOPT_ROOT, 1531 #define OPT_SECURE 3 1532 SHOPT_SECURE, 1533 #define OPT_ANON 4 1534 SHOPT_ANON, 1535 #define OPT_WINDOW 5 1536 SHOPT_WINDOW, 1537 #define OPT_NOSUID 6 1538 SHOPT_NOSUID, 1539 #define OPT_ACLOK 7 1540 SHOPT_ACLOK, 1541 #define OPT_SEC 8 1542 SHOPT_SEC, 1543 #define OPT_NONE 9 1544 SHOPT_NONE, 1545 NULL 1546 }; 1547 1548 static int 1549 map_flavor(char *str) 1550 { 1551 seconfig_t sec; 1552 1553 if (nfs_getseconfig_byname(str, &sec)) 1554 return (-1); 1555 1556 return (sec.sc_nfsnum); 1557 } 1558 1559 /* 1560 * If the option string contains a "sec=" 1561 * option, then use new option syntax. 1562 */ 1563 static int 1564 newopts(char *opts) 1565 { 1566 char *head, *p, *val; 1567 1568 if (!opts || *opts == '\0') 1569 return (0); 1570 1571 head = strdup(opts); 1572 if (head == NULL) { 1573 syslog(LOG_ERR, "opts: no memory"); 1574 return (0); 1575 } 1576 1577 p = head; 1578 while (*p) { 1579 if (getsubopt(&p, optlist, &val) == OPT_SEC) { 1580 free(head); 1581 return (1); 1582 } 1583 } 1584 1585 free(head); 1586 return (0); 1587 } 1588 1589 /* 1590 * Given an export and the clients hostname(s) 1591 * determine the security flavors that this 1592 * client is permitted to use. 1593 * 1594 * This routine is called only for "old" syntax, i.e. 1595 * only one security flavor is allowed. So we need 1596 * to determine two things: the particular flavor, 1597 * and whether the client is allowed to use this 1598 * flavor, i.e. is in the access list. 1599 * 1600 * Note that if there is no access list, then the 1601 * default is that access is granted. 1602 */ 1603 static int 1604 getclientsflavors_old(struct share *sh, struct netbuf *nb, 1605 struct nd_hostservlist *clnames, int *flavors) 1606 { 1607 char *opts, *p, *val; 1608 boolean_t ok = B_FALSE; 1609 int defaultaccess = 1; 1610 boolean_t reject = B_FALSE; 1611 1612 opts = strdup(sh->sh_opts); 1613 if (opts == NULL) { 1614 syslog(LOG_ERR, "getclientsflavors: no memory"); 1615 return (0); 1616 } 1617 1618 flavors[0] = AUTH_SYS; 1619 p = opts; 1620 1621 while (*p) { 1622 1623 switch (getsubopt(&p, optlist, &val)) { 1624 case OPT_SECURE: 1625 flavors[0] = AUTH_DES; 1626 break; 1627 1628 case OPT_RO: 1629 case OPT_RW: 1630 defaultaccess = 0; 1631 if (in_access_list(nb, clnames, val)) 1632 ok++; 1633 break; 1634 1635 case OPT_NONE: 1636 defaultaccess = 0; 1637 if (in_access_list(nb, clnames, val)) 1638 reject = B_TRUE; 1639 } 1640 } 1641 1642 free(opts); 1643 1644 /* none takes precedence over everything else */ 1645 if (reject) 1646 ok = B_TRUE; 1647 1648 return (defaultaccess || ok); 1649 } 1650 1651 /* 1652 * Given an export and the clients hostname(s) 1653 * determine the security flavors that this 1654 * client is permitted to use. 1655 * 1656 * This is somewhat more complicated than the "old" 1657 * routine because the options may contain multiple 1658 * security flavors (sec=) each with its own access 1659 * lists. So a client could be granted access based 1660 * on a number of security flavors. Note that the 1661 * type of access might not always be the same, the 1662 * client may get readonly access with one flavor 1663 * and readwrite with another, however the client 1664 * is not told this detail, it gets only the list 1665 * of flavors, and only if the client is using 1666 * version 3 of the mount protocol. 1667 */ 1668 static int 1669 getclientsflavors_new(struct share *sh, struct netbuf *nb, 1670 struct nd_hostservlist *clnames, int *flavors) 1671 { 1672 char *opts, *p, *val; 1673 char *lasts; 1674 char *f; 1675 boolean_t access_ok; 1676 int count, c, perm; 1677 boolean_t reject = B_FALSE; 1678 1679 opts = strdup(sh->sh_opts); 1680 if (opts == NULL) { 1681 syslog(LOG_ERR, "getclientsflavors: no memory"); 1682 return (0); 1683 } 1684 1685 p = opts; 1686 perm = count = c = 0; 1687 /* default access is rw */ 1688 access_ok = B_TRUE; 1689 1690 while (*p) { 1691 switch (getsubopt(&p, optlist, &val)) { 1692 case OPT_SEC: 1693 /* 1694 * Before a new sec=xxx option, check if we need 1695 * to move the c index back to the previous count. 1696 */ 1697 if (!access_ok) { 1698 c = count; 1699 } 1700 1701 /* get all the sec=f1[:f2] flavors */ 1702 while ((f = strtok_r(val, ":", &lasts)) 1703 != NULL) { 1704 flavors[c++] = map_flavor(f); 1705 val = NULL; 1706 } 1707 /* for a new sec=xxx option, default is rw access */ 1708 access_ok = B_TRUE; 1709 break; 1710 1711 case OPT_RO: 1712 case OPT_RW: 1713 if (in_access_list(nb, clnames, val)) { 1714 count = c; 1715 access_ok = B_TRUE; 1716 } else { 1717 access_ok = B_FALSE; 1718 } 1719 break; 1720 1721 case OPT_NONE: 1722 if (in_access_list(nb, clnames, val)) 1723 reject = B_TRUE; /* none overides rw/ro */ 1724 break; 1725 } 1726 } 1727 1728 if (reject) 1729 access_ok = B_FALSE; 1730 1731 if (!access_ok) 1732 c = count; 1733 1734 free(opts); 1735 1736 return (c); 1737 } 1738 1739 /* 1740 * This is a tricky piece of code that parses the 1741 * share options looking for a match on the auth 1742 * flavor that the client is using. If it finds 1743 * a match, then the client is given ro, rw, or 1744 * no access depending whether it is in the access 1745 * list. There is a special case for "secure" 1746 * flavor. Other flavors are values of the new "sec=" option. 1747 */ 1748 int 1749 check_client(struct share *sh, struct netbuf *nb, 1750 struct nd_hostservlist *clnames, int flavor) 1751 { 1752 if (newopts(sh->sh_opts)) 1753 return (check_client_new(sh, nb, clnames, flavor)); 1754 else 1755 return (check_client_old(sh, nb, clnames, flavor)); 1756 } 1757 1758 static int 1759 check_client_old(struct share *sh, struct netbuf *nb, 1760 struct nd_hostservlist *clnames, int flavor) 1761 { 1762 char *opts, *p, *val; 1763 int match; /* Set when a flavor is matched */ 1764 int perm = 0; /* Set when "ro", "rw" or "root" is matched */ 1765 int list = 0; /* Set when "ro", "rw" is found */ 1766 int ro_val = 0; /* Set if ro option is 'ro=' */ 1767 int rw_val = 0; /* Set if rw option is 'rw=' */ 1768 boolean_t reject = B_FALSE; /* if none= contains the host */ 1769 1770 opts = strdup(sh->sh_opts); 1771 if (opts == NULL) { 1772 syslog(LOG_ERR, "check_client: no memory"); 1773 return (0); 1774 } 1775 1776 p = opts; 1777 match = AUTH_UNIX; 1778 1779 while (*p) { 1780 switch (getsubopt(&p, optlist, &val)) { 1781 1782 case OPT_SECURE: 1783 match = AUTH_DES; 1784 break; 1785 1786 case OPT_RO: 1787 list++; 1788 if (val) ro_val++; 1789 if (in_access_list(nb, clnames, val)) 1790 perm |= NFSAUTH_RO; 1791 break; 1792 1793 case OPT_RW: 1794 list++; 1795 if (val) rw_val++; 1796 if (in_access_list(nb, clnames, val)) 1797 perm |= NFSAUTH_RW; 1798 break; 1799 1800 case OPT_ROOT: 1801 /* 1802 * Check if the client is in 1803 * the root list. Only valid 1804 * for AUTH_SYS. 1805 */ 1806 if (flavor != AUTH_SYS) 1807 break; 1808 1809 if (val == NULL || *val == '\0') 1810 break; 1811 1812 if (in_access_list(nb, clnames, val)) 1813 perm |= NFSAUTH_ROOT; 1814 break; 1815 1816 case OPT_NONE: 1817 /* 1818 * Check if the client should have no access 1819 * to this share at all. This option behaves 1820 * more like "root" than either "rw" or "ro". 1821 */ 1822 if (in_access_list(nb, clnames, val)) 1823 reject = B_TRUE; 1824 break; 1825 } 1826 } 1827 1828 free(opts); 1829 1830 if (flavor != match || reject) 1831 return (NFSAUTH_DENIED); 1832 1833 if (list) { 1834 /* 1835 * If the client doesn't match an "ro" or "rw" 1836 * list then set no access. 1837 */ 1838 if ((perm & (NFSAUTH_RO | NFSAUTH_RW)) == 0) 1839 perm |= NFSAUTH_DENIED; 1840 } else { 1841 /* 1842 * The client matched a flavor entry that 1843 * has no explicit "rw" or "ro" determination. 1844 * Default it to "rw". 1845 */ 1846 perm |= NFSAUTH_RW; 1847 } 1848 1849 1850 /* 1851 * The client may show up in both ro= and rw= 1852 * lists. If so, then turn off the RO access 1853 * bit leaving RW access. 1854 */ 1855 if (perm & NFSAUTH_RO && perm & NFSAUTH_RW) { 1856 /* 1857 * Logically cover all permutations of rw=,ro=. 1858 * In the case where, rw,ro=<host> we would like 1859 * to remove RW access for the host. In all other cases 1860 * RW wins the precedence battle. 1861 */ 1862 if (!rw_val && ro_val) { 1863 perm &= ~(NFSAUTH_RW); 1864 } else { 1865 perm &= ~(NFSAUTH_RO); 1866 } 1867 } 1868 1869 return (perm); 1870 } 1871 1872 /* 1873 * Check if the client has access by using a flavor different from 1874 * the given "flavor". If "flavor" is not in the flavor list, 1875 * return TRUE to indicate that this "flavor" is a wrong sec. 1876 */ 1877 static bool_t 1878 is_wrongsec(struct share *sh, struct netbuf *nb, 1879 struct nd_hostservlist *clnames, int flavor) 1880 { 1881 int flavor_list[MAX_FLAVORS]; 1882 int flavor_count, i; 1883 1884 /* get the flavor list that the client has access with */ 1885 flavor_count = getclientsflavors_new(sh, nb, clnames, flavor_list); 1886 1887 if (flavor_count == 0) 1888 return (FALSE); 1889 1890 /* 1891 * Check if the given "flavor" is in the flavor_list. 1892 */ 1893 for (i = 0; i < flavor_count; i++) { 1894 if (flavor == flavor_list[i]) 1895 return (FALSE); 1896 } 1897 1898 /* 1899 * If "flavor" is not in the flavor_list, return TRUE to indicate 1900 * that the client should have access by using a security flavor 1901 * different from this "flavor". 1902 */ 1903 return (TRUE); 1904 } 1905 1906 /* 1907 * Given an export and the client's hostname, we 1908 * check the security options to see whether the 1909 * client is allowed to use the given security flavor. 1910 * 1911 * The strategy is to proceed through the options looking 1912 * for a flavor match, then pay attention to the ro, rw, 1913 * and root options. 1914 * 1915 * Note that an entry may list several flavors in a 1916 * single entry, e.g. 1917 * 1918 * sec=krb5,rw=clnt1:clnt2,ro,sec=sys,ro 1919 * 1920 */ 1921 1922 static int 1923 check_client_new(struct share *sh, struct netbuf *nb, 1924 struct nd_hostservlist *clnames, int flavor) 1925 { 1926 char *opts, *p, *val; 1927 char *lasts; 1928 char *f; 1929 int match = 0; /* Set when a flavor is matched */ 1930 int perm = 0; /* Set when "ro", "rw" or "root" is matched */ 1931 int list = 0; /* Set when "ro", "rw" is found */ 1932 int ro_val = 0; /* Set if ro option is 'ro=' */ 1933 int rw_val = 0; /* Set if rw option is 'rw=' */ 1934 boolean_t reject; 1935 1936 opts = strdup(sh->sh_opts); 1937 if (opts == NULL) { 1938 syslog(LOG_ERR, "check_client: no memory"); 1939 return (0); 1940 } 1941 1942 p = opts; 1943 1944 while (*p) { 1945 switch (getsubopt(&p, optlist, &val)) { 1946 1947 case OPT_SEC: 1948 if (match) 1949 goto done; 1950 1951 while ((f = strtok_r(val, ":", &lasts)) 1952 != NULL) { 1953 if (flavor == map_flavor(f)) { 1954 match = 1; 1955 break; 1956 } 1957 val = NULL; 1958 } 1959 break; 1960 1961 case OPT_RO: 1962 if (!match) 1963 break; 1964 1965 list++; 1966 if (val) ro_val++; 1967 if (in_access_list(nb, clnames, val)) 1968 perm |= NFSAUTH_RO; 1969 break; 1970 1971 case OPT_RW: 1972 if (!match) 1973 break; 1974 1975 list++; 1976 if (val) rw_val++; 1977 if (in_access_list(nb, clnames, val)) 1978 perm |= NFSAUTH_RW; 1979 break; 1980 1981 case OPT_ROOT: 1982 /* 1983 * Check if the client is in 1984 * the root list. Only valid 1985 * for AUTH_SYS. 1986 */ 1987 if (flavor != AUTH_SYS) 1988 break; 1989 1990 if (!match) 1991 break; 1992 1993 if (val == NULL || *val == '\0') 1994 break; 1995 1996 if (in_access_list(nb, clnames, val)) 1997 perm |= NFSAUTH_ROOT; 1998 break; 1999 2000 case OPT_NONE: 2001 /* 2002 * Check if the client should have no access 2003 * to this share at all. This option behaves 2004 * more like "root" than either "rw" or "ro". 2005 */ 2006 if (in_access_list(nb, clnames, val)) 2007 perm |= NFSAUTH_DENIED; 2008 break; 2009 } 2010 } 2011 2012 done: 2013 /* 2014 * If no match then set the perm accordingly 2015 */ 2016 if (!match || perm & NFSAUTH_DENIED) 2017 return (NFSAUTH_DENIED); 2018 2019 if (list) { 2020 /* 2021 * If the client doesn't match an "ro" or "rw" list then 2022 * check if it may have access by using a different flavor. 2023 * If so, return NFSAUTH_WRONGSEC. 2024 * If not, return NFSAUTH_DENIED. 2025 */ 2026 if ((perm & (NFSAUTH_RO | NFSAUTH_RW)) == 0) { 2027 if (is_wrongsec(sh, nb, clnames, flavor)) 2028 perm |= NFSAUTH_WRONGSEC; 2029 else 2030 perm |= NFSAUTH_DENIED; 2031 } 2032 } else { 2033 /* 2034 * The client matched a flavor entry that 2035 * has no explicit "rw" or "ro" determination. 2036 * Make sure it defaults to "rw". 2037 */ 2038 perm |= NFSAUTH_RW; 2039 } 2040 2041 /* 2042 * The client may show up in both ro= and rw= 2043 * lists. If so, then turn off the RO access 2044 * bit leaving RW access. 2045 */ 2046 if (perm & NFSAUTH_RO && perm & NFSAUTH_RW) { 2047 /* 2048 * Logically cover all permutations of rw=,ro=. 2049 * In the case where, rw,ro=<host> we would like 2050 * to remove RW access for the host. In all other cases 2051 * RW wins the precedence battle. 2052 */ 2053 if (!rw_val && ro_val) { 2054 perm &= ~(NFSAUTH_RW); 2055 } else { 2056 perm &= ~(NFSAUTH_RO); 2057 } 2058 } 2059 2060 free(opts); 2061 2062 return (perm); 2063 } 2064 2065 void 2066 check_sharetab() 2067 { 2068 FILE *f; 2069 struct stat st; 2070 static timestruc_t last_sharetab_time; 2071 timestruc_t prev_sharetab_time; 2072 struct share *sh; 2073 struct sh_list *shp, *shp_prev; 2074 int res, c = 0; 2075 2076 /* 2077 * read in /etc/dfs/sharetab if it has changed 2078 */ 2079 2080 if (stat(SHARETAB, &st) != 0) { 2081 syslog(LOG_ERR, "Cannot stat %s: %m", SHARETAB); 2082 return; 2083 } 2084 2085 if (st.st_mtim.tv_sec == last_sharetab_time.tv_sec && 2086 st.st_mtim.tv_nsec == last_sharetab_time.tv_nsec) { 2087 /* 2088 * No change. 2089 */ 2090 return; 2091 } 2092 2093 /* 2094 * Remember the mod time, then after getting the 2095 * write lock check again. If another thread 2096 * already did the update, then there's no 2097 * work to do. 2098 */ 2099 prev_sharetab_time = last_sharetab_time; 2100 2101 (void) rw_wrlock(&sharetab_lock); 2102 2103 if (prev_sharetab_time.tv_sec != last_sharetab_time.tv_sec || 2104 prev_sharetab_time.tv_nsec != last_sharetab_time.tv_nsec) { 2105 (void) rw_unlock(&sharetab_lock); 2106 return; 2107 } 2108 2109 /* 2110 * Note that since the sharetab is now in memory 2111 * and a snapshot is taken, we no longer have to 2112 * lock the file. 2113 */ 2114 f = fopen(SHARETAB, "r"); 2115 if (f == NULL) { 2116 syslog(LOG_ERR, "Cannot open %s: %m", SHARETAB); 2117 (void) rw_unlock(&sharetab_lock); 2118 return; 2119 } 2120 2121 /* 2122 * Once we are sure /etc/dfs/sharetab has been 2123 * modified, flush netgroup cache entries. 2124 */ 2125 netgrp_cache_flush(); 2126 2127 sh_free(share_list); /* free old list */ 2128 share_list = NULL; 2129 2130 while ((res = getshare(f, &sh)) > 0) { 2131 c++; 2132 if (strcmp(sh->sh_fstype, "nfs") != 0) 2133 continue; 2134 2135 shp = malloc(sizeof (*shp)); 2136 if (shp == NULL) 2137 goto alloc_failed; 2138 if (share_list == NULL) 2139 share_list = shp; 2140 else 2141 /* LINTED not used before set */ 2142 shp_prev->shl_next = shp; 2143 shp_prev = shp; 2144 shp->shl_next = NULL; 2145 shp->shl_sh = sharedup(sh); 2146 if (shp->shl_sh == NULL) 2147 goto alloc_failed; 2148 } 2149 if (res < 0) 2150 syslog(LOG_ERR, "%s: invalid at line %d\n", 2151 SHARETAB, c + 1); 2152 2153 if (stat(SHARETAB, &st) != 0) { 2154 syslog(LOG_ERR, "Cannot stat %s: %m", SHARETAB); 2155 (void) fclose(f); 2156 (void) rw_unlock(&sharetab_lock); 2157 return; 2158 } 2159 last_sharetab_time = st.st_mtim; 2160 (void) fclose(f); 2161 (void) rw_unlock(&sharetab_lock); 2162 return; 2163 2164 alloc_failed: 2165 syslog(LOG_ERR, "check_sharetab: no memory"); 2166 sh_free(share_list); 2167 share_list = NULL; 2168 (void) fclose(f); 2169 (void) rw_unlock(&sharetab_lock); 2170 } 2171 2172 static void 2173 sh_free(struct sh_list *shp) 2174 { 2175 register struct sh_list *next; 2176 2177 while (shp) { 2178 sharefree(shp->shl_sh); 2179 next = shp->shl_next; 2180 free(shp); 2181 shp = next; 2182 } 2183 } 2184 2185 2186 /* 2187 * Remove an entry from mounted list 2188 */ 2189 static void 2190 umount(struct svc_req *rqstp) 2191 { 2192 char *host, *path, *remove_path; 2193 char rpath[MAXPATHLEN]; 2194 struct nd_hostservlist *clnames = NULL; 2195 SVCXPRT *transp; 2196 struct netbuf *nb; 2197 2198 transp = rqstp->rq_xprt; 2199 path = NULL; 2200 if (!svc_getargs(transp, xdr_dirpath, (caddr_t)&path)) { 2201 svcerr_decode(transp); 2202 return; 2203 } 2204 errno = 0; 2205 if (!svc_sendreply(transp, xdr_void, (char *)NULL)) 2206 log_cant_reply(transp); 2207 2208 getclientsnames(transp, &nb, &clnames); 2209 if (clnames == NULL) { 2210 /* 2211 * Without the hostname we can't do audit or delete 2212 * this host from the mount entries. 2213 */ 2214 svc_freeargs(transp, xdr_dirpath, (caddr_t)&path); 2215 return; 2216 } 2217 host = clnames->h_hostservs[0].h_host; 2218 2219 if (verbose) 2220 syslog(LOG_NOTICE, "UNMOUNT: %s unmounted %s", host, path); 2221 2222 audit_mountd_umount(host, path); 2223 2224 remove_path = rpath; /* assume we will use the cannonical path */ 2225 if (realpath(path, rpath) == NULL) { 2226 if (verbose) 2227 syslog(LOG_WARNING, "UNMOUNT: realpath: %s: %m ", path); 2228 remove_path = path; /* use path provided instead */ 2229 } 2230 2231 mntlist_delete(host, remove_path); /* remove from mount list */ 2232 2233 svc_freeargs(transp, xdr_dirpath, (caddr_t)&path); 2234 netdir_free(clnames, ND_HOSTSERVLIST); 2235 } 2236 2237 /* 2238 * Remove all entries for one machine from mounted list 2239 */ 2240 static void 2241 umountall(struct svc_req *rqstp) 2242 { 2243 struct nd_hostservlist *clnames = NULL; 2244 SVCXPRT *transp; 2245 char *host; 2246 struct netbuf *nb; 2247 2248 transp = rqstp->rq_xprt; 2249 if (!svc_getargs(transp, xdr_void, NULL)) { 2250 svcerr_decode(transp); 2251 return; 2252 } 2253 /* 2254 * We assume that this call is asynchronous and made via rpcbind 2255 * callit routine. Therefore return control immediately. The error 2256 * causes rpcbind to remain silent, as opposed to every machine 2257 * on the net blasting the requester with a response. 2258 */ 2259 svcerr_systemerr(transp); 2260 getclientsnames(transp, &nb, &clnames); 2261 if (clnames == NULL) { 2262 /* Can't do anything without the name of the client */ 2263 return; 2264 } 2265 2266 host = clnames->h_hostservs[0].h_host; 2267 2268 /* 2269 * Remove all hosts entries from mount list 2270 */ 2271 mntlist_delete_all(host); 2272 2273 if (verbose) 2274 syslog(LOG_NOTICE, "UNMOUNTALL: from %s", host); 2275 2276 netdir_free(clnames, ND_HOSTSERVLIST); 2277 } 2278 2279 void * 2280 exmalloc(size_t size) 2281 { 2282 void *ret; 2283 2284 if ((ret = malloc(size)) == NULL) { 2285 syslog(LOG_ERR, "Out of memory"); 2286 exit(1); 2287 } 2288 return (ret); 2289 } 2290 2291 static void 2292 sigexit(int signum) 2293 { 2294 2295 if (signum == SIGHUP) 2296 _exit(0); 2297 _exit(1); 2298 } 2299 2300 static tsol_tpent_t * 2301 get_client_template(struct sockaddr *sock) 2302 { 2303 in_addr_t v4client; 2304 in6_addr_t v6client; 2305 char v4_addr[INET_ADDRSTRLEN]; 2306 char v6_addr[INET6_ADDRSTRLEN]; 2307 tsol_rhent_t *rh; 2308 tsol_tpent_t *tp; 2309 2310 switch (sock->sa_family) { 2311 case AF_INET: 2312 v4client = ((struct sockaddr_in *)(void *)sock)-> 2313 sin_addr.s_addr; 2314 if (inet_ntop(AF_INET, &v4client, v4_addr, INET_ADDRSTRLEN) == 2315 NULL) 2316 return (NULL); 2317 rh = tsol_getrhbyaddr(v4_addr, sizeof (v4_addr), AF_INET); 2318 if (rh == NULL) 2319 return (NULL); 2320 tp = tsol_gettpbyname(rh->rh_template); 2321 tsol_freerhent(rh); 2322 return (tp); 2323 break; 2324 case AF_INET6: 2325 v6client = ((struct sockaddr_in6 *)(void *)sock)->sin6_addr; 2326 if (inet_ntop(AF_INET6, &v6client, v6_addr, INET6_ADDRSTRLEN) == 2327 NULL) 2328 return (NULL); 2329 rh = tsol_getrhbyaddr(v6_addr, sizeof (v6_addr), AF_INET6); 2330 if (rh == NULL) 2331 return (NULL); 2332 tp = tsol_gettpbyname(rh->rh_template); 2333 tsol_freerhent(rh); 2334 return (tp); 2335 break; 2336 default: 2337 return (NULL); 2338 } 2339 } 2340