1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * nfs_tbind.c, common part for nfsd and lockd. 28 */ 29 30 #pragma ident "%Z%%M% %I% %E% SMI" 31 32 #define PORTMAP 33 34 #include <tiuser.h> 35 #include <fcntl.h> 36 #include <netconfig.h> 37 #include <stropts.h> 38 #include <errno.h> 39 #include <syslog.h> 40 #include <rpc/rpc.h> 41 #include <rpc/pmap_prot.h> 42 #include <sys/time.h> 43 #include <sys/resource.h> 44 #include <signal.h> 45 #include <netdir.h> 46 #include <unistd.h> 47 #include <string.h> 48 #include <netinet/tcp.h> 49 #include <malloc.h> 50 #include <stdlib.h> 51 #include "nfs_tbind.h" 52 #include <nfs/nfs.h> 53 #include <nfs/nfs_acl.h> 54 #include <nfs/nfssys.h> 55 #include <nfs/nfs4.h> 56 #include <zone.h> 57 #include <sys/socket.h> 58 #include <tsol/label.h> 59 60 /* 61 * Determine valid semantics for most applications. 62 */ 63 #define OK_TPI_TYPE(_nconf) \ 64 (_nconf->nc_semantics == NC_TPI_CLTS || \ 65 _nconf->nc_semantics == NC_TPI_COTS || \ 66 _nconf->nc_semantics == NC_TPI_COTS_ORD) 67 68 #define BE32_TO_U32(a) \ 69 ((((ulong_t)((uchar_t *)a)[0] & 0xFF) << (ulong_t)24) | \ 70 (((ulong_t)((uchar_t *)a)[1] & 0xFF) << (ulong_t)16) | \ 71 (((ulong_t)((uchar_t *)a)[2] & 0xFF) << (ulong_t)8) | \ 72 ((ulong_t)((uchar_t *)a)[3] & 0xFF)) 73 74 /* 75 * Number of elements to add to the poll array on each allocation. 76 */ 77 #define POLL_ARRAY_INC_SIZE 64 78 79 /* 80 * Number of file descriptors by which the process soft limit may be 81 * increased on each call to nofile_increase(0). 82 */ 83 #define NOFILE_INC_SIZE 64 84 85 struct conn_ind { 86 struct conn_ind *conn_next; 87 struct conn_ind *conn_prev; 88 struct t_call *conn_call; 89 }; 90 91 struct conn_entry { 92 bool_t closing; 93 struct netconfig nc; 94 }; 95 96 /* 97 * this file contains transport routines common to nfsd and lockd 98 */ 99 static int nofile_increase(int); 100 static int reuseaddr(int); 101 static int recvucred(int); 102 static int anonmlp(int); 103 static void add_to_poll_list(int, struct netconfig *); 104 static char *serv_name_to_port_name(char *); 105 static int bind_to_proto(char *, char *, struct netbuf **, 106 struct netconfig **); 107 static int bind_to_provider(char *, char *, struct netbuf **, 108 struct netconfig **); 109 static void conn_close_oldest(void); 110 static boolean_t conn_get(int, struct netconfig *, struct conn_ind **); 111 static void cots_listen_event(int, int); 112 static int discon_get(int, struct netconfig *, struct conn_ind **); 113 static int do_poll_clts_action(int, int); 114 static int do_poll_cots_action(int, int); 115 static void remove_from_poll_list(int); 116 static int set_addrmask(int, struct netconfig *, struct netbuf *); 117 static int is_listen_fd_index(int); 118 119 static struct pollfd *poll_array; 120 static struct conn_entry *conn_polled; 121 static int num_conns; /* Current number of connections */ 122 int (*Mysvc4)(int, struct netbuf *, struct netconfig *, int, 123 struct netbuf *); 124 125 extern bool_t __pmap_set(const rpcprog_t program, const rpcvers_t version, 126 const struct netconfig *nconf, const struct netbuf *address); 127 128 /* 129 * Called to create and prepare a transport descriptor for in-kernel 130 * RPC service. 131 * Returns -1 on failure and a valid descriptor on success. 132 */ 133 int 134 nfslib_transport_open(struct netconfig *nconf) 135 { 136 int fd; 137 struct strioctl strioc; 138 139 if ((nconf == (struct netconfig *)NULL) || 140 (nconf->nc_device == (char *)NULL)) { 141 syslog(LOG_ERR, "no netconfig device"); 142 return (-1); 143 } 144 145 /* 146 * Open the transport device. 147 */ 148 fd = t_open(nconf->nc_device, O_RDWR, (struct t_info *)NULL); 149 if (fd == -1) { 150 if (t_errno == TSYSERR && errno == EMFILE && 151 (nofile_increase(0) == 0)) { 152 /* Try again with a higher NOFILE limit. */ 153 fd = t_open(nconf->nc_device, O_RDWR, 154 (struct t_info *)NULL); 155 } 156 if (fd == -1) { 157 syslog(LOG_ERR, "t_open %s failed: t_errno %d, %m", 158 nconf->nc_device, t_errno); 159 return (-1); 160 } 161 } 162 163 /* 164 * Pop timod because the RPC module must be as close as possible 165 * to the transport. 166 */ 167 if (ioctl(fd, I_POP, 0) < 0) { 168 syslog(LOG_ERR, "I_POP of timod failed: %m"); 169 (void) t_close(fd); 170 return (-1); 171 } 172 173 /* 174 * Common code for CLTS and COTS transports 175 */ 176 if (ioctl(fd, I_PUSH, "rpcmod") < 0) { 177 syslog(LOG_ERR, "I_PUSH of rpcmod failed: %m"); 178 (void) t_close(fd); 179 return (-1); 180 } 181 182 strioc.ic_cmd = RPC_SERVER; 183 strioc.ic_dp = (char *)0; 184 strioc.ic_len = 0; 185 strioc.ic_timout = -1; 186 187 /* Tell rpcmod to act like a server stream. */ 188 if (ioctl(fd, I_STR, &strioc) < 0) { 189 syslog(LOG_ERR, "rpcmod set-up ioctl failed: %m"); 190 (void) t_close(fd); 191 return (-1); 192 } 193 194 /* 195 * Re-push timod so that we will still be doing TLI 196 * operations on the descriptor. 197 */ 198 if (ioctl(fd, I_PUSH, "timod") < 0) { 199 syslog(LOG_ERR, "I_PUSH of timod failed: %m"); 200 (void) t_close(fd); 201 return (-1); 202 } 203 204 /* 205 * Enable options of returning the ip's for udp. 206 */ 207 if (strcmp(nconf->nc_netid, "udp6") == 0) 208 __rpc_tli_set_options(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, 1); 209 else if (strcmp(nconf->nc_netid, "udp") == 0) 210 __rpc_tli_set_options(fd, IPPROTO_IP, IP_RECVDSTADDR, 1); 211 212 return (fd); 213 } 214 215 static int 216 nofile_increase(int limit) 217 { 218 struct rlimit rl; 219 220 if (getrlimit(RLIMIT_NOFILE, &rl) == -1) { 221 syslog(LOG_ERR, "getrlimit of NOFILE failed: %m"); 222 return (-1); 223 } 224 225 if (limit > 0) 226 rl.rlim_cur = limit; 227 else 228 rl.rlim_cur += NOFILE_INC_SIZE; 229 230 if (rl.rlim_cur > rl.rlim_max && 231 rl.rlim_max != RLIM_INFINITY) 232 rl.rlim_max = rl.rlim_cur; 233 234 if (setrlimit(RLIMIT_NOFILE, &rl) == -1) { 235 syslog(LOG_ERR, "setrlimit of NOFILE to %d failed: %m", 236 rl.rlim_cur); 237 return (-1); 238 } 239 240 return (0); 241 } 242 243 int 244 nfslib_bindit(struct netconfig *nconf, struct netbuf **addr, 245 struct nd_hostserv *hs, int backlog) 246 { 247 int fd; 248 struct t_bind *ntb; 249 struct t_bind tb; 250 struct nd_addrlist *addrlist; 251 struct t_optmgmt req, resp; 252 struct opthdr *opt; 253 char reqbuf[128]; 254 bool_t use_any = FALSE; 255 bool_t gzone = TRUE; 256 257 if ((fd = nfslib_transport_open(nconf)) == -1) { 258 syslog(LOG_ERR, "cannot establish transport service over %s", 259 nconf->nc_device); 260 return (-1); 261 } 262 263 addrlist = (struct nd_addrlist *)NULL; 264 265 /* nfs4_callback service does not used a fieed port number */ 266 267 if (strcmp(hs->h_serv, "nfs4_callback") == 0) { 268 tb.addr.maxlen = 0; 269 tb.addr.len = 0; 270 tb.addr.buf = 0; 271 use_any = TRUE; 272 gzone = (getzoneid() == GLOBAL_ZONEID); 273 } else if (netdir_getbyname(nconf, hs, &addrlist) != 0) { 274 275 syslog(LOG_ERR, 276 "Cannot get address for transport %s host %s service %s", 277 nconf->nc_netid, hs->h_host, hs->h_serv); 278 (void) t_close(fd); 279 return (-1); 280 } 281 282 if (strcmp(nconf->nc_proto, "tcp") == 0) { 283 /* 284 * If we're running over TCP, then set the 285 * SO_REUSEADDR option so that we can bind 286 * to our preferred address even if previously 287 * left connections exist in FIN_WAIT states. 288 * This is somewhat bogus, but otherwise you have 289 * to wait 2 minutes to restart after killing it. 290 */ 291 if (reuseaddr(fd) == -1) { 292 syslog(LOG_WARNING, 293 "couldn't set SO_REUSEADDR option on transport"); 294 } 295 } else if (strcmp(nconf->nc_proto, "udp") == 0) { 296 /* 297 * In order to run MLP on UDP, we need to handle creds. 298 */ 299 if (recvucred(fd) == -1) { 300 syslog(LOG_WARNING, 301 "couldn't set SO_RECVUCRED option on transport"); 302 } 303 } 304 305 /* 306 * Make non global zone nfs4_callback port MLP 307 */ 308 if (use_any && is_system_labeled() && !gzone) { 309 if (anonmlp(fd) == -1) { 310 /* 311 * failing to set this option means nfs4_callback 312 * could fail silently later. So fail it with 313 * with an error message now. 314 */ 315 syslog(LOG_ERR, 316 "couldn't set SO_ANON_MLP option on transport"); 317 (void) t_close(fd); 318 return (-1); 319 } 320 } 321 322 if (nconf->nc_semantics == NC_TPI_CLTS) 323 tb.qlen = 0; 324 else 325 tb.qlen = backlog; 326 327 /* LINTED pointer alignment */ 328 ntb = (struct t_bind *)t_alloc(fd, T_BIND, T_ALL); 329 if (ntb == (struct t_bind *)NULL) { 330 syslog(LOG_ERR, "t_alloc failed: t_errno %d, %m", t_errno); 331 (void) t_close(fd); 332 netdir_free((void *)addrlist, ND_ADDRLIST); 333 return (-1); 334 } 335 336 /* 337 * XXX - what about the space tb->addr.buf points to? This should 338 * be either a memcpy() to/from the buf fields, or t_alloc(fd,T_BIND,) 339 * should't be called with T_ALL. 340 */ 341 if (addrlist) 342 tb.addr = *(addrlist->n_addrs); /* structure copy */ 343 344 if (t_bind(fd, &tb, ntb) == -1) { 345 syslog(LOG_ERR, "t_bind failed: t_errno %d, %m", t_errno); 346 (void) t_free((char *)ntb, T_BIND); 347 netdir_free((void *)addrlist, ND_ADDRLIST); 348 (void) t_close(fd); 349 return (-1); 350 } 351 352 /* make sure we bound to the right address */ 353 if (use_any == FALSE && 354 (tb.addr.len != ntb->addr.len || 355 memcmp(tb.addr.buf, ntb->addr.buf, tb.addr.len) != 0)) { 356 syslog(LOG_ERR, "t_bind to wrong address"); 357 (void) t_free((char *)ntb, T_BIND); 358 netdir_free((void *)addrlist, ND_ADDRLIST); 359 (void) t_close(fd); 360 return (-1); 361 } 362 363 /* 364 * Call nfs4svc_setport so that the kernel can be 365 * informed what port number the daemon is listing 366 * for incoming connection requests. 367 */ 368 369 if ((nconf->nc_semantics == NC_TPI_COTS || 370 nconf->nc_semantics == NC_TPI_COTS_ORD) && Mysvc4 != NULL) 371 (*Mysvc4)(fd, NULL, nconf, NFS4_SETPORT, &ntb->addr); 372 373 *addr = &ntb->addr; 374 netdir_free((void *)addrlist, ND_ADDRLIST); 375 376 if (strcmp(nconf->nc_proto, "tcp") == 0) { 377 /* 378 * Disable the Nagle algorithm on TCP connections. 379 * Connections accepted from this listener will 380 * inherit the listener options. 381 */ 382 383 /* LINTED pointer alignment */ 384 opt = (struct opthdr *)reqbuf; 385 opt->level = IPPROTO_TCP; 386 opt->name = TCP_NODELAY; 387 opt->len = sizeof (int); 388 389 /* LINTED pointer alignment */ 390 *(int *)((char *)opt + sizeof (*opt)) = 1; 391 392 req.flags = T_NEGOTIATE; 393 req.opt.len = sizeof (*opt) + opt->len; 394 req.opt.buf = (char *)opt; 395 resp.flags = 0; 396 resp.opt.buf = reqbuf; 397 resp.opt.maxlen = sizeof (reqbuf); 398 399 if (t_optmgmt(fd, &req, &resp) < 0 || 400 resp.flags != T_SUCCESS) { 401 syslog(LOG_ERR, 402 "couldn't set NODELAY option for proto %s: t_errno = %d, %m", 403 nconf->nc_proto, t_errno); 404 } 405 } 406 407 return (fd); 408 } 409 410 static int 411 setopt(int fd, int level, int name, int value) 412 { 413 struct t_optmgmt req, resp; 414 struct { 415 struct opthdr opt; 416 int value; 417 } reqbuf; 418 419 reqbuf.opt.level = level; 420 reqbuf.opt.name = name; 421 reqbuf.opt.len = sizeof (int); 422 423 reqbuf.value = value; 424 425 req.flags = T_NEGOTIATE; 426 req.opt.len = sizeof (reqbuf); 427 req.opt.buf = (char *)&reqbuf; 428 429 resp.flags = 0; 430 resp.opt.buf = (char *)&reqbuf; 431 resp.opt.maxlen = sizeof (reqbuf); 432 433 if (t_optmgmt(fd, &req, &resp) < 0 || resp.flags != T_SUCCESS) { 434 t_error("t_optmgmt"); 435 return (-1); 436 } 437 return (0); 438 } 439 440 static int 441 reuseaddr(int fd) 442 { 443 return (setopt(fd, SOL_SOCKET, SO_REUSEADDR, 1)); 444 } 445 446 static int 447 recvucred(int fd) 448 { 449 return (setopt(fd, SOL_SOCKET, SO_RECVUCRED, 1)); 450 } 451 452 static int 453 anonmlp(int fd) 454 { 455 return (setopt(fd, SOL_SOCKET, SO_ANON_MLP, 1)); 456 } 457 458 void 459 nfslib_log_tli_error(char *tli_name, int fd, struct netconfig *nconf) 460 { 461 int error; 462 463 /* 464 * Save the error code across syslog(), just in case syslog() 465 * gets its own error and, therefore, overwrites errno. 466 */ 467 error = errno; 468 if (t_errno == TSYSERR) { 469 syslog(LOG_ERR, "%s(file descriptor %d/transport %s) %m", 470 tli_name, fd, nconf->nc_proto); 471 } else { 472 syslog(LOG_ERR, 473 "%s(file descriptor %d/transport %s) TLI error %d", 474 tli_name, fd, nconf->nc_proto, t_errno); 475 } 476 errno = error; 477 } 478 479 /* 480 * Called to set up service over a particular transport. 481 */ 482 void 483 do_one(char *provider, NETSELDECL(proto), struct protob *protobp0, 484 int (*svc)(int, struct netbuf, struct netconfig *), int use_pmap) 485 { 486 register int sock; 487 struct protob *protobp; 488 struct netbuf *retaddr; 489 struct netconfig *retnconf; 490 struct netbuf addrmask; 491 int vers; 492 int err; 493 int l; 494 495 if (provider) 496 sock = bind_to_provider(provider, protobp0->serv, &retaddr, 497 &retnconf); 498 else 499 sock = bind_to_proto(proto, protobp0->serv, &retaddr, 500 &retnconf); 501 502 if (sock == -1) { 503 (void) syslog(LOG_ERR, 504 "Cannot establish %s service over %s: transport setup problem.", 505 protobp0->serv, provider ? provider : proto); 506 return; 507 } 508 509 if (set_addrmask(sock, retnconf, &addrmask) < 0) { 510 (void) syslog(LOG_ERR, 511 "Cannot set address mask for %s", retnconf->nc_netid); 512 return; 513 } 514 515 /* 516 * Register all versions of the programs in the protocol block list. 517 */ 518 l = strlen(NC_UDP); 519 for (protobp = protobp0; protobp; protobp = protobp->next) { 520 for (vers = protobp->versmin; vers <= protobp->versmax; 521 vers++) { 522 if ((protobp->program == NFS_PROGRAM || 523 protobp->program == NFS_ACL_PROGRAM) && 524 vers == NFS_V4 && 525 strncasecmp(retnconf->nc_proto, NC_UDP, l) == 0) 526 continue; 527 528 if (use_pmap) { 529 /* 530 * Note that if we're using a portmapper 531 * instead of rpcbind then we can't do an 532 * unregister operation here. 533 * 534 * The reason is that the portmapper unset 535 * operation removes all the entries for a 536 * given program/version regardelss of 537 * transport protocol. 538 * 539 * The caller of this routine needs to ensure 540 * that __pmap_unset() has been called for all 541 * program/version service pairs they plan 542 * to support before they start registering 543 * each program/version/protocol triplet. 544 */ 545 (void) __pmap_set(protobp->program, vers, 546 retnconf, retaddr); 547 } else { 548 (void) rpcb_unset(protobp->program, vers, 549 retnconf); 550 (void) rpcb_set(protobp->program, vers, 551 retnconf, retaddr); 552 } 553 } 554 } 555 556 if (retnconf->nc_semantics == NC_TPI_CLTS) { 557 /* Don't drop core if supporting module(s) aren't loaded. */ 558 (void) signal(SIGSYS, SIG_IGN); 559 560 /* 561 * svc() doesn't block, it returns success or failure. 562 */ 563 564 if (svc == NULL && Mysvc4 != NULL) 565 err = (*Mysvc4)(sock, &addrmask, retnconf, 566 NFS4_SETPORT|NFS4_KRPC_START, retaddr); 567 else 568 err = (*svc)(sock, addrmask, retnconf); 569 570 if (err < 0) { 571 (void) syslog(LOG_ERR, 572 "Cannot establish %s service over <file desc." 573 " %d, protocol %s> : %m. Exiting", 574 protobp0->serv, sock, retnconf->nc_proto); 575 exit(1); 576 } 577 } 578 579 /* 580 * We successfully set up the server over this transport. 581 * Add this descriptor to the one being polled on. 582 */ 583 add_to_poll_list(sock, retnconf); 584 } 585 /* 586 * Set up the NFS service over all the available transports. 587 * Returns -1 for failure, 0 for success. 588 */ 589 int 590 do_all(struct protob *protobp, 591 int (*svc)(int, struct netbuf, struct netconfig *), int use_pmap) 592 { 593 struct netconfig *nconf; 594 NCONF_HANDLE *nc; 595 int l; 596 597 if ((nc = setnetconfig()) == (NCONF_HANDLE *)NULL) { 598 syslog(LOG_ERR, "setnetconfig failed: %m"); 599 return (-1); 600 } 601 l = strlen(NC_UDP); 602 while (nconf = getnetconfig(nc)) { 603 if ((nconf->nc_flag & NC_VISIBLE) && 604 strcmp(nconf->nc_protofmly, NC_LOOPBACK) != 0 && 605 OK_TPI_TYPE(nconf) && 606 (protobp->program != NFS4_CALLBACK || 607 strncasecmp(nconf->nc_proto, NC_UDP, l) != 0)) 608 do_one(nconf->nc_device, nconf->nc_proto, 609 protobp, svc, use_pmap); 610 } 611 (void) endnetconfig(nc); 612 return (0); 613 } 614 615 /* 616 * poll on the open transport descriptors for events and errors. 617 */ 618 void 619 poll_for_action(void) 620 { 621 int nfds; 622 int i; 623 624 /* 625 * Keep polling until all transports have been closed. When this 626 * happens, we return. 627 */ 628 while ((int)num_fds > 0) { 629 nfds = poll(poll_array, num_fds, INFTIM); 630 switch (nfds) { 631 case 0: 632 continue; 633 634 case -1: 635 /* 636 * Some errors from poll could be 637 * due to temporary conditions, and we try to 638 * be robust in the face of them. Other 639 * errors (should never happen in theory) 640 * are fatal (eg. EINVAL, EFAULT). 641 */ 642 switch (errno) { 643 case EINTR: 644 continue; 645 646 case EAGAIN: 647 case ENOMEM: 648 (void) sleep(10); 649 continue; 650 651 default: 652 (void) syslog(LOG_ERR, 653 "poll failed: %m. Exiting"); 654 exit(1); 655 } 656 default: 657 break; 658 } 659 660 /* 661 * Go through the poll list looking for events. 662 */ 663 for (i = 0; i < num_fds && nfds > 0; i++) { 664 if (poll_array[i].revents) { 665 nfds--; 666 /* 667 * We have a message, so try to read it. 668 * Record the error return in errno, 669 * so that syslog(LOG_ERR, "...%m") 670 * dumps the corresponding error string. 671 */ 672 if (conn_polled[i].nc.nc_semantics == 673 NC_TPI_CLTS) { 674 errno = do_poll_clts_action( 675 poll_array[i].fd, i); 676 } else { 677 errno = do_poll_cots_action( 678 poll_array[i].fd, i); 679 } 680 681 if (errno == 0) 682 continue; 683 /* 684 * Most returned error codes mean that there is 685 * fatal condition which we can only deal with 686 * by closing the transport. 687 */ 688 if (errno != EAGAIN && errno != ENOMEM) { 689 (void) syslog(LOG_ERR, 690 "Error (%m) reading descriptor %d/transport %s. Closing it.", 691 poll_array[i].fd, 692 conn_polled[i].nc.nc_proto); 693 (void) t_close(poll_array[i].fd); 694 remove_from_poll_list(poll_array[i].fd); 695 696 } else if (errno == ENOMEM) 697 (void) sleep(5); 698 } 699 } 700 } 701 702 (void) syslog(LOG_ERR, 703 "All transports have been closed with errors. Exiting."); 704 } 705 706 /* 707 * Allocate poll/transport array entries for this descriptor. 708 */ 709 static void 710 add_to_poll_list(int fd, struct netconfig *nconf) 711 { 712 static int poll_array_size = 0; 713 714 /* 715 * If the arrays are full, allocate new ones. 716 */ 717 if (num_fds == poll_array_size) { 718 struct pollfd *tpa; 719 struct conn_entry *tnp; 720 721 if (poll_array_size != 0) { 722 tpa = poll_array; 723 tnp = conn_polled; 724 } else 725 tpa = (struct pollfd *)0; 726 727 poll_array_size += POLL_ARRAY_INC_SIZE; 728 /* 729 * Allocate new arrays. 730 */ 731 poll_array = (struct pollfd *) 732 malloc(poll_array_size * sizeof (struct pollfd) + 256); 733 conn_polled = (struct conn_entry *) 734 malloc(poll_array_size * sizeof (struct conn_entry) + 256); 735 if (poll_array == (struct pollfd *)NULL || 736 conn_polled == (struct conn_entry *)NULL) { 737 syslog(LOG_ERR, "malloc failed for poll array"); 738 exit(1); 739 } 740 741 /* 742 * Copy the data of the old ones into new arrays, and 743 * free the old ones. 744 */ 745 if (tpa) { 746 (void) memcpy((void *)poll_array, (void *)tpa, 747 num_fds * sizeof (struct pollfd)); 748 (void) memcpy((void *)conn_polled, (void *)tnp, 749 num_fds * sizeof (struct conn_entry)); 750 free((void *)tpa); 751 free((void *)tnp); 752 } 753 } 754 755 /* 756 * Set the descriptor and event list. All possible events are 757 * polled for. 758 */ 759 poll_array[num_fds].fd = fd; 760 poll_array[num_fds].events = POLLIN|POLLRDNORM|POLLRDBAND|POLLPRI; 761 762 /* 763 * Copy the transport data over too. 764 */ 765 conn_polled[num_fds].nc = *nconf; 766 conn_polled[num_fds].closing = 0; 767 768 /* 769 * Set the descriptor to non-blocking. Avoids a race 770 * between data arriving on the stream and then having it 771 * flushed before we can read it. 772 */ 773 if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) { 774 (void) syslog(LOG_ERR, 775 "fcntl(file desc. %d/transport %s, F_SETFL, O_NONBLOCK): %m. Exiting", 776 num_fds, nconf->nc_proto); 777 exit(1); 778 } 779 780 /* 781 * Count this descriptor. 782 */ 783 ++num_fds; 784 } 785 786 static void 787 remove_from_poll_list(int fd) 788 { 789 int i; 790 int num_to_copy; 791 792 for (i = 0; i < num_fds; i++) { 793 if (poll_array[i].fd == fd) { 794 --num_fds; 795 num_to_copy = num_fds - i; 796 (void) memcpy((void *)&poll_array[i], 797 (void *)&poll_array[i+1], 798 num_to_copy * sizeof (struct pollfd)); 799 (void) memset((void *)&poll_array[num_fds], 0, 800 sizeof (struct pollfd)); 801 (void) memcpy((void *)&conn_polled[i], 802 (void *)&conn_polled[i+1], 803 num_to_copy * sizeof (struct conn_entry)); 804 (void) memset((void *)&conn_polled[num_fds], 0, 805 sizeof (struct conn_entry)); 806 return; 807 } 808 } 809 syslog(LOG_ERR, "attempt to remove nonexistent fd from poll list"); 810 811 } 812 813 /* 814 * Called to read and interpret the event on a connectionless descriptor. 815 * Returns 0 if successful, or a UNIX error code if failure. 816 */ 817 static int 818 do_poll_clts_action(int fd, int conn_index) 819 { 820 int error; 821 int ret; 822 int flags; 823 struct netconfig *nconf = &conn_polled[conn_index].nc; 824 static struct t_unitdata *unitdata = NULL; 825 static struct t_uderr *uderr = NULL; 826 static int oldfd = -1; 827 struct nd_hostservlist *host = NULL; 828 struct strbuf ctl[1], data[1]; 829 /* 830 * We just need to have some space to consume the 831 * message in the event we can't use the TLI interface to do the 832 * job. 833 * 834 * We flush the message using getmsg(). For the control part 835 * we allocate enough for any TPI header plus 32 bytes for address 836 * and options. For the data part, there is nothing magic about 837 * the size of the array, but 256 bytes is probably better than 838 * 1 byte, and we don't expect any data portion anyway. 839 * 840 * If the array sizes are too small, we handle this because getmsg() 841 * (called to consume the message) will return MOREDATA|MORECTL. 842 * Thus we just call getmsg() until it's read the message. 843 */ 844 char ctlbuf[sizeof (union T_primitives) + 32]; 845 char databuf[256]; 846 847 /* 848 * If this is the same descriptor as the last time 849 * do_poll_clts_action was called, we can save some 850 * de-allocation and allocation. 851 */ 852 if (oldfd != fd) { 853 oldfd = fd; 854 855 if (unitdata) { 856 (void) t_free((char *)unitdata, T_UNITDATA); 857 unitdata = NULL; 858 } 859 if (uderr) { 860 (void) t_free((char *)uderr, T_UDERROR); 861 uderr = NULL; 862 } 863 } 864 865 /* 866 * Allocate a unitdata structure for receiving the event. 867 */ 868 if (unitdata == NULL) { 869 /* LINTED pointer alignment */ 870 unitdata = (struct t_unitdata *)t_alloc(fd, T_UNITDATA, T_ALL); 871 if (unitdata == NULL) { 872 if (t_errno == TSYSERR) { 873 /* 874 * Save the error code across 875 * syslog(), just in case 876 * syslog() gets its own error 877 * and therefore overwrites errno. 878 */ 879 error = errno; 880 (void) syslog(LOG_ERR, 881 "t_alloc(file descriptor %d/transport %s, T_UNITDATA) failed: %m", 882 fd, nconf->nc_proto); 883 return (error); 884 } 885 (void) syslog(LOG_ERR, 886 "t_alloc(file descriptor %d/transport %s, T_UNITDATA) failed TLI error %d", 887 fd, nconf->nc_proto, t_errno); 888 goto flush_it; 889 } 890 } 891 892 try_again: 893 flags = 0; 894 895 /* 896 * The idea is we wait for T_UNITDATA_IND's. Of course, 897 * we don't get any, because rpcmod filters them out. 898 * However, we need to call t_rcvudata() to let TLI 899 * tell us we have a T_UDERROR_IND. 900 * 901 * algorithm is: 902 * t_rcvudata(), expecting TLOOK. 903 * t_look(), expecting T_UDERR. 904 * t_rcvuderr(), expecting success (0). 905 * expand destination address into ASCII, 906 * and dump it. 907 */ 908 909 ret = t_rcvudata(fd, unitdata, &flags); 910 if (ret == 0 || t_errno == TBUFOVFLW) { 911 (void) syslog(LOG_WARNING, 912 "t_rcvudata(file descriptor %d/transport %s) got unexpected data, %d bytes", 913 fd, nconf->nc_proto, unitdata->udata.len); 914 915 /* 916 * Even though we don't expect any data, in case we do, 917 * keep reading until there is no more. 918 */ 919 if (flags & T_MORE) 920 goto try_again; 921 922 return (0); 923 } 924 925 switch (t_errno) { 926 case TNODATA: 927 return (0); 928 case TSYSERR: 929 /* 930 * System errors are returned to caller. 931 * Save the error code across 932 * syslog(), just in case 933 * syslog() gets its own error 934 * and therefore overwrites errno. 935 */ 936 error = errno; 937 (void) syslog(LOG_ERR, 938 "t_rcvudata(file descriptor %d/transport %s) %m", 939 fd, nconf->nc_proto); 940 return (error); 941 case TLOOK: 942 break; 943 default: 944 (void) syslog(LOG_ERR, 945 "t_rcvudata(file descriptor %d/transport %s) TLI error %d", 946 fd, nconf->nc_proto, t_errno); 947 goto flush_it; 948 } 949 950 ret = t_look(fd); 951 switch (ret) { 952 case 0: 953 return (0); 954 case -1: 955 /* 956 * System errors are returned to caller. 957 */ 958 if (t_errno == TSYSERR) { 959 /* 960 * Save the error code across 961 * syslog(), just in case 962 * syslog() gets its own error 963 * and therefore overwrites errno. 964 */ 965 error = errno; 966 (void) syslog(LOG_ERR, 967 "t_look(file descriptor %d/transport %s) %m", 968 fd, nconf->nc_proto); 969 return (error); 970 } 971 (void) syslog(LOG_ERR, 972 "t_look(file descriptor %d/transport %s) TLI error %d", 973 fd, nconf->nc_proto, t_errno); 974 goto flush_it; 975 case T_UDERR: 976 break; 977 default: 978 (void) syslog(LOG_WARNING, 979 "t_look(file descriptor %d/transport %s) returned %d not T_UDERR (%d)", 980 fd, nconf->nc_proto, ret, T_UDERR); 981 } 982 983 if (uderr == NULL) { 984 /* LINTED pointer alignment */ 985 uderr = (struct t_uderr *)t_alloc(fd, T_UDERROR, T_ALL); 986 if (uderr == NULL) { 987 if (t_errno == TSYSERR) { 988 /* 989 * Save the error code across 990 * syslog(), just in case 991 * syslog() gets its own error 992 * and therefore overwrites errno. 993 */ 994 error = errno; 995 (void) syslog(LOG_ERR, 996 "t_alloc(file descriptor %d/transport %s, T_UDERROR) failed: %m", 997 fd, nconf->nc_proto); 998 return (error); 999 } 1000 (void) syslog(LOG_ERR, 1001 "t_alloc(file descriptor %d/transport %s, T_UDERROR) failed TLI error: %d", 1002 fd, nconf->nc_proto, t_errno); 1003 goto flush_it; 1004 } 1005 } 1006 1007 ret = t_rcvuderr(fd, uderr); 1008 if (ret == 0) { 1009 1010 /* 1011 * Save the datagram error in errno, so that the 1012 * %m argument to syslog picks up the error string. 1013 */ 1014 errno = uderr->error; 1015 1016 /* 1017 * Log the datagram error, then log the host that 1018 * probably triggerred. Cannot log both in the 1019 * same transaction because of packet size limitations 1020 * in /dev/log. 1021 */ 1022 (void) syslog((errno == ECONNREFUSED) ? LOG_DEBUG : LOG_WARNING, 1023 "NFS response over <file descriptor %d/transport %s> generated error: %m", 1024 fd, nconf->nc_proto); 1025 1026 /* 1027 * Try to map the client's address back to a 1028 * name. 1029 */ 1030 ret = netdir_getbyaddr(nconf, &host, &uderr->addr); 1031 if (ret != -1 && host && host->h_cnt > 0 && 1032 host->h_hostservs) { 1033 (void) syslog((errno == ECONNREFUSED) ? LOG_DEBUG : LOG_WARNING, 1034 "Bad NFS response was sent to client with host name: %s; service port: %s", 1035 host->h_hostservs->h_host, 1036 host->h_hostservs->h_serv); 1037 } else { 1038 int i, j; 1039 char *buf; 1040 char *hex = "0123456789abcdef"; 1041 1042 /* 1043 * Mapping failed, print the whole thing 1044 * in ASCII hex. 1045 */ 1046 buf = (char *)malloc(uderr->addr.len * 2 + 1); 1047 for (i = 0, j = 0; i < uderr->addr.len; i++, j += 2) { 1048 buf[j] = hex[((uderr->addr.buf[i]) >> 4) & 0xf]; 1049 buf[j+1] = hex[uderr->addr.buf[i] & 0xf]; 1050 } 1051 buf[j] = '\0'; 1052 (void) syslog((errno == ECONNREFUSED) ? LOG_DEBUG : LOG_WARNING, 1053 "Bad NFS response was sent to client with transport address: 0x%s", 1054 buf); 1055 free((void *)buf); 1056 } 1057 1058 if (ret == 0 && host != NULL) 1059 netdir_free((void *)host, ND_HOSTSERVLIST); 1060 return (0); 1061 } 1062 1063 switch (t_errno) { 1064 case TNOUDERR: 1065 goto flush_it; 1066 case TSYSERR: 1067 /* 1068 * System errors are returned to caller. 1069 * Save the error code across 1070 * syslog(), just in case 1071 * syslog() gets its own error 1072 * and therefore overwrites errno. 1073 */ 1074 error = errno; 1075 (void) syslog(LOG_ERR, 1076 "t_rcvuderr(file descriptor %d/transport %s) %m", 1077 fd, nconf->nc_proto); 1078 return (error); 1079 default: 1080 (void) syslog(LOG_ERR, 1081 "t_rcvuderr(file descriptor %d/transport %s) TLI error %d", 1082 fd, nconf->nc_proto, t_errno); 1083 goto flush_it; 1084 } 1085 1086 flush_it: 1087 /* 1088 * If we get here, then we could not cope with whatever message 1089 * we attempted to read, so flush it. If we did read a message, 1090 * and one isn't present, that is all right, because fd is in 1091 * nonblocking mode. 1092 */ 1093 (void) syslog(LOG_ERR, 1094 "Flushing one input message from <file descriptor %d/transport %s>", 1095 fd, nconf->nc_proto); 1096 1097 /* 1098 * Read and discard the message. Do this this until there is 1099 * no more control/data in the message or until we get an error. 1100 */ 1101 do { 1102 ctl->maxlen = sizeof (ctlbuf); 1103 ctl->buf = ctlbuf; 1104 data->maxlen = sizeof (databuf); 1105 data->buf = databuf; 1106 flags = 0; 1107 ret = getmsg(fd, ctl, data, &flags); 1108 if (ret == -1) 1109 return (errno); 1110 } while (ret != 0); 1111 1112 return (0); 1113 } 1114 1115 static void 1116 conn_close_oldest(void) 1117 { 1118 int fd; 1119 int i1; 1120 1121 /* 1122 * Find the oldest connection that is not already in the 1123 * process of shutting down. 1124 */ 1125 for (i1 = end_listen_fds; /* no conditional expression */; i1++) { 1126 if (i1 >= num_fds) 1127 return; 1128 if (conn_polled[i1].closing == 0) 1129 break; 1130 } 1131 #ifdef DEBUG 1132 printf("too many connections (%d), releasing oldest (%d)\n", 1133 num_conns, poll_array[i1].fd); 1134 #else 1135 syslog(LOG_WARNING, "too many connections (%d), releasing oldest (%d)", 1136 num_conns, poll_array[i1].fd); 1137 #endif 1138 fd = poll_array[i1].fd; 1139 if (conn_polled[i1].nc.nc_semantics == NC_TPI_COTS) { 1140 /* 1141 * For politeness, send a T_DISCON_REQ to the transport 1142 * provider. We close the stream anyway. 1143 */ 1144 (void) t_snddis(fd, (struct t_call *)0); 1145 num_conns--; 1146 remove_from_poll_list(fd); 1147 (void) t_close(fd); 1148 } else { 1149 /* 1150 * For orderly release, we do not close the stream 1151 * until the T_ORDREL_IND arrives to complete 1152 * the handshake. 1153 */ 1154 if (t_sndrel(fd) == 0) 1155 conn_polled[i1].closing = 1; 1156 } 1157 } 1158 1159 static boolean_t 1160 conn_get(int fd, struct netconfig *nconf, struct conn_ind **connp) 1161 { 1162 struct conn_ind *conn; 1163 struct conn_ind *next_conn; 1164 1165 conn = (struct conn_ind *)malloc(sizeof (*conn)); 1166 if (conn == NULL) { 1167 syslog(LOG_ERR, "malloc for listen indication failed"); 1168 return (FALSE); 1169 } 1170 1171 /* LINTED pointer alignment */ 1172 conn->conn_call = (struct t_call *)t_alloc(fd, T_CALL, T_ALL); 1173 if (conn->conn_call == NULL) { 1174 free((char *)conn); 1175 nfslib_log_tli_error("t_alloc", fd, nconf); 1176 return (FALSE); 1177 } 1178 1179 if (t_listen(fd, conn->conn_call) == -1) { 1180 nfslib_log_tli_error("t_listen", fd, nconf); 1181 (void) t_free((char *)conn->conn_call, T_CALL); 1182 free((char *)conn); 1183 return (FALSE); 1184 } 1185 1186 if (conn->conn_call->udata.len > 0) { 1187 syslog(LOG_WARNING, 1188 "rejecting inbound connection(%s) with %d bytes of connect data", 1189 nconf->nc_proto, conn->conn_call->udata.len); 1190 1191 conn->conn_call->udata.len = 0; 1192 (void) t_snddis(fd, conn->conn_call); 1193 (void) t_free((char *)conn->conn_call, T_CALL); 1194 free((char *)conn); 1195 return (FALSE); 1196 } 1197 1198 if ((next_conn = *connp) != NULL) { 1199 next_conn->conn_prev->conn_next = conn; 1200 conn->conn_next = next_conn; 1201 conn->conn_prev = next_conn->conn_prev; 1202 next_conn->conn_prev = conn; 1203 } else { 1204 conn->conn_next = conn; 1205 conn->conn_prev = conn; 1206 *connp = conn; 1207 } 1208 return (TRUE); 1209 } 1210 1211 static int 1212 discon_get(int fd, struct netconfig *nconf, struct conn_ind **connp) 1213 { 1214 struct conn_ind *conn; 1215 struct t_discon discon; 1216 1217 discon.udata.buf = (char *)0; 1218 discon.udata.maxlen = 0; 1219 if (t_rcvdis(fd, &discon) == -1) { 1220 nfslib_log_tli_error("t_rcvdis", fd, nconf); 1221 return (-1); 1222 } 1223 1224 conn = *connp; 1225 if (conn == NULL) 1226 return (0); 1227 1228 do { 1229 if (conn->conn_call->sequence == discon.sequence) { 1230 if (conn->conn_next == conn) 1231 *connp = (struct conn_ind *)0; 1232 else { 1233 if (conn == *connp) { 1234 *connp = conn->conn_next; 1235 } 1236 conn->conn_next->conn_prev = conn->conn_prev; 1237 conn->conn_prev->conn_next = conn->conn_next; 1238 } 1239 free((char *)conn); 1240 break; 1241 } 1242 conn = conn->conn_next; 1243 } while (conn != *connp); 1244 1245 return (0); 1246 } 1247 1248 static void 1249 cots_listen_event(int fd, int conn_index) 1250 { 1251 struct t_call *call; 1252 struct conn_ind *conn; 1253 struct conn_ind *conn_head; 1254 int event; 1255 struct netconfig *nconf = &conn_polled[conn_index].nc; 1256 int new_fd; 1257 struct netbuf addrmask; 1258 int ret = 0; 1259 char *clnt; 1260 char *clnt_uaddr = NULL; 1261 struct nd_hostservlist *clnt_serv = NULL; 1262 1263 conn_head = (struct conn_ind *)0; 1264 (void) conn_get(fd, nconf, &conn_head); 1265 1266 while ((conn = conn_head) != NULL) { 1267 conn_head = conn->conn_next; 1268 if (conn_head == conn) 1269 conn_head = (struct conn_ind *)0; 1270 else { 1271 conn_head->conn_prev = conn->conn_prev; 1272 conn->conn_prev->conn_next = conn_head; 1273 } 1274 call = conn->conn_call; 1275 free((char *)conn); 1276 1277 /* 1278 * If we have already accepted the maximum number of 1279 * connections allowed on the command line, then drop 1280 * the oldest connection (for any protocol) before 1281 * accepting the new connection. Unless explicitly 1282 * set on the command line, max_conns_allowed is -1. 1283 */ 1284 if (max_conns_allowed != -1 && num_conns >= max_conns_allowed) 1285 conn_close_oldest(); 1286 1287 /* 1288 * Create a new transport endpoint for the same proto as 1289 * the listener. 1290 */ 1291 new_fd = nfslib_transport_open(nconf); 1292 if (new_fd == -1) { 1293 call->udata.len = 0; 1294 (void) t_snddis(fd, call); 1295 (void) t_free((char *)call, T_CALL); 1296 syslog(LOG_ERR, "Cannot establish transport over %s", 1297 nconf->nc_device); 1298 continue; 1299 } 1300 1301 /* Bind to a generic address/port for the accepting stream. */ 1302 if (t_bind(new_fd, (struct t_bind *)NULL, 1303 (struct t_bind *)NULL) == -1) { 1304 nfslib_log_tli_error("t_bind", new_fd, nconf); 1305 call->udata.len = 0; 1306 (void) t_snddis(fd, call); 1307 (void) t_free((char *)call, T_CALL); 1308 (void) t_close(new_fd); 1309 continue; 1310 } 1311 1312 while (t_accept(fd, new_fd, call) == -1) { 1313 if (t_errno != TLOOK) { 1314 #ifdef DEBUG 1315 nfslib_log_tli_error("t_accept", fd, nconf); 1316 #endif 1317 call->udata.len = 0; 1318 (void) t_snddis(fd, call); 1319 (void) t_free((char *)call, T_CALL); 1320 (void) t_close(new_fd); 1321 goto do_next_conn; 1322 } 1323 while (event = t_look(fd)) { 1324 switch (event) { 1325 case T_LISTEN: 1326 #ifdef DEBUG 1327 printf( 1328 "cots_listen_event(%s): T_LISTEN during accept processing\n", nconf->nc_proto); 1329 #endif 1330 (void) conn_get(fd, nconf, &conn_head); 1331 continue; 1332 case T_DISCONNECT: 1333 #ifdef DEBUG 1334 printf( 1335 "cots_listen_event(%s): T_DISCONNECT during accept processing\n", 1336 nconf->nc_proto); 1337 #endif 1338 (void) discon_get(fd, nconf, 1339 &conn_head); 1340 continue; 1341 default: 1342 syslog(LOG_ERR, 1343 "unexpected event 0x%x during accept processing (%s)", 1344 event, nconf->nc_proto); 1345 call->udata.len = 0; 1346 (void) t_snddis(fd, call); 1347 (void) t_free((char *)call, T_CALL); 1348 (void) t_close(new_fd); 1349 goto do_next_conn; 1350 } 1351 } 1352 } 1353 1354 if (set_addrmask(new_fd, nconf, &addrmask) < 0) { 1355 (void) syslog(LOG_ERR, 1356 "Cannot set address mask for %s", 1357 nconf->nc_netid); 1358 return; 1359 } 1360 1361 /* Tell KRPC about the new stream. */ 1362 if (Mysvc4 != NULL) 1363 ret = (*Mysvc4)(new_fd, &addrmask, nconf, 1364 NFS4_KRPC_START, &call->addr); 1365 else 1366 ret = (*Mysvc)(new_fd, addrmask, nconf); 1367 1368 if (ret < 0) { 1369 if (errno != ENOTCONN) { 1370 syslog(LOG_ERR, 1371 "unable to register new connection: %m"); 1372 } else { 1373 /* 1374 * This is the only error that could be 1375 * caused by the client, so who was it? 1376 */ 1377 if (netdir_getbyaddr(nconf, &clnt_serv, 1378 &(call->addr)) == ND_OK && 1379 clnt_serv->h_cnt > 0) 1380 clnt = clnt_serv->h_hostservs->h_host; 1381 else 1382 clnt = clnt_uaddr = taddr2uaddr(nconf, 1383 &(call->addr)); 1384 /* 1385 * If we don't know who the client was, 1386 * remain silent. 1387 */ 1388 if (clnt) 1389 syslog(LOG_ERR, 1390 "unable to register new connection: client %s has dropped connection", clnt); 1391 if (clnt_serv) 1392 netdir_free(clnt_serv, ND_HOSTSERVLIST); 1393 if (clnt_uaddr) 1394 free(clnt_uaddr); 1395 } 1396 free(addrmask.buf); 1397 (void) t_snddis(new_fd, (struct t_call *)0); 1398 (void) t_free((char *)call, T_CALL); 1399 (void) t_close(new_fd); 1400 goto do_next_conn; 1401 } 1402 1403 free(addrmask.buf); 1404 (void) t_free((char *)call, T_CALL); 1405 1406 /* 1407 * Poll on the new descriptor so that we get disconnect 1408 * and orderly release indications. 1409 */ 1410 num_conns++; 1411 add_to_poll_list(new_fd, nconf); 1412 1413 /* Reset nconf in case it has been moved. */ 1414 nconf = &conn_polled[conn_index].nc; 1415 do_next_conn:; 1416 } 1417 } 1418 1419 static int 1420 do_poll_cots_action(int fd, int conn_index) 1421 { 1422 char buf[256]; 1423 int event; 1424 int i1; 1425 int flags; 1426 struct conn_entry *connent = &conn_polled[conn_index]; 1427 struct netconfig *nconf = &(connent->nc); 1428 const char *errorstr; 1429 1430 while (event = t_look(fd)) { 1431 switch (event) { 1432 case T_LISTEN: 1433 #ifdef DEBUG 1434 printf("do_poll_cots_action(%s,%d): T_LISTEN event\n", nconf->nc_proto, fd); 1435 #endif 1436 cots_listen_event(fd, conn_index); 1437 break; 1438 1439 case T_DATA: 1440 #ifdef DEBUG 1441 printf("do_poll_cots_action(%d,%s): T_DATA event\n", fd, nconf->nc_proto); 1442 #endif 1443 /* 1444 * Receive a private notification from CONS rpcmod. 1445 */ 1446 i1 = t_rcv(fd, buf, sizeof (buf), &flags); 1447 if (i1 == -1) { 1448 syslog(LOG_ERR, "t_rcv failed"); 1449 break; 1450 } 1451 if (i1 < sizeof (int)) 1452 break; 1453 i1 = BE32_TO_U32(buf); 1454 if (i1 == 1 || i1 == 2) { 1455 /* 1456 * This connection has been idle for too long, 1457 * so release it as politely as we can. If we 1458 * have already initiated an orderly release 1459 * and we get notified that the stream is 1460 * still idle, pull the plug. This prevents 1461 * hung connections from continuing to consume 1462 * resources. 1463 */ 1464 #ifdef DEBUG 1465 printf("do_poll_cots_action(%s,%d): ", nconf->nc_proto, fd); 1466 printf("initiating orderly release of idle connection\n"); 1467 #endif 1468 if (nconf->nc_semantics == NC_TPI_COTS || 1469 connent->closing != 0) { 1470 (void) t_snddis(fd, (struct t_call *)0); 1471 goto fdclose; 1472 } 1473 /* 1474 * For NC_TPI_COTS_ORD, the stream is closed 1475 * and removed from the poll list when the 1476 * T_ORDREL is received from the provider. We 1477 * don't wait for it here because it may take 1478 * a while for the transport to shut down. 1479 */ 1480 if (t_sndrel(fd) == -1) { 1481 syslog(LOG_ERR, 1482 "unable to send orderly release %m"); 1483 } 1484 connent->closing = 1; 1485 } else 1486 syslog(LOG_ERR, 1487 "unexpected event from CONS rpcmod %d", i1); 1488 break; 1489 1490 case T_ORDREL: 1491 #ifdef DEBUG 1492 printf("do_poll_cots_action(%s,%d): T_ORDREL event\n", nconf->nc_proto, fd); 1493 #endif 1494 /* Perform an orderly release. */ 1495 if (t_rcvrel(fd) == 0) { 1496 /* T_ORDREL on listen fd's should be ignored */ 1497 if (!is_listen_fd_index(conn_index)) { 1498 (void) t_sndrel(fd); 1499 goto fdclose; 1500 } 1501 break; 1502 1503 } else if (t_errno == TLOOK) { 1504 break; 1505 } else { 1506 nfslib_log_tli_error("t_rcvrel", fd, nconf); 1507 1508 /* 1509 * check to make sure we do not close 1510 * listen fd 1511 */ 1512 if (is_listen_fd_index(conn_index)) 1513 break; 1514 else 1515 goto fdclose; 1516 } 1517 1518 case T_DISCONNECT: 1519 #ifdef DEBUG 1520 printf("do_poll_cots_action(%s,%d): T_DISCONNECT event\n", nconf->nc_proto, fd); 1521 #endif 1522 if (t_rcvdis(fd, (struct t_discon *)NULL) == -1) 1523 nfslib_log_tli_error("t_rcvdis", fd, nconf); 1524 1525 /* 1526 * T_DISCONNECT on listen fd's should be ignored. 1527 */ 1528 if (is_listen_fd_index(conn_index)) 1529 break; 1530 else 1531 goto fdclose; 1532 1533 case T_ERROR: 1534 default: 1535 if (event == T_ERROR || t_errno == TSYSERR) { 1536 if ((errorstr = strerror(errno)) == NULL) { 1537 (void) sprintf(buf, 1538 "Unknown error num %d", errno); 1539 errorstr = (const char *) buf; 1540 } 1541 } else if (event == -1) 1542 errorstr = t_strerror(t_errno); 1543 else 1544 errorstr = ""; 1545 syslog(LOG_ERR, 1546 "unexpected TLI event (0x%x) on " 1547 "connection-oriented transport(%s,%d):%s", 1548 event, nconf->nc_proto, fd, errorstr); 1549 fdclose: 1550 num_conns--; 1551 remove_from_poll_list(fd); 1552 (void) t_close(fd); 1553 return (0); 1554 } 1555 } 1556 1557 return (0); 1558 } 1559 1560 static char * 1561 serv_name_to_port_name(char *name) 1562 { 1563 /* 1564 * Map service names (used primarily in logging) to 1565 * RPC port names (used by netdir_*() routines). 1566 */ 1567 if (strcmp(name, "NFS") == 0) { 1568 return ("nfs"); 1569 } else if (strcmp(name, "NLM") == 0) { 1570 return ("lockd"); 1571 } else if (strcmp(name, "NFS4_CALLBACK") == 0) { 1572 return ("nfs4_callback"); 1573 } 1574 1575 return ("unrecognized"); 1576 } 1577 1578 static int 1579 bind_to_provider(char *provider, char *serv, struct netbuf **addr, 1580 struct netconfig **retnconf) 1581 { 1582 struct netconfig *nconf; 1583 NCONF_HANDLE *nc; 1584 struct nd_hostserv hs; 1585 1586 hs.h_host = HOST_SELF; 1587 hs.h_serv = serv_name_to_port_name(serv); 1588 1589 if ((nc = setnetconfig()) == (NCONF_HANDLE *)NULL) { 1590 syslog(LOG_ERR, "setnetconfig failed: %m"); 1591 return (-1); 1592 } 1593 while (nconf = getnetconfig(nc)) { 1594 if (OK_TPI_TYPE(nconf) && 1595 strcmp(nconf->nc_device, provider) == 0) { 1596 *retnconf = nconf; 1597 return (nfslib_bindit(nconf, addr, &hs, 1598 listen_backlog)); 1599 } 1600 } 1601 (void) endnetconfig(nc); 1602 1603 syslog(LOG_ERR, "couldn't find netconfig entry for provider %s", 1604 provider); 1605 return (-1); 1606 } 1607 1608 static int 1609 bind_to_proto(NETSELDECL(proto), char *serv, struct netbuf **addr, 1610 struct netconfig **retnconf) 1611 { 1612 struct netconfig *nconf; 1613 NCONF_HANDLE *nc = NULL; 1614 struct nd_hostserv hs; 1615 1616 hs.h_host = HOST_SELF; 1617 hs.h_serv = serv_name_to_port_name(serv); 1618 1619 if ((nc = setnetconfig()) == (NCONF_HANDLE *)NULL) { 1620 syslog(LOG_ERR, "setnetconfig failed: %m"); 1621 return (-1); 1622 } 1623 while (nconf = getnetconfig(nc)) { 1624 if (OK_TPI_TYPE(nconf) && NETSELEQ(nconf->nc_proto, proto)) { 1625 *retnconf = nconf; 1626 return (nfslib_bindit(nconf, addr, &hs, 1627 listen_backlog)); 1628 } 1629 } 1630 (void) endnetconfig(nc); 1631 1632 syslog(LOG_ERR, "couldn't find netconfig entry for protocol %s", 1633 proto); 1634 return (-1); 1635 } 1636 1637 #include <netinet/in.h> 1638 1639 /* 1640 * Create an address mask appropriate for the transport. 1641 * The mask is used to obtain the host-specific part of 1642 * a network address when comparing addresses. 1643 * For an internet address the host-specific part is just 1644 * the 32 bit IP address and this part of the mask is set 1645 * to all-ones. The port number part of the mask is zeroes. 1646 */ 1647 static int 1648 set_addrmask(fd, nconf, mask) 1649 struct netconfig *nconf; 1650 struct netbuf *mask; 1651 { 1652 struct t_info info; 1653 1654 /* 1655 * Find the size of the address we need to mask. 1656 */ 1657 if (t_getinfo(fd, &info) < 0) { 1658 t_error("t_getinfo"); 1659 return (-1); 1660 } 1661 mask->len = mask->maxlen = info.addr; 1662 if (info.addr <= 0) { 1663 syslog(LOG_ERR, "set_addrmask: address size: %ld", 1664 info.addr); 1665 return (-1); 1666 } 1667 1668 mask->buf = (char *)malloc(mask->len); 1669 if (mask->buf == NULL) { 1670 syslog(LOG_ERR, "set_addrmask: no memory"); 1671 return (-1); 1672 } 1673 (void) memset(mask->buf, 0, mask->len); /* reset all mask bits */ 1674 1675 if (strcmp(nconf->nc_protofmly, NC_INET) == 0) { 1676 /* 1677 * Set the mask so that the port is ignored. 1678 */ 1679 /* LINTED pointer alignment */ 1680 ((struct sockaddr_in *)mask->buf)->sin_addr.s_addr = 1681 (ulong_t)~0; 1682 /* LINTED pointer alignment */ 1683 ((struct sockaddr_in *)mask->buf)->sin_family = 1684 (ushort_t)~0; 1685 } else if (strcmp(nconf->nc_protofmly, NC_INET6) == 0) { 1686 /* LINTED pointer alignment */ 1687 (void) memset(&((struct sockaddr_in6 *)mask->buf)->sin6_addr, 1688 (uchar_t)~0, sizeof (struct in6_addr)); 1689 /* LINTED pointer alignment */ 1690 ((struct sockaddr_in6 *)mask->buf)->sin6_family = 1691 (ushort_t)~0; 1692 } else { 1693 1694 /* 1695 * Set all mask bits. 1696 */ 1697 (void) memset(mask->buf, 0xFF, mask->len); 1698 } 1699 return (0); 1700 } 1701 1702 /* 1703 * For listen fd's index is always less than end_listen_fds. 1704 * end_listen_fds is defined externally in the daemon that uses this library. 1705 * It's value is equal to the number of open file descriptors after the 1706 * last listen end point was opened but before any connection was accepted. 1707 */ 1708 static int 1709 is_listen_fd_index(int index) 1710 { 1711 return (index < end_listen_fds); 1712 } 1713