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 */ 52 53 /* 54 * Copyright (c) 1986-1996,1998 by Sun Microsystems, Inc. 55 * All rights reserved. 56 */ 57 #include "namespace.h" 58 #include "reentrant.h" 59 #include <sys/types.h> 60 #include <sys/fcntl.h> 61 #include <sys/socket.h> 62 #include <netinet/in.h> 63 #include <netinet/tcp.h> 64 #include <stdio.h> 65 #include <errno.h> 66 #include <netdb.h> 67 #include <syslog.h> 68 #include <rpc/rpc.h> 69 #include <rpc/nettype.h> 70 #include <string.h> 71 #include <stdlib.h> 72 #include <unistd.h> 73 #include "un-namespace.h" 74 #include "rpc_com.h" 75 76 extern bool_t __rpc_is_local_host(const char *); 77 int __rpc_raise_fd(int); 78 79 #ifndef NETIDLEN 80 #define NETIDLEN 32 81 #endif 82 83 84 /* 85 * Generic client creation with version checking the value of 86 * vers_out is set to the highest server supported value 87 * vers_low <= vers_out <= vers_high AND an error results 88 * if this can not be done. 89 * 90 * It calls clnt_create_vers_timed() with a NULL value for the timeout 91 * pointer, which indicates that the default timeout should be used. 92 */ 93 CLIENT * 94 clnt_create_vers(const char *hostname, rpcprog_t prog, rpcvers_t *vers_out, 95 rpcvers_t vers_low, rpcvers_t vers_high, const char *nettype) 96 { 97 98 return (clnt_create_vers_timed(hostname, prog, vers_out, vers_low, 99 vers_high, nettype, NULL)); 100 } 101 102 /* 103 * This the routine has the same definition as clnt_create_vers(), 104 * except it takes an additional timeout parameter - a pointer to 105 * a timeval structure. A NULL value for the pointer indicates 106 * that the default timeout value should be used. 107 */ 108 CLIENT * 109 clnt_create_vers_timed(const char *hostname, rpcprog_t prog, 110 rpcvers_t *vers_out, rpcvers_t vers_low, rpcvers_t vers_high, 111 const char *nettype, const struct timeval *tp) 112 { 113 CLIENT *clnt; 114 struct timeval to; 115 enum clnt_stat rpc_stat; 116 struct rpc_err rpcerr; 117 118 clnt = clnt_create_timed(hostname, prog, vers_high, nettype, tp); 119 if (clnt == NULL) { 120 return (NULL); 121 } 122 to.tv_sec = 10; 123 to.tv_usec = 0; 124 rpc_stat = clnt_call(clnt, NULLPROC, (xdrproc_t)xdr_void, 125 NULL, (xdrproc_t)xdr_void, NULL, to); 126 if (rpc_stat == RPC_SUCCESS) { 127 *vers_out = vers_high; 128 return (clnt); 129 } 130 while (rpc_stat == RPC_PROGVERSMISMATCH && vers_high > vers_low) { 131 unsigned int minvers, maxvers; 132 133 clnt_geterr(clnt, &rpcerr); 134 minvers = rpcerr.re_vers.low; 135 maxvers = rpcerr.re_vers.high; 136 if (maxvers < vers_high) 137 vers_high = maxvers; 138 else 139 vers_high--; 140 if (minvers > vers_low) 141 vers_low = minvers; 142 if (vers_low > vers_high) { 143 goto error; 144 } 145 CLNT_CONTROL(clnt, CLSET_VERS, (char *)&vers_high); 146 rpc_stat = clnt_call(clnt, NULLPROC, (xdrproc_t)xdr_void, 147 NULL, (xdrproc_t)xdr_void, 148 NULL, to); 149 if (rpc_stat == RPC_SUCCESS) { 150 *vers_out = vers_high; 151 return (clnt); 152 } 153 } 154 clnt_geterr(clnt, &rpcerr); 155 156 error: 157 rpc_createerr.cf_stat = rpc_stat; 158 rpc_createerr.cf_error = rpcerr; 159 clnt_destroy(clnt); 160 return (NULL); 161 } 162 163 /* 164 * Top level client creation routine. 165 * Generic client creation: takes (servers name, program-number, nettype) and 166 * returns client handle. Default options are set, which the user can 167 * change using the rpc equivalent of _ioctl()'s. 168 * 169 * It tries for all the netids in that particular class of netid until 170 * it succeeds. 171 * XXX The error message in the case of failure will be the one 172 * pertaining to the last create error. 173 * 174 * It calls clnt_create_timed() with the default timeout. 175 */ 176 CLIENT * 177 clnt_create(const char *hostname, rpcprog_t prog, rpcvers_t vers, 178 const char *nettype) 179 { 180 181 return (clnt_create_timed(hostname, prog, vers, nettype, NULL)); 182 } 183 184 /* 185 * This the routine has the same definition as clnt_create(), 186 * except it takes an additional timeout parameter - a pointer to 187 * a timeval structure. A NULL value for the pointer indicates 188 * that the default timeout value should be used. 189 * 190 * This function calls clnt_tp_create_timed(). 191 */ 192 CLIENT * 193 clnt_create_timed(const char *hostname, rpcprog_t prog, rpcvers_t vers, 194 const char *netclass, const struct timeval *tp) 195 { 196 struct netconfig *nconf; 197 CLIENT *clnt = NULL; 198 void *handle; 199 enum clnt_stat save_cf_stat = RPC_SUCCESS; 200 struct rpc_err save_cf_error; 201 char nettype_array[NETIDLEN]; 202 char *nettype = &nettype_array[0]; 203 204 if (netclass == NULL) 205 nettype = NULL; 206 else { 207 size_t len = strlen(netclass); 208 if (len >= sizeof (nettype_array)) { 209 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 210 return (NULL); 211 } 212 strcpy(nettype, netclass); 213 } 214 215 if ((handle = __rpc_setconf((char *)nettype)) == NULL) { 216 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 217 return (NULL); 218 } 219 rpc_createerr.cf_stat = RPC_SUCCESS; 220 while (clnt == NULL) { 221 if ((nconf = __rpc_getconf(handle)) == NULL) { 222 if (rpc_createerr.cf_stat == RPC_SUCCESS) 223 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 224 break; 225 } 226 #ifdef CLNT_DEBUG 227 printf("trying netid %s\n", nconf->nc_netid); 228 #endif 229 clnt = clnt_tp_create_timed(hostname, prog, vers, nconf, tp); 230 if (clnt) 231 break; 232 else 233 /* 234 * Since we didn't get a name-to-address 235 * translation failure here, we remember 236 * this particular error. The object of 237 * this is to enable us to return to the 238 * caller a more-specific error than the 239 * unhelpful ``Name to address translation 240 * failed'' which might well occur if we 241 * merely returned the last error (because 242 * the local loopbacks are typically the 243 * last ones in /etc/netconfig and the most 244 * likely to be unable to translate a host 245 * name). We also check for a more 246 * meaningful error than ``unknown host 247 * name'' for the same reasons. 248 */ 249 if (rpc_createerr.cf_stat != RPC_N2AXLATEFAILURE && 250 rpc_createerr.cf_stat != RPC_UNKNOWNHOST) { 251 save_cf_stat = rpc_createerr.cf_stat; 252 save_cf_error = rpc_createerr.cf_error; 253 } 254 } 255 256 /* 257 * Attempt to return an error more specific than ``Name to address 258 * translation failed'' or ``unknown host name'' 259 */ 260 if ((rpc_createerr.cf_stat == RPC_N2AXLATEFAILURE || 261 rpc_createerr.cf_stat == RPC_UNKNOWNHOST) && 262 (save_cf_stat != RPC_SUCCESS)) { 263 rpc_createerr.cf_stat = save_cf_stat; 264 rpc_createerr.cf_error = save_cf_error; 265 } 266 __rpc_endconf(handle); 267 return (clnt); 268 } 269 270 /* 271 * Generic client creation: takes (servers name, program-number, netconf) and 272 * returns client handle. Default options are set, which the user can 273 * change using the rpc equivalent of _ioctl()'s : clnt_control() 274 * It finds out the server address from rpcbind and calls clnt_tli_create(). 275 * 276 * It calls clnt_tp_create_timed() with the default timeout. 277 */ 278 CLIENT * 279 clnt_tp_create(const char *hostname, rpcprog_t prog, rpcvers_t vers, 280 const struct netconfig *nconf) 281 { 282 283 return (clnt_tp_create_timed(hostname, prog, vers, nconf, NULL)); 284 } 285 286 /* 287 * This has the same definition as clnt_tp_create(), except it 288 * takes an additional parameter - a pointer to a timeval structure. 289 * A NULL value for the timeout pointer indicates that the default 290 * value for the timeout should be used. 291 */ 292 CLIENT * 293 clnt_tp_create_timed(const char *hostname, rpcprog_t prog, rpcvers_t vers, 294 const struct netconfig *nconf, const struct timeval *tp) 295 { 296 struct netbuf *svcaddr; /* servers address */ 297 CLIENT *cl = NULL; /* client handle */ 298 299 if (nconf == NULL) { 300 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 301 return (NULL); 302 } 303 304 /* 305 * Get the address of the server 306 */ 307 if ((svcaddr = __rpcb_findaddr_timed(prog, vers, 308 (struct netconfig *)nconf, (char *)hostname, 309 &cl, (struct timeval *)tp)) == NULL) { 310 /* appropriate error number is set by rpcbind libraries */ 311 return (NULL); 312 } 313 if (cl == NULL) { 314 cl = clnt_tli_create(RPC_ANYFD, nconf, svcaddr, 315 prog, vers, 0, 0); 316 } else { 317 /* Reuse the CLIENT handle and change the appropriate fields */ 318 if (CLNT_CONTROL(cl, CLSET_SVC_ADDR, (void *)svcaddr) == TRUE) { 319 if (cl->cl_netid == NULL) 320 cl->cl_netid = strdup(nconf->nc_netid); 321 if (cl->cl_tp == NULL) 322 cl->cl_tp = strdup(nconf->nc_device); 323 CLNT_CONTROL(cl, CLSET_PROG, (void *)&prog); 324 CLNT_CONTROL(cl, CLSET_VERS, (void *)&vers); 325 } else { 326 CLNT_DESTROY(cl); 327 cl = clnt_tli_create(RPC_ANYFD, nconf, svcaddr, 328 prog, vers, 0, 0); 329 } 330 } 331 free(svcaddr->buf); 332 free(svcaddr); 333 return (cl); 334 } 335 336 /* 337 * Generic client creation: returns client handle. 338 * Default options are set, which the user can 339 * change using the rpc equivalent of _ioctl()'s : clnt_control(). 340 * If fd is RPC_ANYFD, it will be opened using nconf. 341 * It will be bound if not so. 342 * If sizes are 0; appropriate defaults will be chosen. 343 */ 344 CLIENT * 345 clnt_tli_create(int fd, const struct netconfig *nconf, 346 struct netbuf *svcaddr, rpcprog_t prog, rpcvers_t vers, 347 uint sendsz, uint recvsz) 348 { 349 CLIENT *cl; /* client handle */ 350 bool_t madefd = FALSE; /* whether fd opened here */ 351 long servtype; 352 int one = 1; 353 struct __rpc_sockinfo si; 354 extern int __rpc_minfd; 355 356 if (fd == RPC_ANYFD) { 357 if (nconf == NULL) { 358 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 359 return (NULL); 360 } 361 362 fd = __rpc_nconf2fd(nconf); 363 364 if (fd == -1) 365 goto err; 366 if (fd < __rpc_minfd) 367 fd = __rpc_raise_fd(fd); 368 madefd = TRUE; 369 servtype = nconf->nc_semantics; 370 if (!__rpc_fd2sockinfo(fd, &si)) 371 goto err; 372 bindresvport(fd, NULL); 373 } else { 374 if (!__rpc_fd2sockinfo(fd, &si)) 375 goto err; 376 servtype = __rpc_socktype2seman(si.si_socktype); 377 if (servtype == -1) { 378 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 379 return (NULL); 380 } 381 } 382 383 if (si.si_af != ((struct sockaddr *)svcaddr->buf)->sa_family) { 384 rpc_createerr.cf_stat = RPC_UNKNOWNHOST; /* XXX */ 385 goto err1; 386 } 387 388 switch (servtype) { 389 case NC_TPI_COTS: 390 cl = clnt_vc_create(fd, svcaddr, prog, vers, sendsz, recvsz); 391 break; 392 case NC_TPI_COTS_ORD: 393 if (nconf && ((strcmp(nconf->nc_protofmly, "inet") == 0))) { 394 _setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one, 395 sizeof (one)); 396 } 397 cl = clnt_vc_create(fd, svcaddr, prog, vers, sendsz, recvsz); 398 break; 399 case NC_TPI_CLTS: 400 cl = clnt_dg_create(fd, svcaddr, prog, vers, sendsz, recvsz); 401 break; 402 default: 403 goto err; 404 } 405 406 if (cl == NULL) 407 goto err1; /* borrow errors from clnt_dg/vc creates */ 408 if (nconf) { 409 cl->cl_netid = strdup(nconf->nc_netid); 410 cl->cl_tp = strdup(nconf->nc_device); 411 } else { 412 cl->cl_netid = ""; 413 cl->cl_tp = ""; 414 } 415 if (madefd) { 416 CLNT_CONTROL(cl, CLSET_FD_CLOSE, NULL); 417 /* CLNT_CONTROL(cl, CLSET_POP_TIMOD, NULL); */ 418 } 419 420 return (cl); 421 422 err: 423 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 424 rpc_createerr.cf_error.re_errno = errno; 425 err1: if (madefd) 426 _close(fd); 427 return (NULL); 428 } 429 430 /* 431 * To avoid conflicts with the "magic" file descriptors (0, 1, and 2), 432 * we try to not use them. The __rpc_raise_fd() routine will dup 433 * a descriptor to a higher value. If we fail to do it, we continue 434 * to use the old one (and hope for the best). 435 */ 436 int __rpc_minfd = 3; 437 438 int 439 __rpc_raise_fd(int fd) 440 { 441 int nfd; 442 443 if (fd >= __rpc_minfd) 444 return (fd); 445 446 if ((nfd = _fcntl(fd, F_DUPFD, __rpc_minfd)) == -1) 447 return (fd); 448 449 if (_fsync(nfd) == -1) { 450 _close(nfd); 451 return (fd); 452 } 453 454 if (_close(fd) == -1) { 455 /* this is okay, we will syslog an error, then use the new fd */ 456 syslog(LOG_ERR, "could not close() fd %d; mem & fd leak", fd); 457 } 458 459 return (nfd); 460 } 461