1 /* 2 * The contents of this file are subject to the Sun Standards 3 * License Version 1.0 the (the "License";) You may not use 4 * this file except in compliance with the License. You may 5 * obtain a copy of the License at lib/libc/rpc/LICENSE 6 * 7 * Software distributed under the License is distributed on 8 * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either 9 * express or implied. See the License for the specific 10 * language governing rights and limitations under the License. 11 * 12 * The Original Code is Copyright 1998 by Sun Microsystems, Inc 13 * 14 * The Initial Developer of the Original Code is: Sun 15 * Microsystems, Inc. 16 * 17 * All Rights Reserved. 18 * 19 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 20 * unrestricted use provided that this legend is included on all tape 21 * media and as a part of the software program in whole or part. Users 22 * may copy or modify Sun RPC without charge, but are not authorized 23 * to license or distribute it to anyone else except as part of a product or 24 * program developed by the user. 25 * 26 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 27 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 28 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 29 * 30 * Sun RPC is provided with no support and without any obligation on the 31 * part of Sun Microsystems, Inc. to assist in its use, correction, 32 * modification or enhancement. 33 * 34 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 35 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 36 * OR ANY PART THEREOF. 37 * 38 * In no event will Sun Microsystems, Inc. be liable for any lost revenue 39 * or profits or other special, indirect and consequential damages, even if 40 * Sun has been advised of the possibility of such damages. 41 * 42 * Sun Microsystems, Inc. 43 * 2550 Garcia Avenue 44 * Mountain View, California 94043 45 * 46 * @(#)clnt_generic.c 1.4 87/08/11 (C) 1987 SMI 47 * @(#)clnt_generic.c 2.2 88/08/01 4.0 RPCSRC 48 * @(#)clnt_generic.c 1.40 99/04/21 SMI 49 * $NetBSD: clnt_generic.c,v 1.18 2000/07/06 03:10:34 christos Exp $ 50 * $FreeBSD: src/lib/libc/rpc/clnt_generic.c,v 1.15 2004/10/16 06:11:34 obrien Exp $ 51 * $DragonFly: src/lib/libc/rpc/clnt_generic.c,v 1.4 2005/01/31 22:29:38 dillon Exp $ 52 */ 53 54 /* 55 * Copyright (c) 1986-1996,1998 by Sun Microsystems, Inc. 56 * All rights reserved. 57 */ 58 #include "namespace.h" 59 #include "reentrant.h" 60 #include <sys/types.h> 61 #include <sys/fcntl.h> 62 #include <sys/socket.h> 63 #include <netinet/in.h> 64 #include <netinet/tcp.h> 65 #include <stdio.h> 66 #include <errno.h> 67 #include <netdb.h> 68 #include <syslog.h> 69 #include <rpc/rpc.h> 70 #include <rpc/nettype.h> 71 #include <string.h> 72 #include <stdlib.h> 73 #include <unistd.h> 74 #include "un-namespace.h" 75 #include "rpc_com.h" 76 77 extern bool_t __rpc_is_local_host(const char *); 78 int __rpc_raise_fd(int); 79 80 #ifndef NETIDLEN 81 #define NETIDLEN 32 82 #endif 83 84 85 /* 86 * Generic client creation with version checking the value of 87 * vers_out is set to the highest server supported value 88 * vers_low <= vers_out <= vers_high AND an error results 89 * if this can not be done. 90 * 91 * It calls clnt_create_vers_timed() with a NULL value for the timeout 92 * pointer, which indicates that the default timeout should be used. 93 */ 94 CLIENT * 95 clnt_create_vers(const char *hostname, rpcprog_t prog, rpcvers_t *vers_out, 96 rpcvers_t vers_low, rpcvers_t vers_high, const char *nettype) 97 { 98 99 return (clnt_create_vers_timed(hostname, prog, vers_out, vers_low, 100 vers_high, nettype, NULL)); 101 } 102 103 /* 104 * This the routine has the same definition as clnt_create_vers(), 105 * except it takes an additional timeout parameter - a pointer to 106 * a timeval structure. A NULL value for the pointer indicates 107 * that the default timeout value should be used. 108 */ 109 CLIENT * 110 clnt_create_vers_timed(const char *hostname, rpcprog_t prog, 111 rpcvers_t *vers_out, rpcvers_t vers_low, rpcvers_t vers_high, 112 const char *nettype, const struct timeval *tp) 113 { 114 CLIENT *clnt; 115 struct timeval to; 116 enum clnt_stat rpc_stat; 117 struct rpc_err rpcerr; 118 119 clnt = clnt_create_timed(hostname, prog, vers_high, nettype, tp); 120 if (clnt == NULL) { 121 return (NULL); 122 } 123 to.tv_sec = 10; 124 to.tv_usec = 0; 125 rpc_stat = clnt_call(clnt, NULLPROC, (xdrproc_t)xdr_void, 126 NULL, (xdrproc_t)xdr_void, NULL, to); 127 if (rpc_stat == RPC_SUCCESS) { 128 *vers_out = vers_high; 129 return (clnt); 130 } 131 while (rpc_stat == RPC_PROGVERSMISMATCH && vers_high > vers_low) { 132 unsigned int minvers, maxvers; 133 134 clnt_geterr(clnt, &rpcerr); 135 minvers = rpcerr.re_vers.low; 136 maxvers = rpcerr.re_vers.high; 137 if (maxvers < vers_high) 138 vers_high = maxvers; 139 else 140 vers_high--; 141 if (minvers > vers_low) 142 vers_low = minvers; 143 if (vers_low > vers_high) { 144 goto error; 145 } 146 CLNT_CONTROL(clnt, CLSET_VERS, (char *)&vers_high); 147 rpc_stat = clnt_call(clnt, NULLPROC, (xdrproc_t)xdr_void, 148 NULL, (xdrproc_t)xdr_void, 149 NULL, to); 150 if (rpc_stat == RPC_SUCCESS) { 151 *vers_out = vers_high; 152 return (clnt); 153 } 154 } 155 clnt_geterr(clnt, &rpcerr); 156 157 error: 158 rpc_createerr.cf_stat = rpc_stat; 159 rpc_createerr.cf_error = rpcerr; 160 clnt_destroy(clnt); 161 return (NULL); 162 } 163 164 /* 165 * Top level client creation routine. 166 * Generic client creation: takes (servers name, program-number, nettype) and 167 * returns client handle. Default options are set, which the user can 168 * change using the rpc equivalent of _ioctl()'s. 169 * 170 * It tries for all the netids in that particular class of netid until 171 * it succeeds. 172 * XXX The error message in the case of failure will be the one 173 * pertaining to the last create error. 174 * 175 * It calls clnt_create_timed() with the default timeout. 176 */ 177 CLIENT * 178 clnt_create(const char *hostname, rpcprog_t prog, rpcvers_t vers, 179 const char *nettype) 180 { 181 182 return (clnt_create_timed(hostname, prog, vers, nettype, NULL)); 183 } 184 185 /* 186 * This the routine has the same definition as clnt_create(), 187 * except it takes an additional timeout parameter - a pointer to 188 * a timeval structure. A NULL value for the pointer indicates 189 * that the default timeout value should be used. 190 * 191 * This function calls clnt_tp_create_timed(). 192 */ 193 CLIENT * 194 clnt_create_timed(const char *hostname, rpcprog_t prog, rpcvers_t vers, 195 const char *netclass, const struct timeval *tp) 196 { 197 struct netconfig *nconf; 198 CLIENT *clnt = NULL; 199 void *handle; 200 enum clnt_stat save_cf_stat = RPC_SUCCESS; 201 struct rpc_err save_cf_error; 202 char nettype_array[NETIDLEN]; 203 char *nettype = &nettype_array[0]; 204 205 if (netclass == NULL) 206 nettype = NULL; 207 else { 208 size_t len = strlen(netclass); 209 if (len >= sizeof (nettype_array)) { 210 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 211 return (NULL); 212 } 213 strcpy(nettype, netclass); 214 } 215 216 if ((handle = __rpc_setconf((char *)nettype)) == NULL) { 217 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 218 return (NULL); 219 } 220 rpc_createerr.cf_stat = RPC_SUCCESS; 221 while (clnt == NULL) { 222 if ((nconf = __rpc_getconf(handle)) == NULL) { 223 if (rpc_createerr.cf_stat == RPC_SUCCESS) 224 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 225 break; 226 } 227 #ifdef CLNT_DEBUG 228 printf("trying netid %s\n", nconf->nc_netid); 229 #endif 230 clnt = clnt_tp_create_timed(hostname, prog, vers, nconf, tp); 231 if (clnt) 232 break; 233 else 234 /* 235 * Since we didn't get a name-to-address 236 * translation failure here, we remember 237 * this particular error. The object of 238 * this is to enable us to return to the 239 * caller a more-specific error than the 240 * unhelpful ``Name to address translation 241 * failed'' which might well occur if we 242 * merely returned the last error (because 243 * the local loopbacks are typically the 244 * last ones in /etc/netconfig and the most 245 * likely to be unable to translate a host 246 * name). We also check for a more 247 * meaningful error than ``unknown host 248 * name'' for the same reasons. 249 */ 250 if (rpc_createerr.cf_stat != RPC_N2AXLATEFAILURE && 251 rpc_createerr.cf_stat != RPC_UNKNOWNHOST) { 252 save_cf_stat = rpc_createerr.cf_stat; 253 save_cf_error = rpc_createerr.cf_error; 254 } 255 } 256 257 /* 258 * Attempt to return an error more specific than ``Name to address 259 * translation failed'' or ``unknown host name'' 260 */ 261 if ((rpc_createerr.cf_stat == RPC_N2AXLATEFAILURE || 262 rpc_createerr.cf_stat == RPC_UNKNOWNHOST) && 263 (save_cf_stat != RPC_SUCCESS)) { 264 rpc_createerr.cf_stat = save_cf_stat; 265 rpc_createerr.cf_error = save_cf_error; 266 } 267 __rpc_endconf(handle); 268 return (clnt); 269 } 270 271 /* 272 * Generic client creation: takes (servers name, program-number, netconf) and 273 * returns client handle. Default options are set, which the user can 274 * change using the rpc equivalent of _ioctl()'s : clnt_control() 275 * It finds out the server address from rpcbind and calls clnt_tli_create(). 276 * 277 * It calls clnt_tp_create_timed() with the default timeout. 278 */ 279 CLIENT * 280 clnt_tp_create(const char *hostname, rpcprog_t prog, rpcvers_t vers, 281 const struct netconfig *nconf) 282 { 283 284 return (clnt_tp_create_timed(hostname, prog, vers, nconf, NULL)); 285 } 286 287 /* 288 * This has the same definition as clnt_tp_create(), except it 289 * takes an additional parameter - a pointer to a timeval structure. 290 * A NULL value for the timeout pointer indicates that the default 291 * value for the timeout should be used. 292 */ 293 CLIENT * 294 clnt_tp_create_timed(const char *hostname, rpcprog_t prog, rpcvers_t vers, 295 const struct netconfig *nconf, const struct timeval *tp) 296 { 297 struct netbuf *svcaddr; /* servers address */ 298 CLIENT *cl = NULL; /* client handle */ 299 300 if (nconf == NULL) { 301 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 302 return (NULL); 303 } 304 305 /* 306 * Get the address of the server 307 */ 308 if ((svcaddr = __rpcb_findaddr_timed(prog, vers, 309 (struct netconfig *)nconf, (char *)hostname, 310 &cl, (struct timeval *)tp)) == NULL) { 311 /* appropriate error number is set by rpcbind libraries */ 312 return (NULL); 313 } 314 if (cl == NULL) { 315 cl = clnt_tli_create(RPC_ANYFD, nconf, svcaddr, 316 prog, vers, 0, 0); 317 } else { 318 /* Reuse the CLIENT handle and change the appropriate fields */ 319 if (CLNT_CONTROL(cl, CLSET_SVC_ADDR, (void *)svcaddr) == TRUE) { 320 if (cl->cl_netid == NULL) 321 cl->cl_netid = strdup(nconf->nc_netid); 322 if (cl->cl_tp == NULL) 323 cl->cl_tp = strdup(nconf->nc_device); 324 CLNT_CONTROL(cl, CLSET_PROG, (void *)&prog); 325 CLNT_CONTROL(cl, CLSET_VERS, (void *)&vers); 326 } else { 327 CLNT_DESTROY(cl); 328 cl = clnt_tli_create(RPC_ANYFD, nconf, svcaddr, 329 prog, vers, 0, 0); 330 } 331 } 332 free(svcaddr->buf); 333 free(svcaddr); 334 return (cl); 335 } 336 337 /* 338 * Generic client creation: returns client handle. 339 * Default options are set, which the user can 340 * change using the rpc equivalent of _ioctl()'s : clnt_control(). 341 * If fd is RPC_ANYFD, it will be opened using nconf. 342 * It will be bound if not so. 343 * If sizes are 0; appropriate defaults will be chosen. 344 */ 345 CLIENT * 346 clnt_tli_create(int fd, const struct netconfig *nconf, 347 struct netbuf *svcaddr, rpcprog_t prog, rpcvers_t vers, 348 uint sendsz, uint recvsz) 349 { 350 CLIENT *cl; /* client handle */ 351 bool_t madefd = FALSE; /* whether fd opened here */ 352 long servtype; 353 int one = 1; 354 struct __rpc_sockinfo si; 355 extern int __rpc_minfd; 356 357 if (fd == RPC_ANYFD) { 358 if (nconf == NULL) { 359 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 360 return (NULL); 361 } 362 363 fd = __rpc_nconf2fd(nconf); 364 365 if (fd == -1) 366 goto err; 367 if (fd < __rpc_minfd) 368 fd = __rpc_raise_fd(fd); 369 madefd = TRUE; 370 servtype = nconf->nc_semantics; 371 if (!__rpc_fd2sockinfo(fd, &si)) 372 goto err; 373 bindresvport(fd, NULL); 374 } else { 375 if (!__rpc_fd2sockinfo(fd, &si)) 376 goto err; 377 servtype = __rpc_socktype2seman(si.si_socktype); 378 if (servtype == -1) { 379 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 380 return (NULL); 381 } 382 } 383 384 if (si.si_af != ((struct sockaddr *)svcaddr->buf)->sa_family) { 385 rpc_createerr.cf_stat = RPC_UNKNOWNHOST; /* XXX */ 386 goto err1; 387 } 388 389 switch (servtype) { 390 case NC_TPI_COTS: 391 cl = clnt_vc_create(fd, svcaddr, prog, vers, sendsz, recvsz); 392 break; 393 case NC_TPI_COTS_ORD: 394 if (nconf && ((strcmp(nconf->nc_protofmly, "inet") == 0))) { 395 _setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one, 396 sizeof (one)); 397 } 398 cl = clnt_vc_create(fd, svcaddr, prog, vers, sendsz, recvsz); 399 break; 400 case NC_TPI_CLTS: 401 cl = clnt_dg_create(fd, svcaddr, prog, vers, sendsz, recvsz); 402 break; 403 default: 404 goto err; 405 } 406 407 if (cl == NULL) 408 goto err1; /* borrow errors from clnt_dg/vc creates */ 409 if (nconf) { 410 cl->cl_netid = strdup(nconf->nc_netid); 411 cl->cl_tp = strdup(nconf->nc_device); 412 } else { 413 cl->cl_netid = ""; 414 cl->cl_tp = ""; 415 } 416 if (madefd) { 417 CLNT_CONTROL(cl, CLSET_FD_CLOSE, NULL); 418 /* CLNT_CONTROL(cl, CLSET_POP_TIMOD, NULL); */ 419 }; 420 421 return (cl); 422 423 err: 424 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 425 rpc_createerr.cf_error.re_errno = errno; 426 err1: if (madefd) 427 _close(fd); 428 return (NULL); 429 } 430 431 /* 432 * To avoid conflicts with the "magic" file descriptors (0, 1, and 2), 433 * we try to not use them. The __rpc_raise_fd() routine will dup 434 * a descriptor to a higher value. If we fail to do it, we continue 435 * to use the old one (and hope for the best). 436 */ 437 int __rpc_minfd = 3; 438 439 int 440 __rpc_raise_fd(int fd) 441 { 442 int nfd; 443 444 if (fd >= __rpc_minfd) 445 return (fd); 446 447 if ((nfd = _fcntl(fd, F_DUPFD, __rpc_minfd)) == -1) 448 return (fd); 449 450 if (_fsync(nfd) == -1) { 451 _close(nfd); 452 return (fd); 453 } 454 455 if (_close(fd) == -1) { 456 /* this is okay, we will syslog an error, then use the new fd */ 457 syslog(LOG_ERR, "could not close() fd %d; mem & fd leak", fd); 458 } 459 460 return (nfd); 461 } 462