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