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 /* 24 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 25 * Use is subject to license terms. 26 */ 27 28 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 29 /* All Rights Reserved */ 30 /* 31 * Portions of this source code were derived from Berkeley 32 * 4.3 BSD under license from the Regents of the University of 33 * California. 34 */ 35 36 #pragma ident "%Z%%M% %I% %E% SMI" 37 38 #include "mt.h" 39 #include "rpc_mt.h" 40 #include <stdio.h> 41 #include <errno.h> 42 #include <unistd.h> 43 #include <stdlib.h> 44 #include <rpc/rpc.h> 45 #include <rpc/nettype.h> 46 #include <netdir.h> 47 #include <string.h> 48 #include <syslog.h> 49 50 extern int __td_setnodelay(int); 51 extern bool_t __rpc_is_local_host(const char *); 52 extern bool_t __rpc_try_doors(const char *, bool_t *); 53 extern CLIENT *_clnt_vc_create_timed(int, struct netbuf *, rpcprog_t, 54 rpcvers_t, uint_t, uint_t, const struct timeval *); 55 56 CLIENT *_clnt_tli_create_timed(int, const struct netconfig *, struct netbuf *, 57 rpcprog_t, rpcvers_t, uint_t, uint_t, const struct timeval *); 58 59 #ifndef NETIDLEN 60 #define NETIDLEN 32 61 #endif 62 63 /* 64 * Generic client creation with version checking the value of 65 * vers_out is set to the highest server supported value 66 * vers_low <= vers_out <= vers_high AND an error results 67 * if this can not be done. 68 * 69 * It calls clnt_create_vers_timed() with a NULL value for the timeout 70 * pointer, which indicates that the default timeout should be used. 71 */ 72 CLIENT * 73 clnt_create_vers(const char *hostname, const rpcprog_t prog, 74 rpcvers_t *vers_out, const rpcvers_t vers_low, 75 const rpcvers_t vers_high, const char *nettype) 76 { 77 return (clnt_create_vers_timed(hostname, prog, vers_out, vers_low, 78 vers_high, nettype, NULL)); 79 } 80 81 /* 82 * This routine has the same definition as clnt_create_vers(), 83 * except it takes an additional timeout parameter - a pointer to 84 * a timeval structure. A NULL value for the pointer indicates 85 * that the default timeout value should be used. 86 */ 87 CLIENT * 88 clnt_create_vers_timed(const char *hostname, const rpcprog_t prog, 89 rpcvers_t *vers_out, const rpcvers_t vers_low, const rpcvers_t vers_high, 90 const char *nettype, const struct timeval *tp) 91 { 92 CLIENT *clnt; 93 struct timeval to; 94 enum clnt_stat rpc_stat; 95 struct rpc_err rpcerr; 96 rpcvers_t v_low, v_high; 97 98 clnt = clnt_create_timed(hostname, prog, vers_high, nettype, tp); 99 if (clnt == NULL) 100 return (NULL); 101 if (tp == NULL) { 102 to.tv_sec = 10; 103 to.tv_usec = 0; 104 } else 105 to = *tp; 106 107 rpc_stat = clnt_call(clnt, NULLPROC, (xdrproc_t)xdr_void, 108 NULL, (xdrproc_t)xdr_void, NULL, to); 109 if (rpc_stat == RPC_SUCCESS) { 110 *vers_out = vers_high; 111 return (clnt); 112 } 113 v_low = vers_low; 114 v_high = vers_high; 115 while (rpc_stat == RPC_PROGVERSMISMATCH && v_high > v_low) { 116 unsigned int minvers, maxvers; 117 118 clnt_geterr(clnt, &rpcerr); 119 minvers = rpcerr.re_vers.low; 120 maxvers = rpcerr.re_vers.high; 121 if (maxvers < v_high) 122 v_high = maxvers; 123 else 124 v_high--; 125 if (minvers > v_low) 126 v_low = minvers; 127 if (v_low > v_high) { 128 goto error; 129 } 130 CLNT_CONTROL(clnt, CLSET_VERS, (char *)&v_high); 131 rpc_stat = clnt_call(clnt, NULLPROC, (xdrproc_t)xdr_void, 132 NULL, (xdrproc_t)xdr_void, 133 NULL, to); 134 if (rpc_stat == RPC_SUCCESS) { 135 *vers_out = v_high; 136 return (clnt); 137 } 138 } 139 clnt_geterr(clnt, &rpcerr); 140 141 error: 142 rpc_createerr.cf_stat = rpc_stat; 143 rpc_createerr.cf_error = rpcerr; 144 clnt_destroy(clnt); 145 return (NULL); 146 } 147 148 /* 149 * Top level client creation routine. 150 * Generic client creation: takes (servers name, program-number, nettype) and 151 * returns client handle. Default options are set, which the user can 152 * change using the rpc equivalent of ioctl()'s. 153 * 154 * It tries for all the netids in that particular class of netid until 155 * it succeeds. 156 * XXX The error message in the case of failure will be the one 157 * pertaining to the last create error. 158 * 159 * It calls clnt_create_timed() with the default timeout. 160 */ 161 CLIENT * 162 clnt_create(const char *hostname, const rpcprog_t prog, const rpcvers_t vers, 163 const char *nettype) 164 { 165 return (clnt_create_timed(hostname, prog, vers, nettype, NULL)); 166 } 167 168 /* 169 * This the routine has the same definition as clnt_create(), 170 * except it takes an additional timeout parameter - a pointer to 171 * a timeval structure. A NULL value for the pointer indicates 172 * that the default timeout value should be used. 173 * 174 * This function calls clnt_tp_create_timed(). 175 */ 176 CLIENT * 177 clnt_create_timed(const char *hostname, const rpcprog_t prog, 178 const rpcvers_t vers, const char *netclass, const struct timeval *tp) 179 { 180 struct netconfig *nconf; 181 CLIENT *clnt = NULL; 182 void *handle; 183 enum clnt_stat save_cf_stat = RPC_SUCCESS; 184 struct rpc_err save_cf_error; 185 char nettype_array[NETIDLEN]; 186 char *nettype = &nettype_array[0]; 187 bool_t try_others; 188 189 if (netclass == NULL) 190 nettype = NULL; 191 else { 192 size_t len = strlen(netclass); 193 if (len >= sizeof (nettype_array)) { 194 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 195 return (NULL); 196 } 197 (void) strcpy(nettype, netclass); 198 } 199 200 /* 201 * Check to see if a rendezvous over doors should be attempted. 202 */ 203 if (__rpc_try_doors(nettype, &try_others)) { 204 /* 205 * Make sure this is the local host. 206 */ 207 if (__rpc_is_local_host(hostname)) { 208 if ((clnt = clnt_door_create(prog, vers, 0)) != NULL) 209 return (clnt); 210 else { 211 if (rpc_createerr.cf_stat == RPC_SYSTEMERROR) 212 return (NULL); 213 save_cf_stat = rpc_createerr.cf_stat; 214 save_cf_error = rpc_createerr.cf_error; 215 } 216 } else { 217 save_cf_stat = rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 218 } 219 } 220 if (!try_others) 221 return (NULL); 222 223 if ((handle = __rpc_setconf((char *)nettype)) == NULL) { 224 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 225 return (NULL); 226 } 227 rpc_createerr.cf_stat = RPC_SUCCESS; 228 while (clnt == NULL) { 229 if ((nconf = __rpc_getconf(handle)) == NULL) { 230 if (rpc_createerr.cf_stat == RPC_SUCCESS) 231 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 232 break; 233 } 234 clnt = clnt_tp_create_timed(hostname, prog, vers, nconf, tp); 235 if (clnt) 236 break; 237 else { 238 /* 239 * Since we didn't get a name-to-address 240 * translation failure here, we remember 241 * this particular error. The object of 242 * this is to enable us to return to the 243 * caller a more-specific error than the 244 * unhelpful ``Name to address translation 245 * failed'' which might well occur if we 246 * merely returned the last error (because 247 * the local loopbacks are typically the 248 * last ones in /etc/netconfig and the most 249 * likely to be unable to translate a host 250 * name). We also check for a more 251 * meaningful error than ``unknown host 252 * name'' for the same reasons. 253 */ 254 if (rpc_createerr.cf_stat == RPC_SYSTEMERROR) { 255 syslog(LOG_ERR, "clnt_create_timed: " 256 "RPC_SYSTEMERROR."); 257 break; 258 } 259 260 if (rpc_createerr.cf_stat != RPC_N2AXLATEFAILURE && 261 rpc_createerr.cf_stat != RPC_UNKNOWNHOST) { 262 save_cf_stat = rpc_createerr.cf_stat; 263 save_cf_error = rpc_createerr.cf_error; 264 } 265 } 266 } 267 268 /* 269 * Attempt to return an error more specific than ``Name to address 270 * translation failed'' or ``unknown host name'' 271 */ 272 if ((rpc_createerr.cf_stat == RPC_N2AXLATEFAILURE || 273 rpc_createerr.cf_stat == RPC_UNKNOWNHOST) && 274 (save_cf_stat != RPC_SUCCESS)) { 275 rpc_createerr.cf_stat = save_cf_stat; 276 rpc_createerr.cf_error = save_cf_error; 277 } 278 __rpc_endconf(handle); 279 return (clnt); 280 } 281 282 /* 283 * Create a client handle for a well known service or a specific port on 284 * host. This routine bypasses rpcbind and can be use to construct a client 285 * handle to services that are not registered with rpcbind or where the remote 286 * rpcbind is not available, e.g., the remote rpcbind port is blocked by a 287 * firewall. We construct a client handle and then ping the service's NULL 288 * proc to see that the service is really available. If the caller supplies 289 * a non zero port number, the service name is ignored and the port will be 290 * used. A non-zero port number limits the protocol family to inet or inet6. 291 */ 292 293 CLIENT * 294 clnt_create_service_timed(const char *host, const char *service, 295 const rpcprog_t prog, const rpcvers_t vers, 296 const ushort_t port, const char *netclass, 297 const struct timeval *tmout) 298 { 299 int fd; 300 void *handle; 301 CLIENT *clnt = NULL; 302 struct netconfig *nconf; 303 struct nd_hostserv hs; 304 struct nd_addrlist *raddrs; 305 struct t_bind *tbind = NULL; 306 struct timeval to; 307 char nettype_array[NETIDLEN]; 308 char *nettype = &nettype_array[0]; 309 char *hostname, *serv; 310 bool_t try_others; 311 extern int __rpc_minfd; 312 313 314 /* 315 * handle const of netclass 316 */ 317 if (netclass == NULL) 318 nettype = NULL; 319 else { 320 size_t len = strlen(netclass); 321 if (len >= sizeof (nettype_array)) { 322 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 323 return (NULL); 324 } 325 (void) strcpy(nettype, netclass); 326 } 327 328 if (tmout == NULL) { 329 to.tv_sec = 10; 330 to.tv_usec = 0; 331 } else 332 to = *tmout; 333 334 if ((handle = __rpc_setconf(nettype)) == NULL) { 335 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 336 return (NULL); 337 } 338 339 /* 340 * Sinct host, and service are const 341 */ 342 if (host == NULL || (hostname = strdup(host)) == NULL) { 343 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 344 rpc_createerr.cf_error.re_errno = (host ? errno : EINVAL); 345 rpc_createerr.cf_error.re_terrno = 0; 346 return (NULL); 347 } 348 349 if (service == NULL) 350 serv = NULL; 351 else if ((serv = strdup(service ? service : "")) == NULL) { 352 free(hostname); 353 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 354 rpc_createerr.cf_error.re_errno = errno; 355 rpc_createerr.cf_error.re_terrno = 0; 356 return (NULL); 357 } 358 359 hs.h_host = hostname; 360 hs.h_serv = port ? NULL : serv; 361 362 /* 363 * Check to see if a rendezvous over doors should be attempted. 364 */ 365 if (__rpc_try_doors(nettype, &try_others)) { 366 /* 367 * Make sure this is the local host. 368 */ 369 if (__rpc_is_local_host(hostname)) { 370 if ((clnt = clnt_door_create(prog, vers, 0)) != NULL) 371 goto done; 372 else if (rpc_createerr.cf_stat == RPC_SYSTEMERROR) 373 goto done; 374 } else { 375 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 376 } 377 } 378 if (!try_others) 379 goto done; 380 381 rpc_createerr.cf_stat = RPC_SUCCESS; 382 while (clnt == NULL) { 383 tbind = NULL; 384 if ((nconf = __rpc_getconf(handle)) == NULL) { 385 if (rpc_createerr.cf_stat == RPC_SUCCESS) 386 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 387 break; 388 } 389 390 if (port) { 391 if (strcmp(nconf->nc_protofmly, NC_INET) != 0 && 392 strcmp(nconf->nc_protofmly, NC_INET6) != 0) 393 continue; 394 } 395 396 if ((fd = t_open(nconf->nc_device, O_RDWR, NULL)) < 0) { 397 rpc_createerr.cf_stat = RPC_TLIERROR; 398 rpc_createerr.cf_error.re_errno = errno; 399 rpc_createerr.cf_error.re_terrno = t_errno; 400 continue; 401 } 402 403 if (fd < __rpc_minfd) 404 fd = __rpc_raise_fd(fd); 405 406 /* LINTED pointer cast */ 407 if ((tbind = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR)) 408 == NULL) { 409 (void) t_close(fd); 410 rpc_createerr.cf_stat = RPC_TLIERROR; 411 rpc_createerr.cf_error.re_errno = errno; 412 rpc_createerr.cf_error.re_terrno = t_errno; 413 continue; 414 } 415 416 if (netdir_getbyname(nconf, &hs, &raddrs) != ND_OK) { 417 if (rpc_createerr.cf_stat == RPC_SUCCESS) 418 rpc_createerr.cf_stat = RPC_UNKNOWNHOST; 419 if (tbind) 420 (void) t_free((char *)tbind, T_BIND); 421 (void) t_close(fd); 422 continue; 423 } 424 (void) memcpy(tbind->addr.buf, raddrs->n_addrs->buf, 425 raddrs->n_addrs->len); 426 tbind->addr.len = raddrs->n_addrs->len; 427 netdir_free((void *)raddrs, ND_ADDRLIST); 428 429 if (port) { 430 if (strcmp(nconf->nc_protofmly, NC_INET) == NULL) 431 /* LINTED pointer alignment */ 432 ((struct sockaddr_in *) 433 tbind->addr.buf)->sin_port = htons(port); 434 else if (strcmp(nconf->nc_protofmly, NC_INET6) == NULL) 435 /* LINTED pointer alignment */ 436 ((struct sockaddr_in6 *) 437 tbind->addr.buf)->sin6_port = htons(port); 438 } 439 440 clnt = _clnt_tli_create_timed(fd, nconf, &tbind->addr, 441 prog, vers, 0, 0, &to); 442 443 if (clnt == NULL) { 444 if (tbind) 445 (void) t_free((char *)tbind, T_BIND); 446 (void) t_close(fd); 447 continue; 448 } 449 450 (void) CLNT_CONTROL(clnt, CLSET_FD_CLOSE, NULL); 451 452 /* 453 * Check if we can reach the server with this clnt handle 454 * Other clnt_create calls do a ping by contacting the 455 * remote rpcbind, here will just try to execute the service's 456 * NULL proc. 457 */ 458 459 rpc_createerr.cf_stat = clnt_call(clnt, NULLPROC, 460 xdr_void, 0, xdr_void, 0, to); 461 462 rpc_createerr.cf_error.re_errno = rpc_callerr.re_status; 463 rpc_createerr.cf_error.re_terrno = 0; 464 465 if (rpc_createerr.cf_stat != RPC_SUCCESS) { 466 clnt_destroy(clnt); 467 clnt = NULL; 468 if (tbind) 469 (void) t_free((char *)tbind, T_BIND); 470 continue; 471 } else 472 break; 473 } 474 475 __rpc_endconf(handle); 476 if (tbind) 477 (void) t_free((char *)tbind, T_BIND); 478 479 done: 480 if (hostname) 481 free(hostname); 482 if (serv) 483 free(serv); 484 485 return (clnt); 486 } 487 488 /* 489 * Generic client creation: takes (servers name, program-number, netconf) and 490 * returns client handle. Default options are set, which the user can 491 * change using the rpc equivalent of ioctl()'s : clnt_control() 492 * It finds out the server address from rpcbind and calls clnt_tli_create(). 493 * 494 * It calls clnt_tp_create_timed() with the default timeout. 495 */ 496 CLIENT * 497 clnt_tp_create(const char *hostname, const rpcprog_t prog, const rpcvers_t vers, 498 const struct netconfig *nconf) 499 { 500 return (clnt_tp_create_timed(hostname, prog, vers, nconf, NULL)); 501 } 502 503 /* 504 * This has the same definition as clnt_tp_create(), except it 505 * takes an additional parameter - a pointer to a timeval structure. 506 * A NULL value for the timeout pointer indicates that the default 507 * value for the timeout should be used. 508 */ 509 CLIENT * 510 clnt_tp_create_timed(const char *hostname, const rpcprog_t prog, 511 const rpcvers_t vers, const struct netconfig *nconf, 512 const struct timeval *tp) 513 { 514 struct netbuf *svcaddr; /* servers address */ 515 CLIENT *cl = NULL; /* client handle */ 516 extern struct netbuf *__rpcb_findaddr_timed(rpcprog_t, rpcvers_t, 517 struct netconfig *, char *, CLIENT **, struct timeval *); 518 519 if (nconf == NULL) { 520 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 521 return (NULL); 522 } 523 524 /* 525 * Get the address of the server 526 */ 527 if ((svcaddr = __rpcb_findaddr_timed(prog, vers, 528 (struct netconfig *)nconf, (char *)hostname, 529 &cl, (struct timeval *)tp)) == NULL) { 530 /* appropriate error number is set by rpcbind libraries */ 531 return (NULL); 532 } 533 if (cl == NULL) { 534 cl = _clnt_tli_create_timed(RPC_ANYFD, nconf, svcaddr, 535 prog, vers, 0, 0, tp); 536 } else { 537 /* Reuse the CLIENT handle and change the appropriate fields */ 538 if (CLNT_CONTROL(cl, CLSET_SVC_ADDR, (void *)svcaddr) == TRUE) { 539 if (cl->cl_netid == NULL) { 540 cl->cl_netid = strdup(nconf->nc_netid); 541 if (cl->cl_netid == NULL) { 542 netdir_free((char *)svcaddr, ND_ADDR); 543 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 544 syslog(LOG_ERR, 545 "clnt_tp_create_timed: " 546 "strdup failed."); 547 return (NULL); 548 } 549 } 550 if (cl->cl_tp == NULL) { 551 cl->cl_tp = strdup(nconf->nc_device); 552 if (cl->cl_tp == NULL) { 553 netdir_free((char *)svcaddr, ND_ADDR); 554 if (cl->cl_netid) 555 free(cl->cl_netid); 556 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 557 syslog(LOG_ERR, 558 "clnt_tp_create_timed: " 559 "strdup failed."); 560 return (NULL); 561 } 562 } 563 (void) CLNT_CONTROL(cl, CLSET_PROG, (void *)&prog); 564 (void) CLNT_CONTROL(cl, CLSET_VERS, (void *)&vers); 565 } else { 566 CLNT_DESTROY(cl); 567 cl = _clnt_tli_create_timed(RPC_ANYFD, nconf, svcaddr, 568 prog, vers, 0, 0, tp); 569 } 570 } 571 netdir_free((char *)svcaddr, ND_ADDR); 572 return (cl); 573 } 574 575 /* 576 * Generic client creation: returns client handle. 577 * Default options are set, which the user can 578 * change using the rpc equivalent of ioctl()'s : clnt_control(). 579 * If fd is RPC_ANYFD, it will be opened using nconf. 580 * It will be bound if not so. 581 * If sizes are 0; appropriate defaults will be chosen. 582 */ 583 CLIENT * 584 clnt_tli_create(const int fd, const struct netconfig *nconf, 585 struct netbuf *svcaddr, const rpcprog_t prog, const rpcvers_t vers, 586 const uint_t sendsz, const uint_t recvsz) 587 { 588 return (_clnt_tli_create_timed(fd, nconf, svcaddr, prog, vers, sendsz, 589 recvsz, NULL)); 590 } 591 592 /* 593 * This has the same definition as clnt_tli_create(), except it 594 * takes an additional parameter - a pointer to a timeval structure. 595 * 596 * Not a public interface. This is for clnt_create_timed, 597 * clnt_create_vers_times, clnt_tp_create_timed to pass down the 598 * timeout value to COTS creation routine. 599 * (for bug 4049792: clnt_create_timed does not time out) 600 */ 601 CLIENT * 602 _clnt_tli_create_timed(int fd, const struct netconfig *nconf, 603 struct netbuf *svcaddr, rpcprog_t prog, rpcvers_t vers, uint_t sendsz, 604 uint_t recvsz, const struct timeval *tp) 605 { 606 CLIENT *cl; /* client handle */ 607 struct t_info tinfo; /* transport info */ 608 bool_t madefd; /* whether fd opened here */ 609 t_scalar_t servtype; 610 int retval; 611 extern int __rpc_minfd; 612 613 if (fd == RPC_ANYFD) { 614 if (nconf == NULL) { 615 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 616 return (NULL); 617 } 618 619 fd = t_open(nconf->nc_device, O_RDWR, NULL); 620 if (fd == -1) 621 goto err; 622 if (fd < __rpc_minfd) 623 fd = __rpc_raise_fd(fd); 624 madefd = TRUE; 625 if (t_bind(fd, NULL, NULL) == -1) 626 goto err; 627 switch (nconf->nc_semantics) { 628 case NC_TPI_CLTS: 629 servtype = T_CLTS; 630 break; 631 case NC_TPI_COTS: 632 servtype = T_COTS; 633 break; 634 case NC_TPI_COTS_ORD: 635 servtype = T_COTS_ORD; 636 break; 637 default: 638 if (t_getinfo(fd, &tinfo) == -1) 639 goto err; 640 servtype = tinfo.servtype; 641 break; 642 } 643 } else { 644 int state; /* Current state of provider */ 645 646 /* 647 * Sync the opened fd. 648 * Check whether bound or not, else bind it 649 */ 650 if (((state = t_sync(fd)) == -1) || 651 ((state == T_UNBND) && (t_bind(fd, NULL, NULL) == -1)) || 652 (t_getinfo(fd, &tinfo) == -1)) 653 goto err; 654 servtype = tinfo.servtype; 655 madefd = FALSE; 656 } 657 658 switch (servtype) { 659 case T_COTS: 660 cl = _clnt_vc_create_timed(fd, svcaddr, prog, vers, sendsz, 661 recvsz, tp); 662 break; 663 case T_COTS_ORD: 664 if (nconf && ((strcmp(nconf->nc_protofmly, NC_INET) == 0) || 665 (strcmp(nconf->nc_protofmly, NC_INET6) == 0))) { 666 retval = __td_setnodelay(fd); 667 if (retval == -1) 668 goto err; 669 } 670 cl = _clnt_vc_create_timed(fd, svcaddr, prog, vers, sendsz, 671 recvsz, tp); 672 break; 673 case T_CLTS: 674 cl = clnt_dg_create(fd, svcaddr, prog, vers, sendsz, recvsz); 675 break; 676 default: 677 goto err; 678 } 679 680 if (cl == NULL) 681 goto err1; /* borrow errors from clnt_dg/vc creates */ 682 if (nconf) { 683 cl->cl_netid = strdup(nconf->nc_netid); 684 if (cl->cl_netid == NULL) { 685 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 686 rpc_createerr.cf_error.re_errno = errno; 687 rpc_createerr.cf_error.re_terrno = 0; 688 syslog(LOG_ERR, 689 "clnt_tli_create: strdup failed"); 690 goto err1; 691 } 692 cl->cl_tp = strdup(nconf->nc_device); 693 if (cl->cl_tp == NULL) { 694 if (cl->cl_netid) 695 free(cl->cl_netid); 696 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 697 rpc_createerr.cf_error.re_errno = errno; 698 rpc_createerr.cf_error.re_terrno = 0; 699 syslog(LOG_ERR, 700 "clnt_tli_create: strdup failed"); 701 goto err1; 702 } 703 } else { 704 struct netconfig *nc; 705 706 if ((nc = __rpcfd_to_nconf(fd, servtype)) != NULL) { 707 if (nc->nc_netid) { 708 cl->cl_netid = strdup(nc->nc_netid); 709 if (cl->cl_netid == NULL) { 710 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 711 rpc_createerr.cf_error.re_errno = errno; 712 rpc_createerr.cf_error.re_terrno = 0; 713 syslog(LOG_ERR, 714 "clnt_tli_create: " 715 "strdup failed"); 716 goto err1; 717 } 718 } 719 if (nc->nc_device) { 720 cl->cl_tp = strdup(nc->nc_device); 721 if (cl->cl_tp == NULL) { 722 if (cl->cl_netid) 723 free(cl->cl_netid); 724 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 725 rpc_createerr.cf_error.re_errno = errno; 726 rpc_createerr.cf_error.re_terrno = 0; 727 syslog(LOG_ERR, 728 "clnt_tli_create: " 729 "strdup failed"); 730 goto err1; 731 } 732 } 733 freenetconfigent(nc); 734 } 735 if (cl->cl_netid == NULL) 736 cl->cl_netid = ""; 737 if (cl->cl_tp == NULL) 738 cl->cl_tp = ""; 739 } 740 if (madefd) { 741 (void) CLNT_CONTROL(cl, CLSET_FD_CLOSE, NULL); 742 /* (void) CLNT_CONTROL(cl, CLSET_POP_TIMOD, NULL); */ 743 }; 744 745 return (cl); 746 747 err: 748 rpc_createerr.cf_stat = RPC_TLIERROR; 749 rpc_createerr.cf_error.re_errno = errno; 750 rpc_createerr.cf_error.re_terrno = t_errno; 751 err1: if (madefd) 752 (void) t_close(fd); 753 return (NULL); 754 } 755 756 /* 757 * To avoid conflicts with the "magic" file descriptors (0, 1, and 2), 758 * we try to not use them. The __rpc_raise_fd() routine will dup 759 * a descriptor to a higher value. If we fail to do it, we continue 760 * to use the old one (and hope for the best). 761 */ 762 int __rpc_minfd = 3; 763 764 int 765 __rpc_raise_fd(int fd) 766 { 767 int nfd; 768 769 if (fd >= __rpc_minfd) 770 return (fd); 771 772 if ((nfd = fcntl(fd, F_DUPFD, __rpc_minfd)) == -1) 773 return (fd); 774 775 if (t_sync(nfd) == -1) { 776 (void) close(nfd); 777 return (fd); 778 } 779 780 if (t_close(fd) == -1) { 781 /* this is okay, we will syslog an error, then use the new fd */ 782 (void) syslog(LOG_ERR, 783 "could not t_close() fd %d; mem & fd leak", fd); 784 } 785 786 return (nfd); 787 } 788