1 /* 2 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 3 * unrestricted use provided that this legend is included on all tape 4 * media and as a part of the software program in whole or part. Users 5 * may copy or modify Sun RPC without charge, but are not authorized 6 * to license or distribute it to anyone else except as part of a product or 7 * program developed by the user. 8 * 9 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 10 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 11 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 12 * 13 * Sun RPC is provided with no support and without any obligation on the 14 * part of Sun Microsystems, Inc. to assist in its use, correction, 15 * modification or enhancement. 16 * 17 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 18 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 19 * OR ANY PART THEREOF. 20 * 21 * In no event will Sun Microsystems, Inc. be liable for any lost revenue 22 * or profits or other special, indirect and consequential damages, even if 23 * Sun has been advised of the possibility of such damages. 24 * 25 * Sun Microsystems, Inc. 26 * 2550 Garcia Avenue 27 * Mountain View, California 94043 28 */ 29 30 #if defined(LIBC_SCCS) && !defined(lint) 31 static char *rcsid = "$OpenBSD: clnt_tcp.c,v 1.18 2001/09/15 13:51:00 deraadt Exp $"; 32 #endif /* LIBC_SCCS and not lint */ 33 34 /* 35 * clnt_tcp.c, Implements a TCP/IP based, client side RPC. 36 * 37 * Copyright (C) 1984, Sun Microsystems, Inc. 38 * 39 * TCP based RPC supports 'batched calls'. 40 * A sequence of calls may be batched-up in a send buffer. The rpc call 41 * return immediately to the client even though the call was not necessarily 42 * sent. The batching occurs if the results' xdr routine is NULL (0) AND 43 * the rpc timeout value is zero (see clnt.h, rpc). 44 * 45 * Clients should NOT casually batch calls that in fact return results; that is, 46 * the server side should be aware that a call is batched and not produce any 47 * return message. Batched calls that produce many result messages can 48 * deadlock (netlock) the client and the server.... 49 * 50 * Now go hang yourself. 51 */ 52 53 #include <stdio.h> 54 #include <stdlib.h> 55 #include <string.h> 56 #include <unistd.h> 57 #include <rpc/rpc.h> 58 #include <sys/socket.h> 59 #include <netdb.h> 60 #include <errno.h> 61 #include <rpc/pmap_clnt.h> 62 63 #define MCALL_MSG_SIZE 24 64 65 static int readtcp(); 66 static int writetcp(); 67 68 static enum clnt_stat clnttcp_call(CLIENT *, u_long, xdrproc_t, caddr_t, 69 xdrproc_t, caddr_t, struct timeval); 70 static void clnttcp_abort(CLIENT *); 71 static void clnttcp_geterr(CLIENT *, struct rpc_err *); 72 static bool_t clnttcp_freeres(CLIENT *, xdrproc_t, caddr_t); 73 static bool_t clnttcp_control(CLIENT *, u_int, void *); 74 static void clnttcp_destroy(CLIENT *); 75 76 static struct clnt_ops tcp_ops = { 77 clnttcp_call, 78 clnttcp_abort, 79 clnttcp_geterr, 80 clnttcp_freeres, 81 clnttcp_destroy, 82 clnttcp_control 83 }; 84 85 struct ct_data { 86 int ct_sock; 87 bool_t ct_closeit; 88 struct timeval ct_wait; 89 bool_t ct_waitset; /* wait set by clnt_control? */ 90 struct sockaddr_in ct_addr; 91 struct rpc_err ct_error; 92 char ct_mcall[MCALL_MSG_SIZE]; /* marshalled callmsg */ 93 u_int ct_mpos; /* pos after marshal */ 94 XDR ct_xdrs; 95 }; 96 97 /* 98 * Create a client handle for a tcp/ip connection. 99 * If *sockp<0, *sockp is set to a newly created TCP socket and it is 100 * connected to raddr. If *sockp non-negative then 101 * raddr is ignored. The rpc/tcp package does buffering 102 * similar to stdio, so the client must pick send and receive buffer sizes,]; 103 * 0 => use the default. 104 * If raddr->sin_port is 0, then a binder on the remote machine is 105 * consulted for the right port number. 106 * NB: *sockp is copied into a private area. 107 * NB: It is the clients responsibility to close *sockp. 108 * NB: The rpch->cl_auth is set null authentication. Caller may wish to set this 109 * something more useful. 110 */ 111 CLIENT * 112 clnttcp_create(raddr, prog, vers, sockp, sendsz, recvsz) 113 struct sockaddr_in *raddr; 114 u_long prog; 115 u_long vers; 116 int *sockp; 117 u_int sendsz; 118 u_int recvsz; 119 { 120 CLIENT *h; 121 struct ct_data *ct = NULL; 122 struct timeval now; 123 struct rpc_msg call_msg; 124 125 h = (CLIENT *)mem_alloc(sizeof(*h)); 126 if (h == NULL) { 127 (void)fprintf(stderr, "clnttcp_create: out of memory\n"); 128 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 129 rpc_createerr.cf_error.re_errno = errno; 130 goto fooy; 131 } 132 ct = (struct ct_data *)mem_alloc(sizeof(*ct)); 133 if (ct == NULL) { 134 (void)fprintf(stderr, "clnttcp_create: out of memory\n"); 135 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 136 rpc_createerr.cf_error.re_errno = errno; 137 goto fooy; 138 } 139 140 /* 141 * If no port number given ask the pmap for one 142 */ 143 if (raddr->sin_port == 0) { 144 u_short port; 145 if ((port = pmap_getport(raddr, prog, vers, IPPROTO_TCP)) == 0) { 146 mem_free((caddr_t)ct, sizeof(struct ct_data)); 147 mem_free((caddr_t)h, sizeof(CLIENT)); 148 return ((CLIENT *)NULL); 149 } 150 raddr->sin_port = htons(port); 151 } 152 153 /* 154 * If no socket given, open one 155 */ 156 if (*sockp < 0) { 157 *sockp = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 158 (void)bindresvport(*sockp, (struct sockaddr_in *)0); 159 if ((*sockp < 0) 160 || (connect(*sockp, (struct sockaddr *)raddr, 161 sizeof(*raddr)) < 0)) { 162 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 163 rpc_createerr.cf_error.re_errno = errno; 164 if (*sockp != -1) 165 (void)close(*sockp); 166 goto fooy; 167 } 168 ct->ct_closeit = TRUE; 169 } else { 170 ct->ct_closeit = FALSE; 171 } 172 173 /* 174 * Set up private data struct 175 */ 176 ct->ct_sock = *sockp; 177 ct->ct_wait.tv_usec = 0; 178 ct->ct_waitset = FALSE; 179 ct->ct_addr = *raddr; 180 181 /* 182 * Initialize call message 183 */ 184 (void)gettimeofday(&now, (struct timezone *)0); 185 call_msg.rm_xid = arc4random(); 186 call_msg.rm_direction = CALL; 187 call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; 188 call_msg.rm_call.cb_prog = prog; 189 call_msg.rm_call.cb_vers = vers; 190 191 /* 192 * pre-serialize the staic part of the call msg and stash it away 193 */ 194 xdrmem_create(&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE, 195 XDR_ENCODE); 196 if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) { 197 if (ct->ct_closeit) { 198 (void)close(*sockp); 199 } 200 goto fooy; 201 } 202 ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs)); 203 XDR_DESTROY(&(ct->ct_xdrs)); 204 205 /* 206 * Create a client handle which uses xdrrec for serialization 207 * and authnone for authentication. 208 */ 209 xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz, 210 (caddr_t)ct, readtcp, writetcp); 211 h->cl_ops = &tcp_ops; 212 h->cl_private = (caddr_t) ct; 213 h->cl_auth = authnone_create(); 214 return (h); 215 216 fooy: 217 /* 218 * Something goofed, free stuff and barf 219 */ 220 if (ct) 221 mem_free((caddr_t)ct, sizeof(struct ct_data)); 222 if (h) 223 mem_free((caddr_t)h, sizeof(CLIENT)); 224 return ((CLIENT *)NULL); 225 } 226 227 static enum clnt_stat 228 clnttcp_call(h, proc, xdr_args, args_ptr, xdr_results, results_ptr, timeout) 229 CLIENT *h; 230 u_long proc; 231 xdrproc_t xdr_args; 232 caddr_t args_ptr; 233 xdrproc_t xdr_results; 234 caddr_t results_ptr; 235 struct timeval timeout; 236 { 237 struct ct_data *ct = (struct ct_data *) h->cl_private; 238 XDR *xdrs = &(ct->ct_xdrs); 239 struct rpc_msg reply_msg; 240 u_long x_id; 241 u_int32_t *msg_x_id = (u_int32_t *)(ct->ct_mcall); /* yuk */ 242 bool_t shipnow; 243 int refreshes = 2; 244 245 if (!ct->ct_waitset) { 246 ct->ct_wait = timeout; 247 } 248 249 shipnow = 250 (xdr_results == (xdrproc_t)0 && timeout.tv_sec == 0 251 && timeout.tv_usec == 0) ? FALSE : TRUE; 252 253 call_again: 254 xdrs->x_op = XDR_ENCODE; 255 ct->ct_error.re_status = RPC_SUCCESS; 256 x_id = ntohl(--(*msg_x_id)); 257 if ((! XDR_PUTBYTES(xdrs, ct->ct_mcall, ct->ct_mpos)) || 258 (! XDR_PUTLONG(xdrs, (long *)&proc)) || 259 (! AUTH_MARSHALL(h->cl_auth, xdrs)) || 260 (! (*xdr_args)(xdrs, args_ptr))) { 261 if (ct->ct_error.re_status == RPC_SUCCESS) 262 ct->ct_error.re_status = RPC_CANTENCODEARGS; 263 (void)xdrrec_endofrecord(xdrs, TRUE); 264 return (ct->ct_error.re_status); 265 } 266 if (! xdrrec_endofrecord(xdrs, shipnow)) 267 return (ct->ct_error.re_status = RPC_CANTSEND); 268 if (! shipnow) 269 return (RPC_SUCCESS); 270 /* 271 * Hack to provide rpc-based message passing 272 */ 273 if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { 274 return(ct->ct_error.re_status = RPC_TIMEDOUT); 275 } 276 277 278 /* 279 * Keep receiving until we get a valid transaction id 280 */ 281 xdrs->x_op = XDR_DECODE; 282 while (TRUE) { 283 reply_msg.acpted_rply.ar_verf = _null_auth; 284 reply_msg.acpted_rply.ar_results.where = NULL; 285 reply_msg.acpted_rply.ar_results.proc = xdr_void; 286 if (! xdrrec_skiprecord(xdrs)) 287 return (ct->ct_error.re_status); 288 /* now decode and validate the response header */ 289 if (! xdr_replymsg(xdrs, &reply_msg)) { 290 if (ct->ct_error.re_status == RPC_SUCCESS) 291 continue; 292 return (ct->ct_error.re_status); 293 } 294 if (reply_msg.rm_xid == x_id) 295 break; 296 } 297 298 /* 299 * process header 300 */ 301 _seterr_reply(&reply_msg, &(ct->ct_error)); 302 if (ct->ct_error.re_status == RPC_SUCCESS) { 303 if (! AUTH_VALIDATE(h->cl_auth, &reply_msg.acpted_rply.ar_verf)) { 304 ct->ct_error.re_status = RPC_AUTHERROR; 305 ct->ct_error.re_why = AUTH_INVALIDRESP; 306 } else if (! (*xdr_results)(xdrs, results_ptr)) { 307 if (ct->ct_error.re_status == RPC_SUCCESS) 308 ct->ct_error.re_status = RPC_CANTDECODERES; 309 } 310 /* free verifier ... */ 311 if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { 312 xdrs->x_op = XDR_FREE; 313 (void)xdr_opaque_auth(xdrs, &(reply_msg.acpted_rply.ar_verf)); 314 } 315 } /* end successful completion */ 316 else { 317 /* maybe our credentials need to be refreshed ... */ 318 if (refreshes-- && AUTH_REFRESH(h->cl_auth)) 319 goto call_again; 320 } /* end of unsuccessful completion */ 321 return (ct->ct_error.re_status); 322 } 323 324 static void 325 clnttcp_geterr(h, errp) 326 CLIENT *h; 327 struct rpc_err *errp; 328 { 329 struct ct_data *ct = 330 (struct ct_data *) h->cl_private; 331 332 *errp = ct->ct_error; 333 } 334 335 static bool_t 336 clnttcp_freeres(cl, xdr_res, res_ptr) 337 CLIENT *cl; 338 xdrproc_t xdr_res; 339 caddr_t res_ptr; 340 { 341 struct ct_data *ct = (struct ct_data *)cl->cl_private; 342 XDR *xdrs = &(ct->ct_xdrs); 343 344 xdrs->x_op = XDR_FREE; 345 return ((*xdr_res)(xdrs, res_ptr)); 346 } 347 348 static void 349 clnttcp_abort(CLIENT *clnt) 350 { 351 } 352 353 static bool_t 354 clnttcp_control(cl, request, info) 355 CLIENT *cl; 356 u_int request; 357 void *info; 358 { 359 struct ct_data *ct = (struct ct_data *)cl->cl_private; 360 361 switch (request) { 362 case CLSET_TIMEOUT: 363 ct->ct_wait = *(struct timeval *)info; 364 ct->ct_waitset = TRUE; 365 break; 366 case CLGET_TIMEOUT: 367 *(struct timeval *)info = ct->ct_wait; 368 break; 369 case CLGET_SERVER_ADDR: 370 *(struct sockaddr_in *)info = ct->ct_addr; 371 break; 372 default: 373 return (FALSE); 374 } 375 return (TRUE); 376 } 377 378 379 static void 380 clnttcp_destroy(h) 381 CLIENT *h; 382 { 383 struct ct_data *ct = 384 (struct ct_data *) h->cl_private; 385 386 if (ct->ct_closeit) { 387 (void)close(ct->ct_sock); 388 } 389 XDR_DESTROY(&(ct->ct_xdrs)); 390 mem_free((caddr_t)ct, sizeof(struct ct_data)); 391 mem_free((caddr_t)h, sizeof(CLIENT)); 392 } 393 394 /* 395 * Interface between xdr serializer and tcp connection. 396 * Behaves like the system calls, read & write, but keeps some error state 397 * around for the rpc level. 398 */ 399 static int 400 readtcp(ct, buf, len) 401 struct ct_data *ct; 402 caddr_t buf; 403 int len; 404 { 405 fd_set *fds, readfds; 406 struct timeval start, after, duration, delta, tmp; 407 int r, save_errno; 408 409 if (len == 0) 410 return (0); 411 412 if (ct->ct_sock+1 > FD_SETSIZE) { 413 int bytes = howmany(ct->ct_sock+1, NFDBITS) * sizeof(fd_mask); 414 fds = (fd_set *)malloc(bytes); 415 if (fds == NULL) 416 return (-1); 417 memset(fds, 0, bytes); 418 } else { 419 fds = &readfds; 420 FD_ZERO(fds); 421 } 422 423 gettimeofday(&start, NULL); 424 delta = ct->ct_wait; 425 while (TRUE) { 426 /* XXX we know the other bits are still clear */ 427 FD_SET(ct->ct_sock, fds); 428 r = select(ct->ct_sock+1, fds, NULL, NULL, &delta); 429 save_errno = errno; 430 431 gettimeofday(&after, NULL); 432 timersub(&start, &after, &duration); 433 timersub(&ct->ct_wait, &duration, &tmp); 434 delta = tmp; 435 if (delta.tv_sec < 0 || !timerisset(&delta)) 436 r = 0; 437 438 switch (r) { 439 case 0: 440 ct->ct_error.re_status = RPC_TIMEDOUT; 441 if (fds != &readfds) 442 free(fds); 443 return (-1); 444 case -1: 445 if (errno == EINTR) 446 continue; 447 ct->ct_error.re_status = RPC_CANTRECV; 448 ct->ct_error.re_errno = save_errno; 449 if (fds != &readfds) 450 free(fds); 451 return (-1); 452 } 453 break; 454 } 455 if (fds != &readfds) 456 free(fds); 457 458 switch (len = read(ct->ct_sock, buf, len)) { 459 case 0: 460 /* premature eof */ 461 ct->ct_error.re_errno = ECONNRESET; 462 ct->ct_error.re_status = RPC_CANTRECV; 463 len = -1; /* it's really an error */ 464 break; 465 case -1: 466 ct->ct_error.re_errno = errno; 467 ct->ct_error.re_status = RPC_CANTRECV; 468 break; 469 } 470 return (len); 471 } 472 473 static int 474 writetcp(ct, buf, len) 475 struct ct_data *ct; 476 caddr_t buf; 477 int len; 478 { 479 int i, cnt; 480 481 for (cnt = len; cnt > 0; cnt -= i, buf += i) { 482 if ((i = write(ct->ct_sock, buf, cnt)) == -1) { 483 ct->ct_error.re_errno = errno; 484 ct->ct_error.re_status = RPC_CANTSEND; 485 return (-1); 486 } 487 } 488 return (len); 489 } 490