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