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 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * Contains routines that deal with TLI/XTI endpoints and rpc services. 30 */ 31 32 #include <sys/types.h> 33 #include <string.h> 34 #include <fcntl.h> 35 #include <stdlib.h> 36 #include <libintl.h> 37 #include <unistd.h> 38 #include <sys/sysmacros.h> 39 #include <netconfig.h> 40 #include <errno.h> 41 #include <sys/sockio.h> 42 #include "inetd_impl.h" 43 44 uu_list_pool_t *conn_ind_pool = NULL; 45 46 /* 47 * RPC functions. 48 */ 49 50 /* 51 * Returns B_TRUE if the non-address components of the 2 rpc_info_t structures 52 * are equivalent, else B_FALSE. 53 */ 54 boolean_t 55 rpc_info_equal(const rpc_info_t *ri, const rpc_info_t *ri2) 56 { 57 return ((ri->prognum == ri2->prognum) && 58 (ri->lowver == ri2->lowver) && 59 (ri->highver == ri2->highver) && 60 (strcmp(ri->netid, ri2->netid) == 0)); 61 } 62 63 /* 64 * Determine if we have a configured interface for the specified address 65 * family. This code is a mirror of libnsl's __can_use_af(). We mirror 66 * it because we need an exact duplicate of its behavior, yet the 67 * function isn't exported by libnsl, and this fix is considered short- 68 * term, so it's not worth exporting it. 69 * 70 * We need to duplicate __can_use_af() so we can accurately determine 71 * when getnetconfigent() returns failure for a v6 netid due to no IPv6 72 * interfaces being configured: getnetconfigent() returns failure 73 * if a netid is either 'tcp6' or 'udp6' and __can_use_af() returns 0, 74 * but it doesn't return a return code to uniquely determine this 75 * failure. If we don't accurately determine these failures, we could 76 * output error messages in a case when they weren't justified. 77 */ 78 static int 79 can_use_af(sa_family_t af) 80 { 81 struct lifnum lifn; 82 int fd; 83 84 if ((fd = open("/dev/udp", O_RDONLY)) < 0) { 85 return (0); 86 } 87 lifn.lifn_family = af; 88 /* LINTED ECONST_EXPR */ 89 lifn.lifn_flags = IFF_UP & !(IFF_NOXMIT | IFF_DEPRECATED); 90 if (ioctl(fd, SIOCGLIFNUM, &lifn, sizeof (lifn)) < 0) { 91 lifn.lifn_count = 0; 92 } 93 94 (void) close(fd); 95 return (lifn.lifn_count); 96 } 97 98 static boolean_t 99 is_v6_netid(const char *netid) 100 { 101 return ((strcmp(netid, SOCKET_PROTO_TCP6) == 0) || 102 (strcmp(netid, SOCKET_PROTO_UDP6) == 0)); 103 } 104 105 /* 106 * Registers with rpcbind the program number with all versions, from low to 107 * high, with the netid, all specified in 'rpc'. If registration fails, 108 * returns -1, else 0. 109 */ 110 int 111 register_rpc_service(const char *fmri, const rpc_info_t *rpc) 112 { 113 struct netconfig *nconf; 114 int ver; 115 116 debug_msg("Entering register_rpc_service: instance: %s", fmri); 117 118 if ((nconf = getnetconfigent(rpc->netid)) == NULL) { 119 /* 120 * Check whether getnetconfigent() failed as a result of 121 * having no IPv6 interfaces configured for a v6 netid, or 122 * as a result of a 'real' error, and output an appropriate 123 * message with an appropriate severity. 124 */ 125 if (is_v6_netid(rpc->netid) && !can_use_af(AF_INET6)) { 126 warn_msg(gettext( 127 "Couldn't register netid %s for RPC instance %s " 128 "because no IPv6 interfaces are plumbed"), 129 rpc->netid, fmri); 130 } else { 131 error_msg(gettext( 132 "Failed to lookup netid '%s' for instance %s: %s"), 133 rpc->netid, fmri, nc_sperror()); 134 } 135 return (-1); 136 } 137 138 for (ver = rpc->lowver; ver <= rpc->highver; ver++) { 139 if (!rpcb_set(rpc->prognum, ver, nconf, &(rpc->netbuf))) { 140 error_msg(gettext("Failed to register version %d " 141 "of RPC service instance %s, netid %s"), ver, 142 fmri, rpc->netid); 143 144 for (ver--; ver >= rpc->lowver; ver--) 145 (void) rpcb_unset(rpc->prognum, ver, nconf); 146 147 freenetconfigent(nconf); 148 return (-1); 149 } 150 } 151 152 freenetconfigent(nconf); 153 return (0); 154 } 155 156 /* Unregister all the registrations done by register_rpc_service */ 157 void 158 unregister_rpc_service(const char *fmri, const rpc_info_t *rpc) 159 { 160 int ver; 161 struct netconfig *nconf; 162 163 debug_msg("Entering unregister_rpc_service, instance: %s", fmri); 164 165 if ((nconf = getnetconfigent(rpc->netid)) == NULL) { 166 /* 167 * Don't output an error message if getnetconfigent() fails for 168 * a v6 netid when an IPv6 interface isn't configured. 169 */ 170 if (!(is_v6_netid(rpc->netid) && !can_use_af(AF_INET6))) { 171 error_msg(gettext( 172 "Failed to lookup netid '%s' for instance %s: %s"), 173 rpc->netid, fmri, nc_sperror()); 174 } 175 return; 176 } 177 178 for (ver = rpc->lowver; ver <= rpc->highver; ver++) 179 (void) rpcb_unset(rpc->prognum, ver, nconf); 180 181 freenetconfigent(nconf); 182 } 183 184 /* 185 * TLI/XTI functions. 186 */ 187 188 int 189 tlx_init(void) 190 { 191 if ((conn_ind_pool = uu_list_pool_create("conn_ind_pool", 192 sizeof (tlx_conn_ind_t), offsetof(tlx_conn_ind_t, link), 193 NULL, UU_LIST_POOL_DEBUG)) == NULL) { 194 error_msg("%s: %s", gettext("Failed to create uu pool"), 195 uu_strerror(uu_error())); 196 return (-1); 197 } 198 199 return (0); 200 } 201 202 void 203 tlx_fini(void) 204 { 205 if (conn_ind_pool != NULL) { 206 uu_list_pool_destroy(conn_ind_pool); 207 conn_ind_pool = NULL; 208 } 209 } 210 211 /* 212 * Checks if the contents of the 2 tlx_info_t structures are equivalent. 213 * If 'isrpc' is false, the address components of the two structures are 214 * compared for equality as part of this. If the two structures are 215 * equivalent B_TRUE is returned, else B_FALSE. 216 */ 217 boolean_t 218 tlx_info_equal(const tlx_info_t *ti, const tlx_info_t *ti2, boolean_t isrpc) 219 { 220 return ((isrpc || (memcmp(ti->local_addr.buf, ti2->local_addr.buf, 221 sizeof (struct sockaddr_storage)) == 0)) && 222 (strcmp(ti->dev_name, ti2->dev_name) == 0)); 223 } 224 225 /* 226 * Attempts to bind an address to the network fd 'fd'. If 'reqaddr' is non-NULL, 227 * it attempts to bind to that requested address, else it binds to a kernel 228 * selected address. In the former case, the function returning success 229 * doesn't guarantee that the requested address was bound (the caller needs to 230 * check). If 'retaddr' is non-NULL, the bound address is returned in it. The 231 * 'qlen' parameter is used to set the connection backlog. If the bind 232 * succeeds 0 is returned, else -1. 233 */ 234 static int 235 tlx_bind(int fd, const struct netbuf *reqaddr, struct netbuf *retaddr, int qlen) 236 { 237 struct t_bind breq; 238 struct t_bind bret; 239 240 debug_msg("Entering tlx_bind: req: %x, ret: %x, qlen: %d", reqaddr, 241 retaddr, qlen); 242 243 244 if (retaddr != NULL) { /* caller requests bound address be returned */ 245 bret.addr.buf = retaddr->buf; 246 bret.addr.maxlen = retaddr->maxlen; 247 } 248 249 if (reqaddr != NULL) { /* caller requests specific address */ 250 breq.addr.buf = reqaddr->buf; 251 breq.addr.len = reqaddr->len; 252 } else { 253 breq.addr.len = 0; 254 } 255 breq.qlen = qlen; 256 257 if (t_bind(fd, &breq, retaddr != NULL ? &bret : NULL) < 0) 258 return (-1); 259 260 if (retaddr != NULL) 261 retaddr->len = bret.addr.len; 262 263 return (0); 264 } 265 266 static int 267 tlx_setsockopt(int fd, int level, int optname, const void *optval, 268 socklen_t optlen) 269 { 270 struct t_optmgmt request, reply; 271 struct { 272 struct opthdr sockopt; 273 char data[256]; 274 } optbuf; 275 276 debug_msg("Entering tlx_setsockopt, " 277 "fd: %d, level: %d, optname: %d, optval: %x, optlen: %d", 278 fd, level, optname, optval, optlen); 279 280 if (optlen > sizeof (optbuf.data)) { 281 error_msg(gettext("t_optmgmt request too long")); 282 return (-1); 283 } 284 285 optbuf.sockopt.level = level; 286 optbuf.sockopt.name = optname; 287 optbuf.sockopt.len = optlen; 288 (void) memcpy(optbuf.data, optval, optlen); 289 290 request.opt.len = sizeof (struct opthdr) + optlen; 291 request.opt.buf = (char *)&optbuf; 292 request.flags = T_NEGOTIATE; 293 294 reply.opt.maxlen = sizeof (struct opthdr) + optlen; 295 reply.opt.buf = (char *)&optbuf; 296 reply.flags = 0; 297 298 if ((t_optmgmt(fd, &request, &reply) == -1) || 299 (reply.flags != T_SUCCESS)) { 300 error_msg("t_optmgmt: %s", t_strerror(t_errno)); 301 return (-1); 302 } 303 return (0); 304 } 305 306 /* 307 * Compare contents of netbuf for equality. Return B_TRUE on a match and 308 * B_FALSE for mismatch. 309 */ 310 static boolean_t 311 netbufs_equal(struct netbuf *n1, struct netbuf *n2) 312 { 313 return ((n1->len == n2->len) && 314 (memcmp(n1->buf, n2->buf, (size_t)n1->len) == 0)); 315 } 316 317 /* 318 * Create a tli/xti endpoint, either bound to the address specified in 319 * 'instance' for non-RPC services, else a kernel chosen address. 320 * Returns -1 on failure, else 0. 321 */ 322 int 323 create_bound_endpoint(const instance_t *inst, tlx_info_t *tlx_info) 324 { 325 int fd; 326 int qlen; 327 const char *fmri = inst->fmri; 328 struct netbuf *reqaddr; 329 struct netbuf *retaddr; 330 struct netbuf netbuf; 331 struct sockaddr_storage ss; 332 rpc_info_t *rpc = tlx_info->pr_info.ri; 333 334 debug_msg("Entering create_bound_endpoint"); 335 336 if ((fd = t_open(tlx_info->dev_name, O_RDWR, NULL)) == -1) { 337 error_msg(gettext("Failed to open transport %s for " 338 "instance %s, proto %s: %s"), tlx_info->dev_name, 339 fmri, tlx_info->pr_info.proto, t_strerror(t_errno)); 340 return (-1); 341 } 342 343 if (tlx_info->pr_info.v6only) { 344 int on = 1; 345 346 /* restrict to IPv6 communications only */ 347 if (tlx_setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, 348 sizeof (on)) == -1) { 349 (void) t_close(fd); 350 return (-1); 351 } 352 } 353 354 /* 355 * Negotiate for the returning of the remote uid for loopback 356 * transports for RPC services. This needs to be done before the 357 * endpoint is bound using t_bind(), so that any requests to it 358 * contain the uid. 359 */ 360 if ((rpc != NULL) && (rpc->is_loopback)) 361 svc_fd_negotiate_ucred(fd); 362 363 /* 364 * Bind the service's address to the endpoint and setup connection 365 * backlog. In the case of RPC services, we specify a NULL requested 366 * address and accept what we're given, storing the returned address 367 * for later RPC binding. In the case of non-RPC services we specify 368 * the service's associated address. 369 */ 370 if (rpc != NULL) { 371 reqaddr = NULL; 372 retaddr = &(rpc->netbuf); 373 } else { 374 reqaddr = &(tlx_info->local_addr); 375 netbuf.buf = (char *)&ss; 376 netbuf.maxlen = sizeof (ss); 377 retaddr = &netbuf; 378 } 379 380 /* ignored for conn/less services */ 381 qlen = inst->config->basic->conn_backlog; 382 383 if ((tlx_bind(fd, reqaddr, retaddr, qlen) == -1) || 384 ((reqaddr != NULL) && !netbufs_equal(reqaddr, retaddr))) { 385 error_msg(gettext("Failed to bind to the requested address " 386 "for instance %s, proto %s"), fmri, 387 tlx_info->pr_info.proto); 388 (void) t_close(fd); 389 return (-1); 390 } 391 392 return (fd); 393 } 394 395 /* 396 * Takes a connection request off 'fd' in the form of a t_call structure 397 * and returns a pointer to it. 398 * Returns NULL on failure, else pointer to t_call structure on success. 399 */ 400 static struct t_call * 401 get_new_conind(int fd) 402 { 403 struct t_call *call; 404 405 debug_msg("Entering get_new_conind"); 406 407 /* LINTED E_BAD_PTR_CAST_ALIGN */ 408 if ((call = (struct t_call *)t_alloc(fd, T_CALL, T_ALL)) == NULL) { 409 error_msg("t_alloc: %s", t_strerror(t_errno)); 410 return (NULL); 411 } 412 if (t_listen(fd, call) < 0) { 413 error_msg("t_listen: %s", t_strerror(t_errno)); 414 (void) t_free((char *)call, T_CALL); 415 return (NULL); 416 } 417 418 return (call); 419 } 420 421 /* Add 'call' to the connection indication queue 'queue'. */ 422 int 423 queue_conind(uu_list_t *queue, struct t_call *call) 424 { 425 tlx_conn_ind_t *ci; 426 427 if ((ci = malloc(sizeof (tlx_conn_ind_t))) == NULL) { 428 error_msg(strerror(errno)); 429 return (-1); 430 } 431 432 ci->call = call; 433 uu_list_node_init(ci, &ci->link, conn_ind_pool); 434 (void) uu_list_insert_after(queue, NULL, ci); 435 436 return (0); 437 } 438 439 /* 440 * Remove and return a pointer to the first call on queue 'queue'. However, 441 * if the queue is empty returns NULL. 442 */ 443 struct t_call * 444 dequeue_conind(uu_list_t *queue) 445 { 446 struct t_call *ret; 447 tlx_conn_ind_t *ci = uu_list_first(queue); 448 449 if (ci == NULL) 450 return (NULL); 451 452 ret = ci->call; 453 uu_list_remove(queue, ci); 454 free(ci); 455 456 return (ret); 457 } 458 459 /* 460 * Handle a TLOOK notification received during a t_accept() call. 461 * Returns -1 on failure, else 0. 462 */ 463 static int 464 process_tlook(const char *fmri, tlx_info_t *tlx_info) 465 { 466 int event; 467 int fd = tlx_info->pr_info.listen_fd; 468 469 debug_msg("Entering process_tlook:"); 470 471 switch (event = t_look(fd)) { 472 case T_LISTEN: { 473 struct t_call *call; 474 475 debug_msg("process_tlook: T_LISTEN event"); 476 if ((call = get_new_conind(fd)) == NULL) 477 return (-1); 478 if (queue_conind(tlx_info->conn_ind_queue, call) == -1) { 479 error_msg(gettext("Failed to queue connection " 480 "indication for instance %s"), fmri); 481 (void) t_free((char *)call, T_CALL); 482 return (-1); 483 } 484 break; 485 } 486 case T_DISCONNECT: { 487 /* 488 * Note: In Solaris 2.X (SunOS 5.X) bundled 489 * connection-oriented transport drivers 490 * [ e.g /dev/tcp and /dev/ticots and 491 * /dev/ticotsord (tl)] we do not send disconnect 492 * indications to listening endpoints. 493 * So this will not be seen with endpoints on Solaris 494 * bundled transport devices. However, Streams TPI 495 * allows for this (broken?) behavior and so we account 496 * for it here because of the possibility of unbundled 497 * transport drivers causing this. 498 */ 499 tlx_conn_ind_t *cip; 500 struct t_discon *discon; 501 502 debug_msg("process_tlook: T_DISCONNECT event"); 503 504 /* LINTED */ 505 if ((discon = (struct t_discon *) 506 t_alloc(fd, T_DIS, T_ALL)) == NULL) { 507 error_msg("t_alloc: %s", t_strerror(t_errno)); 508 return (-1); 509 } 510 if (t_rcvdis(fd, discon) < 0) { 511 error_msg("t_rcvdis: %s", t_strerror(t_errno)); 512 (void) t_free((char *)discon, T_DIS); 513 return (-1); 514 } 515 516 /* 517 * Find any queued connection pending that matches this 518 * disconnect notice and remove from the pending queue. 519 */ 520 cip = uu_list_first(tlx_info->conn_ind_queue); 521 while ((cip != NULL) && 522 (cip->call->sequence != discon->sequence)) { 523 cip = uu_list_next(tlx_info->conn_ind_queue, cip); 524 } 525 if (cip != NULL) { /* match found */ 526 uu_list_remove(tlx_info->conn_ind_queue, cip); 527 (void) t_free((char *)cip->call, T_CALL); 528 free(cip); 529 } 530 531 (void) t_free((char *)discon, T_DIS); 532 break; 533 } 534 case -1: 535 error_msg("t_look: %s", t_errno); 536 return (-1); 537 default: 538 error_msg(gettext("do_tlook: unexpected t_look event: %d"), 539 event); 540 return (-1); 541 } 542 543 return (0); 544 } 545 546 /* 547 * This call attempts to t_accept() an incoming/pending TLI connection. 548 * If it is thwarted by a TLOOK, it is deferred and whatever is on the 549 * file descriptor, removed after a t_look. (Incoming connect indications 550 * get queued for later processing and disconnect indications remove a 551 * a queued connection request if a match found). 552 * Returns -1 on failure, else 0. 553 */ 554 int 555 tlx_accept(const char *fmri, tlx_info_t *tlx_info, 556 struct sockaddr_storage *remote_addr) 557 { 558 tlx_conn_ind_t *conind; 559 struct t_call *call; 560 int fd; 561 int listen_fd = tlx_info->pr_info.listen_fd; 562 563 debug_msg("Entering tlx_accept: instance: %s", fmri); 564 565 if ((fd = t_open(tlx_info->dev_name, O_RDWR, NULL)) == -1) { 566 error_msg("t_open: %s", t_strerror(t_errno)); 567 return (-1); 568 } 569 570 if (tlx_info->pr_info.v6only) { 571 int on = 1; 572 573 /* restrict to IPv6 communications only */ 574 if (tlx_setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, 575 sizeof (on)) == -1) { 576 (void) t_close(fd); 577 return (-1); 578 } 579 } 580 581 if (t_bind(fd, NULL, NULL) == -1) { 582 error_msg("t_bind: %s", t_strerror(t_errno)); 583 (void) t_close(fd); 584 return (-1); 585 } 586 587 /* 588 * Get the next connection indication - first try the pending 589 * queue, then, if none there, get a new one from the file descriptor. 590 */ 591 if ((conind = uu_list_first(tlx_info->conn_ind_queue)) != NULL) { 592 debug_msg("taking con off queue"); 593 call = conind->call; 594 } else if ((call = get_new_conind(listen_fd)) == NULL) { 595 (void) t_close(fd); 596 return (-1); 597 } 598 599 /* 600 * Accept the connection indication on the newly created endpoint. 601 * If we fail, and it's the result of a tlook, queue the indication 602 * if it isn't already, and go and process the t_look. 603 */ 604 if (t_accept(listen_fd, fd, call) == -1) { 605 if (t_errno == TLOOK) { 606 if (uu_list_first(tlx_info->conn_ind_queue) == NULL) { 607 /* 608 * We are first one to have to defer accepting 609 * and start the pending connections list. 610 */ 611 if (queue_conind(tlx_info->conn_ind_queue, 612 call) == -1) { 613 error_msg(gettext( 614 "Failed to queue connection " 615 "indication for instance %s"), 616 fmri); 617 (void) t_free((char *)call, T_CALL); 618 return (-1); 619 } 620 } 621 (void) process_tlook(fmri, tlx_info); 622 } else { /* non-TLOOK accept failure */ 623 error_msg("%s: %s", "t_accept failed", 624 t_strerror(t_errno)); 625 /* 626 * If we were accepting a queued connection, dequeue 627 * it. 628 */ 629 if (uu_list_first(tlx_info->conn_ind_queue) != NULL) 630 (void) dequeue_conind(tlx_info->conn_ind_queue); 631 (void) t_free((char *)call, T_CALL); 632 } 633 634 (void) t_close(fd); 635 return (-1); 636 } 637 638 /* Copy remote address into address parameter */ 639 (void) memcpy(remote_addr, call->addr.buf, 640 MIN(call->addr.len, sizeof (*remote_addr))); 641 642 /* If we were accepting a queued connection, dequeue it. */ 643 if (uu_list_first(tlx_info->conn_ind_queue) != NULL) 644 (void) dequeue_conind(tlx_info->conn_ind_queue); 645 (void) t_free((char *)call, T_CALL); 646 647 return (fd); 648 } 649 650 /* protocol independent network fd close routine */ 651 void 652 close_net_fd(instance_t *inst, int fd) 653 { 654 debug_msg("Entering close_net_fd: inst: %s, fd: %d", inst->fmri, fd); 655 656 if (inst->config->basic->istlx) { 657 (void) t_close(fd); 658 } else { 659 (void) close(fd); 660 } 661 } 662 663 /* 664 * Consume some data from the given endpoint of the given wait-based instance. 665 */ 666 void 667 consume_wait_data(instance_t *inst, int fd) 668 { 669 int flag; 670 char buf[50]; /* same arbitrary size as old inetd */ 671 672 debug_msg("Entering consume_wait_data: inst: %s, fd: %d", inst->fmri, 673 fd); 674 675 if (inst->config->basic->istlx) { 676 (void) t_rcv(fd, buf, sizeof (buf), &flag); 677 } else { 678 (void) recv(fd, buf, sizeof (buf), 0); 679 } 680 } 681