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